あなたはCSSプロパティ”display”をどのぐらい知っているだろうか?

CSSプロパティの1つであるdisplayは、CSSレイアウトに用いるプロパティの中でも極めて重要なものです。よく使われているのは、blockinlinenoneあたりでしょう。tableinline-blockも、今ではかなり一般的になってきたと言えます。一方、flexは新たに登場したものです。きっとユーザに気に入られるでしょう。これはレイアウト用に特別に作られたdisplayプロパティです。さらには、この先、gridがまもなく私たちの秘密兵器となるでしょう(現在、盛んに取り組まれています)。これもまた、レイアウトに特化したプロパティです。

本記事は、当初予定していたよりもずっと長くなりました。ご希望に応じて、自由にサブセクションに飛んでお読みいただければと思います。もし、お時間を割いて全体を読んでいただけるのでしたら、大変嬉しく思います😁

目次

これまでに様々なレスポンシブウェブデザインを構築してきた経験から、displayプロパティやpositionプロパティはどのように機能するのか、望んだレイアウトにするためにはどのようにメディアクエリと組み合わせたらいいのか、といった多くのことを学んできました。そこで、ここではそれぞれの値について簡単にまとめると同時に、以前私が構築した、displayを多数利用したレスポンシブな要素をいくつかご紹介したいと思います。

displayについてお話しするならば、ボックスの階層について触れないわけにはいきません。基本的にはブラウザがCSSを解析し、ボックスの階層を生成することにより、それをレンダリングします。ボックスの階層は、レンダリングされた文書のフォーマット構造を表すものです。displayプロパティは、ボックスの表示タイプを定義します。

ブラウザが画面上の諸々をどのようにレンダリングするかというトピックは、実に魅力的です。必読文書として強くお勧めしたいのは、Talia Garsiel氏によるHow Browsers Work: Behind the scenes of modern web browsers(ブラウザはどう動く:モダンなウェブブラウザの舞台裏)です。もう1つ、同じく必読文書のお勧めは、W3CのCSS仕様書にも携わっているFantasai氏によるEvolution of CSS Layout: 1990s to the Future(CSSレイアウトの進化:1990年代から将来まで)です。彼女は、Emerging Technologies for the Enterprise(エンタープライズの最新技術)会議でも実際に話をしていますが、動画が見られなければ、フルスクリプトをご覧になるといいでしょう。

既によく知られたもの

楽しい事実があります。実は、いつも使っているdisplayの値はショートハンドで書くことができるのです。例えば、blockblock flowでショートハンドになります。詳細は仕様書から一覧表を参照してください。

全ての要素はデフォルトとしてdisplay値を持っています。しかし、display値として明確に何か別の値を設定されることにより、オーバーライドされることがあります。

display: none;

通常のドキュメントフローから要素とその子要素を削除します。ドキュメントは、要素がそもそも存在しなかったかのように、レンダリングされます。つまり、それが占有するスペースは折りたたまれているのです。要素の内容もスクリーンリーダには読み取られません。

display: inline;

Inline elements
この要素は1つ以上のインラインボックスを生成します。インラインレベル要素は、その名前からも察しがつくとおり、行の中にそのタグが定義する分のスペースを取ります。ブロックレベル要素を補完すると考えることができます。

display: block;

Block elements
この要素はブロックレベルボックスを生成します。特に指定されない限り、ブロックレベル要素は全て新しい行から始まり、コンテナの幅を広げます。

display: list-item;

list-itemとしてレンダリングされるこの要素は、正にブロックレベル要素と似たようなふるまいをするのですが、これもマーカとなるボックスを生成します。list-styleプロパティでスタイルを設定することもできます。<li>要素だけには、デフォルト値としてlist-itemが設定されています。通常は、デフォルトのふるまいをする<li>要素をリセットするために使われます。

display: inline-block;

See the Pen CSS display example by Chen Hui Jing (@huijing) on CodePen.

この要素はブロックレベルボックスを生成しますが、全体のボックスはインライン要素と同じようにふるまいます。上の画像の例を使ったCodePenを開き、ウィンドウの幅を調整してみてください。そうすると、動きをより理解しやすいと思います。

レスポンシブな数値ステッパー

