
CSSで日付範囲を選択する::nth-child(n of selector)を活用したスマートなUI実装術
Webサイトでホテルの予約や航空券の検索を行う際、カレンダーから「開始日」と「終了日」を選ぶUIは欠かせない要素だ。この「日付範囲の選択」を実装する場合、従来はJavaScriptを駆使して、選択された期間内のすべての要素に特定のクラスを付与する手法が一般的だった。
しかし、最新のCSSセレクタを活用すれば、JavaScriptの役割を最小限に抑えつつ、高度な範囲指定のスタイリングが可能になる。特に「:nth-child(n of selector)」という構文は、複雑な要素選択を劇的に簡素化する力を持っている。
この記事では、CSS-Tricksで紹介された手法を基に、最新のCSSセレクタを組み合わせてスマートな日付範囲セレクターを構築する方法を詳しく解説する。コードの保守性を高め、ブラウザの負荷を軽減する新しい実装アプローチを見ていこう。
:nth-child(n of selector) の基礎知識

まず、今回の実装の核となる「:nth-child(n of selector)」について理解を深めておこう。これはCSSの「擬似クラス」と呼ばれる機能の一つで、特定の条件に合う要素の中から、さらに順番を指定して選択できる強力なツールだ。
従来の :nth-child との違い
従来の :nth-child(n) は、「親要素から見て何番目の子要素か」を基準に判定していた。例えば .item:nth-child(2) と書いた場合、「2番目の子要素であり、かつ .item クラスを持っている要素」にスタイルが適用される。もし2番目の要素が別のクラスだった場合、何も選択されないという問題があった。
一方で、新しい :nth-child(n of .selector) 構文は、まず指定したセレクタ(この場合は .selector)に一致する要素だけをフィルタリングし、その抽出されたリストの中からn番目を選択する。これにより、間に別の要素が挟まっていても、特定のクラスを持つ要素だけを正確にカウントできるようになった。
フィルタリング機能の仕組み
この構文の最大のメリットは、動的に変化する状態に対しても柔軟に対応できる点だ。例えば、ユーザーがチェックを入れた要素だけを対象に「1番目のチェック済み要素」や「2番目のチェック済み要素」を指定できる。これは、日付範囲の開始点と終了点を特定する際に非常に役立つ仕組みだ。
このデモのように、特定の要素群(この場合は「項目」)だけを対象にして順番を数えられるのが、このセレクタの革新的な点だ。
カレンダーの基本レイアウトを作成する

日付範囲選択を実装するために、まずは土台となるカレンダーのレイアウトを準備する。CSS Grid(グリッドレイアウト)を使えば、カレンダーのような格子状の配置は驚くほど簡単に記述できる。
Grid Layoutによる7列配置
カレンダーは1週間が7日であるため、7つの列を持つグリッドを作成する。grid-template-columns:repeat(7, 1fr) と指定することで、親要素の幅を均等に7分割した列が自動的に生成される。これにより、日付の数字を順番に並べるだけで、自動的に適切な位置で改行されるようになる。
HTML構造の設計
HTML側では、各日付をリスト要素(<li>)として配置する。各日付の中には、チェック状態を管理するための <input type="checkbox"> を隠し要素として入れておく。ユーザーが日付をクリックした際に、このチェックボックスが切り替わる仕組みだ。
<ul id="calendar">
<!-- 曜日の表示 -->
<li class="day">月</li>
<li class="day">火</li>
<!-- ...土日まで -->
<!-- 日付の表示 -->
<li class="date">01<input type="checkbox" value="01"></li>
<li class="date">02<input type="checkbox" value="02"></li>
<!-- ...31日まで -->
</ul>CSSでは、この #calendar に対して display:grid を適用し、曜日と日付が綺麗に整列するように調整する。各日付(.date)は、ユーザーがクリックしやすいように十分なサイズと適切なパディングを持たせておくことが重要だ。
JavaScriptとCSSの役割分担

日付範囲の選択において、すべての処理をCSSだけで完結させることは現在の仕様では難しい。チェックボックスの「2つまでしか選択させない」といったロジックや、3つ目が選ばれた際の挙動制御にはJavaScriptが必要となる。しかし、ここで大切なのは「役割の最適化」だ。
チェック状態の制御ロジック
JavaScriptの主な仕事は、ユーザーのクリックに応じて checked 属性を適切に操作することだ。CSS-Tricksの記事で紹介されているロジックでは、新しく日付がクリックされた際、既存の選択範囲との位置関係を判定し、開始日または終了日を更新する処理を行っている。
ここで :nth-child(n of selector) がJS内でも威力を発揮する。querySelector メソッドでこのセレクタを使うことで、「現在チェックされている要素のうち、1番目のもの」を :nth-child(1 of :has(:checked)) として直接取得できるのだ。わざわざループを回してインデックスを探す手間が省ける。
CSSセレクタによる要素の特定
JS側で「範囲が選択された」と判断した際、親要素であるカレンダーに isRangeSelected といったクラスを付与する。これ以降の「範囲内の要素を青く塗る」といったビジュアル面の処理は、すべてCSSの領分となる。JSは状態(State)を管理し、CSSは見た目(View)を制御するという理想的な分離が実現できる。
この手法により、JSのコード量は大幅に削減される。DOMの書き換え(クラスの付け外し)を最小限に抑えられるため、ブラウザの再描画コストも低減され、結果としてパフォーマンスの向上につながるのだ。
範囲スタイリングの魔法

