テック技報最新号へ →
CSS

カード全体を1つのリンクでクリック可能にする(stretched link + :has(:focus-visible))

タイトルのリンクの ::after をカードいっぱいに広げてクリック範囲にし、フォーカスリングはカード側に :has() で描く。

@sanyampunia · 投稿 2026-10-29
#カード#リンク#アクセシビリティ#has#focus-visible#疑似要素

どんな時に使う?

  • ブログ一覧や商品一覧のカードで、タイトルだけでなくカードのどこを押しても詳細ページに飛ばしたいとき。
  • カード全体を <a> で囲むと、スクリーンリーダーがカード内の全テキストをリンク名として読み上げてしまい、中にボタンや別リンクも置けない。この方法ならリンクはタイトルの1つだけのままで、クリック範囲だけをカード全体に広げられる。

コード

html
<article class="card">
  <img src="thumb.jpg" alt="">
  <h3><a class="card-link" href="/posts/1">記事タイトル</a></h3>
  <p>概要テキスト…</p>
</article>
css
.card {
  position: relative; /* ::after の基準にする */
}

/* リンクの疑似要素をカード全体に広げる */
.card-link::after {
  content: "";
  position: absolute;
  inset: 0;
}

/* キーボード操作時のフォーカスリングはカード全体に出す */
.card:has(.card-link:focus-visible) {
  outline: 2px solid;
  outline-offset: 2px;
}
.card-link:focus-visible {
  outline: none;
}
  • inset: 0 は top/right/bottom/left: 0 の一括指定。position: relative を持つ一番近い祖先(ここではカード)いっぱいに広がる。
  • リンク自身にリングを出すとタイトル文字の周りだけが囲まれて「どこが押せるのか」が分かりにくい。:has(:focus-visible) で親のカードに枠を出すと、クリック範囲と見た目が一致する。

注意点

  • カード内に別のボタンやリンク(「いいね」ボタン、タグのリンクなど)を置く場合は、それらに position: relative; z-index: 1; を付けて ::after より上に出さないと押せなくなる。
  • カード内のテキストはリンクの上に覆いが乗るので、ドラッグでの文字選択がしにくくなる。選択させたい文章が多いカードには向かない。
  • カードの途中に position: relative を持つ要素があると、::after がそちらに収まってしまうので注意。
  • :has() と :focus-visible は主要ブラウザで利用可能。

出典

X の元の投稿を開く