CSSの三角関数とzoomプロパティを組み合わせて、画面幅に合わせていろいろな物を画像のように拡縮できるというテクニックがXにあったので、その理屈を確認したメモです。
凄いテクニック: https://twitter.com/tak_dcxi/status/1890589347227087120
今回は凄いテクニックをベースに、若干値を変更した以下のデモをベースに説明を書きます
CSSの三角関数とzoomプロパティを組み合わせて、画面幅に合わせていろいろな物を画像のように拡縮できるコード
デモはデザインデータが1400px × 800px になっている状態でそこから取り出したパスの値を使って offset-path: path()
で実装したものを、画面のサイズに合わせて拡大縮小したいデモです。
拡大縮小したい部分を以下の .zoom-wrapper
で囲んでいます。
@property --zoom-factor {
syntax: "<length>";
inherits: false;
initial-value: 0;
}
.zoom-wrapper{
--min-viewport-width: 375px; /* viewportの最小値を下回ったら縮小をやめる */
--max-viewport-width: 2560px; /* viewportの最大値を上回ったら拡大をやめる */
--viewport-width: 1400px; /* デザイン上のサイズ */
--zoom-factor: 100dvi;
--zoom-value: clamp(
tan(atan2(var(--min-viewport-width), var(--viewport-width))),
tan(atan2(var(--zoom-factor), var(--viewport-width))),
tan(atan2(var(--max-viewport-width), var(--viewport-width)))
);
zoom: var(--zoom-value);
-webkit-text-size-adjust: initial; /* iOS Safariのバグ回避 */
}
tan(atan(値1, 値2))
と @property
と zoom
の意味を確認
上記のコードのポイントは tan(atan(値1, 値2))
と @property
を使って、画面幅に応じて zoom
の値を変化させていること。
まずはそれらの関数やアットルールが何かを確認します。
atan2(y, x)
: iOS15.4から
atan2() – CSS: Cascading Style Sheets | MDN
アークタンジェント2(ふたつの引数をとるアークタンジェント)の関数。
CSSのアークタンジェントについての、今回のポイント
atan2(100px, 5vw)
のような異なる単位の数値を入れてもOK。- ふたつの値から角度を表すラジアン(rad)の数値が返る。
そもそものアークタンジェント2とは
アークタンジェント2の仕組みは「x,yの座標の値を入れると角度が出る」。
例えば、xが3、yが2のときは、atan2(2,3)
となり33.69deg
に相当する0.588rad
が返ってくる
計算機:https://calculatorlib.com/ja/atan2-calculator?x=3&y=2
直角三角形の底辺=x、高さ=yで、底辺xに対して高さyの斜辺がなす角度の計算するatan()
と基本は同じ。
atan2()
の方が、xが負の値の時もうまく計算できるというような特徴がある。

参考:http://nomoreretake.net/2013/10/21/arctan2/
参考:https://ja.wikipedia.org/wiki/Atan2
tan()
: iOS15.4から
https://developer.mozilla.org/en-US/docs/Web/CSS/tan
タンジェントの関数。
CSSのタンジェントについての、今回のポイント
tan(33.69deg)
のように角度を渡すと、単位無しの数値が返る。
そもそもタンジェントとは
タンジェントは「角度を渡すと傾きが出る」。傾きは「変化の割合(比率)」。
例えば角度が33.69°のときtan(33.69deg)
となり、2/3
にあたる 0.666665
が返ってくる。
計算機:https://calculatorlib.com/ja/tangent-calculator?angle=33.69&inputUnit=degrees
タンジェントは直角三角形の高さ/底辺で、それがそのまま斜辺の傾きの割合を示している。

@property
: iOS16.4から
@property – CSS: カスケーディングスタイルシート | MDN
CSSカスタムプロパティについて、型の定義や継承するかどうかを設定をするアットルール。
@property
についての、今回のポイント
Safariの場合にatan2()
の計算を正しくさせるためにいったん @property
で型定義したカスタムプロパティに100dviを格納して length であることを明示している。
※ Chromeの場合は前述のatan2()
に 100dvi
を直接渡しても計算できるらしい
zoom
: iOSは昔から / Firefoxが2024年から
zoom – CSS: カスケーディングスタイルシート | MDN
要素の大きさを拡大縮小するプロパティ。
transform:scale()
や scale()
と似ているが、見た目だけではなくてレイアウト計算に使う要素の大きさ自体が変わるのが特徴。
値としては 1
のような数値か 100%
のようなパーセンテージが設定できる。
コード全体の確認
1. @property
で 100dvi
を atan2()
に入れても壊れないようにする
@property --zoom-factor {
syntax: "<length>";
inherits: false;
initial-value: 0;
}
2. 計算の基準に使う画面の幅を設定する
--min-viewport-width: 375px; /* viewportの最小値を下回ったら縮小をやめる */
--max-viewport-width: 2560px; /* viewportの最大値を上回ったら拡大をやめる */
--viewport-width: 1400px; /* デザインのサイズ */
今回は以下の希望から設定値を決定しました。
- 画面幅が375px未満の時、2560pxを超えるときは拡縮を止めたい
- 画面幅が1400pxのときはzoomの値は1(100%の意味)にしたい
3. zoomに設定したい値の計算式を作る
--zoom-factor: 100dvi;
--zoom-value: clamp(
tan(atan2(var(--min-viewport-width), var(--viewport-width))),
tan(atan2(var(--zoom-factor), var(--viewport-width))),
tan(atan2(var(--max-viewport-width), var(--viewport-width)))
);
tan(atan2(値1, 値2))
とすると、結果としては 値1 / 値2
(の単位無し)が得られるので、結果的に以下のような感じになります。
- 最小値:375 / 1400 (およそ0.268)
- 推奨値:画面の幅 / 1400(画面幅700のとき0.5 / 画面幅1400のとき1など)
- 最大値:2560 / 1400(およそ1.829)
4. zoomプロパティに計算した値を渡す
zoom: var(--zoom-value);
これで、画面の幅が700pxならzoom:0.5
、画面の幅が1400pxなら zoom:1
のように画面の幅に応じて値が変わる zoom
プロパティの設定完了です。
※そのほか-webkit-text-size-adjust: initial;
を入れることで別途iOS Safariのズーム関連のバグを回避しています。
【再確認】CSSの三角関数とzoomプロパティを組み合わせて、画面幅に合わせていろいろな物を画像のように拡縮できるコード
@property --zoom-factor {
syntax: "<length>";
inherits: false;
initial-value: 0;
}
.zoom-wrapper{
--min-viewport-width: 375px; /* viewportの最小値を下回ったら縮小をやめる */
--max-viewport-width: 2560px; /* viewportの最大値を上回ったら拡大をやめる */
--viewport-width: 1400px; /* デザイン上のサイズ */
--zoom-factor: 100dvi;
--zoom-value: clamp(
tan(atan2(var(--min-viewport-width), var(--viewport-width))),
tan(atan2(var(--zoom-factor), var(--viewport-width))),
tan(atan2(var(--max-viewport-width), var(--viewport-width)))
);
zoom: var(--zoom-value);
-webkit-text-size-adjust: initial; /* iOS Safariのバグ回避 */
}
コメント