0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Stretched Link パターン — カード内でリンク先を分けるテクニック

0
Posted at

概要

PostCard でカード全体をクリックすると投稿詳細に遷移し、アバター部分だけクリックするとユーザーページに遷移させたかった。HTML ではリンク(<a>)のネストは無効なので、CSS の ::after 疑似要素を使った「Stretched Link パターン」で解決した。

どういうこと?

image.png

例えば上みたいな

  • 1投稿をクリックしたらその投稿の詳細画面にいける
  • 右下のアバターアイコンをクリックしたら、そのUserのprofile画面に飛べる

でこれをやろうとして、この投稿(Card)を全部 Link で囲んで、
アバターのアイコンをLinkで囲むってことをやろうとしたが、
そもそも a タグは ネストできないらしいのでどうしましょということが起きた。

最初は以下のように 投稿の画像は専用のLinkでavatarは別のLinkでやっていた。
ただCardにホバーしたら 大きくなるcss組み込んでて、「全部クリックできる」UXを
醸し出していたから気持ち悪さが残っていた。

    <Card>
      <Link>
        <div>
          {/* 投稿の画像の部分 */}
        </div>
      </Link>
      <CardContent>
        {/* tagの部分 */}
        <Link>
          {/* avatarの部分 */}
        </Link>
      </CardContent>
    </Card>

結論

やりたいこと 方法
カード全体を 1 つのリンクにする ::after + absolute + inset: 0 でリンク領域を親要素全体に広げる
一部だけ別のリンクにする そのリンクに relative + z-index を付けて ::after の上に浮かせる

::after 疑似要素とは

CSS の ::after は、要素の内部の末尾に自動で挿入される擬似的な子要素。HTML の DOM には現れないが、CSS でサイズや位置を持たせることができる。

.link::after {
  content: ""; /* これがないと生成されない */
  position: absolute;
  inset: 0; /* top/right/bottom/left 全て 0 → 親要素いっぱいに広がる */
}

content: "" で空の要素が生成され、absolute + inset: 0 で直近の position: relative な祖先要素を基準に全体を覆う。見た目は透明だが、クリック可能な領域として機能する。

仕組み

要素の構造

Card (relative)              ← ::after の基準
├── Link (after:absolute after:inset-0)
│   ├── ::after              ← Card 全体を覆う透明なクリック領域
│   └── 画像
└── CardContent
    ├── タグ                 ← ::after の下 → クリックすると Link が反応
    └── アバター Link (z-10) ← ::after の上 → クリックするとこちらが反応

z-index による重なり制御

z-index: 10  → アバター Link(ユーザーページへ)
z-index: 0   → ::after 疑似要素(投稿詳細へ)

::after はカード全体を覆っているが、アバターは z-10 でその上にいるため、アバターの領域だけはアバターのリンクが優先される。

クリック時の挙動

クリック場所 何が受け取るか 遷移先
画像 ::after(= 画像の Link) 投稿詳細
タグ ::after(= 画像の Link) 投稿詳細
アバター アバターの Link(z-10) ユーザーページ

実装(Tailwind CSS)

<Card className="relative">
  {/* カード全体のリンク: ::after で Card 全体にクリック領域を広げる */}
  <Link href="/posts/1" className="after:absolute after:inset-0">
    <Image ... />
  </Link>

  <CardContent>
    <div>タグ</div>
    {/* アバターだけ別リンク: z-10 で ::after の上に浮かせる */}
    <Link href="/users/1" className="relative z-10">
      <Image ... />
    </Link>
  </CardContent>
</Card>

Tailwind の after: プレフィックスは ::after 疑似要素にスタイルを適用する。content: "" は Tailwind が自動で付与するため明示不要。

When using these variants, Tailwind will automatically add content: '' by default so you don't have to specify it unless you want a different value:

注意点

  • Card に relative がないと、::afterabsolute が意図しない祖先を基準にしてしまう
  • <a> のネストは HTML 仕様で無効なので、このパターンはネストを避けつつ同等の UX を実現する手段として有効

終わりに

前作った時に、Linkを2つくらいに分けて作った記憶があり、スマートじゃないなと感じてたのでよかった。わーい。他の方法あれば教えてください。SNS系とか投稿系のサービスはよく使うテクニックだと思う。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?