DEMO
選択中:テキスト
CODE
<div class="demo-stage csl-stage">
<div class="csl-field">
<label class="csl-label" for="csl-select">エフェクトの種類</label>
<select class="csl-select" id="csl-select">
<button><selectedcontent></selectedcontent></button>
<option value="text"><span class="csl-ic" aria-hidden="true" data-ic="Aa"></span><span class="csl-name">テキスト</span></option>
<option value="scroll"><span class="csl-ic" aria-hidden="true" data-ic="↕"></span><span class="csl-name">スクロール</span></option>
<option value="loading"><span class="csl-ic" aria-hidden="true" data-ic="◌"></span><span class="csl-name">ローディング</span></option>
<option value="modal"><span class="csl-ic" aria-hidden="true" data-ic="▣"></span><span class="csl-name">モーダル</span></option>
</select>
<p class="csl-status" id="csl-status" aria-live="polite">選択中:テキスト</p>
</div>
</div>
.csl-stage { position:relative; overflow:hidden; display:flex; align-items:flex-start; justify-content:center; padding:2.2rem 1.25rem; background:#0B0B10; min-height:340px; }
.csl-field { display:flex; flex-direction:column; gap:.5rem; width:100%; max-width:280px; }
.csl-label { color:#EDEDED; font-size:.82rem; font-weight:600; }
.csl-select { min-height:48px; padding:0 .9rem; border-radius:12px; border:1px solid rgba(255,255,255,.2); background:#16161D; color:#EDEDED; font:inherit; font-size:.9rem; }
.csl-select:focus-visible { outline:2px solid #fff; outline-offset:3px; }
.csl-status { margin:0; color:#A1A1AA; font-size:.78rem; }
/* ここから下は、ブラウザが対応している時だけ有効(未対応なら普通の select のまま) */
@supports (appearance: base-select) {
.csl-select, .csl-select::picker(select) { appearance: base-select; }
.csl-select { display:flex; align-items:center; gap:.6rem; cursor:pointer; transition: border-color .2s; }
.csl-select:open { border-color:#F472B6; }
.csl-select::picker-icon { color:#F472B6; transition: rotate .3s cubic-bezier(.22,1,.36,1); }
.csl-select:open::picker-icon { rotate:180deg; }
.csl-select::picker(select) { margin-top:6px; padding:.35rem; border:1px solid rgba(255,255,255,.14); border-radius:12px; background:#1E1E26; color:#EDEDED;
box-shadow:0 16px 40px rgb(0 0 0 / .5);
opacity:0; translate:0 -6px; transition: opacity .2s, translate .25s cubic-bezier(.22,1,.36,1), overlay .25s allow-discrete, display .25s allow-discrete; }
.csl-select:open::picker(select) { opacity:1; translate:0 0; }
@starting-style { .csl-select:open::picker(select) { opacity:0; translate:0 -6px; } }
.csl-select option { display:flex; align-items:center; gap:.7rem; min-height:44px; padding:0 .7rem; border-radius:8px; font-size:.88rem; cursor:pointer; }
.csl-select option:hover { background:rgba(209,23,122,.22); }
.csl-select option:focus-visible { background:rgba(209,23,122,.22); outline:2px solid #F472B6; outline-offset:-2px; } /* キーボードの現在地は3:1以上の枠で示す */
.csl-select option:checked { font-weight:700; }
.csl-select option::checkmark { order:1; margin-left:auto; color:#F472B6; }
.csl-ic { display:inline-flex; align-items:center; justify-content:center; width:28px; height:28px; border-radius:8px; background:#D1177A; color:#fff; font-size:.72rem; font-weight:700; }
/* アイコンの文字は CSS で出す=未対応ブラウザの普通の select に「Aa」などが混ざらない */
.csl-ic::before { content: attr(data-ic); }
.csl-select selectedcontent { display:flex; align-items:center; gap:.6rem; }
}
@media (prefers-reduced-motion: reduce) {
.csl-select::picker(select), .csl-select::picker-icon { transition:none; }
}
(function(){
var sel = document.getElementById('csl-select');
var status = document.getElementById('csl-status');
if (!sel || !status) return;
sel.addEventListener('change', function(){
var o = sel.options[sel.selectedIndex];
var name = o.querySelector('.csl-name');
status.textContent = '選択中:' + (name ? name.textContent : o.textContent.trim());
});
})();
AI PROMPT
ネイティブの select のまま、選択肢にアイコンを入れて開くメニューをふわっと出す、カスタマイズ可能な select を作って。select の最初の子に <button><selectedcontent></selectedcontent></button> を置き(閉じた select に選んだ option の中身が複製される)、各 option には aria-hidden="true" の小さなアイコンの span(中身は空にして data-ic 属性に記号を入れ、::before の content: attr(data-ic) で表示する=未対応ブラウザの普通の select に記号が混ざらない)と名前の span を入れる。スタイルは全て @supports (appearance: base-select) の中に書き、select と select::picker(select) に appearance: base-select を指定する。select:open で枠の色を変え、::picker-icon(下向き矢印)は開くと rotate:180deg で回す。::picker(select) は opacity:0・translate:0 -6px から :open で opacity:1・translate:0 0 へ、@starting-style で開く瞬間の値を指定し、overlay と display に allow-discrete を付けて閉じる時も消える動きを見せる。option は display:flex・高さ44px 以上にし、キーボードで移動した時の :focus-visible は背景色だけでなく 2px の枠線(背景との差が3:1以上)で示し、:checked は太字、::checkmark は order:1 と margin-left:auto で右端に置く。selectedcontent も flex でアイコンと名前を横に並べる。change イベントで「選択中:名前」を aria-live の欄に表示する(option の中に要素があっても名前の span から文字を取る)。未対応のブラウザでは button や span が無視されて普通の select になることを前提にする。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)
※本サイトはアフィリエイトリンクを含みます。リンク経由のご購入・お申し込みで運営者が紹介料を受け取る場合があります。
カスタマイズ可能な select は、HTML の select 要素のまま、閉じた時のボタン・開いたメニュー・矢印・選択中の印・各選択肢の見た目を CSS で作り変えられる仕組みです。select と ::picker(select) に appearance: base-select を指定すると有効になり、MDN の解説では、開いたメニューを ::picker(select)、矢印を ::picker-icon、選択中の印を ::checkmark で指定し、option の中には画像などの要素も入れられると説明されています。
当サイトの Segmented Control は選択中の背景が弾むように滑る切り替えのタブ、Floating Label Input はフォーカスするとラベルが上へ移動する入力欄、Popover API Menu は popover 属性で JavaScript なしに開閉するポップオーバーです。本ページはフォームの select そのものの見た目を変える別テーマです。
これまで select の見た目を大きく変えるには、div と JavaScript でドロップダウンを作り直すしかなく、キーボード操作や読み上げへの対応が抜けがちでした。select のまま作り変えられるので、国や言語の選択、アイコン付きの種類の選択のように、見た目にこだわりたいフォームの部品に向いています。
未対応のブラウザではどうなりますか?
MDN の説明では、この書き方は未対応のブラウザで従来の select に戻るように作られていて、先頭の button と selectedcontent は無視され、option の中の要素は文字だけが残ります。MDN の互換性データ(browser-compat-data 2026-09-24 版)では、appearance: base-select は Chrome・Edge 135 と Safari 27 から使え、Firefox は 149 以降でもフラグを有効にした時だけです。本実装はスタイルを @supports (appearance: base-select) の中にまとめています。
独自のドロップダウンを JavaScript で作るのと比べて何が違いますか?
select のまま見た目を変えるので、キーボード操作(矢印キー・Enter・Esc)、フォームへの値の送信、読み上げソフトでの読み上げ、スマートフォンでの操作など、select に元からある動きがそのまま使えます。div と JavaScript で作り直すと、これらを全て自分で作る必要があり、抜けがあると使えない人が出ます。
コードは無料で使えますか?
はい。Motion LabのコードスニペットとAIプロンプトは、クレジット表記なしで自由に使えます。コピーしてそのままプロジェクトに利用できます。