2016年8月5日
あなたはCSSプロパティ”display”をどのぐらい知っているだろうか?
(2016-06-18)by Chen Hui Jing
本記事は、原著者の許諾のもとに翻訳・掲載しております。
CSSプロパティの1つである display は、CSSレイアウトに用いるプロパティの中でも極めて重要なものです。よく使われているのは、 block
や inline
、 none
あたりでしょう。 table
や inline-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 の値はショートハンドで書くことができるのです。例えば、 block
は block flow
でショートハンドになります。詳細は 仕様書 から一覧表を参照してください。
全ての要素はデフォルトとして display 値を持っています。しかし、 display 値として明確に何か別の値を設定されることにより、オーバーライドされることがあります。
display: none;
通常のドキュメントフローから要素とその子要素を削除します。ドキュメントは、要素がそもそも存在しなかったかのように、レンダリングされます。つまり、それが占有するスペースは折りたたまれているのです。要素の内容もスクリーンリーダには読み取られません。
display: inline;
この要素は1つ以上のインラインボックスを生成します。インラインレベル要素は、その名前からも察しがつくとおり、行の中にそのタグが定義する分のスペースを取ります。ブロックレベル要素を補完すると考えることができます。
display: block;
この要素はブロックレベルボックスを生成します。特に指定されない限り、ブロックレベル要素は全て新しい行から始まり、コンテナの幅を広げます。
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を理解するには大変役立ってくれるウェブサイトをリストアップしておきます。
- A Complete Guide to Flexbox(Flexbox完全ガイド) 、著者Chris Coyier
- Solved by Flexbox(Flexboxで解決しよう) 、著者 Philip Walton
- Flexbox Froggy(Flexboxカエル) 、著者 Thomas Spark
- Using CSS flexible boxes(CSSフレキシブルボックスの使用) 、著者 Mozilla Developer Network
- CSS Flexbox Specification (Editor’s Draft)(CSS flexbox仕様書(編集者によるドラフト版))
要素で 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://flags
と opera://flags
に飛び、「試験運用版のウェブプラットフォームの機能」を有効にします。Firefoxの場合は、 about:config
に飛び、 layout.css.grid.enabled
と layout.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のリンクにアクセスすることができます。
- Deep Dive into Grid Layout Placement(Grid Layoutを詳しく) 、著者 Manuel Rego Casasnovas
- A Complete Guide to Grid(Grid完全ガイド) 、著者 Chris House
- Grid by Example(Grid実施例) 、著者 Rachel Andrew
比較的曖昧かつ実験的なもの
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 as Indigo Five Alpha , Dr. Sameen Shaw or simply Shaw , is a physician and a former operative for the U.S. Army Intelligence Support Activity . Prior to joining the team Shaw was part of an operation known as Catalyst Indigo, responsible for acting on relevant list intelligence delivered by the Machine , which she knew only as “Research”.
同様の効果を得るためにfloatを使うこともできますが、それはハック的な方法の一種になります。ボディコピーを持つヘッダのベースラインの整列はかなり難しいものです。ヘッダのフォントサイズやボディコピーの行の高さがうまく合うまで微調整しなければならないからです。しかも、ヘッダが2行以上「キャッチ」してしまうという状況もあるかもしれません。
代わりにヘッダで display: inline
を使いたい場合、ヘッダ要素をボディコピーのパラグラフ要素でネストしない限り、それは機能しません(なぜなら、 p
はブロック要素だからです)。しかも、それは意味的に正しくありません。ですので、私個人的には、この実装を見るのは好きですが、ブラウザベンダーとしては、現時点で懸念するべき、より優先順位の高い仕様が他にあるのだろうと推測します。
display: ruby;
この特殊なプロパティがどういうものかを理解するには、\<ルビ>要素の導入が必要です。簡単に言えば、これは通常、発音の仕方をサポートする要素としてテキストのベースラインに表示される注釈のことなのです。こうしたものは、中国語や日本語など東アジアの言語ではかなり一般的です。研究する中で見つけたものの大半は2010年前後のものでしたから、 2016年のHTMLの\<ルビ>の状況 についても書いてみました。
display: ruby
と display: 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レイアウトについて学びたいと思っていただけたら嬉しいです。
参考
株式会社リクルート プロダクト統括本部 プロダクト開発統括室 グループマネジャー 株式会社ニジボックス デベロップメント室 室長 Node.js 日本ユーザーグループ代表
- Twitter: @yosuke_furukawa
- Github: yosuke-furukawa