CSS Media Queryを使うときに気を付けること及び知見
CSS Media Query、特にmin-widthまたはmax-widthを利用する場合に気を付けた方が良いパターンや知見について紹介する。これらのメディア特性が自由に扱われているスタイルは破綻しやすい。
主にメディア特性がmin-widthまたはmax-widthである場合に限定して、利用する場合に気をつけた方が良いパターンや知見について紹介します。
同種のメディア特性ではMedia Queryのネストを避ける
そもそもMedia Queryをネストして書けることを知らない方が多いと思いますし、min-widthやmax-width以外のメディア特性に慣れていない方が多いと思いますが、Media Queryでは画面幅だけでなくカラーや端末の種類や向きなど様々なメディア特定が利用でき、さらには論理演算子に加えてネストも許容されているなど、様々な記述が出来ます。
例えば次の記述は横長で、横幅が300px以上の端末にマッチします。
@media (min-width: 300px) and (orientation: landscape) {
/* ... */
}
これはネストを利用して次のようにも書けます。
@media (min-width: 300px) {
@media (orientation: landscape) {
/* ... */
}
}
また、カンマ区切りで指定するとORになるため、次は横幅が300pxまたは横長の端末にマッチします。
@media (min-width: 300px), (orientation: landscape) {
/* ... */
}
これらの記述はとても便利ですが、一方で同種のメディア特性(min-widthとmax-widthなど)をネスト表記で指定してしまうと、適用範囲の可読性が著しく落ちる場合があります。
@media (max-width: 742px) {
@media (max-width: 1024px) {
/* ... */
}
@media (min-width: 1024px) {
/* ... */
}
}
/* ネストしたメディアクエリ内のルールセットの優先度は高くなるのか */
@media (max-width: 1024px) {
/* ... */
}
メディア特性min-widthとmax-widthの併用を避ける
メディア特性min-widthとmax-widthを併用していると、後から記述されたものの方が優先度が高くなるCSSの性質や、min-widthとmax-widthどちらも指定した値を含む範囲に適用される都合上、記述する順序によって適用される範囲が変わってしまうため、どちらかに制限した上で利用した方が可読性の高いコードになることが多いです。
いずれも極端な例ですが、次のようなケースが考えられます。
例:h1とh2の色が一致しない。
@media (min-width: 340px) {
h1 {
color: blue;
}
}
@media (max-width: 720px) {
h1 {
color: red;
}
}
@media (max-width: 720px) {
h2 {
color: red;
}
}
@media (min-width: 340px) {
h2 {
color: blue;
}
}
例:状態が3つ出来てしまう(red, 300px)→(blue, 300px)→(blue, 200px)
h1 {
color: red;
width: 200px;
}
@media (min-width: 340px) {
h1 {
color: blue;
}
}
@media (max-width: 340px) {
h1 {
width: 300px;
}
}
またmin-widthとmax-widthいずれかを利用するのに合わせて、値に応じてソートするルールをstylelintなどで書けることを推奨します。CSSの優先度をまだあまり理解していない方の場合、後ろにあるメディアクエリで誤って上書きしてしまうということがよくある印象です。
例:h1の色は780px以上でも青色になる
@media (min-width: 780px) {
h1 {
color: red;
}
}
@media (min-width: 340px) {
h1 {
color: blue;
}
}
例:h1の色は340px以下でも青色になる
@media (max-width: 340px) {
h1 {
color: red;
}
}
@media (max-width: 780px) {
h1 {
color: blue;
}
}
メディア特性をmin-widthとmax-widthどちらを利用するかについては、モバイルとデスクトップどちらを優先して実装するかに合わせてやるとスムーズだと個人的には思います。
範囲の重複を避けるためにnot allを利用する
Media Queryでは、not演算子を利用して条件を反転できます。次の記述では、ルールセットが340px未満で適用されます。
@media not all and (min-width: 340px){
/* ... */
}
これを利用すれば、min-widthとmax-widthを利用する場合と異なり、範囲の重複を気にせず記述できるようになります。ですが、現在はMedia Query Level 4で追加されたrange型を持った特性を利用した方が良いと思います。
Media Query Level 4 range型を持ったメディア特性
既にほとんどのモダンブラウザで利用できるMedia Query Level 4の機能を利用すれば、より柔軟性が高く可読性の良い記述が利用できます。Media Query Level 4ではrange型のメディア特性に加えて、or演算子やメディア特性と値のペアに対して付けられるnotなども追加されています。
例:720px未満にマッチする
@media (width < 720px) {
/* ... */
}
例:340pxより大きく720px以下の範囲でマッチする
@media (340px < width <= 720px) {
/* ... */
}
この記述であれば範囲を非常に認識しやすくなりますが、CSSの優先度などの問題は引き続き存在するため、記述する順序には気を付ける必要があります。