これまでに構築しなければならなかったコンポーネントの1つに、乗客の種類(大人/乳幼児/子供)別に数を入力する数値ステッパーがありました。モバイル向けレイアウトとデスクトップ向けレイアウトでそれぞれ1つずつ静的なPhotoshopファイルを用意しました。しかし、レイアウトが “崩れ” なかった中間の幅があったのです。

その主な原因は、括弧内のテキストがうまく折り返されなかったことでした。そこで、様々な幅に対し、関連する要素の表示や幅を調整するために、たくさんのメディアクエリを投入しなければなりませんでした。ウィンドウ幅を変えたときに、このコンポーネントがどのようなレスポンスをするか、フルサイズのCodepenを開いてチェックしてみてください。

See the Pen Responsive numeric stepper by Chen Hui Jing (@huijing) on CodePen.

tableベースのレイアウトを覚えているだろうか?

要素に、単なるHTMLのtableのようなふるまいをさせるdisplay値のセットがあります。私の仲間で、シンガポールを拠点に活動するColin Toh氏は、display: tableプロパティに関する素晴らしい記事を書いています。ぜひとも読んでみてください。

もはやtableベースのレイアウトはほとんど使われていませんが、display: tableは、ある場合においては今でも非常に便利なのです。例えば、レイアウトの幅が広げられたときにだけtableを入れたいが、幅が狭められたときには典型的なブロックレイアウトのままにしたいという場合です。これは、display(さらに追記する擬似要素で)とメディアクエリを組み合わせて、動き方を見るためにウィンドウサイズを調整するだけで実現できます。

   
table <table> HTML要素に相当します。これは、ブロックレベルボックスを定義します。
table-header-group <thead> HTML要素に相当します。
table-row <tr> HTML要素に相当します。
table-cell <td> HTML要素に相当します。
table-row-group <tbody> HTML要素に相当します。
table-footer-group <tfoot> HTML要素に相当します。
table-column-group <colgroup> HTML要素に相当します。
table-column <col> HTML要素に相当します。
table-caption <caption> HTML要素に相当します。
inline-table 直接HTML要素に相当するものがない唯一の値です。要素はtableのHTML要素と同じようにふるまいますが、ブロックレベル要素ではなく、インラインブロックのようにふるまいます。
@media screen and (min-width: 720px) {
  .table {
    display: table;
    width: 100%;
    border-collapse: collapse;
  }
}

.tr {
  margin-bottom: 1.6rem;
}

@media screen and (min-width: 720px) {
  .tr {
    display: table-row;
  }
}

@media screen and (min-width: 720px) {
  .td {
    display: table-cell;
    border: #f0f0f0 1px solid;
    padding: 0.4rem;
  }
  .td:first-child {
    width: 11em;
  }
}

.th {
  font-size: 1rem;
  line-height: 1.6rem;
  font-family: "Palo Alto";
}

@media screen and (min-width: 720px) {
  .th {
    font-size: 1.294rem;
    line-height: 1.6rem;
  }
}

@media screen and (min-width: 720px) {
  .th {
    font-size: 0.8rem;
    line-height: 1.6rem;
    font-family: "Roboto Slab", Rockwell, serif;
    font-weight: 700;
  }
}

@media screen and (min-width: 720px) and (min-width: 720px) {
  .th {
    font-size: 1rem;
    line-height: 1.6rem;
  }
}

.th::before {
  content: 'display: ';
}

@media screen and (min-width: 720px) {
  .th::before {
    content: '';
  }
}

.th::after {
  content: ';';
}

@media screen and (min-width: 720px) {
  .th::after {
    content: '';
  }
}

blockにおける新顔たち

flexboxならびにgridの仕様書の筆頭著者であるTab Atkins Jr.氏は、こうしたの新しいレイアウト固有のdisplayモードについて、際立つ特徴を示しました。

flexboxは1次元のレイアウト向けです。つまり、一直線上にレイアウトされるべきものに対して使います(あるいは破線上に。破線も重なれば1つの直線になります)。
gridは2次元のレイアウト向けです。機能としてやや劣るflexboxの代わりに使うこともできます(1カラムrow gridがflexboxに非常に似たふるまいをすることを確認しようとしています)が、それではgridの機能は生かしきれてはいないことになります。
www-styleまでTab Atkins Jr.氏より。

これらの新しいCSSレイアウトを取り入れるときや、これらはそれぞれどんな場合に使ったら良いのかと迷ったときのために、ぜひとも覚えておいてください。

display: flex;

