恐竜に教える現代のCSS – Part 1


注釈:
「CSSでピクセルをいじるのは確かに難しかった! 今じゃHTMLで非セマンティックなクラス名とかインラインCSSとかを使うのがクールで、JavaScriptでCSSスタイルを書いたりもできるって!」
「『ファミリー・ガイ』の『CSS』GIF(訳注:米アニメ『ファミリー・ガイ』のキャラクターを使った、CSSを扱う厄介さを示唆するGIF画像)をここに挿入」
「ハハッ!」

CSSは不思議なことに、Web開発者が学ぶ中で非常に易しいとも難しいとも考えられている言語です。確かに、CSSは簡単に始められます。特定の要素に適用するスタイルの属性と値を定義して、それから……いえ、差し当たって必要な作業はほぼそれだけです。しかし、比較的大規模なプロジェクト向けに意義のある形でCSSを組むとなると、作業は複雑に入り組んできます。あるページのある要素のスタイルを指定しようとCSSのどの行を変更しただけでも、他のページの要素に意図しなかった変化をもたらすことも多いのです。

本来複雑なCSSに対応するために、多様なベストプラクティスが確立されています。問題なのは、どのベストプラクティスが実際に最善であるかについて見解がはっきり一致しておらず、多くのベストプラクティスが完全に相反しているように見えることです。CSSを初めて学ぼうとしている人は、この状況に少なくとも混乱してしまうでしょう。

本記事の目的は、CSSのアプローチとツールが2018年の今日までどう進化してきたかについて歴史的背景をご紹介することです。歴史を理解すれば、各アプローチと、それらを自分のためにどう利用できるかが理解しやすくなるはずです。では始めましょう。

CSSを基本的なスタイル指定に使う

基本的なWebサイトを例に見ていきましょう。単純なindex.htmlファイルが別個のindex.cssファイルにリンクしているという構成です。

1. 2018-02-21_131352

現在のところ、このHTMLにclassやidはなく、使っているのはセマンティックタグだけです。CSSの指定が特になければ、このWebサイトの外観は以下のようになります(プレースホルダテキストを使用)。


実行例はこちら

実用面の支障はないものの、あまり見栄えがしません。index.cssにCSSの指定を追加して、基本的な体裁を改善しましょう。

  1. /* BASIC TYPOGRAPHY */
  2. /* from https://github.com/oxalorg/sakura */
  3. html {
  4. font-size: 62.5%;
  5. font-family: serif;
  6. }
  7.  
  8. body {
  9. font-size: 1.8rem;
  10. line-height: 1.618;
  11. max-width: 38em;
  12. margin: auto;
  13. color: #4a4a4a;
  14. background-color: #f9f9f9;
  15. padding: 13px;
  16. }
  17.  
  18. @media (max-width: 684px) {
  19. body {
  20. font-size: 1.53rem;
  21. }
  22. }
  23.  
  24. @media (max-width: 382px) {
  25. body {
  26. font-size: 1.35rem;
  27. }
  28. }
  29.  
  30. h1, h2, h3, h4, h5, h6 {
  31. line-height: 1.1;
  32. font-family: Verdana, Geneva, sans-serif;
  33. font-weight: 700;
  34. overflow-wrap: break-word;
  35. word-wrap: break-word;
  36. -ms-word-break: break-all;
  37. word-break: break-word;
  38. -ms-hyphens: auto;
  39. -moz-hyphens: auto;
  40. -webkit-hyphens: auto;
  41. hyphens: auto;
  42. }
  43.  
  44. h1 {
  45. font-size: 2.35em;
  46. }
  47.  
  48. h2 {
  49. font-size: 2em;
  50. }
  51.  
  52. h3 {
  53. font-size: 1.75em;
  54. }
  55.  
  56. h4 {
  57. font-size: 1.5em;
  58. }
  59.  
  60. h5 {
  61. font-size: 1.25em;
  62. }
  63.  
  64. h6 {
  65. font-size: 1em;
  66. }

