スマホで写真が縦長に伸びて表示されるとき|width・height属性を残したままCSSで幅だけ縮めると起きる仕組みと、共通CSSの1行で全ページ直す手順
スマホで写真が縦長に伸びて表示されるとき|width・height属性を残したままCSSで幅だけ縮めると起きる仕組みと、共通CSSの1行で全ページ直す手順
パソコンで見ると問題ないのに、スマホで開くと写真だけが縦にびよんと伸びている。スタッフの顔が面長になり、店内写真の柱が間延びして見える。お客さまから「写真が変ですよ」と言われて初めて気づくこともあります。
この症状は、画像ファイルが壊れているわけでも、スマホの機種の問題でもありません。ほとんどの場合、サイト全体に効く共通CSSの書き方に原因があります。
結論:共通CSSのimgルールに「height: auto」を足す
先に結論をまとめます。
- 原因は、
img { max-width: 100%; }にheight: auto;がセットで書かれていないこと。HTML側にwidthとheightの属性が残っている画像は、幅だけが画面に合わせて縮み、高さは属性の値のまま残ります。その結果、縦長に伸びて見えます - 直す場所は、伸びている画像1枚ずつではなく、共通CSSのimgルール1か所。ここに
height: auto;を足せば、全ページ・全画像が一度に直ります - HTMLの
width・height属性は消さない。この属性は、画像の読み込み前に表示領域を確保してページのガタつきを防ぐ役割を持っています。消すのではなく、CSS側で高さを自動計算させるのが正しい直し方です - 共通ルールを触る前に、影響範囲を数えて確かめる。ビルド後のCSSで「クラスの付かないimg指定」が何件あるかを調べれば、1行足しても他のレイアウトが壊れないかを事前に判断できます
以降、当社が運営している店舗向けWebサービスの紹介サイトで実際に行った対応をもとに、仕組みと手順を説明します。
なぜ写真だけが縦に伸びるのか
width・height属性とCSSの関係
いまのHTMLでは、画像に元のサイズを書いておくのが標準的な作法です。
<img src="salon.jpg" width="840" height="560" alt="店内の様子">
WordPressも、記事に画像を挿入するとこの2つの属性を自動で付けます。ブラウザはこの値から縦横比を読み取り、画像がまだ届いていない段階で「ここに3対2の領域が必要だ」と場所を空けておきます。読み込みの途中で文章がガクッと下にずれる現象を防ぐための、大事な仕組みです。
一方、スマホ対応のサイトでは、画像が画面からはみ出さないように次のCSSを入れるのが定番です。
img { display: block; max-width: 100%; }
問題はこの2つが組み合わさったときに起こります。画面の幅が360pxのスマホでは、max-width: 100% によって画像の幅は840pxから360px前後まで縮みます。ところが高さについては何も指定が無いため、HTML属性の「560px」がそのまま使われます。幅360px・高さ560pxの枠に、本来は横長の写真が引き伸ばされて収まる。これが「縦に伸びる」の正体です。
パソコンで気づけない理由
パソコンの画面では、画像を置く枠の幅が840px以上あることが多く、max-width: 100% による縮小がそもそも発生しません。幅も高さも属性の値どおりに表示されるので、比率は正しいままです。
つまりこの不具合は、「画像の元サイズより、表示枠が狭くなったとき」だけ現れます。パソコンで制作し、パソコンで確認している限り見つかりません。ブラウザの幅を少し狭めた程度では再現しないことも多く、実際のスマホ幅(360〜390px)まで縮めて初めて見えてきます。スマホだけで起きる崩れの探し方は、スマホだけ文字が重なる原因でも紹介しています。
正しい書き方
対処は1行です。
img { display: block; max-width: 100%; height: auto; }
height: auto があると、ブラウザは「縮んだ後の幅」と「width・height属性から読み取った縦横比」を使って高さを計算し直します。属性は残っているので、読み込み前の領域確保もそのまま働きます。max-width: 100% と height: auto は必ずセットで書く、と覚えておくのが確実です。
WordPressの標準テーマや多くの市販テーマには、この2つがセットで入っています。症状が出やすいのは、オリジナルでテーマを作ったサイトや、フレームワークで一から組んだサイト、リニューアル時にCSSを書き直したサイトです。
実例:同じ症状が別の場所に出たら、共通定義を調べる
当社が運営する店舗向けWebサービスの紹介サイト(12ページ構成)で、スマホ表示の写真が縦長に伸びる症状が確認されました。最初に見つかったのは、機能紹介ページの写真3点。続いて同じ日に、トップページの導入実績の写真でも同じ症状が見つかりました。
この種の不具合は、見つかった画像に個別のCSSを当てれば、その場では直ります。表示の確認も通ります。ただ、同じ症状が違う場所に2度出た時点で、原因は個々の画像ではなく、その上流にある共通の定義にあると考えるのが正しい進め方です。個別の修正は「直った」という手応えがあるぶん、根本原因を探すきっかけを失わせます。放っておけば、新しい写真を追加するたびに同じ問い合わせが繰り返されることになります。
そこで共通CSSを確認したところ、サイト全体のimgルールが img { display: block; max-width: 100%; } となっており、height: auto が入っていませんでした。画像は width="840" height="560" の属性付きで出力されていたため、前の章で説明したとおりの条件がそろっていたわけです。
修正は、共通CSSのこの1行に height: auto; を加えただけです。変更の差分は1ファイル1行。これで、個別に直した箇所も、まだ誰も気づいていなかった箇所も含めて、全ページの画像が正しい比率で表示されるようになりました。
共通CSSに1行足す前の安全確認
「共通CSSを触ると、別の場所が崩れるのでは」という不安は当然です。要素そのものを対象にした指定は全ページに効くため、確認なしに変えるべきではありません。当社では次の順番で確かめてから反映しました。
手順1:クラスの付かないimg指定が何件あるか数える
ビルド後(実際に配信される状態)のCSSファイルを検索し、img { のようにクラス名が付かない、いわゆる「裸のセレクタ」のimg指定が何件あるかを数えます。今回のサイトでは、該当は問題の1件だけでした。ほかに裸のimg指定が無ければ、1行足したことで別の共通ルールと競合する心配はありません。
開発中のソースではなく、ビルド後のCSSを見るのがポイントです。フレームワークや外部ライブラリが出力するCSSも含めて、実際にブラウザへ届くものを調べます。
手順2:高さを指定している画像枠がクラス付きか確かめる
サイトには、わざと高さを固定している画像もあります。たとえばカードの上部で写真を枠いっぱいに切り抜いて見せる、次のような指定です。
.service-photo img { width: 100%; height: 100%; object-fit: cover; }
ここに共通の height: auto が効いてしまうと、枠のデザインが崩れます。ただしCSSには優先順位の決まり(詳細度)があり、.service-photo img のようにクラスの付いた指定は、クラスの無い img の指定に必ず勝ちます。書かれている順番は関係ありません。
今回は、height: 100% と object-fit: cover を使う枠がすべてクラス付きで書かれていることを確認できたので、影響なしと判断しました。逆に、もしクラスの無い指定で高さを決めている箇所が見つかったら、先にそちらへクラスを付けてから共通ルールを直します。
あわせて、HTMLの height 属性だけで大きさを決めている古いバナーやアイコンが無いかも見ておくと安心です。
手順3:反映前にバックアップ、反映後は数値で確かめる
本番へ反映する前に、公開中のファイル一式をバックアップしました。反映後は、目で見るだけでなく次の点を確かめています。
- ビルドがエラーなく完了していること
- 本番で配信されているCSSに
height:autoが入っていること(手元のビルド結果とファイルが一致すること) - 全12ページとサイトマップが正常に開くこと(HTTPステータス200)
- 主要ページのHTMLが、手元のビルド結果と一致していること
なお、先に当てていた個別の height: auto は、共通ルールと内容が重なるだけで害が無いため、そのまま残しました。動いているものを「きれいにするため」だけに消して、別の確認作業を増やす必要はありません。
自分のサイトで確かめる方法
制作会社に頼む前に、自分で切り分けることもできます。
1. スマホ実機で、写真の多いページを上から下まで見る。 トップページだけでなく、スタッフ紹介・メニュー・ブログ記事など、画像の出し方が違うページを一通り確認します。人の顔や、丸い時計・お皿など「本来の形が分かるもの」が写った写真で見ると、伸びに気づきやすくなります。
2. パソコンのブラウザで検証する。 Chromeなら、ページ上で右クリック→「検証」を開き、検証パネルの左上にあるスマホのアイコンを押すと、スマホ幅での表示を再現できます。伸びている画像を選ぶと、右側に効いているCSSの一覧が表示されます。max-width: 100% はあるのに height: auto が見当たらず、高さが属性の値(例:560)のままなら、この記事の原因に当てはまります。
3. 画像が多いサイトは、機械的に洗い出す。 同じ検証画面の「Console」に次の1行を貼ると、元画像の縦横比と表示上の縦横比が2%以上ずれている画像のURLが一覧で出ます。
[...document.images].filter(i => i.naturalWidth && getComputedStyle(i).objectFit === 'fill' && Math.abs(i.clientWidth / i.clientHeight - i.naturalWidth / i.naturalHeight) > 0.02).map(i => i.currentSrc)
object-fit で意図的に切り抜いている画像は除外しているので、結果が空なら、その時点で読み込まれている画像に伸びはありません。スマホ幅の表示に切り替え、ページを一番下までスクロールして画像を読み込ませてから実行してください。
height: autoを入れても直らないとき
共通CSSを直しても伸びが残る場合は、別の原因を疑います。
- もっと強い指定で高さが固定されている。
.gallery img { height: 300px; }のようなクラス付きの指定があると、共通のheight: autoは負けます。その枠で写真を切り抜いて見せたいならobject-fit: coverを足し、切り抜きたくないなら高さの固定を外します - 画像が横並びレイアウト(flex)の直接の子になっている。 横並びの指定では、子要素の高さを一番背の高い要素にそろえる動きが初期設定です。画像を直接並べると、隣の文章の高さに合わせて写真が縦に引き伸ばされます。画像を
divで包むか、画像にalign-self: flex-startを指定すると解消します - インラインで高さが書かれている。
style="height:560px"のようにHTMLへ直接書かれた指定は、CSSファイルの指定より優先されます。古い編集画面やページビルダーで作ったページに残っていることがあります
なお、画像が「伸びる」のではなく「ぼやける」場合は原因が別です。こちらはレスポンシブ画像がぼやける原因はsizes属性をご覧ください。
まとめ
- スマホで写真だけが縦に伸びるのは、HTMLのwidth・height属性が残ったまま、CSSで幅だけが縮むために起こる。パソコンでは表示枠が広く縮小が起きないため、気づけない
- 直し方は、共通CSSのimgルールに
height: autoを足す1行。max-width: 100%とは必ずセットで書く。width・height属性は、読み込み時のガタつきを防ぐ役割があるので消さない - 共通ルールを触る前に、ビルド後のCSSで「クラスの付かないimg指定」の件数と、高さを固定している画像枠がクラス付きで書かれているかを確かめる。クラス付きの指定は詳細度で勝つので、共通の1行を足しても崩れない
- 反映前にバックアップを取り、反映後は「配信中のCSSに入っているか」「全ページが正常に開くか」を数値で確認する
- 同じ症状が違う場所に2度出たら、個別の修正をやめて共通の定義を調べる。1枚ずつ直しても、次に追加した写真でまた同じことが起こる
写真はお店の印象を決める要素です。新しい写真を載せたとき、リニューアルした直後は、パソコンだけでなくスマホの実機でも一度、上から下まで確認してみてください。