さて、いよいよ本題である「範囲内のスタイリング」について解説する。クラスを一つずつ付与することなく、CSSだけで「開始日と終了日の間」を特定するには、高度なセレクタの組み合わせが必要だ。
兄弟要素セレクタ(~)との組み合わせ
範囲を指定するための第一歩は、後続兄弟結合子(~)を使うことだ。これは「ある要素より後ろにある兄弟要素」をすべて選択する記号だ。:nth-child(1 of :has(:checked)) ~ .date と記述すれば、1番目にチェックされた日付より後ろにあるすべての日付を選択できる。
否定擬似クラス(:not)による制御
しかし、これだけでは「終了日より後ろの要素」まで選択されてしまう。そこで :not セレクタを組み合わせて、範囲を制限する。具体的には、「2番目にチェックされた要素より後ろにある要素ではないもの」という条件を加えるのだ。
.isRangeSelected :nth-child(1 of :has(:checked)) ~ :not(:nth-child(2 of :has(:checked)) ~ .date) {
background-color:rgb(228 239 253);
}この一見複雑なコードを分解すると、「1番目のチェック要素より後にある要素」の中から、「2番目のチェック要素より後にある要素」を除外していることになる。結果として、1番目と2番目の間にある要素だけが綺麗に抽出されるという仕組みだ。
※このデモはCSSの概念を視覚化したイメージだ。実際の動作はブラウザのデベロッパーツール等で確認してほしい。
実務におけるメリットと独自の分析

この新しいアプローチには、単に「コードが短くなる」以上の価値がある。Web制作の実務において、どのようなインパクトをもたらすのかを考察してみよう。
コードの保守性とパフォーマンス
最大のメリットは、JavaScriptがDOMの状態を過剰に意識しなくて済むようになることだ。従来の手法では、日付がクリックされるたびに、範囲内の全要素をループで回して .is-in-range といったクラスを付け替える必要があった。要素数が多い場合、この処理は無視できない負荷になる。
一方、今回の手法では、JSが行うのは「どのチェックボックスをオンにするか」という最小限の状態変更のみだ。見た目の更新はブラウザのCSSエンジンがネイティブで高速に処理するため、ユーザー体験はより滑らかになる。また、スタイルの変更が必要になった際も、JSを触ることなくCSSの修正だけで完結する保守のしやすさがある。
アクセシビリティへの配慮
この実装は、アクセシビリティ(利用しやすさ)の観点からも優れている。ネイティブのチェックボックスをベースにしているため、スクリーンリーダーなどの支援技術に対しても「どの項目が選択されているか」という情報を標準的な方法で伝えることができる。見た目だけでなく、情報の構造としても正しい状態を保ちやすいのだ。
ただし、注意点もある。:nth-child(n of selector) は比較的新しい機能であるため、古いブラウザ(特に数年前のスマートフォンなど)では動作しない可能性がある。実務で導入する際は、対象となるユーザーのブラウザ利用状況を確認し、必要に応じて基本的な背景色のみを適用するようなフォールバック(代替処理)を用意するのが賢明だろう。
この記事のポイント
:nth-child(n of selector)は特定の条件に合う要素の中だけで順番を数えられる- JavaScriptは状態管理に専念し、複雑な範囲スタイリングはCSSに任せるのが現代流
- 兄弟要素セレクタ(
~)と否定擬似クラス(:not)を組み合わせることで範囲を特定できる - DOM操作の削減により、コードの保守性とパフォーマンスの両立が可能になる

・ 複数業界における17年間のデジタルビジネス開発経験
・ ウェブサイト開発のためのHTML、PHP、CSS、Java等の実用的知識
・ 15ヶ国語対応の多言語SaaSの開発経験
・ 17年間にも及ぶ、Eコマース長期運営経験
・ 幅広い業界でのSEO最適化の豊富な経験

Webデザインの60/30/10ルール:配色比率で迷わず美しいサイトを作る方法
Webサイトのデザインで配色に迷った経験はないだろうか。色を選んでも何かまとまりがなく、プロのような洗練された見た目にならない。その解決策が「60/30/10ルール」だ。これはデザイン全体の配色を60%、30%、10%の3つの比率に分ける単純なガイドラインである。
WP Mayorの記事によると、このルールは元々インテリアデザインから生まれた。壁、家具、アクセサリーに色を割り振る考え方が、ファッション、グラフィックデザインを経て、今ではUIやWebデザインの基本原則として定着している。背景色、補助色、アクセント色に明確な役割と割合を与えることで、迷うことなくバランスの取れたビジュアル階層を構築できる。
この記事では、60/30/10ルールの具体的な意味、実践的な適用方法、そしてWordPressサイトでこのルールを体系化するためのテクニックを解説する。デザインの専門家でなくても、今日から実践できる配色のフレームワークだ。
60/30/10ルールが解決するデザインの根本問題

