:target擬似クラスではフラグメント識別子と一致する要素に対してスタイルを当てることができる。これを利用するとCSSだけでインタラクティブにデザインを変更することが可能になる。一方History APIではページの遷移なくフラグメント識別子を含め、アクセス中のURLを書き換えることができる。では:target擬似クラスで有効になっているスタイルは、History APIでフラグメント識別子を変更した場合に動的に切り替わってくれるだろうか。

Demo: :target and history.replaceState()

デモ・ページではEnable #test:targetをクリックするとURLに#testというフラグメント識別子が追加される。#test:targetセレクターを通して、文字色を緑にするようにしてあるので、クリック後文章が緑になることだろう。Disable #test:target by history.replaceState()ボタンを押すとhistory.replaceState()を使ってURLからフラグメント識別子が削られる。ここで文字色が緑から黒になればCSSにも反映されることになる。

しかし、だいたいのブラウザーで緑のままなので、history.replaceState()によるフラグメント識別子の変更に:target擬似クラスは応じてくれないようだ。もしかするとどこかでこういう挙動になるべきと決まっているのかもしれないが、残念ながら僕には見つけられなかった。


:target擬似クラスを使ったオーバーレイのフルスクリーン・ナビゲーションを作ろうかなという過程で、CSSだけだと消せないためどうしてやろうかと考えていて、History APIを使ってみたらダメだった、という過程で発見した。「珍」というほどではないが、直感的な動作とは思えないのでCSS珍百景 Advent Calendar 2014の19日目として提供しておく。

対策はそれほど難しくはない。location.hash = ''でフラグメント識別子を空にし、:target擬似クラスを無効にした後、改めてhistory.replaceState('', '', location.pathname)とすれば良い。