No.195
BUTTON CSS

CSS if() Variants

--variant という変数を primary・ghost・danger に変えるだけで、ボタンの背景・文字色・枠線が CSS の if() で切り替わり、色がふわっと変わるデモ。タッチ操作の画面では余白も広げます。

MY COLLECTION RANDOM ↗

DEMO

--variant

このブラウザは if() に未対応のため、:has() の代わりの指定で色を切り替えています

CODE

HTML
<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>
CSS
.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

Claude Code Cursor v0
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

📖 なかしまぁ先生のCSSアニメーション入門 📖 UIデザインの教科書 新版 マルチデバイス時代のインターフェース設計 📖 Fundamentals of Web Animation with GSAP

※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。

学びを止めない · AMAZONサブスク

📚 Kindle Unlimited — 技術書・デザイン書が読み放題。30日無料体験 → 🎧 Audible — 移動中に耳で学ぶオーディオブック。30日無料体験 → 📦 Amazon Prime — Prime Reading・配送特典つき。30日無料体験 → 🎵 Music Unlimited — 作業用BGMに。1億曲が聴き放題・30日無料体験 →

※当サイトはAmazonアソシエイトプログラムの参加者です。リンクから商品をご購入いただくと、当方に紹介料が発生します。

CREATOR TOOLS · スクール(PR)

🎬 Adobe Creative Cloud — After Effects / Photoshop 業界標準ツール → 💻 SkillHacks — プログラミング・動画編集オンラインスクール → 🚀 デイトラ — Web制作スクール・実案件レベルまで習得 →

※本サイトはアフィリエイトリンクを含みます。リンク経由のご購入・お申し込みで運営者が紹介料を受け取る場合があります。

RELATED EFFECTS

↗ MORE
→ PULSATING BUTTON → TAILWIND GRADIENT BUTTON → MORPHING BLOB BUTTON

if()(CSS の条件分岐)とは

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プロンプトは、クレジット表記なしで自由に使えます。コピーしてそのままプロジェクトに利用できます。