多くのWebサイト担当者が直面する問題は、色の使いすぎだ。5色も6色もほぼ均等に使ってしまい、訪問者の目がどこに向かえばいいかわからない状態になる。WP Mayorの著者は、自社製品サイトのリデザイン中にこの問題に直面した。レイアウトは技術的に問題なくても、何かが「完全にずれている」と感じていたという。
デザイナーの友人から「5色をほぼ同じ重みで使っている。目に行き場がない」と指摘され、60/30/10の分割を適用したところ、約20分で全体がまとまったと述べている。このルールの本質は、色の「量」を制御することで、無意識のうちにユーザーの視線を誘導する視覚的階層を作り出すことにある。
3つの役割:ドミナント・セカンダリー・アクセント
60/30/10ルールでは、3つの色に異なる役割を割り当てる。
- ドミナントカラー(60%):全体の基調色。背景や大きな面を覆い、他のすべての要素のキャンバスとなる。多くの場合、白、オフホワイト、薄いグレーなどのニュートラルカラー、またはダークデザインの場合は深いダークトーンが選ばれる。サイト全体の「空気感」を決定する色だ。
- セカンダリーカラー(30%):ドミナントを補完する色。ナビゲーションバー、サイドバー、カードの背景、セクションの区切りなど、構造とコントラストを提供する。注目を集めようと競合することなく、ページに秩序をもたらす。
- アクセントカラー(10%):行動を促す色。コールトゥアクションボタン、ハイライトされたテキスト、アイコン、リンクなどに使用する。訪問者の目に「次にどこへ行くべきか」を伝える、最も戦略的な色だ。
色は装飾ではなく「コミュニケーション」である
このルールを理解する上で最も重要なのは、色の持つ心理的影響だ。研究によれば、人は製品に対する第一印象を90秒以内に形成し、その評価の大部分は色だけに基づいている。訪問者は一言も読む前に、色を通じてあなたのブランドについて潜在意識で判断を下している。
異なる色は異なる連想を呼び起こす。青は信頼性と落ち着きを、赤は緊急性と興奮を、緑は自然と健康を、黄色は注意力とエネルギーを連想させる。これらの連想は、どの色をどの役割に割り当てるかを考える上で重要な要素となる。
例えば、ドミナントの60%に深いネイビーブルーを使えば、サイトはコピーを読む前から権威的で信頼できる印象を与える。アクセントの10%にオレンジや赤を使えば、CTAボタンのA/Bテストで一貫して高い成果が期待できる。色の「どれを」選ぶかは、「どれだけ」使うかと同じくらい重要なのである。
60/30/10ルールをあなたのWebサイトに適用する4ステップ

ルールを実際のサイトデザインに落とし込むには、3つの具体的な決定を順を追って行えばよい。WP Mayorの記事では、これを3つのステップに分解することを推奨している。
ステップ1:60%のドミナントカラーを最初に選ぶ
まずは基調色から決める。これはあなたのキャンバスであり、ページの最も広い視覚的領域を覆う。その上に配置されるすべてのものと戦わない、控えめな色を選ぶ必要がある。
ほとんどのWebサイトでは、白、オフホワイト、または非常に薄いニュートラルがこの役割を果たす。ダークモードのデザインを構築する場合は、チャコール、ニアブラック、彩度を抑えたダークトーンなどが該当する。どちらの方向でも構わないが、重要なのは一貫した背景を作り出すことだ。
「誰も特定のコンテンツを見ていないとき、私のサイトはどんな雰囲気に包まれるべきか」と自問してみよう。その答えがあなたの60%の色となる。
ステップ2:30%のセカンダリーカラーを決定する
セカンダリーカラーは構造層だ。ページを分割し整理する要素、つまりサイドバー、ナビゲーションの背景、カードコンテナ、セカンダリーセクションの塗りつぶしなどに適用する。
ドミナントカラーに対して十分なコントラストを持ち、目に見える分離を作り出す必要があるが、競合しているように感じるほど強くはないことが望ましい。有効なテストは、デザインを遠くから目を細めて見ることだ。セカンダリーカラーがアクセントカラーのように飛び出して見えるなら、それは強すぎる。
ステップ3:10%のアクセントカラーを選ぶ
ここに色の心理学に関する戦略的思考の大部分が適用される。アクセントカラーは、パレットの他の部分に対してエネルギッシュに感じられるべきだ。ボタン、リンク、ハイライトされたコールアウト、ユーザーに操作してほしいUI要素に現れる。
ここでアクセシビリティが重要になる。アクセントカラーが、ドミナントとセカンダリーの両方の背景に対して十分なコントラストを持ち、視覚障害のあるユーザーにも読みやすいことを確認しなければならない。WebAIMのコントラストチェッカーのようなツールを使えば、簡単に検証できる。WCAG(Web Content Accessibility Guidelines)では、通常のテキストに対する最低コントラスト比は4.5:1と定められている。
ステップ4:適用前にテストする
3色の大まかな配色が決まったら、立ち上がって画面から離れてみよう。デザイナーから教わったこのトリックは今でも有効だ。2メートル離れたところから、ページの適切な領域があなたの目を引くだろうか。アクセントがその役割を果たしていれば、考えなくてもCTAや主要なインタラクションに引き寄せられる感覚を覚えるはずだ。
CoolorsやAdobe Colorのようなツールは、補色パレットを生成し、3色がどのように調和するかを適用前にチェックするのに本当に役立つ。
60/30/10ルールの実例:実際のサイトで学ぶ

