記事を検索

余白とタイポグラフィのスケーリング設計

WEBサイトは、様々な文字情報から構成されます。
キャッチコピー、本文、見出し、注釈、ボタン、その他コンポーネント等々。
そしてこれらの情報を配置していく時に、各コンテンツ間が見やすくなるように、余白が必要です。

文字と余白のサイズ」をどのように決めるかは、サイトのデザインに大きく影響するだけでなく、情報の伝達というWEBの本質にも関わってきます。

タイポグラフィには文字によって情報を伝達するという明白な義務がある。

エミール・ルーダー 『タイポグラフィ』

モジュラースケーリング

そこで、個人のなんとなくの感覚でサイズ感を決めるのではなく、数学的・周波数的に美しく調和した比率例えば、黄金比の1.618、完全五度の1.5など)を使ってサイズバリエーションを導き出そうというのが、「モジュラースケーリング」と呼ばれる手法です。

例えば、以下のボックスは、比率1.5の等比数列で段階的にサイズを変化させたものです。

Demo Preview

どうでしょう、調和のとれた一定のリズムで大きさが変化していく様子になんとなく気持ちよさを感じるのではないでしょうか。

かっこよくオシャレなWEBサイトを作ろうとすると、色彩感覚やフォントの選び方、構図の勉強や動きのあるアニメーションも駆使していかねばなりません。
いわゆるデザインセンスというものも必要になってくるでしょう。

しかしながら、サイズ感・余白の間隔さえ美しい比率で構成することができれば、誰にでも「シンプルで情報が読みやすいWEBサイト」を作ることができるのではないかと個人的には考えています。

必読の参考記事:「音楽、数学、タイポグラフィ」

さて、ざっくりとモジュラースケーリングについて把握したところで、個人的にWEBに関わる人全員が一度は目を通しておくべきだと思っている素晴らしすぎる記事を紹介します。

音楽、数学、タイポグラフィ 先日開催された「フロントエンドカンファレンス福岡2019」で、「音楽、数学、タイポグラフィ」というプレゼンテーションをする機会をいただきました。ここにその内容を再構成して掲載します。
シフトブレイン/スタンダードデザインユニット

タイポグラフィに限らず、デザインと音楽は深い関連がある。そしてその背後には必ず数学的なロジックが潜んでいるようなんです。
文字サイズのスケールは音楽におけるスケール、つまり音階、ドレミファソラシドに当たります。
(~中略~) ウェブサイトやアプリケーションのタイポグラフィ設計は、まず文字サイズのスケールを定義するところから始める必要があります。

音楽、数学、タイポグラフィ

美しいスケーリングとはどういうものか、一度でも考えたことがある人であればほぼ必ず目にするであろう記事(動画)です。
なので、すでに知っている方も多いかとは思いますが、触れず進むことはできないため紹介させていただきます。

ここから先の話も、この「音楽、数学、タイポグラフィ」の内容に基づいたものです。

モジュラースケーリングで使われる比率の種類

美しいとされる比率は色々あります。有名なものであれば黄金比や白銀比なんかがありますが、モジュラースケーリングでは、純正律(周波数の比が整数比の音律)と一致する比率が採用されることが多いようです。

https://ja.wikipedia.org/wiki/%E7%B4%94%E6%AD%A3%E5%BE%8B
ja.wikipedia.org

例えば、フォントサイズや余白のスケーリングとして採用する場合、黄金率などは比率(ジャンプ率)が大きすぎて実際には扱いづらいです。
そこで、もう少し控えめな 長2度(9/8)、短3度(6/5)、長3度(5/4)あたりが使いやすいかなと思います。

Demo Preview
別タブで表示 ↗
.demo-fz-scalling {
	--fz-scale: 1.2;
	--fz--xs: calc(1rem / var(--fz-scale) / var(--fz-scale));
	--fz--s: calc(1rem / var(--fz-scale));
	--fz--base: 1rem;
	--fz--l: calc(1rem * var(--fz-scale));
	--fz--xl: calc(1rem * var(--fz-scale) * var(--fz-scale));
	--fz--2xl: calc(1rem * pow(var(--fz-scale), 3));
	--fz--3xl: calc(1rem * pow(var(--fz-scale), 4));
	--fz--4xl: calc(1rem * pow(var(--fz-scale), 5));
	--fz--5xl: calc(1rem * pow(var(--fz-scale), 6));
}

