はじめに:select要素のデザイン制限がついに解放
ウェブフォームで最も基本的なUI要素の一つである<select>は、長らく「スタイリングがほぼ不可能な要素」として知られてきました。ブラウザごとに異なるデフォルトのドロップダウンデザインを無理やり変えようとすると、JavaScriptでカスタムドロップダウンを一から作る必要がありました。しかし、今やCSSだけでselectの外観、ドロップダウンの位置、option内部のレイアウトまで完全に制御できる時代が来ました。
この記事では、以下の3つの実践デモを通じてカスタマイズ可能なselectの核心技術を習得します。
- フォルダスタック – オプションを曲線状に積み上げるアニメーション
- カードデッキ – 扇状に広がるカードピッカー
- 円形絵文字ピッカー – 三角関数で配置する放射状選択UI
注意: この機能は現在Chromiumベースのブラウザ(Chrome、Edgeなど)でのみ動作します。FirefoxやSafariでは通常のselectにフォールバックするため、プログレッシブエンハンスメントの観点で導入しましょう。
関連記事:フレームワーク依存からの脱却 2025年Web開発の未来を見たカンファレンスレポート

デモ1:曲線状に積み重なるフォルダスタック
ステップ1:基本HTMLマークアップ
各optionに<span>を入れ、選択された項目のテキストスタイリングを個別に行えるようにします。
<select>
<option><span>Documents</span></option>
<option><span>Photos</span></option>
<option><span>Music</span></option>
<option><span>Videos</span></option>
<option><span>Downloads</span></option>
<option><span>Desktop</span></option>
<option><span>Projects</span></option>
<option><span>Backups</span></option>
<option><span>Trash</span></option>
</select>
ステップ2:カスタムselectの有効化(appearance: base-select)
select,
::picker(select) {
appearance: base-select;
}
appearance: base-selectの1行で、selectのボタン、ドロップダウン、optionすべてのスタイリング権限を取得します。
ステップ3:ボタンスタイリング&pickerアイコン非表示
select {
background: linear-gradient(
135deg,
rgba(40, 40, 50, 0.4) 0%,
rgba(60, 60, 70, 0.25) 50%,
rgba(50, 50, 60, 0.35) 100%
);
backdrop-filter: blur(12px) saturate(180%);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.2),
inset 0 1px 1px rgba(255, 255, 255, 0.15),
inset 0 -1px 1px rgba(0, 0, 0, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: white;
min-inline-size: 12rem;
}
select::picker-icon {
display: none;
}
ステップ4:ドロップダウンコンテナを透明に
::picker(select) {
background: transparent;
border: none;
box-shadow: none;
overflow: visible;
}
これで各optionがドロップダウン領域の外に自由に配置できるようになります。
ステップ5:チェックマークとoptionの装飾
option::checkmark {
content: "●";
color: #222;
}
option::before {
content: "📁";
margin-right: 0.5rem;
}
ステップ6:sibling-index()で曲線効果を実現
option {
--rotation-offset: -4deg;
rotate: 0deg;
transition: rotate 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
transition-delay: calc((sibling-index() - 1) * 0.01s);
transform-origin: right calc(sibling-index() * -1.5rem);
}
select:open option {
rotate: calc(sibling-index() * -1 * var(--rotation-offset));
}
@starting-style {
select:open option {
rotate: 0deg;
}
}
sibling-index()はoptionの兄弟インデックスを返す新しいCSS関数です。まだすべてのブラウザでサポートされていないため、使用前にCan I Useで確認してください。
これでselectを開くとフォルダが1つずつ曲線状に広がるアニメーションが実現します!

デモ2:扇状に広がるカードデッキ
核心アイデア:sibling-count()で中央基準の回転
option {
--card-fan-rotation: 7deg;
--card-fan-spread: -11vmin;
--option-index: calc(sibling-index() - 1);
--center: calc(sibling-count() / 2);
--offset-from-center: calc(var(--option-index) - var(--center));
rotate: calc(var(--offset-from-center) * var(--card-fan-rotation));
translate: calc(var(--offset-from-center) * var(--card-fan-spread)) 0;
transform-origin: center 75vmin;
}
@propertyを活用したアニメーション
@property --card-fan-rotation {
syntax: '<angle>';
inherits: false;
initial-value: 7deg;
}
option {
--card-fan-rotation: 0deg;
transition: --card-fan-rotation 0.2s ease-out;
}
select:open option {
--card-fan-rotation: initial;
}
@starting-style {
select:open option {
--card-fan-rotation: 0deg;
}
}
デモ3:円形絵文字ピッカー
ドロップダウンの位置をボタン中心に変更
::picker(select) {
top: calc(anchor(top) - var(--radius));
left: calc(anchor(left) - var(--radius));
width: calc(var(--radius) * 2 + var(--option-size));
height: calc(var(--radius) * 2 + var(--option-size));
}
三角関数でoptionを配置
option {
position: absolute;
--angle: calc((sibling-index() - 2) * (360deg / (sibling-count() - 1)) - 90deg);
top: 50%;
left: 50%;
translate:
calc(-50% + cos(var(--angle)) * var(--radius))
calc(-50% + sin(var(--angle)) * var(--radius));
}
CSSのcos()とsin()関数のおかげで、複雑なJavaScript計算なしに円形配置が可能になりました。

実務適用時の注意点
- ブラウザ互換性: この機能はChromiumベースのブラウザ専用です。SafariとFirefoxでは
appearance: base-selectが無視されるため、通常のselectにフォールバックします。必ずプログレッシブエンハンスメント戦略を取ってください。 - アクセシビリティ: カスタマイズされたselectは、デフォルトのselectのアクセシビリティ(キーボードナビゲーション、スクリーンリーダー)をそのまま維持します。ただし、視覚効果が過剰だとユーザビリティを損なう可能性があるため、
prefers-reduced-motionメディアクエリを検討しましょう。 sibling-index()のサポート状況: まだドラフト段階のCSS関数であるため、プロダクションで使用する場合はポリフィルや代替スタイルを準備することをお勧めします。
次のステップとしての学習方向
- CSS Anchor Positioningの公式ドキュメントを読む(
anchor()、position-area) @starting-styleat-ruleのさまざまな活用事例を探る- CSS
@propertyでカスタムプロパティのアニメーションをマスターする
参考資料: この記事の内容はCSS-Tricksの原文を基に再構成しています。
関連記事:React Server Components、DoSおよびソースコード露出の脆弱性に関する注意喚起(CVE-2025-55184等)