概念を理解するには、実際のサイトでどのように適用されているかを見るのが最も効果的だ。WP Mayorの記事では、Hipcamp、Apple News+、WooCommerceの3サイトを具体例として挙げている。
Hipcamp:自然と調和した明確な階層
アウトドア宿泊施設を検索できるHipcampは、このルールが意図した通りに機能するクリーンな実例だ。ドミナントの60%は、中立で開放感のある背景を提供する薄いグレーがかった白。ブランドアイデンティティの緑がセカンダリーカラーとして機能し、テキスト、ボタン、インタラクティブ要素全体に現れる。パレットの他の部分が非常に控えめであるため、緑は膨大な視覚的重みを持ち、自然を重視するアイデンティティと完璧に調和している。
最後に、オレンジがユーザーをサイトの主要なアクションである検索へと導く。色の割り当てがビジネス目標と明確に連動している好例である。
Apple News+:究極の抑制と意図
Apple News+は、このルールの可能な限りクリーンな例と言える。純白が60%全体を占め、完全に中立なキャンバスとして機能し、すべての視覚的重みをコンテンツとタイポグラフィに委ねている。ダークチャコールが構造的な30%を担当し、すべてのナビゲーション項目、見出し、本文ブロックがこのニアブラックを一貫して使用することで、ページの可読性と階層が生まれている。
コーラルピンクのアクセントは、正確に3箇所にのみ現れる。ナビゲーションの「Try it free」ボタン、ヒーローセクションの「Try it free」CTA、ロゴマークの下の「Apple News+」ラベルだ。この抑制こそがポイントである。ページ上で何かピンク色のものを見つけたときには、すでに「ここが行動する場所だ」という意味だと理解している。
WooCommerce:色の「役割」の徹底
WooCommerceは、セカンダリーの30%がセクションに適用される単色ではないという点で有用な例だ。ソフトなラベンダーが、ヒーローコンテンツの背後にある大きな有機的なブロブ形状で使用される。これは何かと競合することなく、視覚的興味と深みを提供する。白いキャンバスは依然として60%を支配し、ラベンダーはすべての背景構造を処理する。
ミディアムパープルは、ページ上のすべてのインタラクティブ要素のために確保されている。ロゴ、「Log in」リンク、プライマリーCTAボタン、その下のテキストリンクだ。ヒーローセクションを過ぎてスクロールすると、パープルはクリックまたは関与することを意図したものにのみ再び現れる。この規律こそが、10%を装飾的ではなく意図的なものに感じさせる所以である。
WordPressで60/30/10ルールを実装する方法

WordPressを利用している場合、このルールを実装する実用的な方法がいくつかある。重要なのは、3色を一度だけシステムレベルで定義し、そこから適用することだ。60/30/10ルールは、ホームページだけでなくすべてのページで一貫して適用されて初めて、規律として機能する。
ページビルダーを使う場合:グローバルカラーを設定する
Elementorを使用している場合、グローバルカラーはサイト設定内にある。ここであなたの3色のパレットカラーを定義すれば、それらのグローバルが適用されているすべてのインスタンスがサイト全体で更新される。個々のウィジェット設定を探し回る必要はない。
GeneratePressはカスタマイザーにグローバルカラーを組み込んでおり、ゼロから構造化されたカラーシステムを実装するための優れたテーマ選択肢の一つとなっている。Beaver Builderも同様に機能する独自のカラーパレット設定を持っている。
ブロックテーマを使う場合:theme.jsonで定義する
ブロックテーマを実行している場合、カラーパレットはtheme.jsonファイルで定義される。ここに3色を設定すれば、ブロックエディタ全体でプリセットオプションとして表示される。カラーシステムをロックし一貫性を保つための最もクリーンなアプローチだ。
具体的には、theme.jsonの`settings.color.palette`配列に、あなたのドミナント、セカンダリー、アクセントの各色をスラッグとカラーコードで定義する。これにより、サイトエディタや投稿編集画面でこれらの色がパレットとして利用可能になり、デザインの一貫性が担保される。
ルールが適用しにくいケースとよくある失敗

60/30/10ルールが柔軟になるべき場合
60/30/10ルールはフレームワークであって法律ではない。適用が難しいケースも存在する。
写真を多用するサイトが最も一般的な例外だ。ポートフォリオサイト、旅行サイト、画像ギャラリーなど、全面写真を中心に構築されたサイトでは、写真自体が非常に多くの視覚情報を運んでいるため、レイアウト全体に色の分布を主張しようとするのは無駄な戦いになる。正しい動きは、イメージ自体がパレットになるように、ニュートラルに近いインターフェース(非常に白いか非常に暗い)に移行することである。
モノクロマティックデザインは、3つの異なる色ではなく、1つの色を複数のトーンとシェードで使用する。最も薄いトーンが60%を支配し、中間トーンが30%で構造を提供し、最も深いまたは最も鮮やかなバージョンが10%でアクセントの役割を処理するため、このルールは精神的な面では依然として適用される。
高エネルギーまたはキャンペーン固有のページは、特に緊急性や興奮を呼び起こす文脈では、より多くの色を押し出すことで利益を得ることがある。セールランディングページ、イベントサイト、製品ローンチを考えてみよう。50/30/20に向かって突破したり、2番目のアクセントとして4色目を追加したりすることがここでは有効だ。ただし、明確な視覚的階層がまだ存在し、1色がまだ誘導を行っていることを確認する必要がある。
バランスを崩すよくある間違い
これらは、ルールが誤って適用される場合に最もよく見られるパターンだ。
- アクセントカラーの使いすぎ:10%の色がレイアウトの20%や25%をカバーし始めると、それはアクセントではなくセカンダリーになってしまう。すべてが平坦になり、提供されるはずだった緊急性や方向性が消える。
- 彩度が似すぎた色を選ぶ:ドミナント、セカンダリー、アクセントがすべてほぼ同じトーンと明るさの場合、階層は生まれない。目はどこへ行けばいいかわからない。役割間のコントラストは、割合自体と同じくらい重要だ。
- 画像をカラーシステムから切り離して扱う:色の分布が完璧に調整されていても、ヒーロー画像にパレットと衝突する5つの彩度の高い色が含まれている場合、画像がすべてを上書きする。パレットと一致する、または意図的に中立な写真を選択または作成する。
- ページ間での一貫性のない適用:異なる人々によって時間をかけて構築されたWordPressサイトでこれを絶えず目にする。ホームページは1つのパレットに従い、ブログはアクセントカラーのわずかに異なる色合いを使用し、WooCommerceショップは独自のことが起こっている。このルールは、どこにでも適用されて初めて信頼とブランド認知を構築する。
この記事のポイント
- 60/30/10ルールは、背景色(60%)、構造色(30%)、アクセント色(10%)の3役割に分ける配色の黄金比率である。
- 色は装飾ではなくコミュニケーションであり、訪問者はコンテンツを読む前に色を通じてブランドを判断する。
- 実装は「ドミナント→セカンダリー→アクセント」の順で色を決定し、適用前に遠くから視認性をテストする。
- WordPressでは、ページビルダーのグローバルカラー機能やブロックテーマのtheme.jsonを活用し、システムレベルで色を一元管理する。
- 写真多用サイトやモノクロデザインなど例外はあるが、基本原則としてデザインの迷いを大きく減らせる。

