DEMO
このブラウザは if() に未対応のため、:has() の代わりの指定で色を切り替えています
CODE
<div class="demo-stage cif-stage">
<fieldset class="cif-pick">
<legend class="cif-legend">--variant</legend>
<label class="cif-opt"><input type="radio" name="cif-v" value="primary" checked> primary</label>
<label class="cif-opt"><input type="radio" name="cif-v" value="ghost"> ghost</label>
<label class="cif-opt"><input type="radio" name="cif-v" value="danger"> danger</label>
</fieldset>
<div class="cif-row">
<button type="button" class="cif-btn">保存する</button>
<button type="button" class="cif-btn">共有する</button>
</div>
<p class="cif-note">このブラウザは if() に未対応のため、:has() の代わりの指定で色を切り替えています</p>
</div>
.cif-stage { position:relative; overflow:hidden; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:1.2rem; padding:2rem 1.25rem; background:#0B0B10; min-height:300px; --variant: primary; }
.cif-stage:has(input[value="ghost"]:checked) { --variant: ghost; }
.cif-stage:has(input[value="danger"]:checked) { --variant: danger; }
.cif-pick { display:flex; gap:.4rem; flex-wrap:wrap; justify-content:center; margin:0; padding:0; border:0; }
.cif-legend { width:100%; margin-bottom:.4rem; color:#A1A1AA; font-size:.75rem; font-family:ui-monospace,monospace; text-align:center; }
.cif-opt { display:inline-flex; align-items:center; gap:.35rem; min-height:44px; padding:0 .9rem; border-radius:999px; border:1px solid rgba(255,255,255,.2); color:#EDEDED; font-size:.8rem; font-family:ui-monospace,monospace; cursor:pointer; }
.cif-opt:has(:checked) { border-color:#F472B6; color:#F9A8D4; }
.cif-opt:has(:focus-visible) { outline:2px solid #fff; outline-offset:2px; }
.cif-opt input { accent-color:#D1177A; margin:0; }
.cif-row { display:flex; gap:.7rem; flex-wrap:wrap; justify-content:center; }
.cif-btn { min-height:44px; padding:.6rem 1.2rem; border-radius:10px; border:1px solid transparent; font:inherit; font-weight:600; font-size:.9rem; cursor:pointer;
/* if() 未対応のブラウザ向けの既定値(primary) */
background-color:#D1177A; color:#fff;
transition: background-color .35s, color .35s, border-color .35s, padding .35s, scale .15s; }
.cif-btn:active { scale:.97; }
.cif-btn:focus-visible { outline:2px solid #fff; outline-offset:3px; }
.cif-note { margin:0; color:#FCD34D; font-size:.76rem; text-align:center; }
@supports (color: if(else: red)) {
.cif-note { display:none; }
.cif-btn {
background-color: if(style(--variant: ghost): transparent; style(--variant: danger): #B91C1C; else: #D1177A);
color: if(style(--variant: ghost): #F9A8D4; else: #fff);
border-color: if(style(--variant: ghost): rgb(249 168 212 / .6); else: transparent);
padding: if(media(pointer: coarse): .8rem 1.5rem; else: .6rem 1.2rem);
}
}
@supports not (color: if(else: red)) {
.cif-stage:has(input[value="ghost"]:checked) .cif-btn { background-color:transparent; color:#F9A8D4; border-color:rgb(249 168 212 / .6); }
.cif-stage:has(input[value="danger"]:checked) .cif-btn { background-color:#B91C1C; }
}
@media (prefers-reduced-motion: reduce) {
.cif-btn { transition:none; }
}
AI PROMPT
CSS の if() 関数で、--variant という変数を primary・ghost・danger に変えるだけでボタンの見た目が切り替わるデモを作って。親の枠に --variant: primary を置き、:has(input[value="ghost"]:checked) のように3つのラジオボタン(fieldset と legend で囲み、各ラベルは高さ44px 以上)の選択で --variant を書き換える。ボタンには if() 未対応ブラウザ向けの既定値(背景 #D1177A・白文字)を先に書き、@supports (color: if(else: red)) の中で background-color: if(style(--variant: ghost): transparent; style(--variant: danger): #B91C1C; else: #D1177A)、color・border-color も同じように if() と style() で分け、padding は if(media(pointer: coarse): 大きめ; else: 通常) でタッチ操作の画面だけ広げる(else を必ず書く。無いと条件に合わない時に無効な値になり、継承されないプロパティは初期値・継承されるプロパティは親の値になる)。background-color・color・border-color・padding に 0.35秒の transition を付け、切り替えた時に色がふわっと変わるようにする。@supports not (color: if(else: red)) の中には :has() で同じ色を直接当てる代わりの指定を書き、未対応ブラウザ向けの注記は対応ブラウザでは消す。prefers-reduced-motion: reduce の時は transition を無効化する。 Acceptance criteria: works with prefers-reduced-motion (animation disabled), zero console errors, zero layout shift
AIエージェントでの実装ガイド → Claude Code でWebアニメーションを実装する
BOOKS · PR · AMAZON
※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。
学びを止めない · AMAZONサブスク
※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。
CREATOR TOOLS · スクール(PR)
※本サイトはアフィリエイトリンクを含みます。リンク経由のご購入・お申し込みで運営者が紹介料を受け取る場合があります。
if() は、条件に応じてプロパティの値を切り替える CSS の関数です。MDN では、条件にスタイルクエリ(style())、メディアクエリ(media())、機能クエリ(supports())を使えると説明されています。style(--variant: danger) のように書くと、その要素の変数の値で分岐できるので、1つのルールの中でボタンの種類ごとの色をまとめて書けます。
当サイトの Pulsating Button は外側に波紋が広がり続けるボタン、Tailwind Gradient Button はグラデーションの背景が光る CTA ボタン、Morphing Blob Button は角の丸みがゆらぐブロブ形状のボタンです。本ページはボタンの動きではなく、種類の違いを変数1つで切り替える書き方の別テーマです。
これまでボタンの種類は .btn-primary や .btn-danger のように class を増やし、それぞれに色を書き分けていました。if() を使うと部品の側は1つのルールのまま、使う側は変数を1つ書き換えるだけになります。対応が Chromium 系だけのうちは、既定の見た目を先に書き、その上に @supports で足す形にしておくと、未対応のブラウザでも見た目が崩れません。
if() が使えないブラウザではどうなりますか?
MDN の互換性データ(browser-compat-data 2026-09-24 版)では、if() は Chrome・Edge 137 から使え、Firefox と Safari は未対応で、仕様も実験的な扱いです。MDN にも「if() は自然に劣化しないので、未対応のブラウザ向けの代わりの値を明示する必要がある」とあります。本実装は既定の見た目を先に書き、if() は @supports (color: if(else: red)) の中だけで使い、未対応のブラウザには :has() で同じ色を当てています。
else を書き忘れるとどうなりますか?
MDN の説明では、どの条件にも当てはまらず else も無い時、if() は無効な値を返します。その場合、background-color や padding のように継承されないプロパティは初期値(透明・0)に、color のように継承されるプロパティは親の値になり、どちらも意図した値にはなりません。最後に else で既定の値を必ず書いておきます。
コードは無料で使えますか?
はい。Motion LabのコードスニペットとAIプロンプトは、クレジット表記なしで自由に使えます。コピーしてそのままプロジェクトに利用できます。