このCSSの大部分は、体裁(フォントとそのサイズ、行の高さなど)と、色や中央配置を指定しています。そうした各属性にどんな値が適しているかを知るにはデザインを勉強する必要があるでしょう(今回のスタイルはsakura.cssを使用)。しかし、ここで適用しているCSS自体は読み解くのがさほど難しいものではありません。結果、ページは以下のようになります。


実行例はこちら

何という違いでしょう。これがCSSの頼もしさです。プログラミングや複雑なロジックなしに、単純な方法でドキュメントにスタイルを追加できるのです。残念ながら、単に体裁や色を指定する以上のことをCSSで行おうとすると(次のセクションで扱います)、状況は厄介になってきます。

CSSをレイアウトに使う

CSSがまだ広く採用されていなかった1990年代、ページのコンテンツをレイアウトする方法は多くありませんでした。HTMLは本来、サイドバーや段組みのある動的なWebサイトではなく、プレーンなドキュメントを作成する言語として設計されました。そんな初期の頃は、レイアウトはHTMLテーブルを用いて行われることが多く、Webページ全体が1個のテーブルに収められ、コンテンツはテーブルの行や列として配置されたものです。このアプローチはうまくいきましたが、欠点はコンテンツと見栄えが厳密に組み合わされることでした。サイトのレイアウトを変更したければ、かなりの量のHTMLを書き直す必要があったのです。

CSSが登場すると、コンテンツ(HTMLで記述)と見栄え(CSSで記述)を切り離そうという声が強まり、全てのレイアウトコードをHTMLから外して(テーブル方式をやめて)CSSに移す方法が工夫されました。注意が必要なのは、CSSが設計された本当の目的もHTMLと同様、ページのコンテンツをレイアウトするためではなかったということです。よって、この関心の分離に対する初期の試みは、なかなか見事には成功しませんでした。

前述の例で、実際どんな外観になるか見てみましょう。CSSレイアウトを定義する前に、まずマージンとパディング(レイアウトの計算に影響)をリセットし、セクションの色分けを指定します(見栄えを良くするためではなく、様々なレイアウトをテストする時に各セクションが見た目に分かりやすくなるようにするためです)。

  1. /* RESET LAYOUT AND ADD COLORS */
  2. body {
  3. margin: 0;
  4. padding: 0;
  5. max-width: inherit;
  6. background: #fff;
  7. color: #4a4a4a;
  8. }
  9. header, footer {
  10. font-size: large;
  11. text-align: center;
  12. padding: 0.3em 0;
  13. background-color: #4a4a4a;
  14. color: #f9f9f9;
  15. }
  16. nav {
  17. background: #eee;
  18. }
  19. main {
  20. background: #f9f9f9;
  21. }
  22. aside {
  23. background: #eee;
  24. }

サイトの現時点の外観は以下のようになります。


実行例はこちら

これで、CSSを用いてこのページのコンテンツをレイアウトする準備ができました。以下では3種類のアプローチを年代順に見ていきます。まずは、クラシックなfloatベースのレイアウトです。

floatベースのレイアウト

CSSのfloat属性は元々、画像を段組みテキストの中で左か右に浮いた(フロートした)ような感じで配置させる目的で導入されました(新聞でおなじみのレイアウトです)。2000年代初めのWeb開発者は、画像に限らずどの要素でもフロートさせられる、つまりコンテンツのdiv要素全体をフロートさせれば行と列のように扱えるということを利用したのです。しかし、繰り返しますがfloatはその目的のために設計された属性ではなかったため、このアプローチが常にうまくいくわけではありませんでした。

2006年、有名な記事「In Search of the Holy Grail」(Holy Grailレイアウトの探求)が『A List Apart』に掲載されました。ヘッダ、3段組み、フッタで構成した「Holy Grail」と呼ばれるレイアウトを組むためのアプローチを詳しく周到に論じた記事です。かなり簡単に思えるレイアウトがHoly Grail(聖杯)と称されるのは何だかおかしな感じですが、実のところ当時は、純粋なCSSを用いて一貫したレイアウトを構築するのは大変難しいことだったのです。