・ 複数業界における17年間のデジタルビジネス開発経験
・ ウェブサイト開発のためのHTML、PHP、CSS、Java等の実用的知識
・ 15ヶ国語対応の多言語SaaSの開発経験
・ 17年間にも及ぶ、Eコマース長期運営経験
・ 幅広い業界でのSEO最適化の豊富な経験

スクロール要素で消えるドロップダウンを解決する——CSSとJSによる決定版ガイド
WordPressの管理画面や複雑なデータテーブルを構築している際、ドロップダウンメニューが枠外で切れて見えなくなる現象に遭遇したことはないだろうか。スクロール可能な要素の中にメニューを配置すると、本来最前面に表示されるべき要素がコンテナの縁で無残にカットされてしまう。この問題は、CSSの仕様が複雑に絡み合うことで発生する。
元記事の著者であるGodstime Aburu氏は、このバグを「overflowのクリッピング」「スタック文脈(Stacking Context)」「包含ブロック(Containing Block)」という3つのブラウザシステムの衝突であると分析している。これら3つの仕組みを個別に理解していても、それらが重なったときに何が起きるかを把握している開発者は意外に少ない。
本記事では、なぜドロップダウンが壊れるのかという技術的背景を整理し、ポータル(Portal)や最新のCSS Anchor Positioningを用いた解決策を詳しく解説する。これを理解すれば、z-indexの数値を闇雲に上げるだけの「終わらない戦い」から解放されるはずだ。
なぜスクロール要素内でドロップダウンは「壊れる」のか

ドロップダウンが消えたり、意図しない位置に表示されたりする原因は、主に3つのブラウザシステムが干渉し合っているためだ。著者のAburu氏は、これらが衝突することで予測不能な挙動が生まれると指摘している。
overflowプロパティによるクリッピングの罠
最も一般的な原因は、親要素に設定された overflow: hidden や overflow: auto だ。これらが設定されると、ブラウザはコンテナの境界線からはみ出した子要素を強制的に切り取る。たとえ子要素に position: absolute を指定していても、このクリッピングから逃れることはできない。
.scroll-container {
overflow: auto;
height: 200px;
}
.dropdown-menu {
position: absolute;
/* 親のoverflowによって、枠外に出ると見えなくなる */
}スクロール枠(overflow: auto)
上記のデモでは、黒いドロップダウンメニューが白いコンテナの底に達した時点で切り取られていることがわかる。これは視覚的な問題だけでなく、アクセシビリティ上の問題も引き起こす。スクリーンリーダーの利用者はメニュー項目をフォーカスできるが、晴眼者にはそれが見えないという乖離が発生するためだ。
「スタック文脈」が引き起こす表示順の混乱
次に厄介なのが「スタック文脈(Stacking Context)」だ。これは要素の重なり順を管理する「密閉されたレイヤー」のようなものだ。特定のプロパティ( opacity が1未満、 transform 、 filter など)が適用されると、その要素は新しいスタック文脈を生成する。
一度スタック文脈の中に閉じ込められると、その中の子要素に z-index: 9999 を指定しても、文脈の外にある要素の上に表示させることはできない。z-indexの比較は、同じスタック文脈内の兄弟要素間でのみ行われるからだ。これが「z-indexをいくら上げても効かない」という現象の正体である。
包含ブロックと座標計算のズレ
3つ目の要因は「包含ブロック(Containing Block)」だ。 position: absolute を指定した要素は、直近の「位置指定された(positionがstatic以外)」先祖要素を基準に配置される。しかし、スクロールコンテナが深い位置にある場合、ドロップダウンの座標計算はコンテナ基準になってしまう。コンテナがスクロールしてもドロップダウンの座標が更新されないため、トリガーボタンだけが移動し、メニューがその場に取り残されるという現象が起きる。
根本的な解決策1:ポータル(Portal)パターンの活用

