現場でCSSを触っていると、「JavaScriptで制御するほどじゃないけど、ちょっとしたインタラクションが欲しい」という場面、よくあるよね。そんなとき、多くのエンジニアが即座に`addEventListener`を書き始めるのを見て、私はいつも「ちょっと待て、それはCSSだけで完結できるかもしれないぞ」と声をかけたくなる。
今日は、そんな「隠れた実力者」である `:target` 擬似クラスについて、現場目線で深く掘り下げていこう。
—
:target 擬似クラス:URLの「現在地」をCSSのフックにする
`:target` は、URLのフラグメント識別子(`#`で始まるアレ)が、ページ内の特定の要素の `id` と一致した瞬間に、その要素に対してスタイルを適用する擬似クラスだ。
ブラウザの裏側で何が起きているのか?
ブラウザはURLのハッシュ値が変わったことを検知すると、まずそのIDを持つ要素へスクロールを試みる。その際、ブラウザの内部状態として「現在のターゲット」が更新される。CSSエンジンはこの「現在のターゲット」情報をリアルタイムで監視しており、該当する要素の `:target` スタイルを再計算するんだ。
ここで重要なのは、JavaScriptを一切介さないということ。ブラウザのネイティブな挙動にフックしているからこそ、レンダリングのオーバーヘッドが極めて低く、非常にパフォーマンスが高い。
—
実践:JS不要のモーダルウィンドウ・アコーディオン
現場でよくある「タブ切り替え」や「モーダル表示」を、JSなしで実装する例を見てみよう。これを知っておくと、プロトタイプ作成や、軽量なUI実装で一目置かれるはずだ。
/ ターゲットになった要素にだけスタイルを当てる /
.modal-window {
display: none; / デフォルトは非表示 /
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
background: rgba(0, 0, 0, 0.7);
}
/ :targetが発動したときだけ表示する /
.modal-window:target {
display: flex;
justify-content: center;
align-items: center;
}
/ 閉じるボタンの挙動:ハッシュを空にするだけ /
.close-link {
display: block;
padding: 10px;
background: #fff;
}
CSSだけで動くモーダルです。
どうだい? 非常にシンプルだろう。JSのイベントリスナーを登録して、クラスを付け替えて……といった泥臭いDOM操作から解放される。
—
現場で使う上での「泥臭い」注意点
もちろん、銀の弾丸なんて存在しない。実務で使う際にハマりやすいポイントを伝授しておく。
1. 履歴スタックの汚染
`:target` を使うと、閉じるたびにブラウザの履歴にハッシュが残る。`history.pushState` を使って履歴を管理しない限り、ユーザーが「戻る」ボタンを押すと、閉じたはずのモーダルが復活してしまう。これが許容できないUIなら、素直にJSを採用すべきだ。
2. スクロールの強制
`:target` はブラウザのデフォルト挙動として、その要素までスクロールさせようとする。ページ下部の要素をターゲットにした場合、画面がガクッと動いてしまう。これを避けるには `scroll-behavior: smooth;` を活用したり、場合によっては `id` とは別のラッパーを用意するなどの工夫が必要になる。
3. アクセシビリティ(a11y)の意識
単に `div` を切り替えるだけでなく、スクリーンリーダーに対しても状態の変化が伝わるよう、`aria-hidden` の属性値も一緒に制御したいところだ。実はCSSの `attr()` 関数と組み合わせることで、属性値の切り替えもCSS側で擬似的に表現できなくはないが、やりすぎると保守性が落ちる。バランス感覚が大切だ。
—
最後に:なぜあえて `:target` を使うのか
私がこの `:target` を好む理由は、「宣言的なインターフェース」だからだ。
「もしURLがこうなったら、見た目はこうなる」というルールをCSSに記述するだけで、状態管理の複雑さから解放される。
フロントエンドの現場では、JSでガチガチにロジックを書きたがるエンジニアも多いが、CSSだけで表現できるなら、それが最もバグを生みにくく、最も速い。
「JSで書けばいいや」と安易に逃げる前に、まずはCSSの仕様を隅々まで見渡してほしい。そこに、君が求めていたエレガントな解決策が眠っているはずだ。
さて、次はどのCSSの深淵を覗いてみる?またいつでも質問してくれ。

コメント