webサイトを表示する画面のサイズはパソコンのような幅の広い画面だけでなく、i Phoneのような幅の狭い画面でも表示する事があります。
webサイトの特性によってはむしろパソコンではなくスマホから見る事が多い場合もあるでしょう。
例えばお店の予約システムなどの場合、そのページが収益の要です。
お店の予約なのでスマホユーザーが8割にも関わらずスマホ対応していないためにデザインが崩れてしまいユーザーがスマホから予約をする事が困難な場合、かなりの損失です。
そのような損失が起こらないようにパソコンのような大きな画面でもスマホのような小さな画面でも問題なく適切なデザインが表示されるように実装できるスキルを身につけましょう。
このような画面サイズに合わせて最適化した実装を行う事をレスポンシブデザイン対応と言います。
この章では動的なcssという事でレスポンシブ対応を行うために必要な知識である、変数、cssでの数値の計算、メディアクエリについて学びます。
メディアクエリ
cssにはメディアクエリというものが存在します。
メディアクエリは○○px以下の時に適応させるcss、○○px以上の時に適応させるcssというように画面の幅によって適応させるcssをコントロールする事ができます。
メディアクエリの記載方法は以下です。
@mediaを使用する事で画面サイズに応じてcssを切り替える事が可能です。
まず、メディアクエリを有効にするにはhtmlファイルのhead内に以下の記述を追加しなければいけません。
<meta name="viewport" content="width=device-width, viewport-fit=cover">
その後、cssにメディアクエリを記載しますが、メディアクエリの構文は以下になります。
@media メディアタイプ and (ブレークポイントのルール) { /* ルールをここに記載 */ }
メディアタイプ
このコードがどのようなメディア(例えば、印刷、画面)のためのものであるかをブラウザーに伝えます。
ここに記載するメディアタイプには以下がります。
all
(すべて)print
(印刷)screen
(画面)speech
(音声合成)
一般的には画面サイズによってcssを変化させたいのでscreenを使用します。
@media screen and (ブレークポイントのルール) { /* 宣言をここに記載 */ }
ブレークポイントのルール
どの画面幅でcssを適応させたいかのルールをブラウザに伝えます。
ブレークポイントの書き方は以下です。
@media screen and (max-width: 1023px) { /* 1023px以下の時の宣言をここに記載 */ } @media screen and (min-width: 1024px) { /* 1024px以上の時の宣言をここに記載 */ }
max-width, min-widthを使用して記載します。
max-width: 1023pxとはマックス(最大)の幅が1023pxなので、
今の幅 <= 1023px この式が成り立つ時、すなわち1023以下の時となります。
min-width: 1024pxとはミニマム(最小)の幅が1024pxなので、
今の幅 >= 1024px この式が成り立つ時、すなわち1024px以上の時となります。
複数のメディアクエリ
メディアクエリは論理値を使用して複数の値を組わせて使用する事が可能です。
論理値とはorやandの事で、orは「もしくは」と表し、andは「かつ」を表します。
例えば786px~1023pxの間でのみcssを適応したい場合は以下のようにブレークポイントのルールを組わせて使用します。
@media screen and (min-width: 786px) and (max-width: 1023px) { /* 786px以上1023px以下の時の宣言をここに記載 */ }
グローバルナビゲーションの非表示
よくあるデザインで、グローバルナビゲーションになにかしらのアクションボタンを設置している場合がありますが、横幅を取るのでスマホ画面では非表示にしたいという事がありますが、メディアクエリを使う事で簡単に実装する事が可能です。
See the Pen Untitled by tora (@-tora-) on CodePen.
※このページでは画面幅が足りないので、codepenへアクセスして確認してください。
ボタンが2つ並んでいますが、どちらもl-header__buttonというclass名が付いています。
そして、その要素を消すためにはdisplay:none;を宣言すると要素を消す事ができるのでdisplay:none;を宣言します。
例えば今回は画面幅が767px以下の時にこのボタンを消すcssを適応させてたいとするとメディアクエリにはmax-width: 767pxと記載し、そのメディアクエリで対象のルールを囲ってやる事で完成です。
@media screen and (max-width: 767px) { .l-header__button { display: none; } }
その他のメディアクエリ
メディアクエリは多くの場合、ブレークポイントと合わせて画面サイズの条件で使用すされる事が多いです。
ですが、メディアクエリにはブレークポイント以外にも条件を書く事が可能で、その中でも比較的使用する事が多いものを紹介します。
hoverが可能なデバイスを判断するクエリ
以下のデモのようにパソコン上でマウスを要素の上に持ってくると下線が出てくる実装をする場合、表示してるデバイスがホバーに対応しているのかを知る必要があります。
— 補足 —
スマホではホバースタイルを当てる事はあまりありません。
理由はそもそもホバースタイルはリンクなどに行う事が一般的です。
スマホでホバーのスタイルを実装した場合、タップをする事で発動します。
ですのが、リンクと同時にタップする事なのですぐにリンク先のページに移動してしまいあまり意味がないのです。
— /補足 —
See the Pen Untitled by tora (@-tora-) on CodePen.
メディアクエリを使用する事で表示してるデバイスがホバーに対応していればホバー時のスタイルを適応するとう事が可能です。
@media (hover: hover) { // ホバー時の宣言を書く }
ライトモード、ダークモードを判断するクエリ
windows、Macどちらでも画面の表示モードとしてライトモードとダークモードどちらかに切り換える事が可能です。
どちらにも対応したい場合はそれぞれのcssを記載する必要がありますが、どちらのcssを適応するか、ユーザーの設定しているモードを知る必要があります。
メディアクエリからモードを条件に記載する事でこちらの実装が可能となります。
@media (prefers-color-scheme :dark ){ /* ダークモード宣言を書く */ }
css変数
上のセクションでライトモードとダークモードの切り替えについて触れました。
ライト、ダークを切り替えるためにはそれぞれのモードの時のスタイルを用意する必要がありますが、以下のように色が異なるだけの重複スタイルを記載する必要があります。
.item { // ライトモードの時 color: #333; @media (prefers-color-scheme :dark ){ // ダークモードの時 color: #fff; } }
この例ではルールが1つですので混乱する事なく管理可能ですが、webサイト1つを作るとなると大量のスタイルを記載する必要があり、管理に苦労しますし、何より毎回記載するのが面倒です。
そんな時に活躍するのがcss変数で、css変数は強力な武器となります。
css変数の「変数」とは
変数とは箱のようなもので、箱の中の値を柔軟に変更する事ができます。
各スタイルは箱の中みを見て箱の中に入っている値をスタイルに適応します。
そのためにはまずは箱を用意しなければいけません。
箱(変数)を用意するためには以下のように記載します。
--変数名: 値;
変数名には箱の名前を記入し、値には箱に入れる値を記入します。
※変数名の先頭に「—」をつけるのを忘れずに!
そして、その変数の中身を参照したい場合は以下のようにする事で変数の中身の値を使用する事ができます。
var(--変数名);
変数名には先ほど制作した変数の名前が入ります。
例えば「css変数-図-1」のようにアイテムの色を変数でコントロールしたい場合は以下のようなコードになります。
--color: red; .item { color: var(--color); }
css変数を使ってライトモード、ダークモードを切り替える
このcss変数を活用してライトモード、ダークモードの切り替えを行う事で効率的にcssを管理する事ができます。
.item { color: var(--color); // ライトモードの時 --color: #333; @media (prefers-color-scheme :dark ){ // ダークモードの時 --color: #fff; } }
一見逆に記載する事が増えただけに見えますが、これはcssが複数になった時に威力を発揮します。
例えば以下のような場合です。
.parent { // ライトモードの時 --color: #333; @media (prefers-color-scheme :dark ){ // ダークモードの時 --color: #fff; } } .item1 { color: var(--color); } .item2 { color: var(--color); } .item3 { color: var(--color); }
このように1つの変数にまとめてその変数を複数の要素が参照する事で管理が楽になります。
また、モードの切り替え対応だけでなく、後々色を変更する事がありそうな時などにも、変数の色を変更するだけでページ全体の色を変更する事ができるのでとても効率的にサイトの開発を進める事が可能です。
ですが、効率的に開発するために変数にまとめるというスキルは中々難しいので沢山の練習が必要になってきます。
はじめは効率的などを意識せずに数をこなす事がおすすめです。
変数のスコープ
以下は先ほど出した例ですが、いきなりparent要素が出てきてparentに変数を宣言しましたが、これにはきちんとした理由があります。
.parent { // ライトモードの時 --color: #333; @media (prefers-color-scheme :dark ){ // ダークモードの時 --color: #fff; } } .item1 { color: var(--color); } .item2 { color: var(--color); } .item3 { color: var(--color); }
そして、このコードが機能するためにはhtml構造を以下のようにする必要があります。
<!--- 正しいので機能します --> <div class="parent"> <div class="item1"> item1 </div> </div> <!--- 正しくないので機能しません --> <div class="parent"> </div> <div class="item1"> item1 </div>
上記のようにparentに変数を宣言し、parantないにitem1要素をセットする必要がある理由は変数のスコープにあります。
スコープとは参照可能な範囲の事です。
変数は宣言した要素の中でのみ参照する事ができます。
今回はparentの中で変数を宣言したのでparentの中でしか変数の値を参照する事ができませんでした。
これをどこからでも参照できるようにするためにはどうしたらよいでしょうか。
グローバルなcss変数の宣言
css変数をどこからでも参照できるようにすうためには:rootセレクターないに変数を宣言します。
:root { --color: red; }
こらは結局のところhtmlタグにたいして変数を宣言しているにすぎません。
すべての要素は一番トップレベルのhtmlタグの中に記載するのでhtmlタグに宣言する事で全ての要素で使う事ができるのです。
calcの計算
cssで値をセットする際に横幅を3つに均等に分けたい場合どうすればよいでしょうか。
calcを知らなければ33.33…%と割り切れない数字書く事になります。
このように割る事のできない数字が必要な場合や、値を計算しする必用がある場合に
100% / 3と書いたり、calcを使う事で計算式が必要な様々な問題を解決する事ができます。
calcのメンタルモデル
calcは計算式をcssに記載する時に使用すうものです。
まずは計算式の構成について理解しましょう。
計算式はオペランドとオペレータから成り立ちます。
オペランド、オペレータを組み合わせて式を作り、それをcalc()で囲う事でcssで動作します。
使用できるオペレータ
clacで使用する事のできるオペレータは以下になります。
- + 足し算
- – 引き算
- * 掛け算
- / 割り算
オペランドのユニット(単位)の付け方のルール
calc-図-1を見て最初のオペランドには%のユニットが付いているが、2つ目の3にはユニットが付いていないのはなぜだろうと思ったのではないでしょうか。
理由はユニットの付け方にはルールがあるからです。
例えば図の式をcalc(100% / 3%)というように記載すると正しく動作しません。
足し算と引き算の場合
- 足し算と引き算の場合は計算する両方の値に単位をつけます。単位は別々でも構いません。
例
calc(100% + 50px);OK
calc(100vw – 50px);OK
calc(100% + 50);NG
calc(100 – 50);NG
掛け算の場合
- 掛け算の場合はどちらか片方の値にのみ単位を付けます。かける方かけられる方、単位は問いません。
例
calc(100% * 5);OK
calc(100 * 5em);OK
calc(100% * 5px);NG
calc(100 * 5);NG
割り算の場合
- 割り算の場合は割られる方にのみ単位を付けます。割る方、つまり右側には単位を付けてはいけません。
例
calc(100% / 5);OK
calc(100 / 5px);NG
calc(100 / 5);NG
calc(100% / 5px);NG
ユニットの付け方で迷った場合、calcがうまく機能しない場合
ユニットの付け方で迷った場合、calcがうまく機能しない場合は以下の解説記事を読んでください。
calcの計算式のルールと使い方。calcが動かない時の対処法はこれ
要素のサイズを範囲指定する
以下のデモを見てください。
このようにある一定の値以上には広がらないようなデザインを再現したい場合、どのように実装すればよいでしょうか。
例えば今回は600px以上には要素が広がってほしくないとします。
単純にwidth: 600pxと指定してしまうと600px以上には広がりませんが、要素の横幅が600pxで固定されてしまうので画面を縮めた時に600px以下になる事もなく、オーバーフローしてしまいます。
この問題を解決するのがmax-widthとmin-widthです。
max-width
max-widthを使用するとセットした値以上にサイズが大きくなる事がなくなります。
メディアクエリの章でも出てきましたが、例えばmax-width: 600pxと宣言すると要素の横幅は600px以上になる事はありませんが、小さくなることに関しては制限はありません。
ですので上の例だと、画面幅をさらに小さくすると以下のようになり、デザインが崩れてしまいます。
そこでmax-widthと対になる最小値も設定します。
min-width
max-widthを使用するとセットした値以下にサイズが小さくなる事がなくなります。
要素の幅はmin-widthにセットした値以下にはならないのでそれよりも小さい画面サイズになると要素はオーバーフローしてしまうので注意が必要です。
width,max-width,min-widthの組わせ
今紹介したmax-widthとmin-widthにwidthを組み合わせて以下のようなデザインを再現してみましょう。
↑ ↑ ↑ 画面幅が狭い時はボタンはボタンのテキスト以下のサイズにはなりません↑ ↑ ↑
↑ ↑ ↑ 画面幅を広げるとボタンは画面幅の50%の値を保ちます↑ ↑ ↑
↑ ↑ ↑ 画面幅がさらに広くなった場合、ボタンは50%の幅を保とうとしますが、300pxよりも大きくなる事はありません ↑ ↑ ↑
この動きを再現するためにはどうすればよいでしょか。
少し考えてみて、以下の回答を見てください。
回答
この動きはwidth,min-width,max-widthを組み合わせる事で実現可能です。
考え方としては一旦最小値と最大値を考えずに要素の横幅をセットする事を考えます。
今回は画面幅の50%なので、以下を宣言する事で画面幅の50%の横幅にする事ができます。
button { width: 50%; }
次に最小値と最大値の制限を設けましょう。
最小値はmin-widthでセットする事ができ、最大値はmax-widthでセットする事ができます。
今回の場合、最小値はボタンcontentの大きさになりますのでmax-contentをセットします。
button { min-width: max-content; width: 50%; max-width: 300px; }
これで完成です。
See the Pen Untitled by tora (@-tora-) on CodePen.
max-contentについては以下の章で解説しています。
レイアウトロジックとメンタルモデル > blockの特徴:スペースを占有す
フレキシブルなコンテンツ
以下のようにフォントサイズを画面幅に合わせて一定の範囲内で比例して変化させる方法を考えます。
今までのメディアクエリ,clac,rem,vwなどを組わせて制作する事が可能です。
こちらの記事で解説しているので回答はこちらを見てください。
少し難しい計算やscssというまた違った知識が必要になりますのでわからなくても問題ありません。