著者のAburu氏が最終的に最も信頼できる解決策として挙げているのが「ポータル」だ。これはドロップダウンのDOM要素を、本来の階層構造から切り離し、 document.body の直下にレンダリングする手法である。
DOMの最上位に配置することで、親要素の overflow: hidden や特定のスタック文脈による制限を完全に回避できる。ReactやVueといったモダンなフレームワークには、この「ポータル」を実現するための機能が標準で備わっている。
// Reactでのポータル実装例
import { createPortal } from 'react-dom';
function Dropdown({ isOpen, anchorRef, children }) {
if (!isOpen) return null;
// document.bodyの直下にレンダリングする
return createPortal(
<div className="dropdown-menu" style={{
position: 'absolute',
top: anchorRef.current.getBoundingClientRect().bottom + window.scrollY,
left: anchorRef.current.getBoundingClientRect().left + window.scrollX
}}>
{children}
</div>,
document.body
);
}バニラJavaScriptであっても document.body.appendChild() を使えば同様のことが可能だ。ただし、ポータルを使用する場合は、テーマのコンテキスト(CSS変数など)が引き継がれないことや、キーボード操作のフォーカス管理を自分で行う必要がある点に注意が必要だ。メニューを閉じた際に元のボタンにフォーカスを戻すといった処理を忘れると、アクセシビリティを損なう原因になる。
根本的な解決策2:CSSの最新機能を使いこなす

JavaScriptによる座標計算に頼らず、ブラウザのネイティブ機能で解決する方法も普及し始めている。特に「CSS Anchor Positioning」と「Popover API」の組み合わせは、次世代の標準となる可能性が高い。
CSS Anchor Positioningの可能性
CSS Anchor Positioningは、特定の要素(アンカー)を基準に別の要素を配置できる機能だ。これを使えば、ドロップダウンが画面端で切れないように自動で位置を反転させる(フリップ)処理もCSSだけで記述できる。
.trigger {
anchor-name: --menu-anchor;
}
.dropdown-menu {
position: absolute;
position-anchor: --menu-anchor;
top: anchor(bottom);
left: anchor(left);
/* 画面端で切れる場合に自動で反転 */
position-try-fallbacks: flip-block;
}※このデモはCSSの概念を視覚化したイメージです。実際の動作はChrome DevToolsで確認してください。現在、Chromium系ブラウザでは強力なサポートがあるが、Firefoxなどではポリフィルが必要になる場合があるため、導入にはターゲットブラウザの確認が欠かせない。
Popover APIによるレイヤー管理の簡略化
もう一つの注目機能が「Popover API」だ。 popover 属性を持つ要素は、ブラウザの「トップレイヤー(Top Layer)」と呼ばれる特殊な層にレンダリングされる。この層は、どんなz-indexよりも上に表示され、 overflow: hidden の影響も受けない。
<button popovertarget="my-menu">メニューを開く</button>
<div id="my-menu" popover="manual" role="menu">
メニューの内容
</div>Popover APIは「重なり順」の問題を解決するが、配置(座標計算)の問題は解決しない。そのため、配置には前述のAnchor PositioningやJavaScriptを組み合わせて使用するのが一般的だ。この2つを組み合わせることで、ライブラリに頼らずとも堅牢なUIを構築できるようになる。
実務での分析:WordPressサイトでの適用

WordPressの運用において、このドロップダウン問題は特に出現しやすい。例えば、管理画面(ダッシュボード)のカスタマイズや、Gutenbergブロック内での設定パネルの実装などが挙げられる。WordPressの管理画面は多くのネストされた要素と overflow: auto を多用しているため、独自の実装が簡単にクリップされてしまうのだ。
独自の分析として、既存のWordPressサイトでこの問題を手軽に修正したい場合は、以下の優先順位で検討することをお勧めする。
- DOM構造の変更: 可能であれば、ドロップダウンをスクロールコンテナの外に配置し直す。これが最も副作用が少なく、パフォーマンスも良い。
- CSSによる微調整: 親要素の
overflowを一時的にvisibleに変更できるか検討する。ただし、スクロール機能が失われるリスクがある。 - ライブラリの活用: 自前で座標計算を実装するのは難易度が高いため、Floating UIなどの定評あるライブラリを導入し、ポータル機能を利用するのが現実的だ。
特に、パフォーマンスを重視するWordPressサイトでは、不要なJavaScriptを減らすために最新のCSS機能を段階的に導入する(プログレッシブ・エンハンスメント)姿勢が重要になるだろう。
状況別・最適な解決策の選び方

どの手法を選ぶべきかは、プロジェクトの要件やサポートブラウザによって異なる。著者のAburu氏が提示したガイドラインを元に、選択の基準を整理した。
- ネストが深く、親要素を制御できない場合: ポータル(Portal)一択だ。DOMを移動させることで、すべての干渉を断ち切ることができる。
- モダンブラウザのみを対象とする場合: CSS Anchor PositioningとPopover APIの組み合わせがベストだ。CSSで簡潔に記述でき、メンテナンス性が高い。
- 軽量な実装を求める場合:
position: fixedを活用する。ただし、先祖要素にtransformなどが設定されていないことを確認する必要がある。 - 複雑なロジックを避けたい場合: DOM構造を見直し、最初からスクロールコンテナの外にメニューを配置するよう設計を変更する。
どのような手法を採るにせよ、最終的には「ユーザーが正しく操作できるか」が重要だ。視覚的な修正に満足せず、キーボード操作やスクリーンリーダーでの挙動を必ずテストしてほしい。
この記事のポイント
- ドロップダウンが欠ける原因は、overflow、スタック文脈、包含ブロックの3要素の衝突にある
- ポータルパターンは、DOMを最上位に移動させることでクリッピングを回避する最も確実な手法だ
- CSS Anchor PositioningとPopover APIは、ネイティブで重なりと配置を解決する次世代の標準である
- z-indexを増やすだけでは解決しないため、どの先祖要素がスタック文脈を作っているか特定することが重要だ
- アクセシビリティ(フォーカス管理やARIA属性)は、実装の「仕上げ」ではなく「必須要件」として扱うべきである
出典
- Smashing Magazine WordPress「Dropdowns Inside Scrollable Containers: Why They Break And How To Fix Them Properly」(2026年3月20日)