flexboxレイアウトモード、あるいは、CSSフレキシブルボックスの導入によって初めて、ブラウザでのコンテンツのレイアウトに関する仕様書が作られたのです。ウェブでのコンテンツのレイアウトは、初めてHTMLが導入されてから、かなり進化してきました。デザイナーが何かクリエイティブなレイアウトを作ろうと考えたとき、最初に使われたテクニックはHTML tableのネスティング、あるいは、いわゆるtableベースのレイアウトでした。

CSSが軌道に乗り始めると、私たちはfloatベースのレイアウトに移行していきました。望んだとおりのレイアウトにするため、様々なdiv要素でコンテンツをネスティングし、周囲を回り込むようにしたのです。floatベースのレイアウトは今でもかなり一般的なものですが、本記事執筆時点では、flexboxとgridこそレイアウトにはもってこいの手段だと、広く認識されるようになるまで時間はかからないだろうと感じています。flexboxとgridについては後で取り上げます。

Scott Vandehey氏による記事、What IS Flexbox?(Flexboxとは何か)についてお話ししましょう。同記事では、同氏がTab Atkins Jr.氏にflexboxの歴史について尋ねています。それによると、初めて仕様書ドラフト版が発表されたのは2009年7月23日となっていますが、議論はその数年前に始まっていたということです。

しかしながら、正式に体系化されないまま、様々なブラウザベンダーがflexboxを実装しました。しかし実際には、仕様書に則ってはいなかったのです。これがflexboxの構文がかなり厄介になった理由です(古いブラウザでの下位互換性に関して言えば、今でもそうなのです)。

flexboxモデルは非常に強力で、できることも多くあります。ですから、これがどのように機能し、どのように使ったらいいのか、完全に理解するには努力が必要です。flexbox、gridについてお話しするなら、いずれも徹底的に掘り下げた長編記事でなくては足りません。そのため、ここにflexboxを理解するには大変役立ってくれるウェブサイトをリストアップしておきます。

Flexbox diagram

要素でdisplay: flexを宣言することにより、それはflexコンテナになり、その子要素はflexアイテムになります。これはもうカスケードはしません。つまり、flexプロパティは孫要素までは拡張されないということです。flexコンテナとflexアイテムの両方に、それぞれ独自のflexプロパティがあります。

flexコンテナのプロパティ

   
flex-direction main axisやflexアイテムの方向を定義します。flex-directionの値の一覧表
flex-wrap flexアイテムを1つのrow(行)に入るように調整するのか、あるいは折り返しをして複数のrow(行)にまたがってもいいのかを指定します。flex-wrapの値の一覧表
flex-flow flex-directionとflex-wrapのショートハンドプロパティです。flex-flowの値の一覧表
justify-content スペースをmain axisに沿ってflexアイテムの間や周囲へどのように配置するかを定義します。justify-contentの値の一覧表
align-items スペースをmain axisと垂直にflexアイテムの間や周囲へどのように配置するかを定義します。align-itemsの値の一覧表
align-content flexアイテムのラインをflexコンテナ内でどのように配置するかを指定します。flexアイテムが1つのライン上にあるならば適用されません。align-contentの値の一覧表

flexアイテムのプロパティ

   
order flexアイテムをレイアウトする順序を指定します。要素はorderの値の昇順に配置されます。orderの値が同じであるflexアイテムはソースコード内の順に従い配置されます。Orderの値の一覧表
flex-grow 利用可能なスペースがある場合に、要素をどれだけ大きくできるかを定義します。この値で、要素がどのくらい拡大できるか、スペースの割合を決めます(これは複雑だとお話ししました)。flex-growの値の一覧表
flex-shrink 十分なスペースがない場合に、要素をどれだけ小さくできるかを定義します。この値で、要素がどのくらい縮小できるか、スペースの割合を決めます。flex-shrinkの値の一覧表
flex-basis flexアイテム全ての利用可能なスペースがどのぐらいか決まるまで、要素のデフォルトのサイズを定義します。flex-basisの値の一覧表
flex flex-grow、flex-shrink、flex-basisの順序で指定するショートハンドです。flexの値の一覧表
align-self 1つのflexアイテムのアライメントをオーバーライドできるようにします。align-selfの値の一覧表

繰り返しになりますが、上記に挙げたflexboxに関するウェブサイトのリストをチェックすることを強くお勧めします。このリストには、flexboxをコード内で使う際に役立つ例が満載です。

