15KB
公開:

2025/10/28

 ブログをちょっと手入れしたのでそれについて。

 これを読む私へ。以下でうだうだ語ってるけど、まとめると外部リンクにアイコン追加したら実装が面倒なことになったって話。

 この間とある記事を読んでいたところ、そういやこのブログ、外部リンクを外部リンクと表示していないな、というのに気付かされた。
 ただ、外部リンクへのアイコンって別タブで開く時に使うイメージもあったので確認した。デジタル庁デザインシステムのガイドラインを見ると、“新規タブで開くことを示すアイコン"として四角形から矢印が飛び出すアイコンを使っている。ほな違うか〜と思いつつ、U.S. Web Design System (USWDS)のLinkの項を見てみると、“a link that opens in the current tab and goes to an external website”でも“a link that opens in a new tab and goes to an external website”でも四角形から矢印が飛び出すアイコンを使っている。ということで、target=”_blank”しない私のサイトでもこの四角形から矢印が飛び出すアイコンを外部リンクに対してつけることにした。(注:デジタル庁デザインシステムのアイコンもUSWDSのアイコンも、矢印は四角形から飛び出してはいない。飛び出さない方が枠が綺麗な正方形に収まるのでアイコンの大きさや位置決めがしやすいとかの理由があるのだろうが、今回このサイト用のアイコンでは気分で飛び出させてみることにした。)

 ところが、実装してみようとすると、色々と問題があることがわかった。まず、text-decoration: underline;は使えない。これはテキストに対する装飾で、svgに対しては装飾しないからだ。私としてはsvgをクリックしてもリンクを開くようにしたいので、svgまで下線を伸ばしたかった。そこで、アイコンフォントを利用することを検討した。ただ、これは少し面倒そうだった(ので、保留し他の選択肢へ。(最終的にこれは選択しなかった。やるならGoogleのマテリアル シンボルみたいな感じになると思う。)その次は、border-bottom: solid;の利用を検討した。しかし、要素が途中で改行される場合にうまく表示させることができなかった。そこで、AIに導かれるまま、background-imageを利用して下線を引くようにした。コードは以下のよう。

document.addEventListener("DOMContentLoaded", () => {
  const currentHost = window.location.hostname;
  const allLinks = document.querySelectorAll('a');

  const iconSrc = {{ absURL "external_link.svg" }};
  // This site was generated by Hugo.
  
  const iconTemplate = document.createElement('img');
  iconTemplate.src = iconSrc;
  iconTemplate.alt = ' (外部リンク)';
  iconTemplate.className = 'external-link-icon';

  allLinks.forEach(link => {
    if (link.hostname && link.hostname !== currentHost) {
      
      const icon = iconTemplate.cloneNode(false); 
      
      // <a>要素の子要素
      link.appendChild(icon);

      link.rel = 'noopener noreferrer';
    }
  });
});
a:any-link {
  color: #b3b3b3;
  text-decoration: underline;
  text-decoration-color: oklch(0.67 0 0);
  text-decoration-thickness: 1px;
  /* 
  このtext-decoration周りの設定は以下のサイトを参考にさせていただきました。
  https://yuheiy.com/2025-03-18-underline-with-less-visual-noise
  */
}

.article a:any-link {
  text-decoration: none; /* 元の下線を消す */

  /* こんなコードが許されていいのか */
  display: inline;
  padding-bottom: 3px;
  /* (display: inline;なのでpaddingは無視されるけれど、大体の実装で存在はするので、background-imageがpaddingの部分まで表示されるようになる......) */
  /* 本当は1pxだけ実際のpadding-bottomで、2px仮想のpadding-bottomが欲しい。 */

  /* 背景画像として線を描画 */
  background-image: linear-gradient(
    oklch(0.67 0 0), /* 開始色 */
    oklch(0.67 0 0)  /* 終了色 */
  );

  background-size: 100% 1px;
  background-repeat: no-repeat;
  background-position: 0 calc(100% - 1px);
}

/* 外部リンクアイコン用のスタイル */
.external-link-icon {
  width: 0.8em;
  height: 0.8em;
  margin-left: 0.2em;
  vertical-align: top;
  display: inline;
}

 このCSS、自分の中ではかなり問題作。コメントでもとても悩んでいる。謎の実実装頼りのコードはよくない。(これって、どこかで定義された動作なんですかね。)が、手元の端末ではうまく表示されているので、また気力が湧くまではこれでいく(これ使わなくても行ける気がしなくもない。)そんなことよりも、このサイト、JPEG XLとかいうブラウザ普及率10.37%の画像ファイルフォーマットを多用しているのをどうにかした方がいい。自分の端末でも表示できないことが多々あって困る。
 あと、link.rel = 'noopener noreferrer';って要るんですかね。noreferrerはサイト側で指定するものじゃないような気もする。個々人のブラウザの設定に依るのがいいように思っているので、消そうかな〜。

 この間のイベントで出せなかった諸々をこっちで公開しようかと思って色々画策中なので、それを頑張りたいね。ただ、さまざまなタスクが山積みなので、なかなか厳しい。