クモのようにコツコツと

フロントエンドエンジニア イイダリョウの技術ブログ。略称「クモコツ」

もしかしてだけどCSSのvwやvhを使うとメディアクエリ無しでレスポンシブ対応できちゃうんじゃないの?(オマケにvmin、vmaxも)

タイトルのようなことをふと思ったのでCSSのvw、vhをいろいろ試してみました。
PCは横長、スマホは縦長とまったく異なる縦横比率なために生じるレスポンシブ対応。それを実現するメディアクエリはとても便利ですが、何種類もCSSスタイルを書き分けるのは少々複雑ではあります。ここを突破する一番シンプルな方法を追求したい。そう、vw、vhでね。それでは参りませう!

※目次:

※参考:CSSの基本はこちら
【CSSの基本】書ける前に読む!HTML、CSS、JSの書式-3 - クモのようにコツコツと

レスポンシブ対応とは

レスポンシブ対応とは、ワンソース(1つのHTMLソース)でありながら複数のデバイス(主にPCとスマホですね)に最適化した画面表示をすることです。なぜそれが必要かというと、冒頭にも書きましたがPCは横長、スマホは縦長と根本的に異なる縦横比率で使用するためです。どちらかに合わせた画面ではどちらかが使いにくくなるわけです。これを実現する技術がCSSの「メディアクエリ」です。

メディアクエリとは

メディアクエリを実現するにはまずHTMLのhead要素内にmeta要素を加えます。

<head>
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0">
</head>

name属性でviewport設定が有効になります。ビューポートは画面サイズのことで、content属性に画面サイズにたいする表示設定が書かれています。

次にCSSにメディアクエリを書きます。

/*600px以下はこのスタイル*/
@media screen and (max-width: 600px) {
   /* スマホのスタイルを書く*/
}

@mediaは以前「CSSの基本」で触れた@ルールです。画面の幅が最大600pxまではこのスタイルを優先する、という意味です。
PCのスタイルをメインにして、スマホにだけ特定のスタイルを適用したい場合にこういう書き方をします。なお、600pxはスタイルの切り替えの境界で「ブレイクポイント」といいます。

こちらはスマホのスタイルをメインにして、PCだけに特定のスタイルを適用したい場合の書き方。

/*600px以上はこのスタイル*/
@media screen and (min-width: 600px) {
   /* PCのスタイルを書く*/
} 

画面の幅が最小600pxまではこのスタイルを優先する、という意味です。

メディアクエリの書き分けは、少々手間なんですよね。同じ場所に対するスタイルが二箇所に分散するので、後から探しにくくもあります。 そしてタブレット用とか大画面モニター用とかブレイクポイントが増えるごとにさらに分散します。

vh、vwとは

さて、CSSには様々な単位がありますが、CSS3で新しく加わった単位に「vw」「vh」というものあります。 それぞれvwは「viewport width」、vhは「viewport height」の略です。viewportとは先ほどのレスポンシブ設定で出ましたね。画面サイズという意味です。 こんな書き方です。

section {
    width: 100vw;
    height: 100vh;
}

おなじみの%と同じで100が基準値となります。vwは画面幅に対する相対値、vhは画面高さに対する相対値です。これに対して%は親要素に対する相対値です。なお、もう一つおなじみのpxなどはピクセルの絶対値です。

  • %、vw、vhともに100が基準値
  • %は親要素に対する相対値
  • vwは画面幅に対する相対値
  • vhは画面高さに対する相対値
  • pxなどはピクセルの絶対値

100% のサンプル「そうだ 小田急 乗ろう」

今回、おなじみ%とvw、vhの違いがわかるように、ダミーサイト「そうだ 小田急 乗ろう」を作りました。こちらの例は%で作っています。

※フル画面は「こちら

/*vh vr テスト*/
.main .bg img {
  width: 100%;
}

メイン画像の幅を100%にしています。高さはデフォルト設定のautoで縦横比率は保たれます。 なお、この画像の元はインスタのため縦横比は正方形です。 このままだとスマホでは適度なサイズですがPCでは下が見切れてしまいます。

100vw、100vh に変えてみた

これを 100vw、100vh に打ち替えてみるとどうなるか。

/*vh vr テスト*/
.main .bg img {
  width: 100vw;
  height: 100vh;
}

こうなった。

※フル画面は「こちら

おっとっと。画面サイズに対して画像が幅いっぱい、高さいっぱいになってるけど、縦横比率もびよ〜んと伸びてしまった。PCでは横長、スマホでは縦長になってしまっていると思います。

