CSSの三角関数を使ってJSなしできれいな斜線を引きたい!
この記事はCSS Advent Calendar 2024の18日目の記事です。
LAWGUEでは、Wordのようにテーブルセル内で斜線を表示する機能があります。
現在は transform: rotate
でDOM要素を回転させて斜線を表示していますが、他にも新しい機能や方法があるのではないかと思い、斜線の描画方法についていくつか検証してみました。
既存の斜線の例
グラデーションの斜線
おそらく斜線を引きたい場合これが一番使われているのではないかと思います。
background-image: linear-gradient(to top right, transparent calc(50% - 1px), black, transparent calc(50% + 1px));
メリット
- 簡単に斜線が引ける
デメリット
- 角度などによってはアンチエイリアスが効かない挙動に見える場合がある
参考: https://www.will3in.co.jp/frontend-blog/article/antialiasing-linear-gradient-oblique-line/
薄い色だと目立たないが黒などの濃い色だと目立ちやすい - 複雑なカスタマイズが難しい
rotate で傾ける斜線
現状のLAWGUEで用いている方法。
JSで縦幅と横幅を取得し、傾きを計算。要素のサイズが変更される場合、ResizeObserver
の対応も必要です。
メリット
- DOM を回転しているだけなので柔軟にカスタマイズができる
デメリット
- 斜線を引きたいだけなのにJSを使わないといけない感がある
CSS の三角関数 atan2 とコンテナークエリーの長さ単位を使って計算できるか?
CSS の 三角関数 atan2
を使うと、要素の横幅と高さが分かれば角度を求めることができます。つまり、どうにかして要素の高さと横幅をCSS側で取得することができれば…
最近出た cqw
や cqh
で要素の横幅と高さは取れるはず!
クエリーコンテナーとして設定したものに対してサイズが取得できるはずなので、それを用いて試してみました。
<div class="container">
<!-- 可変コンテンツの例 -->
<textarea readonly style="display: block; width: calc(100vw - 16px); max-width: calc(100vw - 16px); height: calc(100vh - 16px); max-height: calc(100vh - 16px); outline: none;">
</textarea>
<div class="diagonal-box"></div>
</div>
.container {
position: relative;
width: fit-content;
}
.diagonal-box {
container-type: size;
position: absolute;
height: 100%;
background: rgba(0,0,0,0.25);
top: 0;
left: 0;
width: 100%;
overflow: hidden;
pointer-events: none;
&::before {
content: "";
display: block;
position: absolute;
width: max(200cqh, 200cqw); // どちらか2倍すればとりあえずははみ出る
border-bottom: 1px solid #000;
transform: rotate(atan2(100cqh, 100cqw)); // atan2 を用いて角度を取得
transform-origin: left top;
top: 0;
left: 0;
}
}
.container
を position: relative;
にし、その中に斜線を描画する div
を配置します。その div
をクエリーコンテナーとして container-type: size;
を設定した上で、擬似要素 ::before
で cqh
と cqw
を用いて角度を計算し、斜線を引くという仕組みです。
検証結果
以下は2024年12月18日時点での各ブラウザでの挙動です。
Chrome
なぜか45度固定のような挙動になり、 atan2(100cqh, 100cqw)
が常に atan2(1,1)
のように処理されているように見えました。値が正しく解釈されていないようです。(無効値扱いになってほしいところですが…)
Firefox
角度がつかず、ただの水平線になってしまいました。
現時点では atan2
内でコンテナークエリーの長さ単位を使用すると、Firefox では無効な値として解釈されているようです。
Safari
うまくいってる!
Safari では期待通りうまく斜線が引けました!
デモ(現状 Safari でしか動きません)
古い Safari だと
18.2 より前のものだと Chrome と同じように45度になるようでした。
18.2 のリリースノートだと calc で変更があったようなので、その対応で atan2 も調整が入ったのかもしれません。18.2 ではうまくいき、18.1 では45度になってしまうようでは現状使い所が難しい印象です。
まとめ
現状最新の Safari でしか期待通りに動きませんが、うまく斜線を引くことができました。atan2
と cqw/cqh
を組み合わせることで、JSを用いずに要素のサイズに応じた斜線を描ける可能性があることがわかりました。他のブラウザでも対応が進むことを期待します。
それでは、よいCSSライフを!
Discussion