以下は、その記事で紹介された手法を基に組んだ、今回のページ例向けのfloatベースレイアウトです。

  1. /* FLOAT-BASED LAYOUT */
  2. body {
  3. padding-left: 200px;
  4. padding-right: 190px;
  5. min-width: 240px;
  6. }
  7. header, footer {
  8. margin-left: -200px;
  9. margin-right: -190px;
  10. }
  11. main, nav, aside {
  12. position: relative;
  13. float: left;
  14. }
  15. main {
  16. padding: 0 20px;
  17. width: 100%;
  18. }
  19. nav {
  20. width: 180px;
  21. padding: 0 10px;
  22. right: 240px;
  23. margin-left: -100%;
  24. }
  25. aside {
  26. width: 130px;
  27. padding: 0 10px;
  28. margin-right: -100%;
  29. }
  30. footer {
  31. clear: both;
  32. }
  33. * html nav {
  34. left: 150px;
  35. }

CSSを見ると、うまくレイアウトするにはかなり多くのテクニックが要ると分かるでしょう(負のマージン、clear: both属性、ハードコードされた幅指定など)。記事では、それぞれの詳しい理由がきちんと説明されています。これを適用すると、ページは以下のようになります。


実行例はこちら

なかなかの出来ですが、3段組みの背景色の高さがバラバラで、ページも画面の高さに届いていません。これはfloatベースのアプローチにおける本質的な問題です。float属性ではコンテンツをあるセクションの左か右に配置することしか指定できないため、他のセクションにあるコンテンツの高さを推測する手段がCSSにはないのです。この問題に対する直接的な解決法は、何年もあとにflexboxベースのレイアウトが登場するまで見つかりませんでした。

flexboxベースのレイアウト

CSSのflexbox属性は2009年に初めて提案されましたが、2015年頃まではブラウザの採用が広がりませんでした。flexboxは、単一の列や行に対して空間の配分方法を定義する目的で設計されたため、floatを用いる方式よりもレイアウトの定義に向いています。こうして、floatベースレイアウトを用いた約10年を経て、Web開発者はついに、float方式で要求されるテクニックの必要なくCSSをレイアウトに使えるようになったのです。

下記は、『Solved by Flexbox』(flexboxを用いた様々なレイアウト例を紹介している人気リソース)の手法を基に組んだ、今回のページ例向けのflexboxベースレイアウトです。なお、flexboxでレイアウトするには、3段組みを包含するラッパーとしてのdiv要素をHTMLに追加する必要があります。

2018-02-21_130506

そして、以下がCSSに記述したflexboxのコードです。

  1. /* FLEXBOX-BASED LAYOUT */
  2. body {
  3. min-height: 100vh;
  4. display: flex;
  5. flex-direction: column;
  6. }
  7. .container {
  8. display: flex;
  9. flex: 1;
  10. }
  11. main {
  12. flex: 1;
  13. padding: 0 20px;
  14. }
  15. nav {
  16. flex: 0 0 180px;
  17. padding: 0 10px;
  18. order: -1;
  19. }
  20. aside {
  21. flex: 0 0 130px;
  22. padding: 0 10px;
  23. }

floatベースレイアウトのアプローチよりずっとコンパクトですね。flexboxの属性と値は一見少々分かりにくい感じですが、floatベースレイアウトで要求された負のマージンのような数々のテクニックは必要なく、圧倒的に便利です。これを適用すると、ページは以下のようになります。


実行例はこちら

はるかに良くなりました。3段組みの高さがそろっていて、ページ全体の高さに届いています。ある意味これは完璧に見えますが、flexbox方式にはいくつかささいな欠点があります。1つはブラウザのサポート状況です。現在のところ、モダンブラウザはどれもflexboxに対応しているものの、旧式ブラウザの中には対応が見込めないものもあります。幸い、ブラウザベンダはそうした旧式ブラウザのサポート終了に向けた取り組みを強めており、Webデザイナーの開発エクスペリエンスはより一貫したものになっています。別の欠点は、<div class="container">をマークアップに追加する必要があることです。回避できた方がいいですよね。「CSSを用いてレイアウトを組む際にはHTMLマークアップを全く変更しなくていい」というのが理想でしょう。

