この記事は Snow Monkey / unitone Advent Calendar 2024 6日目の記事です。まだまだ空きがたくさんあるので、ぜひお気軽にご参加ください!
unitone にはブロック全体にリンクを設定できる機能があります(unitone ではこれをブロックリンクと呼んでいます)。ただ、WordPress はブロックの中にはブロックを入れることができるし、当然テキストにはテキストリンクが設定できるので、いわゆる「リンクの中のリンクどうする問題」が発生します。
これまでブロックリンクの実装は CSS でおこなっていたのですが、先日の unitone のアップデートで JavaScript を使った実装に変更しました。今回はなぜそのような変更をしたのか、どういう変更をしたのかについて書きたいと思います。
a 要素でラップする実装(非推奨)
これは unitone ではやっていなかったのですが、一応こういう実装方法もあるよということで紹介します。
例えばこういうふうに a
でラップすることで、全体にリンクを設定することができます。
<a href="#">
<div>
これはブロックです。
</div>
</a>
ただ、a
の中に a
を入れることはできないので、テキストリンクを設定することができません。
<a href="#">
<div>
これはブロックです。<a href="#">テキストリンク</a>は不可…。
</div>
</a>
CSS による実装
ということで、unitone では不可視の a
をボックス全体に広げる形で実装していました。
※わかりやすくするために一部実際とは変えています。
<div data-unitone-layout="decorator">
<div data-unitone-layout="decorator__inner">
<div>
<p>これはブロックです。<a href="#">テキストリンク</a>も動作します。</p>
</div>
<a data-unitone-layout="decorator__link" href="#">さらに詳しく</a>
</div>
</div>
[data-unitone-layout~="decorator"] {
position: relative;
}
[data-unitone-layout~="decorator__inner"] {
position: static !important;
}
:where([data-unitone-layout~="decorator__inner"] > :not([data-unitone-layout~="decorator__link"]) a) {
position: relative;
z-index: 2;
}
[data-unitone-layout~="decorator__link"] {
position: static !important;
display: block !important;
height: 0 !important;
width: 0 !important;
text-indent: -99999px !important;
&::before {
content: '';
position: absolute;
inset: 0;
z-index: 1;
}
}
まぁおおよそこれでも良いんですけど、position
や z-index
をごにょごにょしないといけないので、中に入れるブロックによっては干渉したりコントロールが難しかったりして、微妙だなーと感じていました。
JavaScript による実装
ということで、JavaScript を使って、ブロックをクリックしたらその中の不可視の a
が自動的にクリックされるようにしたら良いんじゃないの?とひらめきました。
ただ、何も考えずに普通にやっちゃうとブロックに触れた段階でリンクしちゃうからテキストのコピーができないとか、キーボードユーザー・音声ブラウザユーザーが使いにくいとかがあると思うので、どういう実装が良いのかなと調べていたところ、下記の記事がとても参考になりました。
そして、なんかデザインに既視感があるなーと思っていたら、Every Layout の Heydon Pickering さんのサイトでした。すごい!
ということで、アップデートしてこういう実装に変更しました。
// JavaScript は苦手なのでもっとスマートな実装がありそう。
// もっと良い書き方があれば教えてください!
document.addEventListener( 'DOMContentLoaded', () => {
const decorators = document.querySelectorAll( '[data-unitone-layout~="decorator"][data-unitone-layout~="-has-link"]' );
[].slice.call( decorators ).forEach( ( decorator ) => {
let down, up;
const link = decorator.querySelector(
':scope > [data-unitone-layout~="decorator__inner"] > [data-unitone-layout~="decorator__link"]'
);
if ( !! link ) {
decorator.addEventListener( 'mousedown', ( event ) => {
event.stopPropagation();
down = +new Date();
} );
decorator.addEventListener( 'mouseup', ( event ) => {
event.stopPropagation();
if (
[ 'A', 'BUTTON', 'INPUT', 'SELECT', 'TEXTAREA' ].includes(
event.target?.tagName
)
) {
return false;
}
up = +new Date();
if ( up - down < 200 ) {
link.click();
}
} );
}
} );
} );
[data-unitone-layout~="decorator"] {
position: relative;
}
[data-unitone-layout~="decorator"][data-unitone-layout~="-has-link"] {
cursor: pointer;
&:has(:focus-visible) {
outline: auto;
outline: auto -webkit-focus-ring-color; /* for Chrome */
}
}
[data-unitone-layout~="decorator__link"] {
position: static !important;
display: block !important;
height: 0 !important;
width: 0 !important;
text-indent: -99999px !important;
}
結構使い勝手が良かったので、Snow Monkey Blocks のボックスブロックにもブロックリンクの機能を追加しました。
コメントを残す