CSSで正方形を作る方法!レスポンシブに対応させるには?
2021/07/26
CSSで正方形のコンテンツ(デザイン)を作りたい時、悩みの種となるのが「レスポンシブ対応」です。
小さい画面で閲覧した時、正方形がハミ出てしまったり…形が縦長に崩れてしまったり…。
そこで今回は、どんな画面から見ても、きちんと正方形のままリサイズさせる方法を解説したいと思います。
また記事の後半では、レスポンシブ化した正方形をコンテンツとして実用化するためのテクニックも合わせてご紹介します。
- 正方形の中央にテキストを配置
- 正方形に画像をはめ込み、縦横比を維持したままトリミング
- 正方形のコンテンツを均等に並べる
例えば、下図のような正方形の画像リンク(サムネイル)一覧を作りたい方にも参考になるかと思います。
コピペ用のコードを用意しているので、初心者でも簡単に実装できますよ。
もくじ
1.正方形をレスポンシブにする3つの方法
CSSだけで正方形をレスポンシブに対応させるには、主に以下の3つの方法が有効です。
- 幅と高さを「vw」や「vmin」で指定する ⇒ 画面(ビューポート)に対する比率
- paddingで高さを補完する ⇒ 親要素の横幅に対する比率
- 疑似要素のpaddingで高さを補完する ⇒ 固定値(px)で指定可
各方法には、それぞれメリット・デメリットがあるため、用途に合わせて使い分けると良いでしょう。
1-1.幅と高さを「vw」や「vmin」で指定する
width
・height
の値として指定する単位には「px
」や「%
」のほかにも、ビューポート(画面)に対する割合を表す「vw
」や「vmin
」があります。
「px
」の代わりに、これらの単位を使うことで、レスポンシブな正方形を簡単に作ることができます。
まず、共通のHTMLは以下の通りです。
1 |
<div class="square_box"></div> |
「vw
」で正方形を作るスタイルは以下の通りです。
1 2 3 4 5 |
.square_box { width: 30vw; height: 30vw; background: #ffb6c1; } |
「vw
」は「viewport width」の略で、「画面幅に対する割合」の単位です。
例えば「30vw」の場合は、画面幅に対する30%が要素の幅・高さに適用されます。
つまり、画面幅が960pxなら、その30%にあたる「288px × 288px」分の正方形が表示できます。
一方、「vmin
」は「viewport minimum」の略で、「画面の幅・高さのうち、小さい方に対する割合」の単位です。
CSSでは以下のように記します。
1 2 3 4 5 |
.square_box { width: 30vmin; height: 30vmin; background: #ffb6c1; } |
コード上は、先ほどの「vw
」を使ったスタイルとほとんど変わりません(単位が変わっただけ)が、挙動は大きく異なります。
例えば、「960px × 540px」の画面で閲覧する場合、画面の高さ540pxの30%にあたる162pxが要素の幅と高さに適用されます。
逆に「360px × 760px」のようなスマホ画面で閲覧すると、画面の幅360pxが対象になります。
ただし、「vw
」「vmin
」は新しくCSSに加わった単位のため、対応ブラウザに注意を払う必要があります。
参考:「vw」「vmin」の対応ブラウザ一覧(Can I use)
主要ブラウザでは対応が進められていますが、IEでは未対応です。
1-2.paddingで高さを補完する
前節で紹介した「vw
」「vmin
」を使った方法は、画面サイズを基準とした割合で正方形をレスポンシブ化しました。
しかし、以下のようにボックス(親要素)内に正方形を収めたい場合には不向きです。
1 2 3 |
<div class="square_content"> <div></div> </div> |
1 2 3 4 5 6 7 8 9 |
.square_content { max-width: 400px; } .square_content div { width: 30vw; height: 30vw; background: #ffb6c1; } |
上記のコードでは、閲覧する画面サイズによって親要素から正方形(子要素)がハミ出してしまいます。
あくまで「vw
」や「vmin
」は画面サイズに対する割合なので、親要素の横幅(2行目)は無視されてしまうからです。
では、親要素の横幅に対する割合で正方形を作るには、どうしたら良いのでしょうか?
例えば、widthやheightにはお馴染みの単位として「%
」があり、親要素の幅・高さを値を算出できます。
1 2 3 4 5 6 7 8 9 10 |
.square_content { max-width: 400px; height: 400px; } .square_content div { width: 50%; height: 50%; background: #ffb6c1; } |
しかし、親要素の幅・高さの値は必ずしも一致していると限りません。
下図のように、レスポンシブで親要素の横幅が変化すると、子要素の正方形はたちまち崩れてしまいます。
問題は高さの値が固定されたままであることです。
横幅に合わせて高さも可変するようにするにはheight
の代わりにpadding
を使用します。
以下のように、子要素のスタイルを修正してみてください。
1 2 3 4 5 6 7 8 9 |
.square_content { max-width: 400px; } .square_content div { width: 50%; padding-top: 50%; background: #ffb6c1; } |
公式定義によれば、padding
の値を%
で指定すると、包含ブロック(親要素)の横幅が基準となるようです。
参考:padding – 公式定義(MDN Web docs)
そのため、width
と同じ比率をpadding-top
に指定することで、親要素の横幅に合わせて正方形の幅・高さを一緒に変化させることができます(padding-bottom
でも同様な結果が得られます)。
また、参照される値は親要素の横幅だけなので、正方形を作るために親要素の高さを設ける必要もなくなります。
上図のように、画面の横幅を伸縮しても正方形を維持できれば成功です。
1-3.疑似要素のpaddingで高さを補完する
画面や親要素に対する相対的な値ではなく、任意の値で正方形を作りたい場合は疑似要素を使うと良いでしょう。
まず、HTML&CSSを確認してください。
1 |
<div class="square_box"></div> |
1 2 3 4 5 6 7 8 9 10 |
.square_box { max-width: 300px; background: #ffb6c1; } .square_box::before { content: ""; display: block; padding-top: 100%; } |
前節に引き続き「%
で指定する時、親要素の横幅を基準とする」というpadding
の特性を利用します。
この場合、親要素は.square_box
です。
親要素の横幅(2行目)に対して疑似要素のpadding-top
は100%
(9行目)なので、疑似要素の高さには親要素の幅と同じ値が反映されています。
そして、親要素の領域が疑似要素の高さまで引き延ばされるため、最大「300px × 300px」の正方形が作れます。
仕組みは前節と一緒ですが、HTML自体は入れ子にしなくて済みますし、また好みの値で正方形を作りやすくなります。
2.レスポンシブな正方形の中央にテキストを配置するには?
CSSで正方形を作る、と言ってもコンテンツとして使えなければ意味がありません。
例えば、前節で紹介した疑似要素とpadding
を使ったテクニックでは、要素内に幅と同じ長さの余白を埋めることで正方形を維持しているに過ぎません。
そのため、以下のようにテキストを要素内に入れてしまうと、形が崩れてしまいます
1 2 3 |
<div class="square_box"> <p>こんな風にテキストを入れても正方形を維持出来たら良いのになぁ~。</p> </div> |
レスポンシブな正方形を維持したままテキストを入れるには、CSSでposition
を操作すると良いでしょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
.square_box { position: relative; max-width: 300px; background: #ffb6c1; } .square_box::before { content: ""; display: block; padding-bottom: 100%; } .square_box p { position: absolute; top: 0; margin: 10px; } |
上記のように親要素のposition
をrelative
に、子要素(p
)をabsolute
に変更してください。
また、子要素のtop
プロパティを0
にすることで、正方形の上端にテキストを配置できます。
あるいは、テキストを中央に配置したい場合は、以下のようにCSSを修正してください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
.square_box { position: relative; max-width: 300px; background: #ffb6c1; } .square_box::before { content: ""; display: block; padding-bottom: 100%; } .square_box p { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); } |
段落のスタイルをtop
・left
で50%
ずつ移動させ、さらにtranslate()
関数で中央に配置されるよう微調整します。
3.画像を正方形にトリミング&縦横比を維持したい
次は、レスポンシブな正方形に画像をはめ込み、かつ縦横比を維持する方法を解説します。
HTML・CSSは以下の通りです。
1 2 3 |
<a class="square_image" href="#"> <img src="./01.jpg"> </a> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
.square_image { display: block; position: relative; max-width: 300px; } .square_image::before { content: ""; display: block; padding-top: 100%; } .square_image img { position: absolute; width: 100%; height: 100%; top: 0; object-fit: cover; } |
まず、画像を囲むaのdisplay
をblock
にして、横幅(max-width
)を指定します。
そして、疑似要素のpadding-top
で横幅と同じ分だけ高さを設けてください(10行目)。
ここまでは、今まで解説してきた正方形を作る方法と変わりありません。
次に、画像(img
)のスタイルを調整しましょう。
正方形の内部は疑似要素の余白(padding-top
)で埋まっているため、画像をそのまま配置してしまうと正方形から締め出されてしまいます。
そのため、親要素のposition
をrelative
に(3行目)、画像をabsolute
に(14行目)し指定しレイアウトから切り離します。
さらに、画像の幅・高さを100%
に(15-16行目)、top
を0
に調整(17行目)して、親要素と完全に重ね合わせましょう。
この時点で、画像は正方形にリサイズされますが、強制的な伸縮によって縦横比が崩れてしまいます。
この場合、object-fit
プロパティをcover
に指定することで、画像を正方形にリサイズしながら縦横比も維持することができます。
4.レスポンシブな正方形コンテンツを均等に並べる方法
今度は、レスポンシブな正方形を均等に並べてみましょう。
イメージとしては、下図のように3列に整列させてみたいと思います。
まず、HTMLを確認してください。
1 2 3 4 5 6 |
<div class="square_contents"> <div><p>テキスト</p></div> <div><p>テキスト</p></div> <div><p>テキスト</p></div> <!-- 以下略 --> </div> |
正方形を増やしたい場合は、.square_contents
内のdiv
を追加してください。
CSSは以下の通りです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
.square_contents { display: flex; flex-wrap: wrap; max-width: 600px; } .square_contents div { position: relative; width: 31%; background: #ffb6c1; margin: 1%; } .square_contents div::before { content: ""; display: block; padding-top: 100%; } .square_contents p { position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); } |
ブロック要素を均等に並べるならflex-boxがとても便利です。
親要素のdisplay
をflex
に指定(2行目)するだけで、簡単に子要素を横並べできます。
また、任意の列で改行させるようflex-wrap
をwrap
に指定(3行目)しておいてください。
3列にしたい場合は、各要素の(余白を含む)横幅 × 3列 = 100%になるよう調整(9行目)します。
左右にmargin
を設ける(11行目)ことを想定すると、30%前後が丁度良いかと思います。
100%を超えると3列以下で改行されてしまうので気を付けてください。
ちなみに、上記のコードは正方形の中にテキストを入れることを想定していますが、下図のように画像を並べることも可能です。
サムネイル一覧などに応用できる手法です。
まず、HTMLは以下の通りです。
1 2 3 4 5 6 |
<div class="square_contents"> <a href="#"><img src="./01.jpg"></a> <a href="#"><img src="./02.jpg"></a> <a href="#"><img src="./03.jpg"></a> <!-- 以下略 --> </div> |
リンクできるよう、各画像はa
タグで囲んでおくと良いでしょう。
次に、CSSを見てみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
.square_contents { display: flex; flex-wrap: wrap; max-width: 600px; } .square_contents a { display: block; position: relative; width: 31%; margin: 1%; } .square_contents a::before { content: ""; display: block; padding-top: 100%; } .square_contents img { position: absolute; width: 100%; height: 100%; top: 0; object-fit: cover; } |
先ほど解説した要素を整列するコードと基本的なテクニックは同じです。
気を付けてほしいのはa
はインライン要素なので、display
をblock
に変更(8行目)しておいてください。
画像を正方形にし、かつ縦横比を維持する方法については前章をご覧ください。
まとめ
- 「
vw
」「vmin
」を使えば、簡単に正方形を作れるが、画面幅に依存する padding
の特性を利用すれば、親要素の横幅を基準にして正方形を作れる- さらに疑似要素と組み合わせれば、任意の数値(
px
)で正方形を表示できる - 正方形にテキストや画像を入れる場合は
position
を調整しよう - 正方形を均等に並べたい場合はflex-boxを応用しよう