.fz--xs { font-size: var(--fz--xs); }
.fz--s { font-size: var(--fz--s); }
.fz--base { font-size: var(--fz--base); }
.fz--l { font-size: var(--fz--l); }
.fz--xl { font-size: var(--fz--xl); }
.fz--2xl { font-size: var(--fz--2xl); }
.fz--3xl { font-size: var(--fz--3xl); }
.fz--4xl { font-size: var(--fz--4xl); }
.fz--5xl { font-size: var(--fz--5xl); }

ハーモニックモジュラースケーリング

さて、さらにここから、音楽・数学・タイポグラフィ では「調和数列」に基づいた「ハーモニックモジュラースケーリング」というものが紹介されています。

フォントサイズのスケーリングを具体的に試してみた時、普通のモジュラースケーリングだと、ベースサイズ(1rem)周辺にもう少し細かなバリエーションが欲しくなるケースがけっこうあります。

かといって、全体のスケーリング比率を下げてしまうとダイナミックさがなくなってしまうため、大きい文字サイズまで到達させようとすると段階数を増やさなければなりません。

そこで登場するのが「調和数列」で、これは各項の逆数が等差数列になっている数列のことです。

引用 - 音楽・数学・タイポグラフィ

実は、Every Layout という書籍の中でも、モジュラースケーリングに触れられる章でこの数列が登場します。

そこでは、このような数列は「倍音列」と呼ばれています。(原文表記では「harmonic series」)

周波数、ピッチ、ハーモニー(和音)といった概念を耳にしたことがあるでしょう。これらはすべて数学的に定義可能なものですが、私たちが認識する「音の高さ」が、実は複数の周波数の重なりによって形作られていることをご存知でしょうか。
ギターの弦を弾いたときに出るような単一の音でさえ、それ自体がひとつの「楽曲(コンポジション)」といえます。そこに含まれる様々な周波数(倍音)は、全体として倍音列を構成しています。倍音列とは、1ずつ増加する等差数列に基づいた分数の数列のことです。

引用 - Modular scale - Every Layout

harmonic series(倍音列)
1,½,⅓,¼,⅕,⅙,...

呼び方がなんであれ、どうやらこの数列は音楽的・数学的に調和のとれた数列であるそうです。

そして、この数列の分子部分の数値を大きくした数列をフォントサイズのスケーリングに活用すると、かなりいい感じになります。

分子8、等差1の調和数列: 8/1, 8/2, 8/3, 8/4, 8/5, 8/6, 8/7, 8/8, ...
分子7、等差1の調和数列: 7/1, 7/2, 7/3, 7/4, 7/5, 7/6, 7/7, 7/8, ...

