リンクカードを実装するなら代替リンクも残さないか?
2025-11-05
リンクカードを実装した。
この行は変換されます。
https://github.com/ras0q
この行は変換されません。
[@ras0q](https://github.com/ras0q)
が、以下のように変換される。
<p>この行は変換されます。</p>
<p><a href="https://github.com/ras0q" target="_blank" rel="noopener">https://github.com/ras0q</a></p>
<aside class="linkcard bg-neutral-200 dark:bg-neutral-700 bg-opacity-50!">
<img src="https://avatars.githubusercontent.com/u/66677201?v=4?s=400" alt="ras0q - Overviewのサムネイル" loading="lazy">
<div>
<a href="https://github.com/ras0q" target="_blank" rel="noopener">ras0q - Overview</a>
<p>. ras0q has 133 repositories available. Follow their code on GitHub.</p>
</div>
</aside>
<p>この行は変換されません。</p>
<p><a href="https://github.com/ras0q" target="_blank" rel="noopener">@ras0q</a></p>
設定しているCSS
.linkcard {
position: relative;
display: flex;
flex-wrap: wrap;
margin: 1.25rem 0;
& > img {
width: 100%;
height: auto;
margin: 0;
object-fit: contain;
aspect-ratio: 2 / 1;
}
& > div {
padding: 1rem;
& > a::after {
position: absolute;
inset: 0;
content: "";
}
& > p {
margin: 0;
overflow: hidden;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
line-clamp: 3;
}
}
}
この変換が上手くいっていれば、直接リンクを貼ったときだけリンクカードが表示されているはず。↓
この行は変換されます。
この行は変換されません。
ここからは実装の話。アクセシビリティを意識したつもりだが、多分間違っているので指摘してほしい。
変換はRemarkプラグインとして実装した。HTMLに変換済みの各ページを愚直にVisitして該当するリンクをリンクカードに変換している。
https://github.com/ras0q/blog/blob/9edd5ef85613aa6b8d7fd3814d48c5e86dfbdf72/_config.ts#L36-L128
https://lume.land/plugins/remark/
ちなみに <https://github.com/ras0q> のように <> で囲んでも同じく変換される。Remarkでは <> で囲んでもそうでなくても構造に違いがないため、これらを区別できなかった。
実装方針を調べると <a> タグの中に ブロック要素を入れて大きなカードリンクとする方法と、ブロック要素の中に入れた <a> タグのクリック範囲をCSSで広げる方法の2つがあった。後者はBootstrapでStretched linkとして採用されている方法で、今回はこちらを使うことにした。Stretched linkを使うとカード全体がリンクとなるため、カード内のテキストを選択できなくなることには注意。
https://getbootstrap.com/docs/5.3/helpers/stretched-link/
僕はリーダー (アプリによってリーディングモードやリーダービューやイマーシブリーダーとも呼ぶ) で記事を読むことが多いのだが、世のWebページに実装されているリンクカードはことごとくこのリーダーからは見えなくなってしまう。これが大変不便で、せめて自分だけは...とZennにリンクカードと共に生リンクを貼る抵抗をしている。
参考:
https://zenn.dev/trap/articles/af32614c07214d
リーダーによって抽出のアルゴリズムが異なるため、リンクカードが消えるのは仕方がないということにしてリンクカードとは別に生のリンクを描画することにした。
生のリンクが見れるならリーダーでは必ずしもリンクカードを表示する必要はないため、<aside> で囲んで隠すようにした。これでも一部のリーダーでは表示されてしまうし、表示するならするで本文と区別するような描画になってくれると嬉しいのだが、<blockquote> を使うのも違う気がしたので現在はこの実装になっている。