・ 複数業界における17年間のデジタルビジネス開発経験
・ ウェブサイト開発のためのHTML、PHP、CSS、Java等の実用的知識
・ 15ヶ国語対応の多言語SaaSの開発経験
・ 17年間にも及ぶ、Eコマース長期運営経験
・ 幅広い業界でのSEO最適化の豊富な経験

CSSでここまでできる!カスタマイズ可能なselect要素で作る革新的UIデザイン3選
HTMLのselect要素は、長年にわたりWeb制作者にとってスタイリングが最も困難なパーツの一つであった。ブラウザごとに異なるデフォルトの見た目を持ち、ドロップダウン部分に至ってはCSSでの制御がほぼ不可能だったからだ。
しかし現在、Chromium系ブラウザを中心に「カスタマイズ可能なselect要素(Customizable Select)」という新機能の実装が進んでいる。この機能により、開発者はJavaScriptで独自のコンポーネントを自作することなく、標準のselect要素に対して自由なデザインを適用できるようになった。
本記事では、CSS-Tricksで紹介された先進的なデモを基に、この新機能がもたらす可能性と具体的な実装手法を解説する。従来の常識を覆すような、扇形や円形のセレクトメニューがどのように構築されているのか、その核心に迫る。
1. appearance: base-select によるスタイリングの解禁
カスタマイズ可能なselect機能を利用するための第一歩は、新しいCSSプロパティの値を適用することだ。元記事の著者であるPatrick Brosset氏は、この機能を有効化することで、select要素全体(ボタン、ドロップダウン、オプション)のフルカスタマイズが可能になると指摘している。
制御を可能にする「base-select」の宣言
まず、select要素とそのドロップダウン部分(ピッカー)に対して、`appearance: base-select` を指定する。これにより、ブラウザの標準的なスタイルがリセットされ、開発者が自由にスタイルを定義できる土台が整う。ピッカー部分は `::picker(select)` という新しい擬似要素で指定する仕組みだ。
/* カスタマイズ機能を有効化する基本設定 */
select,
::picker(select) {
appearance: base-select;
}この宣言がない場合、select要素は従来通りの制限されたスタイルしか適用できない。この「オプトイン(明示的な有効化)」方式により、既存のWebサイトのデザインを壊すことなく新機能を提供できる設計となっている。
擬似要素による構成パーツの個別操作
新機能では、これまでアクセスできなかったパーツも擬似要素として操作できる。例えば、右側に表示される矢印アイコンは `::picker-icon`、選択状態を示すチェックマークは `::checkmark` という擬似要素で制御可能だ。
著者のBrosset氏は、デモにおいて `::picker-icon` を `display: none` で非表示にし、代わりに独自のアイコンや装飾を施している。また、これまではoption要素の中にテキストしか入れられなかったが、新しい仕様ではspanやimgといったHTMLタグを混在させることも可能になった。これはUIデザインの幅を大きく広げる重要な変更だ。
2. フォルダが扇状に広がるUIの構築
最初のデモとして紹介されているのは、フォルダのリストが扇状に展開されるユニークなセレクトメニューだ。このUIを実現するために、最新のCSS関数が効果的に活用されている。
sibling-index() による動的な回転制御
各フォルダ(option要素)を少しずつ異なる角度で回転させるために、`sibling-index()` という関数が使われている。これは、兄弟要素の中での自身のインデックス番号を返す関数だ。例えば、1番目の要素なら1、2番目なら2を返す。
記事によれば、このインデックス番号に一定の角度(例:-4度)を掛け合わせることで、リストの下に行くほど回転角が大きくなる「扇状」のレイアウトを数行のコードで実現している。これは従来、JavaScriptでループ処理を行ってインラインスタイルを付与していた作業だ。
option {
--rotation-offset: -4deg;
/* インデックス番号に応じて回転角を計算 */
rotate: calc(sibling-index() * var(--rotation-offset));
/* 右側を支点にして回転させる */
transform-origin: right calc(sibling-index() * -1.5rem);
}このデモは、sibling-index()を利用して要素ごとに異なる角度を適用するイメージを示している。
@starting-style で実現する登場アニメーション
メニューが開いた瞬間にアニメーションさせる際、課題となるのが「要素が表示された瞬間の初期状態」の定義だ。通常、displayプロパティが none から block に変わる瞬間はトランジションが効かない。
そこで著者は `@starting-style` という新しいアットルールを使用している。これは要素がレンダリングを開始する直前のスタイルを指定できるもので、これにより「閉じた状態(回転0度)」から「開いた状態(扇状)」への滑らかなアニメーションが可能になる。
3. トランプのデッキを再現するカードピッカー
二つ目のデモは、トランプのカードを扇形に並べたカードピッカーだ。ここでは、配置の自由度を極限まで高めるためのテクニックが紹介されている。
アンカーポジショニングによる配置の自由化
デフォルトのselect要素は、ボタンの真下にリストが表示される。しかし、カスタマイズ可能なselectでは「アンカーポジショニング(Anchor Positioning)」という技術が組み込まれており、リストの表示位置を自由に制御できる。
著者の手法では、`position-area: center center` を使用して、ドロップダウンをボタンの中央に重ねて表示させている。さらに `inset: 0` を指定することで、ピッカーが画面全体のスペースを利用できるように設定している。これにより、ボタンの枠に縛られないダイナミックなレイアウトが可能になる。
@property を活用したカスタムプロパティのアニメーション
カードが広がるアニメーションをより精密に制御するため、`@property` を使って独自のCSS変数を定義している。CSS変数は通常、単なる文字列として扱われるため数値的な補間(アニメーション)ができないが、`@property` で型(この場合は “)を指定することで、ブラウザが変数そのものをアニメーションさせることが可能になる。
@property --card-fan-rotation {
syntax: '<angle>';
inherits: false;
initial-value: 7deg;
}
option {
/* 変数自体をアニメーション対象にする */
transition: --card-fan-rotation 0.2s ease-out;
}この手法により、カードの広がり具合を一つの変数で管理し、CSSのみで滑らかな動きを実現している。JavaScriptによる座標計算は一切不要だという点は、パフォーマンスの観点からも非常に優れている。
4. 三角関数を用いた円形絵文字ピッカー
最後のデモは、ボタンを中心に絵文字が円形に並ぶ「ラジアルメニュー(放射状メニュー)」だ。近年のCSSに追加された数学関数の威力が発揮されている。
sin() と cos() による座標計算
要素を円形に配置するには、角度からX座標とY座標を導き出す必要がある。以前はSassの関数やJavaScriptで行っていた計算だが、現在のCSSでは `sin()`(正弦)と `cos()`(余弦)が直接使用できる。
記事によれば、`sibling-index()` で得たインデックス番号を基に角度(–angle)を算出し、それを `translate` プロパティの中で三角関数に渡している。これにより、各option要素が中心から一定の半径(–radius)の位置に自動的に配置される仕組みだ。
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));
}三角関数を利用して、中心のボタンの周囲に要素を円形配置するレイアウトのデモ。
アクセシビリティの継承
これほどまでに見た目が変化しても、ベースは標準のselect要素である。著者は、マウス操作だけでなくキーボードによる選択や、スクリーンリーダーによる読み上げといったブラウザ標準のアクセシビリティ機能がそのまま維持される点を強調している。
独自にUIコンポーネントを自作する場合、これらのアクセシビリティ対応をゼロから実装するのは非常に困難でミスが起きやすい。標準要素を拡張するこのアプローチは、堅牢なWebサイト制作において極めて合理的な選択と言える。
5. 実務での導入とプログレッシブ・エンハンスメント
非常に魅力的な新機能だが、現時点での導入には注意も必要だ。著者のPatrick Brosset氏も述べている通り、この機能はまだChromium系ブラウザの最新バージョンに限定された実装である。
ブラウザ互換性とフォールバック戦略
未対応のブラウザ(SafariやFirefoxなど)では、`appearance: base-select` が無視される。その結果、ユーザーには「標準的な、見慣れたセレクトボックス」が表示されることになる。
これは「プログレッシブ・エンハンスメント(段階的向上)」の考え方に合致する。最新ブラウザを使うユーザーにはリッチな体験を提供し、そうでないユーザーにも基本機能を損なうことなくコンテンツを届けることができる。著者は、デモの中で `@supports` を使って未対応ブラウザ向けのメッセージを表示する工夫も凝らしている。
Web制作における今後の展望
カスタマイズ可能なselect要素が一般化すれば、重い外部ライブラリに頼ることなく、ブランドイメージに合わせたUIが構築可能になる。特に、フォームのデザイン性を重視するキャンペーンサイトや、複雑なオプション選択が必要なECサイトにおいて、その価値は計り知れない。
今後の課題は、他のブラウザエンジン(WebKit, Gecko)での実装状況だ。クロスブラウザでの対応が進めば、Web制作のワークフローにおいて「セレクトボックスのカスタマイズ」はもはや悩みの種ではなく、クリエイティビティを発揮する場へと変わるだろう。
この記事のポイント
- appearance: base-select を宣言することで、select要素の全パーツをCSSで制御可能になる。
- sibling-index() や sibling-count() を使うと、要素の順序に基づいた動的なレイアウトがノーコードで実現できる。
- Anchor Positioning により、ドロップダウンメニューをボタンの周囲の好きな場所に配置できる。
- 三角関数(sin, cos) を活用すれば、円形などの複雑な配置もCSSのみで完結する。
- 未対応ブラウザでは標準のselectとして動作するため、プログレッシブ・エンハンスメントとして導入しやすい。
出典
- CSS-Tricks「Abusing Customizable Selects」(2026年3月11日)

・ 複数業界における17年間のデジタルビジネス開発経験
・ ウェブサイト開発のためのHTML、PHP、CSS、Java等の実用的知識
・ 15ヶ国語対応の多言語SaaSの開発経験
・ 17年間にも及ぶ、Eコマース長期運営経験
・ 幅広い業界でのSEO最適化の豊富な経験
