【実務・中級編】 訪問済みリンク擬似クラス :visited – CSS実践ガイド

こんにちは。フロントエンドチームのコードレビューを見ていると、時折「おっ、そこに手を出すか」とハッとさせられるコードに出会うことがあります。

今回は、CSSの歴史のかなり古い部分から存在しながら、現代のWeb開発でも意外とハマりどころが多い擬似クラス、`:visited` について話をさせてください。

「リンクの色を訪問済みで変えるやつね、知ってるよ」と思ったそこの中級エンジニアのあなた。実務で「なぜか `:visited` で `color` 以外のプロパティが効かない」「背景色(`background-color`)を変えようとしたのに無視される」といった謎のバグ(仕様です)に直面し、頭を抱えた経験はありませんか?

今回は、ブラウザが裏側で抱える「セキュリティの闇」と、それをいかにスマートに回避して実務で使い倒すかという実践的な知見を、シニアの視点からたっぷりとシェアしたいと思います。

—

なぜ `:visited` は嫌われるのか?(ブラウザのプライバシー防衛ライン)

まず大前提として、`:visited` は CSS の中でも極めて特殊な制約を受けます。
「ユーザーが過去にどのURLを訪れたか」という情報は、個人のプライバシーそのものです。もし悪意あるサードパーティのサイトが、CSSの `:visited` と JavaScript(`getComputedStyle` など)を巧みに組み合わせることで、「このユーザーは特定の宗教サイトや競合の管理画面を見たことがあるか?」を全自動でハッキング(履歴スニッフィング)できたらどうなるでしょうか?

……ゾッとしますよね。

そのため、現代のモダンブラウザは、`:visited` で変更できるスタイルを猛烈に制限しています。具体的に言うと、変更が許可されているのは以下のプロパティにごく一部限られます。

  • `color`
  • `background-color`(※注意が必要、後述)
  • `border-color`(各方向含む)
  • `outline-color`
  • `column-rule-color`
  • SVGの `fill` および `stroke`

「あれ、じゃあ `background-color` は行けるじゃん!」と思ったあなた、甘い。ブラウザはさらにその上を行く「ピクセル単位の情報漏洩を防ぐための防衛策」を実装しています。

制限の裏側:計算済みスタイル(Computed Style)の隠蔽

ブラウザは、`:visited` が適用されている要素に対して、JavaScript の `window.getComputedStyle()` が呼ばれた際、強制的に「未訪問(unvisited)の状態のスタイル」を返すように裏でコントロールしています。

さらに、`background-color` などの変更も、透明度(alphaチャンネル)や複雑な合成処理を通じて、ユーザーのブラウジング履歴が外部スクリプトに透けて見えないよう、厳格な制限(Color Blending の制限など)がかけられています。そのため、実務では `:visited` で触っていいのは実質的に `color`(文字色)くらいにしておくのが、無用なバグを生むリスクをゼロにするプロの知恵 です。

—

現場で即戦力になる!美しい `:visited` の書き方

では、実際にどう書くのがベストプラクティスなのか。
ただ文字色を変えるだけではなく、UIコンポーネントとして破綻しない、コピペしてすぐに使える実践的なサンプルコードを見てみましょう。

実務向けサンプルコード

/ =================================================================
リンクの基本設計 (Link Base Styles)
================================================================ /
.c-link {
/ 変数でリンクの色を管理するのがモダンなアプローチです /
–link-color: #2563eb; / 未訪問時の青 /
–link-visited: #7c3aed; / 訪問済みの紫 /
–link-hover: #1d4ed8; / ホバー時の濃い青 /

color: var(–link-color);
text-decoration: underline;
text-underline-offset: 0.2em;
transition: color 0.2s ease, text-decoration-color 0.2s ease;
}

/ ホバー時は未訪問・訪問済みに関わらず共通のアクションカラーにするのが親切 /
.c-link:hover {
color: var(–link-hover);
text-decoration-color: var(–link-hover);
}

/ =================================================================
重要: 訪問済みリンクの定義
================================================================ /
.c-link:visited {
/ 制限があるため、原則として ‘color’ の変更に留めるのが鉄則です /
color: var(–link-visited);

/
【重要】
下線の色(text-decoration-color)も変更可能ですが、
ブラウザのバージョンや環境によってはうまく継承されないことがあるため、
確実に行いたい場合はカラーを個別に指定します。
/
text-decoration-color: var(–link-visited);
}

日々のコーディングで役立つ情報は、
CSSアーキテクチャ論の解説記事
や、チームで共有している
フロントエンド開発ガイドライン
をチェックしてみてください。

—

シニアから送る、実務でのハマりどころとTips

このコードを現場に導入するにあたって、後輩によくある質問や、やりがちなミスを先回りしていくつか共有しておきます。

1. 詳細度(Specificity)の罠に気をつける

CSSを書いていると、「あれ? `:visited` を書いたのに、親要素のユーティリティクラス(例: `.text-gray-900`)に上書きされて色が戻っちゃうんだけど!」という現象によく遭遇します。
これは詳細度(Specificity)の計算ミスが原因です。`:visited` は擬似クラスなので通常のクラスと同じ詳細度を持ちますが、CSSの記述順や、すでに定義されている他のリンクカラーのセレクタに負けてしまうことがあります。
対策: リンクの基本スタイルと同じセレクタ構造、あるいはそれ以上の詳細度を担保して定義してください。

2. リセットCSSとの組み合わせ

最近のモダンなリセットCSS(Modern CSS Resetなど)では、`a` タグの色を `inherit` にしているケースが多いです。そのため、親要素から文字色を継承してしまい、`:visited` を書いたつもりが効いているのかどうか分からない、という事故が起きます。
リンクには必ず、明示的な初期カラー(Unvisited)と訪問済みカラー(Visited)のセットを持たせることを忘れないようにしましょう。

3. デバッグ時の注意点

「ちゃんとコードを書いたのに、訪問済みの色が反映されない!」と悩んだら、まず疑うべきは「本当にそのURLをブラウザで踏んでいるか(履歴にあるか)」です。
シークレットモード(プライベートブラウジング)で検証している場合は当然履歴が残らないため、`:visited` のスタイルは絶対に確認できません。通常ウインドウで一度リンクを踏んでからリロードして確認する、という泥臭いデバッグが必要になります。

—

まとめ

CSSの `:visited` は、セキュリティという強固な制約の壁に囲まれた、少し扱いにくいヤツです。しかし、その仕様の背景にあるプライバシー保護の文脈を理解していれば、「ここでは無理に背景色を変えず、文字色(`color`)と下線の制御だけに留めよう」という、プロとして納得のいく設計判断ができるようになります。

「動かないからハックしてやろう」ではなく、「ブラウザのセキュリティ仕様と仲良く共存する」。
こういう細かい仕様への理解の積み重ねが、あなたをワンランク上のフロントエンドエンジニアへと押し上げてくれます。

明日からのコードレビューや実装に、ぜひこの知見を活かしてみてください。それでは、また現場でお会いしましょう!

コメント

タイトルとURLをコピーしました