はやわかり レスポンシブルCSS
プログラミング
- TOP
- Old Archives
- はやわかり レスポンシブルCSS
まえがき
リクエストがあったので、レスポンシブルウェブサイトを構築するCSSの基本的な考え方を簡単にまとめよう。
これは、CSSやHTML自体を書けない人を対象にしたものでは ない 。
ケース分けの仕方
CSSのメディアクエリを使用する。 メディアクエリの詳細についてはMDNに記事がある。
ほとんどの場合メディア特性にはwidth
またはheight
を使用する。
広く使われてはいないが、aspect-ratio
,
orientation
は基本的なメディア特性であり、非常に有用である。
この両者を組み合わせることで(ゲーム画面のように)スクリーンサイズに合致するレイアウトが可能になる。
典型的なケースでは、レイアウトボックスが1000px
幅だとして、ビューポートに1000pxがなければ画面いっぱいにfallbackする。
@media screen and (min-width: 1000px) {
#MainBox {
width: 1000px;
margin: auto;
}
}@media screen and (max-width: 999px) {
#MainBox {
width: 100%;
margin: 0px;
} }
ただし、このようなケースでは次のように書くべきだ。 そして、実際にこのように書くべきケースは非常に多く、メディアクエリを必要とするケースは表示切り替えくらいのものである。
#MainBox {
width: 1000px;
max-width: 100%;
margin: auto;
}
この場合、#MainBox
は幅1000px
をまず確保しようとする。
しかし、min-width
によって制約されているため、1000px
の幅が包括ブロックの100%を越える場合は包括ブロックの100%に留められる。
これによってビューポート幅を突き破ることがないようにできる。
width
によって判定するのは「コンテナの中央寄せ」という、2003年以来の文法に従っているためだ。
だから、しっかりとデザインするのであればまた異なった設定になるだろう。
HTML構造
基本的なレイアウトでは全体を収めるためのボックスを用意する。
<body>
<section id="MainBox">
</section>
</body>
この中にレイアウトしていくのだが、基本的には「左であり、上である」「右であり、下である」という順序で書く。 これを入れ替えるのはCSSでは少し難しい。 ただ、良いCSSを書くには「可能な限りJavaScriptに頼らない」という気持ちは必須である。
「本文コンテナとサイドバー」という構成であれば、サイドバーの内容を上にしたいのであれば左サイドバーになるし、サイドバーの内容を下にしたいのであれば右サイドバーになる。
<body>
<section id="MainBox">
<article id="MainContent">
</article>
<nav id="SideBar">
</nav>
</section>
</body>
横並びレイアウトで最も基本的なのは「コンテナをテーブルに、コンテンツをセルに」である。
この場合、例え縮小しても横並びは維持されるし、min-width
などではみ出す場合、そのままoverflowする。
#MainBox {
display: table;
margin: auto;
}#MainContent {
width: 800px;
display: table-cell;
}#SideBar {
width: 300px;
display: table-cell;
}
コンテナ側のサイズが決まっていて、サイドバーのサイズを指定しないことでサイドバーをある程度縮小させることを許すことができる。 これは、最低限必要な幅を確保した上で、それよりも幅があるのであればもう少しスペースをとって表示することができる。
次のCSSでは、1000px
を下回るのであればtableによる表示を諦めるが、ボックス自体は最大1200px
まで伸張する。
1200px
の場合、その割合としてはサイドバーが200px
から300px
の間で、残りがメインになる。
@media screen and (min-width: 1000px) {
#MainBox {
display: table;
margin: auto;
min-width: 1000px;
max-width: 1200px;
}#MainContent {
min-width: 800px;
display: table-cell;
}#SideBar {
min-width: 200px;
max-width: 300px;
display: table-cell;
} }
十分なスペースがないときに右のボックスを下に送るのであれば、メディアクエリは必要ない。
inline-block
として配置することで、overflow時はボックスを並べないようにすることができる。
この場合、サイズ指定は並んだときに確保すべきボックスと、単独になったときに伸張すべきボックスの大きさを意識する必要がある。
また、内包されているボックスの位置と大きさはいずれも#MainBox
にbindされていることを忘れてはいけない。
#MainBox {
width: 1450px;
max-width: 100%;
margin: auto;
}#MainContent {
min-width: 800px;
max-width: 100%;
display: inline-block;
}#SideBar {
min-width: 300px;
max-width: 100%;
display: inline-block;
}
表示ボックスそのものの変更
ボックスのレイアウトではなく、内容そのものをレスポンシブルに変更したい場合はdisplay
を上手に使うといい。
例えば次の場合、#TOC
は十分な幅がないとき省略される。
@media screen and (max-width: 999px) {
#TOC { display: none; }
}
メニューは十分な幅があれば横に配列しようとするが、ないのであればそのまま縦に配列する。
@media screen and (min-width: 1000px) {
#MainMenu li { display: inline-block; }
}
同一の内容に対して異なる表示を提供したい場合は、予め複数書いておくようにして、メディアクエリでdisplay: block;
とdisplay: none
を入れ替えるのが良い。
この場合、同内容はジェネレータによって生成されるべきである。PureBuilder
Simplyの場合、Pandocテンプレートを使うことにより内容の反復を避けることができる。
より一般的にはテンプレートそのものをeRubyなどで生成し、値を置き換えるのが良いだろう。
順序の変更も、「複数書いておいて、表示を切り替える」のが最も無難である。
がんばるのであれば、position: absolute
あるいはposition: fixed
を使うことで「見かけ上の順序」をごまかすことができる。
これらはビューポートをそのまま使うブロックに対して指定することが多いためあまり意識しないだろうが、座標起点は包括ブロックであり、また包括ブロックとしても機能する。
以下の例では十分な幅があればサイドバーは左に表示されるが、十分な幅がないとき、サイドバーは下に表示される。
<body>
<section id="MainBox">
<nav id="SideBar">
</nav>
<article id="MainContent">
</article>
</section>
</body>
#MainBox {
width: 1000px;
max-width: 100%;
margin: auto;
}
@media screen and (min-width: 1100px) {
#SideBar {
position: absolute;
top: 0px;
left: 0px;
min-width: 300px;
max-width: 300px;
}
#MainContent {
position: absolute;
top: 0px;
right: 0px;
min-width: 700px;
max-width: 700px;
} }
表示コンテンツの変更
レスポンシブルに異なるバナーをコンテンツ中に表示したいような場合は、JavaScriptを利用するほうが良い。 ただし、メディアクエリと背景画像を使うことでCSSで処理できないこともない。
各ページ共通のものであればテンプレートに組み込んで表示ボックスの切り替えが良い。
表示コンテンツの表示の仕方でいえば、max-width
,
min-width
,
そしてmargin
の値をコントロールするようにするといいだろう。
おまけ。ビューポートを全部使う
文字主体のコンテンツの場合、文字サイズをビューポートに基づくようにすれば問答無用でビューポートいっぱい使うデザインが可能。
#MainBox {
max-width: 100%;
margin: 0px;
padding: 0px;
}@media (orientation: portrait) {
#MainContent {
font-size: 5vw;
}
}@media (orientation: landscape) {
#MainContent {
font-size: 5vh;
} }
5vw
は一応、1行に20文字入る計算になる。
この場合、横幅が小さい場合は文字数が、縦幅が小さい場合は行数がある程度確保されるようにするという基準になっている。
その上でなるべく大きい文字にする。画面いっぱい使って大きく文字を表示するのでお年寄りにもやさしい。
標準的に1920pxに対して16pxの文字とすると120文字入るので0.85vh
となるのだが、これをすると非常に小さくなってしまう。
これをやると拡大縮小がかなり制限されてしまうことから、「大きく文字を表示する」前提で考えたほうが良い。
2vh
くらいあればちょっと大きめに表示されるが、拡大できないので2.5vh
くらいをスタートに考えたほうが良いかもしれない。
特にウィンドウをタイルしたときなどで縦長になるとすごく小さい、などということもありえるのだ。