display: grid;

gridレイアウトに関してお話しする際、私はいつも、CSS gridの第一人者であると考えるRachel Andrew氏をご紹介しています。彼女は、この新しいdisplayプロパティへの認知を広めるため、最前線に立って講演を行ったり、記事やチュートリアルを執筆したり、努力してきました。

CSS gridは、gridシステムを作成し、gridアイテムの配置をCSSによって純粋にコントロールする方法を提供するものです。HTMLの懸念事項から解放されます。メディアクエリと併せて使う場合、フレキシブルなレイアウトのデザインと構築を強力にサポートしてくれるCSS gridが、お手持ちのツールに仲間入りします。

gridに関しては現在、CSS Grid Layout Module Level 1が最新版となっています。この仕様書は、2011年にワーキングドラフトとしてスタートしました。flexbox同様、HTMLのセマンティクスを犠牲にすることなく、ウェブ上のコンテンツをレイアウトするための適切な方法を知りたいというニーズが高まったことにより、制定されました。

Microsoft EdgeとInternet Explorerは、ベンダープレフィックスである-ms-を推奨していた古いバージョンの仕様書をサポートしてはいますが、CSS gridはどのブラウザでも正式には実装されていないことにご注意ください。これは、それほど驚くことではありません。なぜなら、もともとgrid仕様書の編集者の大半がMicrosoft出身者だったからです。

flexboxの仕様が雑然と実装され、CSS gridの開発は様々なアプローチが取られ始めています。各ブラウザベンダーは、開発者がテストを行えるようにブラウザに実験的な機能を追加するベンダープレフィックスを使えるようにしています。この機能は、仕様書が洗練され、オフィシャルなものになる前に、不備がないかを洗い出すプロセスに大いに役立っているのです。

その作業に代わり、CSS gridはフラグのおかげで開発されてきました。これは、開発者の手作業によって有効にする必要があります。ChromeとOperaでは、それぞれchrome://flagsopera://flagsに飛び、「試験運用版のウェブプラットフォームの機能」を有効にします。Firefoxの場合は、about:configに飛び、layout.css.grid.enabledlayout.css.grid-template-subgrid-value.enabledの値をtrueに設定します。

主なCSS grid用語

   
gridコンテナ flexコンテナの概要と同じく、display: grid;のとおり指定された要素がグリッド要素となり、直接の子孫(子要素)がgridアイテムになります。。
gridアイテム 親要素がdisplay: grid;のとおり指定されたグリッド要素ならば、その子要素がgridアイテムと見なされます。gridアイテムの子要素はgridアイテムとは見なされません。。
gridトラック gridのcolumn(列)とrow(行)を総称して指します。
gridライン gridの構造を決めるライン(線)です。gridトラック間の線と考えます。
gridセル 分けられた個々のgridユニットです。隣接した水平および垂直のgridラインで囲まれているスペースを指します。
grid領域 さて、これこそクールな部分です。gridにより、複数のgridセルで構成された領域を定義することができるのです。

この短いサブセクションでgridについて書こうとするのは、仕様書に大きな害を及ぼすようなものです。なぜなら、gridの機能は極めて多くあるからです。そこで、以下にリストアップしたCSS gridに関するウェブサイトや実施例をお読みいただきたいと思います。実際に、今すぐGrid by Exampleに飛べば、あらゆる使用ケースにおけるCSS gridの使い方をデモンストレートしたCodePenのリンクにアクセスすることができます。

比較的曖昧かつ実験的なもの

display: run-in;

さて、これは、CSS Display specification(CSS display仕様書)を読み始めるまでは聞いたこともなかった興味深いものです。Chris Coyier氏の書いた2010年の記事、CSS Run-in Display Valueも発見しました。残念ながら、ブラウザベンダーはこの仕様を全く好んでいないらしく、全てのブラウザから削除されてしまっているようです。そのため、これについては代わりに実際の仕様を考えればいいと思います¯\_(ツ)_/¯

理論的には、要素のdisplayプロパティにrun-inを設定した場合、run-in box(同行見出しボックス)としてレンダリングされます。ユースケースは、同行見出しを生成するためのネイティブメソッドです。これは、グラフィックデザイン業界での言い方をすれば、ボディコピーの次の行と同行に入れた見出しだと言えます。