obcect-fitでトリミング

こういうときは、私の愛してやまない「object-fit」で外接リサイズしようではあ〜りませんか。

/*vh vr テスト*/
.main .bg img {
  width: 100vw;
  height: 100vh;
  object-fit: cover;
}

object-fitプロパティの値をcoverにすると…

※フル画面は「こちら

画面をスクロールしていただくと、画像の幅、高さがちょうど画面いっぱいのサイズでありながら、縦横比率を保ってトリミングされているのがわかります。

なお、object-fitは残念ながらデフォルトではIEが対応してくれないので、IEに対応する方法はこちらをご覧ください。

※参考:私が愛してやまない待望の外接リサイズobject-fitを使うのにIEのせいであと1年半も待ってらんないっ!! - クモのようにコツコツと

100vw、80vhが最高にレスポンシブ!?

さて、高さが100vhだと、一見するとメイン画像の下にコンテンツが続いているがわかりにくいですね。80vhにしてみて、画面の下20%くらいに続きのコンテンツが見切れていると、スムーズにコンテンツに誘導できるのではないでせうか?

/*vh vr テスト*/
.main .bg img {
  width: 100vw;
  height: 80vh;
  object-fit: cover;
}

こうなった。お!いい感じ??

※フル画面は「こちら

どうですかこれ!PCでもスマホでも下に続きがあることがわかるので、下スクロールに誘導しやすいですよね! この3行でメディアクエリやらブレイクポイントやらの設定なしに、PCにもスマホにも最適な画面が実現できちゃいましたよ。やったね!!

100vhで揃えてみる

さて、せっかくなのでもう少し試してみませう。幅、高さとも100vhで揃えてみるとどうなるでしょうか。

/*vh vr テスト*/
.main .bg img {
  width: 100vh;
  height: 100vh;
  object-fit: cover;
}

こうなった。

※フル画面は「こちら

PCでは「内接リサイズ」的な、画面高さに合わせて幅が縮小していますね。でも、スマホで見ると、画面高さいっぱいで幅が画面幅よりも広がって横スクロールが発生してしまいます。うーむ、イマイチ。。

100vwで揃えてみる

今度は幅、高さとも100vwで揃えてみるとどうなるか。

/*vh vr テスト*/
.main .bg img {
  width: 100vw;
  height: 100vw;
  object-fit: cover;
}

こうなった。

※フル画面は「こちら

お、これは、最初の100%と同じになりましたね。画面幅いっぱいのまま、PCは高さが画面をすぎてしまい大きすぎます。スマホは正方形で適度なサイズ。

100vimで揃えてみる

さて、ここで新しい単位をご紹介。vminです。画面の幅、高さの中で「小さい方」に合わせてリサイズされます。両方100vminにしてみるとどうなるか。

/*vh vr テスト*/
.main .bg img {
  width: 100vmin;
  height:  100vmin;
  object-fit: cover;
}

こうなった。

※フル画面は「こちら

お、これは「内接リサイズ」ですね!PCでは画面高さに合わせて左右に余白ができる。スマホでは画面幅に合わせて下にコンテンツが続く。これはこれで使い道がありそうです。

100vmaxで揃えてみる

最後にvmaxという単位をご紹介。こちらは画面の幅、高さの中で「大きい方」に合わせてリサイズされます。両方100vmaxにしてみるとどうなるか。

/*vh vr テスト*/
.main .bg img {
  width: 100vmax;
  height:  100vmax;
  object-fit: cover;
}

こうなった。

※フル画面は「こちら

うーむ…。PCは100%と同じく幅いっぱいで高さが見切れている。そしてスマホでは100vhと同じく左右が画面幅より伸びて横スクロールになってしまっている。これは一番イマイチだなぁ。vmaxの有効活用方法はまだよくわからない。。

まあvmin、vmaxはよく使われる最小min、最大maxの単語なので名前は覚えやすいですね!

使用した写真

今回使用した写真はこちら。以前インスタにアップした写真です。 f:id:idr_zz:20200523125546j:plain

元のインスタはこちらです。 www.instagram.com

最後に

vw、vh、vmin、vmaxの挙動をいろいろ試し、%との違いも比較してみました。私のおすすめはやはり幅が100vwで高さが80vhです! これがあればメディアクエリの設定なしにCSSもワンソースでレスポンシブ対応ができそうな気がしました!vw、vh、これからも積極的に使っていきたいと思います。それでは!


※参考:ネイティブHTML & CSSやってみたシリーズ
qiita.com