今更ですが新年明けましておめでとうございます。
本年もAGNチームブログをよろしくお願いいたします。
さて、今年1発目は軽い小ネタから。いきなり重いと胃もたれしちゃいますからね。
昔固定幅で作ったWebサイトをHTMLや画像はそのままにレスポンシブ化したいという案件で使った小技です。
固定幅の頃
昔(おそらくスマートフォンの出たてかそれくらい)固定幅で作られたそのサイトは画像多めのサイトで、フロートを駆使してなおかつちょっとでもレンダリング速度を上げたいのでいける画像は背景にして利用していました。
ボックス全体がサイト幅で、そのうちコンテンツが50%、残り50%は画像に見えるけど実は背景、みたいなことをフロートを駆使しつつ作っていたわけです。
※だからフロートでつまづく人は大概背景が表示途中で切れちゃうことに大きな悩みを持っていたのです。Clearfixの歴史を振り返ればみんながフロートとどのように戦ってきたかわかるかもしれません。
そのサイトは単純な角版の画像がほとんどなくて、複数の画像を斜めに組み合わせてみたり、ちょっと凝った画像が多かったのです。
それでも制作された当時と違って、background-positionがより使いやすくなったり(オフセット記法が可能になった)、bacground-sizeが使えるようになったりしているので、その辺を使ってなんとかレイアウトしていこう、という感じでした。
※全面に背景を引きたくてbacground-size : cover;が使えなかった頃はJavaScriptで実装したりしてたんですよ。そう、角丸を画像で組み立てていた頃に近いですね…
実際にやってみる
考え方はよくあるレスポンシブWebデザインの考え方でいきます。
メディアクエリで振り分けて、左側 (右側)にある背景画像をある幅以下の時はコンテンツの下(上)にレイアウトしましょう、というやり方です。よくあるやつですね。
方法1:背景画像じゃなくて擬似要素で配置する。
background-imageでしていたものを擬似要素(::before、::after)のcontentで配置しようというわけです。
それで擬似要素をdisplay: block;にでもしておけば勝手に下に落とせますからね。
ただこのやり方だとうまくいかない場合があるのです。
contentプロパティで配置された画像はサイズの調整が難しいのです。
というのも、contentプロパティで配置された画像はサイズの指定ができないのです。
擬似要素にサイズ(width、height)を指定してもだめ。どんな時に困るかというと、もともとの画像が画面幅より大きかった時。
これ、画像が見切れます。
さて、困った。
この問題そのものに対する解はネット上でもよく見かけますが、contentプロパティで配置するのではなくて、擬似要素のサイズを指定してその背景が画像として使う、ということかもしれません。
方法2:背景画像でいく
今日触れたいのはこちら。
背景画像として使うけど、コンテンツと重なるのは嫌だ、というお客様のために。
方法としてはpaddingで領域を確保してそこに背景画像を100%で表示させます。
この方法のメリットはデバイス幅が変わっても比率を維持できる点です。
領域を確保する
領域を動的にpaddingを使って確保するためにpaddingを%で指定します。
この方法でわかっておかなくてはいけないのは画像の縦横の比率(サイズではなくて)です。
画像の縦横の比率のパーセンテージ分だけpadding-bottom(padding-top)を指定してあげます。
どういうことかと言いますと、
例えば画像サイズが800 × 600だったとします。
これをコンテンツの下に背景用の領域を確保するためにはpadding-bottomに
(600/800)*100%を指定してあげるのです。
これでなんでうまいこと領域が計算できているかというと、これはpaddingの特性を利用しているのです。
The percentage is calculated with respect to the width of the generated box’s containing block, even for ‘padding-top’ and ‘padding-bottom’. If the containing block’s width depends on this element, then the resulting layout is undefined in CSS 2.1.
Unlike margin properties, values for padding values cannot be negative. Like margin properties, percentage values for padding properties refer to the width of the generated box’s containing block.パーセンテージは、 ‘padding-top’と ‘padding-bottom’の場合でも、生成されたボックスの包含ブロックの幅に対して計算されます。包含ブロックの幅がこの要素に依存する場合、結果のレイアウトはCSS 2.1で定義されていません。
マージンプロパティとは異なり、パディング値の値は負であってはなりません。マージンプロパティと同様に、パディングプロパティのパーセンテージ値は、生成されたボックスの包含ブロックの幅を参照します。https://www.w3.org/TR/CSS2/box.html#propdef-paddingより引用
大事なところは、
生成されたボックスの包含ブロックの幅に対して計算されます。
ここです。
計算は包含ブロック(ざっくりと親の要素)の高さから計算しているわけではないのです。
包含ブロックの幅を元に計算するので上の式でいけるんですね。
画像がもし親要素に対し幅100%だったとした時に、幅に対する高さの割合を求め、その分だけ親要素に余白(padding)を持たせることで、背景画像の領域が確保されたわけです。
これはマップや動画を100%で埋め込みたい、という時と同じ考え方ですね。
そんなに多様するわけではないけれど、まぁちょっとCSSのお勉強の小ネタ、ということで。
蛇足ですが…
ちょっとハマったのが、iOSでbackground-size: cover;がうまくいかなかったことです。
これはbackground-attachment: fixed;と一緒に使っているとダメみたいです。
背景固定して全面画像みたいなことができないじゃないか…
ちなみにこれはbackground-sizeを100vhにすることでやりたかったことに近くなったので今回はOKにしました。
background-attachment: fixed;で背景固定して、background-size: auto 100vh;で。