WordPressでスマホだけレイアウトが崩れる時の対処法

実測 に検証

PC では正常。スマホで見ると崩れている。あるいはその逆。

最初に確認すべきは「サーバーが端末ごとに違うものを返しているか」です。 同じ HTML が返っているなら、原因はサーバー側ではありません。 これを先に確定させると、調べる範囲が半分になります。

実測: User-Agent を変えても HTML は同一

同じ URL に対して、PC とスマホの User-Agent で取得して比較しました。

PC     md5 369bfc303a0ff9ec792d1dfe5b281f11
iPhone md5 369bfc303a0ff9ec792d1dfe5b281f11
→ 完全に同一

サーバーは端末を区別していませんでした。 つまりこのサイトで「スマホだけ崩れる」なら、原因は

  • CSS(メディアクエリ、viewport
  • ブラウザ側(キャッシュ、拡張機能)

のどちらかに絞れます。サーバー設定やキャッシュを調べる必要はありません。

比較するときの注意

最初の計測では PC と iPhone で md5 が違い、「端末で出し分けている」と 誤判定しました。同じ UA で 2 回取っても md5 が違いました。

原因は、テーマが出力しているデバッグ情報(生成時間、クエリ数、ピークメモリ)が リクエストごとに変わることでした。

PC-1 0d6416af92f5bb6e802516652ac55c0b
PC-2 e08ae9203bf48a5a11cff5978e93a3c1   ← 同じ UA でも違う

リクエストごとに変わる部分を除いてから比較します。

UA_PC="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 Chrome/130.0"
UA_SP="Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 Mobile/15E148"

# 変動する行を除いて比較する
for ua in "$UA_PC" "$UA_SP"; do
  curl -s -A "$ua" https://example.com/ \
   | grep -vE "nonce|csrf|[0-9]+\.[0-9]+ 秒|ver=[0-9]" | md5
done

2 つが一致すればサーバーは無罪、違えば端末ごとに出し分けています。

出し分けている場合

wp_is_mobile() という関数があり、User-Agent を見て判定します。実測です。

UAwp_is_mobile()
Mac / Chromefalse
iPhone / Safaritrue

テーマやプラグインがこれを使っていると、サーバーが返す HTML が端末で変わります。 この場合に問題になるのがキャッシュです。

キャッシュが PC 版をスマホに返す

キャッシュプラグインや CDN は、同じ URL に対して 1 つのキャッシュを持ちます。 最初にアクセスしたのが PC だったら、その HTML がスマホにも返ります。

症状の特徴で見分けられます。

  • 特定のページだけ崩れる(キャッシュが作られたページだけ)
  • キャッシュを消すと直り、しばらくすると再発する
  • ログイン中は正常(ログインユーザーはキャッシュを使わない設定が多い)

この 3 つが揃っていたらキャッシュです。

対処は 2 つあります。

  1. キャッシュ側で「モバイル別キャッシュ」を有効にする (設定名は「Mobile support」「Separate mobile cache」など)
  2. そもそも端末で出し分けない(レスポンシブ CSS だけで対応する)

2 のほうが根本的です。出し分けをやめれば、キャッシュの設定ミスで 壊れる余地が無くなります。

確認方法: Vary ヘッダ

端末ごとに違うものを返すなら、Vary: User-Agent を付けるのが正しい作法です。

curl -s -o /dev/null -D - -A "$UA_SP" https://example.com/ | grep -i '^vary'

出し分けているのに Vary が無い場合、CDN やブラウザが 「どの端末でも同じもの」と判断してキャッシュします。これが崩れの原因になります。

実測環境では出し分けをしていないため Vary もありませんでした(正しい状態です)。

出し分けていない場合(CSS 側)

サーバーが同じ HTML を返しているなら、原因は CSS かメタタグです。

viewport メタタグ

これが無いと、スマホは「PC 用の幅(980px 程度)」で描画してから縮小表示します。 メディアクエリが効かず、文字が極端に小さくなります。

curl -s https://example.com/ | grep -o '<meta name="viewport"[^>]*>'

実測環境の値です。

<meta name="viewport" content="width=device-width, initial-scale=1">

これが出ていなければ、テーマ側の問題です。 wp_head() を呼んでいないテーマや、header.php を自作したときに欠けます。

横スクロールが出る

スマホで崩れる原因として最も多いのがこれです。画面幅より広い要素が 1 つでもあると、ページ全体に横スクロールが出て崩れて見えます。

幅を固定した表が画面の右にはみ出している

幅 1200px に固定した表を、幅 390px のスマホ表示で開いた画面。ページ全体の幅が 1220px になり、表の右側が切れる

犯人は決まっています。

  • 固定幅(width: 1200px)の要素
  • はみ出した画像(max-width: 100% が無い)
  • 幅の広いテーブル(overflow-x: auto が無い)
  • 長い URL やコードが折り返されていない

ブラウザの開発者ツールで探せます。

// 画面幅を超えている要素を列挙する
[...document.querySelectorAll('*')].filter(
  el => el.getBoundingClientRect().right > document.documentElement.clientWidth + 1
).slice(0, 10)

キャッシュされた CSS

CSS を修正したのにスマホだけ古いままなら、端末のブラウザキャッシュです。 アセットの ?ver= が更新されていないと起きます。 → CSS が効かない の「読み込まれているのに効かない場合」

切り分けの順番

  1. UA を変えて HTML を比較する(変動部分を除く)
  2. 同一 → CSS 側。viewport メタ、横にはみ出した要素を探す
  3. 違う → 出し分けている。Vary ヘッダとキャッシュの設定を見る
  4. 「消すと直る・しばらくすると再発」ならキャッシュで確定

AMP を使っている場合

AMP は別 URL(/amp/ など)の別ページです。 通常ページと AMP ページで表示が違う場合は、 まずどちらを見ているのかを確認します。スマホの検索結果から来ると AMP ページが表示されるため、「スマホだけ違う」に見えます。

この場合の原因は AMP テンプレート側にあり、通常ページの CSS を直しても変わりません。