カード全体を1つのリンクでクリック可能にする(stretched link + :has(:focus-visible))
タイトルのリンクの ::after をカードいっぱいに広げてクリック範囲にし、フォーカスリングはカード側に :has() で描く。
どんな時に使う?
- ブログ一覧や商品一覧のカードで、タイトルだけでなくカードのどこを押しても詳細ページに飛ばしたいとき。
- カード全体を
<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は主要ブラウザで利用可能。
出典
- @sanyampunia(2026-10-29 投稿)