上記の数列の中で、数値が1となるポイント(8/87/7)が、それぞれのベースサイズ(≒ 1rem)となるようにスケーリングを定義します。(大きい方向のバリエーション数には上限があるという点には注意が必要です。

このようなスケーリングを「ハーモニックモジュラースケーリング」と呼ぶそうです。

実際にフォントサイズに適用する例

分子を8とする調和数列をハーモニックモジュラースケーリングとして採用する場合のCSSの例を以下に示します。

--fz--base: 1rem; /* 8/8 = 1 */
--fz--l: 1rem * 8/7; /* 8/7 = 1.1428571428571428 */
--fz--xl: 1rem * 8/6; /* 8/6 = 1.3333333333333333 */
--fz--2xl: 1rem * 8/5; /* 8/5 = 1.6 */
--fz--3xl: 1rem * 8/4; /* 8/4 = 2 */
--fz--4xl: 1rem * 8/3; /* 8/3 = 2.6666666666666665 */
--fz--5xl: 1rem * 8/2; /* 8/2 = 4 */
--fz--6xl: 1rem * 8/1; /* 8/1 = 8 */

実際に確認してみましょう(分子を7,8,9で切り替えれるようなデモを用意しました)。

Demo Preview
別タブで表示 ↗
.demo-fz-scalling[data-harmonic="8"] {
	--fz--xs: calc(1rem * (8 / 10));
	--fz--s: calc(1rem * (8 / 9));
	--fz--base: 1rem;
	--fz--l: calc(1rem * (8 / 7));
	--fz--xl: calc(1rem * (8 / 6));
	--fz--2xl: calc(1rem * (8 / 5));
	--fz--3xl: calc(1rem * (8 / 4));
	--fz--4xl: calc(1rem * (8 / 3));
	--fz--5xl: calc(1rem * (8 / 2));
}
.demo-fz-scalling[data-harmonic="9"] {
	--fz--xs: calc(1rem * (9 / 11));
	--fz--s: calc(1rem * (9 / 10));
	--fz--base: 1rem;
	--fz--l: calc(1rem * (9 / 8));
	--fz--xl: calc(1rem * (9 / 7));
	--fz--2xl: calc(1rem * (9 / 6));
	--fz--3xl: calc(1rem * (9 / 5));
	--fz--4xl: calc(1rem * (9 / 4));
	--fz--5xl: calc(1rem * (9 / 3));
}
.demo-fz-scalling[data-harmonic="7"] {
	--fz--xs: calc(1rem * (7 / 9));
	--fz--s: calc(1rem * (7 / 8));
	--fz--base: 1rem;
	--fz--l: calc(1rem * (7 / 6));
	--fz--xl: calc(1rem * (7 / 5));
	--fz--2xl: calc(1rem * (7 / 4));
	--fz--3xl: calc(1rem * (7 / 3));
	--fz--4xl: calc(1rem * (7 / 2));
	--fz--5xl: calc(1rem * (7 / 1));
}

.fz--xs { font-size: var(--fz--xs); }
.fz--s { font-size: var(--fz--s); }
.fz--base { font-size: var(--fz--base); }
.fz--l { font-size: var(--fz--l); }
.fz--xl { font-size: var(--fz--xl); }
.fz--2xl { font-size: var(--fz--2xl); }
.fz--3xl { font-size: var(--fz--3xl); }
.fz--4xl { font-size: var(--fz--4xl); }
.fz--5xl { font-size: var(--fz--5xl); }

個人的には、日本語サイトなら分子8がちょうど良いいくらいかなと感じます。
ただ、英語であれば分子7くらいのダイナミックさがあっても良さそうですね。

調和数列をもとにした文字サイズのスケーリングの特徴

調和数列をもとにした文字サイズのスケールにはもうひとつ特徴があります。日本語や中国語など、全角文字を並べたときに、このように数文字ごとに幅が揃うんです。(…中略…) ここで重要なのは並べたときにきっちり幅が揃うということよりも、それぞれのサイズが意味のある比率にもとづいているという点です。

音楽・数学・タイポグラフィ

引用 - 調和数列に基づく一連の文字サイズ

これはまさに、さきほど Every Layout から引用した 倍音列の周波数の図の通りの特徴です。
調和の取れたスケーリングとなっていることがわかります。

縦のリズムとフィボナッチ数列

次に、音楽・数学・タイポグラフィでは「縦のリズム」についても触れていきます。

タイポグラフィには「縦のリズム」、ヴァーティカル・リズムという概念があります。これは横組である欧文のタイポグラフィに由来する概念で、行の折り返しによって生まれる行間や、要素間の余白に一貫性があるかどうか、という視点です。この縦のリズムに規則性がないと、読みづらかったり、情報のヒエラルキーが正しく伝わらなかったりします。これはビューが縦方向に長くなるスマホではとくに重要な視点です。

音楽・数学・タイポグラフィ

行間・余白のベースサイズをリズムの単位と捉える考え方のようです。

この縦のリズムの視点から考えてみると、普通のモジュラースケーリングを採用した場合、それぞれのスケーリング数値はベースとなる数値(リズムの単位)の整数倍にはならない、つまりリズムが乱れてしまうことに気づきます。

ではどうすればリズム感を保ったスケーリングができるでしょうか。

そこで登場するのが、フィボナッチ数列です。

1、1、2、3、5……フィボナッチ数列は、各項の値が前の2つの項の合計になっています。そして隣り合う項の比率がどんどん黄金比(1.618)に近づいていくという特徴があります。これをスペーシングのスケールに利用します。

音楽・数学・タイポグラフィ
フィボナッチ数列のスケーリング感

さて、これを見てどう感じましたでしょうか。
個人的には、とても美しく感じます。これを初めて見た時にとてもしっくりきたのを覚えています。

リズムの単位を決める

このフィボナッチ数列を採用するにあたって、重要となってくるのは1にあたる数値をどうするかです。

つまり、リズムの単位をどう決めるかです。 こればかりは、いろいろ試してみて、そのサイトにとって一番良いものを選ぶしかないですね。

「音楽・数学・タイポグラフィ」では、行間の単位を4px、スペーシングの単位を8pxを一つの単位として定義することを(あくまでただの一案として)提案されています。

8や4の倍数というのは、WEBデザインではしばしば使われる数値ですね。基本はこのあたりの数値感を目安にするのが良いかと思います。

余白のスケーリングの個人的な採用例

スケーリング単位は4pxまたは8pxで組むとよいかなと感じました。

4, 8 を基準にしたそれぞれのフィボナッチ数列は次のような並びです。

4: 4 8 12 20 32 52 84 136 220
8: 8 16 24 40 64 104 168 272

どちらかの数列をそのまま採用してもいいのですが、個人的には少し混ぜて使うとちょうどよく感じました。

:root {
/* 余白の単位 ( 0.5rem = 8px ) */
--s-unit: calc(var(--REM) * 0.5); /* ≒ 8px */
/* 単位 8 での フィボナッチ数列 */
--s--10: var(--s-unit);
--s--20: calc(2 * var(--s-unit));
--s--30: calc(3 * var(--s-unit));
--s--40: calc(5 * var(--s-unit));
--s--50: calc(8 * var(--s-unit));
--s--60: calc(13 * var(--s-unit));
--s--70: calc(21 * var(--s-unit));
--s--80: calc(34 * var(--s-unit));
/* 例外 */
--s--5: calc(0.5 * var(--s-unit));
--s--15: calc(1.5 * var(--s-unit));
}

基本は 8ベースのフィボナッチ数列を 10, 20, 30, … に並べ、例外的に 5, 15 を追加しています。

縦のリズムを組む時は基本的に 10, 20, 30, 40 … のトークン値(≒ 8の倍数)を使いながら、テキストとアイコンの隙間などの横方向の余白としては細かい 5 が欲しかったり、ボックスのpaddingで 15 くらいがあると便利だったりします。

この時、5, 10, 15 は 4を単位としたフィボナッチ数列の前半の並びとも一致するので、ちょうど不自然にならない良い感じのスケーリングとなります。

Demo Preview

行間(line-height)をどうするか?

さて、難しいのが行間の管理です。

「よし、じゃあ行間の単位を 4px としよう」と決めたとして、WEBではそれをどう管理していけばよいでしょうか。

いろんなフォントサイズの要素があるため、それらに対して一つずつline-heightも計算してセットしていくのは少し現実的ではありません。 全要素に影響するような部分でスクリプトを使うのも、できれば避けたいです。

フォントサイズのバリエーションをせっかく美しい規則でスケーリング設定して用意しているのだから、それだけを使うようにしてそれぞれに対してline-heightも4pxの倍数でセットするようにすればいいかもしれませんが、実際は例外的なサイズが出てきたりしますし、同じフォントサイズだからといって常に同じ行間をセットすればよいというものでもありません。

もう少し汎用的で、かつ少ないコード量で、しかも縦のリズムを崩さずにline-heightを管理する方法はないだろうか…?

と考えた末、個人的に思いついた管理方法を紹介しておきます。

line-height はハーフレディングで管理する

ハーフレディングとは

line-heightによって文字の上下に余白が生まれますが、この上下の余った部分の余白を、ハーフレディング(Half-Leading)と呼びます。

例えば、font-size:16pxline-height: 1.5の場合、テキストの上下に余るスペースは単純計算すると16px * 0.25 = 4pxずつとなります。この4pxがハーフレディングの値になります。

私が提案する手法は、「タイポグラフィにおける縦のリズムで重要となるのは、line-height全体の数値感ではなく、このハーフレディングの余白感の方ではないか…?」 という仮説を前提にしています。

もしそうであれば、「line-heigh ≒ フォントサイズ(1em) + ハーフレディング」なので、ハーフレディング部分を変数として可変できるようにしておけばいいじゃないかと思ったわけです。

実際にどんなCSSになるか、見ていただきましょう。

/* bodyには基準値をセット */
body{
--hl: var(--hl--base);
}
/* 全て要素のline-heightを、ハーフレディングで管理 */
* {
line-height: calc(1em + var(--hl) * 2);
}

初見だとなかなか気持ち悪いことをしていると思われるかもしれませんが、このようにして、全要素のline-heightを、ハーフレディングを基準とするようにカスタマイズしています。

ハーフレディングのスケーリング

line-height--hlという変数に依存する値となったため、スケーリングさせるのもこの--hlとなります。

ハーフレディングのスケーリングは、基準とする単位(リズムの単位)を --hl-unit として定義した上で、その数値による等差数列で定義します。

:root{
/* 単位 ≒ 0.125rem ≒ 2px ( 上下合わせて ≒ 4px) */
--hl-unit: calc(var(--REM) * 0.125);
/* --hl-unit の等差にすることで、上下合わせて ≒ 4pxずつ増減する */
--hl--xs: var(--hl-unit);
--hl--s: calc(var(--hl-unit) * 2);
--hl--base: calc(var(--hl-unit) * 3);
--hl--l: calc(var(--hl-unit) * 4);
}

ハーフレディングの単位を2pxから始めることで、上下合わせて4pxの倍数の余白がどんな文字サイズに対しても付けれるようになります。

この管理方式ののメリット

この方式のメリットは3点あります。

  1. 文字上下の余白量が一定になることで、縦のリズムをキープしやすい。
  2. ハーフレディングのトリミングに計算式が必要なくなる。
  3. フォントサイズが大きい時に行間が大きくなりすぎてしまう問題が発生しない。

個人的推しポイントは 3. です。

これは実際に見てもらったほうが早いでしょう。

以下のデモでは、フォントサイズに8を分子とするハーモニックモジュラースケーリングを採用した上で、ハーフレディングを基準とするようにline-height をカスタマイズしています。

Demo Preview
別タブで表示 ↗
:root {
	/* 分子8 の ハーモニックモジュラースケーリング */
	--fz--xs: calc(1rem * (8 / 10));
	--fz--s: calc(1rem * (8 / 9));
	--fz--base: 1rem; /* ここを clamp() にしてもOK */
	--fz--l: calc(1rem * (8 / 7));
	--fz--xl: calc(1rem * (8 / 6));
	--fz--2xl: calc(1rem * (8 / 5));
	--fz--3xl: calc(1rem * (8 / 4));
	--fz--4xl: calc(1rem * (8 / 3));
	--fz--5xl: calc(1rem * (8 / 2));


	/* ハーフレディング単位 を 0.125rem ≒ 2px ( 上下合わせて ≒ 4px) とする */
	--hl-unit: calc(var(--fz--base) * 0.125);

	/* --hl-unit の等差にすることで、上下合わせて ≒ 4pxずつ増減する */
	--hl--xs: var(--hl-unit);
	--hl--s: calc(var(--hl-unit) * 2);
	--hl--base: calc(var(--hl-unit) * 3);
	--hl--l: calc(var(--hl-unit) * 4);
}

body{
	--hl: var(--hl--base);
	font-size: var(--fz--base);
}

/* 全て要素のline-heightを、ハーフレディングで管理 */
* {
	line-height: calc(1em + var(--hl) * 2);
}


.demo-fz-scalling > p{
	max-inline-size: 25em;
}
.demo-fz-scalling > * + * {
	margin-block-start: 2rem;
}

.fz--xs { font-size: var(--fz--xs)}
.fz--s { font-size: var(--fz--s); }
.fz--base { font-size: var(--fz--base); }
.fz--l { font-size: var(--fz--l); }
.fz--xl { font-size: var(--fz--xl); }
.fz--2xl { font-size: var(--fz--2xl)}
.fz--3xl { font-size: var(--fz--3xl); }
.fz--4xl { font-size: var(--fz--4xl);}
.fz--5xl { font-size: var(--fz--5xl);}

.hl--xs { --hl: var(--hl--xs) }
.hl--s { --hl: var(--hl--s) }
.hl--base { --hl: var(--hl--base) }
.hl--l { --hl: var(--hl--l) }

少し運用面で癖があるものの、気持ちいリズムが自然とできてはいないでしょうか。

これまでは、h1, h2, .fz—xl などの要素に対してベーススタイルとして行間を調整していましたが、なにもしなくても読みやすい行間となっており、細部での必要な箇所でのみ --hl を変化させればよくなりました。

Lism CSS では、さらにここにclamp()を使った流体タイポグラフィを導入したりしています。

まとめ

  • フォントサイズには、ベースサイズ周辺のバリエーションが豊富な「ハーモニックモジュラースケーリング」(調和数列)が使いやすい
  • 余白には、整数倍で縦のリズムを保ちながら黄金比に近づく「フィボナッチ数列」が有効
  • 行間 (line-height)には、ハーフレディングを基準とするようなカスタマイズを加えることで、縦のリズムをキープしやすくなる