しかし最大の欠点は、CSSのコード自体です。flexboxを用いるとfloat方式での数々のテクニックは不要なものの、レイアウトを定義するにしてはコードの表現が自明ではありません。flexboxのCSSを読み解いて全ての要素がページにどう配置されるかを視覚的につかむことが難しいため、flexboxベースレイアウトを書く際には推測とチェックを重ねる必要があるのです。

再び注意したいのは、flexboxが単一の列や行の中で各要素を配置するために設計された属性であるということです。つまり、ページ全体のレイアウト向けには作られていないのです。確かにflexboxは(floatベースレイアウトよりずっと)便利ではあるものの、複数の行や列のあるレイアウトを扱うための特別な仕様が別途開発されることとなりました。CSSグリッドと呼ばれる仕様です。

グリッドベースのレイアウト

CSSグリッドは(flexboxが提案されてからそれほど経っていない)2011年に初めて提案されましたが、ブラウザに広く採用されるまでには長い時間がかかりました。2018年初め現在、CSSグリッドは大部分のモダンブラウザでサポートされています(1~2年前と比べても大幅な進歩です)。

以下は、こちらの『CSS-Tricks』の記事で紹介されている最初の方法で組んだ、今回のページ例向けのグリッドベースレイアウトです。この例では、flexboxベースレイアウトで追加する必要のあった<div class="container">が不要なことに注目してください。元のHTMLを変更せずにそのまま使えるのです。CSSは以下のようになります。

  1. /* GRID-BASED LAYOUT */
  2. body {
  3. display: grid;
  4. min-height: 100vh;
  5. grid-template-columns: 200px 1fr 150px;
  6. grid-template-rows: min-content 1fr min-content;
  7. }
  8. header {
  9. grid-row: 1;
  10. grid-column: 1 / 4;
  11. }
  12. nav {
  13. grid-row: 2;
  14. grid-column: 1 / 2;
  15. padding: 0 10px;
  16. }
  17. main {
  18. grid-row: 2;
  19. grid-column: 2 / 3;
  20. padding: 0 20px;
  21. }
  22. aside {
  23. grid-row: 2;
  24. grid-column: 3 / 4;
  25. padding: 0 10px;
  26. }
  27. footer {
  28. grid-row: 3;
  29. grid-column: 1 / 4;
  30. }

上記を適用すると、ページの外観はflexboxベースレイアウトの時と同一になります。しかし、求めるレイアウトを明確に表現するという点において、このCSSの方がはるかに優れています。列と行のサイズと形状はbodyセレクタで定義し、グリッドの各アイテムは直接それぞれの位置を指定して定義するのです。

1つ紛らわしいのはgrid-column属性で、これは列の「開始点 / 終了点」を定義するものです。紛らわしい理由は、この例では全部で3列しかないのに、数値の範囲は1~4となるからです。以下の図をご覧いただくと分かりやすくなるでしょう。


実行例はこちら

1列目は1で始まって2で終わり、2列目は2で始まって3で終わり、3列目は3で始まって4で終わるのです。headerはページ全体にわたるようgrid-column1 / 4にし、navは1列目にわたるようgrid-column1 / 2にする、といった具合です。

このグリッドの構文に慣れれば、間違いなくCSSでレイアウトを表現する理想的な方法となります。グリッドベースレイアウトの本当の欠点はブラウザのサポート状況だけで、繰り返しますがそれはここ1年で大幅に改善しています。CSSにおいて真にレイアウト用に設計された最初の本格的ツールとして、CSSグリッドの重要性はいくら強調してもしすぎることはないでしょう。ある意味、Webデザイナーは独創的なレイアウトを組むことに対して常に大変慎重な態度を取らざるを得ませんでした。従来のツールは確固たるものではなく、様々なテクニックや回避策を駆使する必要があったからです。しかし、CSSグリッドが登場したことで、以前では考えられなかったような独創的なレイアウトデザインが続々と生まれる土壌が整いました。刺激的な時代がやって来たのです。


訳:
「分かっただろ? CSSのどこかを変えると別の所がダメになるなんて笑えるな!」
「かもね。でもflexboxとかグリッドとかの新しい方法のおかげで、随分やり易くなってきたんだろ!」
「ハハッ! CSSはレイアウト以外でも問題山積みさ!」