このプロジェクトでは、リキッドレイアウトの基準となるアートボード幅の定義と、ビューポート単位の課題を解決するためのカスタムプロパティ、および特定のビューポート単位の使用を制限するStylelintの設定を提供します。
リキッドレイアウトを実装する際の基準となる、デザインカンプのアートボードの最小幅と最大幅をCSSカスタムプロパティとして定義します。
/* ======================================================
// MARK: Art Board Width
//
// リキッドレイアウトの基準となるデザインカンプのアートボードの幅を指定します。
// ====================================================== */
@property --art-board-width-min {
syntax: '<length>';
inherits: false;
initial-value: 375px;
}
@property --art-board-width-max {
syntax: '<length>';
inherits: false;
initial-value: 1440px;
}--art-board-width-min: デザインが対応する最小の幅 (初期値:375px)--art-board-width-max: デザインが対応する最大の幅 (初期値:1440px)
これらの値は、要素のサイズやマージンなどを可変にする際の計算基準として利用します。
ビューポート単位 svi, dvi, lvi をより安全かつ柔軟に利用するためのカスタムプロパティです。
100svi, 100dvi, 100lvi といったビューポートのフルサイズを表す値を @property を用いて <length> 型として定義します。これは、tan(atan2()) を使用した計算を異なる単位で組み合わせる際に、型が明確でないと正しく機能しないためです。
/* ======================================================
// MARK: Viewport Inline Size
//
// `tan(atan2())` は `@property` で `length型` で定義しないと異なる単位で組み合わせた際に機能しないため、`100svi`, `100dvi`, `100lvi` は型付けを行います。
// ====================================================== */
@property --svi-full {
syntax: '<length>';
initial-value: 0; /* :rootで実際の値が設定される */
inherits: false;
}
@property --dvi-full {
syntax: '<length>';
initial-value: 0; /* :rootで実際の値が設定される */
inherits: false;
}
@property --lvi-full {
syntax: '<length>';
initial-value: 0; /* :rootで実際の値が設定される */
inherits: false;
}svi, dvi, lvi 単位を直接使用すると、Chrome 系ブラウザでズーム機能が正しく動作しない問題が報告されています。
この問題を回避するため、三角関数 (tan(atan2())) を利用してこれらのビューポート単位を px 値に変換するカスタムプロパティを提供します。
これにより、任意の数値をビューポート単位相当の px 値として扱うことができ、ズーム機能が正しく動作します。
:root {
/* ------------------------------------------------------
// `calc`関数で number を `svi` `dvi` `lvi` に変換するためのカスタムプロパティ。
// `svi` `dvi` `lvi` をそのまま使用すると Chrome 系ブラウザのズーム機能が効かなくなるため、三角関数を使用して `px` 値に変換します。
//
// @use inline-size: calc(240 * var(--to-svi));
//
*/
--svi-full: 100svi;
--to-svi-min: calc(tan(atan2(var(--svi-full), var(--art-board-width-min))) * 1px);
--to-svi-max: calc(tan(atan2(var(--svi-full), var(--art-board-width-max))) * 1px);
--dvi-full: 100dvi;
--to-dvi-min: calc(tan(atan2(var(--dvi-full), var(--art-board-width-min))) * 1px);
--to-dvi-max: calc(tan(atan2(var(--dvi-full), var(--art-board-width-max))) * 1px);
--lvi-full: 100lvi;
--to-lvi-min: calc(tan(atan2(var(--lvi-full), var(--art-board-width-min))) * 1px);
--to-lvi-max: calc(tan(atan2(var(--lvi-full), var(--art-board-width-max))) * 1px);
}使用例:
ある数値をSmall Viewport Inline (svi) に基づいたピクセル値に変換したい場合:
.element {
/* 例えば、240という数値を --art-board-width-min における svi ベースのピクセル値に変換 */
inline-size: calc(240 * var(--to-svi-min));
}--to-svi-min,--to-dvi-min,--to-lvi-min: それぞれのビューポート単位を、--art-board-width-minを基準としたpxに変換するための係数。--to-svi-max,--to-dvi-max,--to-lvi-max: それぞれのビューポート単位を、--art-board-width-maxを基準としたpxに変換するための係数。
特定の古いビューポート単位の使用を制限し、新しい動的なビューポート単位の使用を推奨するためのStylelintルールです。
module.exports = {
rules: {
'unit-disallowed-list': [
[
'vw',
'vh',
'vi',
'vb',
'vmin',
'vmax'
],
{
message: (unit) => {
const recommendationMap = {
vw: 'svw, dvw, lvw',
vh: 'svh, dvh, lvh',
vi: 'svi, dvi, lvi',
vb: 'svb, dvb, lvb',
vmin: 'svmin, dvmin, lvmin',
vmax: 'svmax, dvmax, lvmax'
}
return `\`${unit}\`は使用しないでください。代わりに\`${recommendationMap[unit]}\`を検討してください。`
},
severity: 'warning'
}
],
},
ignoreFiles: ['**/node_modules/**']
}- 禁止される単位:
vwvhvivbvminvmax
- 推奨される単位:
vwの代わりにsvw,dvw,lvwvhの代わりにsvh,dvh,lvhviの代わりにsvi,dvi,lvivbの代わりにsvb,dvb,lvbvminの代わりにsvmin,dvmin,lvminvmaxの代わりにsvmax,dvmax,lvmax
- 重要度:
warning(警告)- これらの単位が検出された場合、Stylelintは警告を出力しますが、ビルドプロセスを停止させることはありません。
- 無視するファイル:
**/node_modules/**以下のファイルは、このルールのチェック対象外となります。
この設定により、より予測可能で安定したレイアウトを実現するために、新しい動的ビューポート単位への移行を促します。
vwやvhは環境によって表示に差があるから。- 接頭辞が無い
vwやvhは互換性のために残されているという雰囲気がひしひしと仕様の文から伝わってくるから。 vhやvwはモバイルブラウザのツールバーの影響で誤動作することがある。常にdv-,sv-,lv-を使い分ける意識をしておきたいから。- 例えば
vhは暗黙的にlvhとみなされるという定義になっている。故にモバイル端末でアドレスバーが出現している場合に見切れる可能性がある。
- 例えば
このスニペットは、コンテナクエリを利用するための基本的なCSSカスタムプロパティとコンテナコンテキスト定義、およびデバッグ用のスタイルを迅速にセットアップするためのものです。
スニペット名: container
生成されるコード:
--_container-size-min: $1;
--_container-size-max: $2;
--_to-cqi-min: calc(tan(atan2(1px, var(--_container-size-min))) * 100cqi);
--_to-cqi-max: calc(tan(atan2(1px, var(--_container-size-max))) * 100cqi);
container: $3 / inline-size;
@container style(--debug: true) {
overflow-inline: auto;
resize: inline;
}特定のコンテナ要素のサイズに基づいてスタイルを適用するコンテナクエリの実装を支援します。
このスニペットは、コンテナのベースの最小/最大サイズを定義し、それに基づいた cqi (container query inline-size) 単位へ変換するカスタムプロパティを生成します。また、コンテナの命名と、デバッグ時に役立つ視覚的なフィードバック(リサイズハンドル)を提供します。
スニペットを展開する際に、以下の値を入力します。
$1: デザインカンプで取得するコンテナの最小幅 (例:320px)--_container-size-minに設定されます。
$2: デザインカンプで取得するコンテナの最大幅 (例:1024px)--_container-size-maxに設定されます。
$3: コンテナ名 (例:my-container)containerプロパティの値として設定され、この名前でコンテナクエリの対象を指定できるようになります。
--_container-size-min:- コンテナが取りうる最小のインラインサイズ(幅)を指定します。プレースホルダー
$1の値が設定されます。
- コンテナが取りうる最小のインラインサイズ(幅)を指定します。プレースホルダー
--_container-size-max:- コンテナが取りうる最大のインラインサイズ(幅)を指定します。プレースホルダー
$2の値が設定されます。
- コンテナが取りうる最大のインラインサイズ(幅)を指定します。プレースホルダー
--_to-cqi-min:--_container-size-minを基準としたcqi値に変換するための係数を計算します。- 使用例:
width: calc(50 * var(--_to-cqi-min));は、コンテナの最小幅の約50%の幅を指定する意図で使えます。
--_to-cqi-max:--_container-size-maxを基準として、同様の計算を行います。
--_to-cqi-min および --_to-cqi-max の計算式は、コンテナの幅そのものを 100cqi とみなし、それに対する相対的なスケール値を算出するものです。これにより、コンテナの最小幅または最大幅を基準点として、レスポンシブな値を設定する際に役立ちます。例えば、あるコンポーネントがコンテナの最小幅の時には X px、最大幅の時には Y px といった値を、これらのカスタムプロパティと calc() を使って表現しやすくなります。
container: $3 / inline-size;:- コンテナクエリのコンテキストを定義します。
$3には指定したコンテナ名が入ります。inline-sizeは、コンテナのインライン幅に基づいてクエリが評価されることを意味します。
@container style(--debug: true) { ... }:- デバッグ用のスタイルコンテナクエリ。
:rootに--debug: true;を指定することでアクティブになります。 - コンテナのインライン方向にリサイズハンドルを表示し、手動でコンテナの幅を変更できるようにします。コンテナクエリの挙動をテストするのに非常に便利です。
- デバッグ用のスタイルコンテナクエリ。
使用例:
スニペットを展開し、以下のように値を入力した場合:
$1(最小幅):300px$2(最大幅):800px$3(コンテナ名):sidebar
生成されるCSS:
--_container-size-min: 300px;
--_container-size-max: 800px;
--_to-cqi-min: calc(tan(atan2(1px, var(--_container-size-min))) * 100cqi);
--_to-cqi-max: calc(tan(atan2(1px, var(--_container-size-max))) * 100cqi);
container: sidebar / inline-size;
@container style(--debug: true) {
overflow-inline: auto;
resize: inline;
}