floatもflexも頼らない、inline-blockとそのお供
こんにちは。
開発チームのワイルド担当、まんだいです。
最近、ひたすらHTMLのコーディングを数年ぶりにやっていて、CSS3のブラウザ対応が進んでページが作りやすくなってきました。
開発環境もSASSやLESSでプログラマブルにまとめる事もでき、gulp、gruntやwebpackでコンパイルも自動化するなど様相が変わってきました。
開発環境は変わっても、CSSでレスポンシブにサイトを作るためのTipsは変わらないということで、inline-blockを使った横並びのアイテムをレスポンシブに構築するためのテクを今回はまとめてみます。
floatの弊害
一昔前、リストを横に並べるには、float: leftを設定するのが当たり前のような時代がありました。
ただ、floatで横に並べると、横には並ぶけれど、親のアイテムの高さが0になるという弊害があります。
- hoge
- hoge
- hoge
- hoge
- hoge
- hoge
<style> .hoge-list1 { float: left; background-color: blue; color: white; margin-left: 10px; } </style> <ul style="list-style: none; background-color: pink;"> <li style="margin: 0;" class="hoge-list1">hoge</li> <li style="margin: 0;" class="hoge-list1">hoge</li> <li style="margin: 0;" class="hoge-list1">hoge</li> <li style="margin: 0;" class="hoge-list1">hoge</li> <li style="margin: 0;" class="hoge-list1">hoge</li> <li style="margin: 0;" class="hoge-list1">hoge</li> </ul>
直後のdiv要素にmargin-topで10px設定してあるのですが、これがうまく効かずスペースが取れません。
これを回避するために、色々と不要なタグを追加したり、CSSで何とかしていた時代がおよそ10年くらい前でしょうか。
display:flexもあるが
時代は2016年。W3Cも色々と知恵を絞って、最新の仕様では、display:flexというプロパティを策定しました。
これがまた便利なヤツで、レスポンシブを前提に作られているので、画面サイズによって横に並べる個数を変えると、自動的に幅をフィットしてくれるので、bootstrapのGRIDシステムが必要なくなるとも言われています。
ただ、2016年にもIE問題はあって、IE11が機能限定で対応しているだけで、IE10以前のブラウザでは無効なプロパティです。
よって、display:flexに限らず、inline-flexなどのflex系のプロパティをガンガン使っていけるのは、もう少し先になりそうです。
inline-blockとは
そこで出てくるのが、inline-blockというプロパティです。
これは、IE8から対応していて、CSS2時代からあるプロパティなので枯れている、という認識で問題ないと思います。
なので、今回はこれを使って横に並べていきたいと思います。
先ほどの例を、inline-blockを使って書き換えると、以下のようになります。
- hoge
- hoge
- hoge
- hoge
- hoge
- hoge
<style> .hoge-list2 { display: inline-block; background-color: blue; color: white; margin-left: 10px; } </style> <div style="border: 1px solid #ddd; border-radius: 4px; width: calc(100% - 40px); margin-left: 20px; margin-right: 20px; height: 300px; background-color: #eee;"> <ul style="list-style: none; background-color: pink;"> <li style="margin: 0;" class="hoge-list2">hoge</li> <li style="margin: 0;" class="hoge-list2">hoge</li> <li style="margin: 0;" class="hoge-list2">hoge</li> <li style="margin: 0;" class="hoge-list2">hoge</li> <li style="margin: 0;" class="hoge-list2">hoge</li> <li style="margin: 0;" class="hoge-list2">hoge</li> </ul> <div style="clear: both; margin-top: 10px;">test</div> </div>
これだけで、先ほどは見えていなかったul要素の高さが設定されるようになり、背景色のピンクが表示されるようになりました。
横に2列並べたい場合は、マージンを消し、widthを50%にすれば、お望みのレイアウトが出来上がります。
- hoge
- hoge
- hoge
- hoge
- hoge
- hoge
<style> .hoge-list3 { display: inline-block; background-color: blue; color: white; margin: 0; padding: 0; width: 50%; } </style> <div style="border: 1px solid #ddd; border-radius: 4px; width: calc(100% - 40px); margin-left: 20px; margin-right: 20px; height: 300px; background-color: #eee;"> <ul style="list-style: none; background-color: pink; margin: 0; padding: 0;"> <li style="margin: 0;" class="hoge-list3">hoge</li> <li style="margin: 0;" class="hoge-list3">hoge</li> <li style="margin: 0;" class="hoge-list3">hoge</li> <li style="margin: 0;" class="hoge-list3">hoge</li> <li style="margin: 0;" class="hoge-list3">hoge</li> <li style="margin: 0;" class="hoge-list3">hoge</li> </ul> <div style="clear: both; margin-top: 10px;">test</div> </div>
お、幅を50%(半分)にしても、2つ並びませんね・・・。
これを解決するために、inline-blockとセットで使うCSSプロパティを次に紹介します。
inline-blockのお供
実は使わないでもいいパターンもあるので、その例を示します。
- hoge
- hoge
- hoge
- hoge
- hoge
- hoge
<style> .hoge-list4 { display: inline-block; background-color: blue; color: white; margin: 0; padding: 0; width: 50%; } </style> <div style="border: 1px solid #ddd; border-radius: 4px; width: calc(100% - 40px); margin-left: 20px; margin-right: 20px; height: 300px; background-color: #eee;"> <ul style="list-style: none; background-color: pink; margin: 0; padding: 0;"> <li style="margin: 0;" class="hoge-list4">hoge</li><li style="margin: 0;" class="hoge-list4">hoge</li><li style="margin: 0;" class="hoge-list4">hoge</li><li style="margin: 0;" class="hoge-list4">hoge</li><li style="margin: 0;" class="hoge-list4">hoge</li><li style="margin: 0;" class="hoge-list4">hoge</li> </ul> <div style="clear: both; margin-top: 10px;">test</div> </div>
※ wordpressでは、勝手にHTMLタグ毎に改行コードが入ってしまうため、サンプルのHTMLをコピーし、別環境でお試しください。
何かというと、li要素の後ろにある改行コードやスペース、タブが微かな幅を取っているがために、幅50%でジャストフィットさせる事ができなくなっている、というのが原因でした。
これを回避するためには、
- 先のコードのコードのように、li要素の直後の制御文字やHTMLの体裁を整えるためのタブやスペースを取り除く
- li要素の親(つまり、ul)要素で一旦、文字が取り得る幅をなくしてしまう
の2つの方法があります。
ひとつ目の方法はHTMLの書き方の問題なので、2つ目の方でどう対処するかを見てみます。
文字幅を制御するCSSプロパティ、letter-spacingを親要素で設定します。
その後、子要素でletter-spacingを基に戻します。
この動作を加えたものが、下のサンプルになります。
- hoge
- hoge
- hoge
- hoge
- hoge
- hoge
<style> .hoge-list5 { display: inline-block; background-color: blue; color: white; margin: 0; padding: 0; width: 50%; letter-spacing: normal; } </style> <div style="border: 1px solid #ddd; border-radius: 4px; width: calc(100% - 40px); margin-left: 20px; margin-right: 20px; height: 300px; background-color: #eee;"> <ul style="list-style: none; background-color: pink; margin: 0; padding: 0; letter-spacing: -0.4em;"> <li style="margin: 0;" class="hoge-list5">hoge</li> <li style="margin: 0;" class="hoge-list5">hoge</li> <li style="margin: 0;" class="hoge-list5">hoge</li> <li style="margin: 0;" class="hoge-list5">hoge</li> <li style="margin: 0;" class="hoge-list5">hoge</li> <li style="margin: 0;" class="hoge-list5">hoge</li> </ul> <div style="clear: both; margin-top: 10px;">test</div> </div>
親要素には、「letter-spacing: -0.4em;」、子要素には「letter-spacing: normal;」を追加しました。
-0.4emという値が何を意味しているのかまったく謎ですが、-0.4emより小さい数字であれば、望み通りのレイアウトになります。
もう一つのお供
もう一つ、合わせて設定しておいたほうが良いプロパティがあるので紹介します。
先ほどは、中身が1行のリストだったので問題は見えませんでしたが、これが以下のようなリストだった場合、レイアウトが崩れます。
- hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge
- hoge
- hoge
- hoge
- hoge
- hoge
<style> .hoge-list6 { display: inline-block; background-color: blue; color: white; margin: 0; padding: 0; width: 50%; letter-spacing: normal; } </style> <div style="border: 1px solid #ddd; border-radius: 4px; width: calc(100% - 40px); margin-left: 20px; margin-right: 20px; height: 300px; background-color: #eee;"> <ul style="list-style: none; background-color: pink; margin: 0; padding: 0; letter-spacing: -0.4em;"> <li style="margin: 0;" class="hoge-list6">hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge </li> <li style="margin: 0;" class="hoge-list6">hoge</li> <li style="margin: 0;" class="hoge-list6">hoge</li> <li style="margin: 0;" class="hoge-list6">hoge</li> <li style="margin: 0;" class="hoge-list6">hoge</li> <li style="margin: 0;" class="hoge-list6">hoge</li> </ul> <div style="clear: both; margin-top: 10px;">test</div> </div>
わかりにくいですが、1つ目のリストが複数行になった場合、隣に並ぶ2つ目のリストが1つ目のリストの下を基準に並ぶので、2つ目のリストの上によくわからないスペースができます。なので、そこにはピンクのul要素の背景色が表示されている状況です。
通常は、上部を基準に並べるレイアウトが多いと思いますので、これを調整するため、vertical-alignを設定します。
設定後のものが、以下のサンプルになります。
- hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge
- hoge
- hoge
- hoge
- hoge
- hoge
<style> .hoge-list7 { display: inline-block; background-color: blue; color: white; margin: 0; padding: 0; width: 50%; letter-spacing: normal; vertical-align: top; } </style> <div style="border: 1px solid #ddd; border-radius: 4px; width: calc(100% - 40px); margin-left: 20px; margin-right: 20px; height: 300px; background-color: #eee;"> <ul style="list-style: none; background-color: pink; margin: 0; padding: 0; letter-spacing: -0.4em;"> <li style="margin: 0;" class="hoge-list7">hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge hoge </li> <li style="margin: 0;" class="hoge-list7">hoge</li> <li style="margin: 0;" class="hoge-list7">hoge</li> <li style="margin: 0;" class="hoge-list7">hoge</li> <li style="margin: 0;" class="hoge-list7">hoge</li> <li style="margin: 0;" class="hoge-list7">hoge</li> </ul> <div style="clear: both; margin-top: 10px;">test</div> </div>
これで綺麗に上の面が揃ったリストができました。
レスポンシブ対応は、@mediaでデバイス幅によって、widthを調節するという形で対応しています。
この辺りの概念が分かれば、レイアウトで困る事はあまりないかなと思います。
今回やったコーディングでは、上記のようなテクニックでHTMLを共通化する事にも成功し、思った以上に工数が掛かりませんでした。
CSSは奥が深く、面白いですね。
また、結果的にCSS3でもHTML5でもなかった事を心よりお詫びしたいと思います。
以上です。