Sameen Shaw.Also known asIndigo Five Alpha,Dr. Sameen Shawor simplyShaw, is a physician and aformer operative for the U.S. ArmyIntelligence SupportActivity. Prior to joining the team Shaw was part of anoperation known as Catalyst Indigo, responsible for actingon relevant list intelligence delivered bythe Machine, whichshe knew only as “Research”.
同様の効果を得るためにfloatを使うこともできますが、それはハック的な方法の一種になります。ボディコピーを持つヘッダのベースラインの整列はかなり難しいものです。ヘッダのフォントサイズやボディコピーの行の高さがうまく合うまで微調整しなければならないからです。しかも、ヘッダが2行以上「キャッチ」してしまうという状況もあるかもしれません。

代わりにヘッダでdisplay: inlineを使いたい場合、ヘッダ要素をボディコピーのパラグラフ要素でネストしない限り、それは機能しません(なぜなら、pはブロック要素だからです)。しかも、それは意味的に正しくありません。ですので、私個人的には、この実装を見るのは好きですが、ブラウザベンダーとしては、現時点で懸念するべき、より優先順位の高い仕様が他にあるのだろうと推測します。

display: ruby;

この特殊なプロパティがどういうものかを理解するには、<ルビ>要素の導入が必要です。簡単に言えば、これは通常、発音の仕方をサポートする要素としてテキストのベースラインに表示される注釈のことなのです。こうしたものは、中国語や日本語など東アジアの言語ではかなり一般的です。研究する中で見つけたものの大半は2010年前後のものでしたから、2016年のHTMLの<ルビ>の状況についても書いてみました。

display: rubydisplay: table;の間にはいくつか類似点がありますが、仕様書では、ルビテキストを表示するために、spanのような非ルビ要素にルビのdisplay値を適用しないよう強く勧めています。スクリーンリーダや非CSレンダラーがルビ構造を解釈することができるよう、むしろコンテンツをHTMLのルビ要素を使ってマークアップするべきなのです。

   
ruby HTML要素の<ruby>に相当します。ルビコンテナボックスを生成します。これは、内部ルビボックスとしてマークされた子要素向けにルビの書式コンテキストを確立します。
ruby-base HTML要素の<rb>に相当します。ルビの書式コンテキストにおける内部ルビボックスです。
ruby-text HTML要素の<rt>に相当します。ルビの書式コンテキストにおける内部ルビボックスです。
ruby-base-container HTML要素の<rbc>に相当します。ルビの書式コンテキストにおける内部ルビボックスです。
ruby-text-container HTML要素の<rtc>に相当します。ルビの書式コンテキストにおける内部ルビボックスです。

display: contents;

要素自体がボックスを生成することはありませんが、その子要素と疑似要素は通常どおりのボックスを生成します。ボックスの生成とレイアウトのために、要素は、まるで文書ツリー内でその子要素と疑似要素に置換されたかのように扱われなくてはいけません。
CSS Display Module Level 3より。

仕様書が言わんとしていることは、次のとおりです。要素にdisplay: contentsを設定すると、それはDOMから消えてしまいますが、その子要素は全て残り、それが占有していたスペースを引き受けます。残念ながら、この仕様をサポートしているのは、現在Firefoxのみです。どのように機能するのかを実感していただくために、フルサイズのCodePenをFirefoxでリサイズしてみてください。

See the Pen CSS display: contents by Chen Hui Jing (@huijing) on CodePen.

これまでに、displayプロパティについて書かれた2つの記事を紐解きました。Sam Rueby氏の書いたFirefox is releasing support for CSS display: contents(FirefoxはCSS display: contentsをサポートするためにリリースされている)Rachel Andrew氏が書いたVanishing boxes with display contents(display contentsで消え行くボックス)です。Rachel Andrew氏はflexアイテムを持つこのプロパティの素晴らしいユースケースも提示しています。両方の記事をぜひともチェックしてみてください。

まとめ

やれやれ、本記事は私が当初想定していたよりも随分と長くなってしまいました。これほど長い記事を全て読んでくださった方、とても感謝しています。私は、まもなく使えるようになる新たな選択肢を本当に楽しみにしています。ハック的な手段に頼らずに、ユニークなレイアウトを作り出すことができるのです。本記事を読むことで、皆さんがもっとCSSレイアウトについて学びたいと思っていただけたら嬉しいです。

参考