レイアウトシフト(ページ読み込み後のずれ)を回避する方法

要素の比率を維持して可変させる方法では、画像を可変させる方法や高さ不明(固定できない)要素の縦横比を維持して可変させる方法を紹介しました。

今回はこの方法を応用して、レイアウトシフト(ページ読み込み後のずれ)を回避してユーザーのストレスを軽減するテクニックを紹介します!

画像のレイアウトシフトについて

例として下記のようなページを用意しました。

ブラウザ表示

記述例は下記で、メインビジュアル、リード文、その下に2カラムでコンテンツを表示しています。

HTML

<div class="hero">
  <img class="hero__image" src="img/maintain_sample.jpg" alt="" />
  <p class="hero__text">ここはリード文など、画像の下に配置されているコンテンツです。ここはリード文など、画像の下に配置されているコンテンツです。</p>
</div>

<div class="items">
  <div class="item">
    <img class="item__image" src="img/maintain_v2_sample_03.png" alt="" />
    <p class="item__text">ここにテキストが入ります。ここにテキストが入ります。</p>
  </div>
  <div class="item">
    <img class="item__image" src="img/maintain_v2_sample_03.png" alt="" />
    <p class="item__text">ここにテキストが入ります。ここにテキストが入ります。</p>
  </div>
</div>

CSS

div {
  box-sizing: border-box;
}
img {
  width: 100%;
  height: auto;
  box-sizing: border-box;
  vertical-align: bottom;
}
.hero {
  text-align: center;
}
.hero__image {
  width: 100%;
  max-width: 1280px;
  height: auto;
  box-sizing: border-box;
}
.hero__text {
  padding: 10px;
  font-size: calc(0.875rem + ((1vw - 4.8px) * 0.6944));
  text-align: left;
  line-height: 2;
}
.items {
  display: flex;
  justify-content: space-between;
  width: 100%;
  flex-wrap: nowrap;
  padding: 0 4vw;
}
.item:nth-child(2n) {
  margin-left: 4vw;
}
.item__image {
  max-width: 320px;
}
.item__text {
  max-width: 320px;
  padding: 10px 0 30px;
  font-size: calc(0.875rem + ((1vw - 4.8px) * 0.6944));
}
@media (max-width: 480px) {
  .hero__text {
    font-size: 14px;
  }
}
@media (min-width: 768px) {
  .hero__text {
    font-size: 16px;
  }
}

このままでも悪くはないのですが、画像表示の点で考えると2つ気になる所があります。

  • 何らかのエラーで画像が表示されなくなった場合にその下のコンテンツが上に詰まる
  • ページ読み込み時に画像が遅れて表示されるとコンテンツがその画像のスペース分ガクッと下にずれる

順番に説明します。

画像の下にあるコンテンツが上に詰まる

画像がリンク切れなど何らかのエラーで表示されない場合をchromeのデベロッパーツールで再現します。

chrome デベロッパーツールでの操作

これではレイアウトが崩れますし、コンテンツがそこにあるべきものなのかもわかりません。

コンテンツが画像のスペース分ガクッと下にずれる

ページ読み込み時にコンテンツがガクッと下にずれるのを再現した動画です。

画像の読み込みの方がテキストよりも遅いので、一瞬コンテンツがガクッとずれたのがわかるでしょうか。

スクロール最中やタップしようとした時にこれが起きるとストレスです…

こういったようなページにガタツキが生じる挙動のことを「レイアウトシフト」と言います。配置(レイアウト)が移動(シフト)するってことですね。

画像のレイアウトシフトによるストレスを軽減する方法

これらを解決する方法です。

記述例

HTMLは先程と変わりません。

<div class="hero">
  <img class="hero__image" src="img/maintain_sample.jpg" alt="" />
  <p class="hero__text">ここはリード文など、画像の下に配置されているコンテンツです。ここはリード文など、画像の下に配置されているコンテンツです。</p>
</div>

<div class="items">
  <div class="item">
    <img class="item__image" src="img/maintain_v2_sample_03.png" alt="" />
    <p class="item__text">ここにテキストが入ります。ここにテキストが入ります。</p>
  </div>
  <div class="item">
    <img class="item__image" src="img/maintain_v2_sample_03.png" alt="" />
    <p class="item__text">ここにテキストが入ります。ここにテキストが入ります。</p>
  </div>
</div>

CSS

div {
  box-sizing: border-box;
}
img {
  width: 100%;
  height: auto;
  box-sizing: border-box;
  vertical-align: bottom;
}
.hero {
  position: relative;
  text-align: center;
}
.hero::before {
  content: "";
  display: block;
  padding-top: calc(((720 / 1280) * 100%));
}
.hero__image {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  max-width: 1280px;
  height: auto;
  box-sizing: border-box;
}
.hero__text {
  padding: 10px;
  font-size: calc(0.875rem + ((1vw - 4.8px) * 0.6944));
  text-align: left;
  line-height: 2;
}
.items {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  justify-content: space-between;
  width: 100%;
  -ms-flex-wrap: nowrap;
  flex-wrap: nowrap;
  padding: 0 4vw;
}
.item {
  position: relative;
}
.item::before {
  content: "";
  display: block;
  padding-top: calc(((320 / 320) * 100%));
}
.item:nth-child(2n) {
  margin-left: 4vw;
}
.item__image {
  position: absolute;
  top: 0;
  left: 0;
  max-width: 320px;
}
.item__text {
  max-width: 320px;
  padding: 10px 0 30px;
  font-size: calc(0.875rem + ((1vw - 4.8px) * 0.6944));
}
@media (max-width: 480px) {
  .hero__text {
    font-size: 14px;
  }
}
@media (min-width: 768px) {
  .hero__text {
    font-size: 16px;
  }
}

ブラウザ表示を再現した動画です。

先程の読み込み時とは違い、初めから画像分の高さが確保されているのがわかるでしょうか。

ポイントはCSS14行目と47行目の擬似要素(before)への指定です。

要素の比率を維持して可変させる方法で紹介したブロック要素の比率を維持して可変させる方法を使って、画像を括っているブロック要素の擬似要素(before)にpadding-topを%で指定して高さを確保しています。

後は画像自体をposition: absolute;で配置すればOKです。

高さが確保されているのかはchromeのデベロッパーツールでも確認できます。

chrome デベロッパーツールでの操作

ファーストビューに入ってくるキービジュアルに使うだけでもグッと良くなります。

ちなみにこの方法は背景に画像を配置する場合にも使えますし、iframeなどの動画を埋め込む場合にも使えます。

まとめ

このように画像の配置方法を工夫すると、画像表示の点で下記が改善されます。

  • 何らかのエラーで画像が表示されなくなった場合でもレイアウト(コンテンツの高さ)を維持できる
  • ページ読み込み時の「レイアウトシフト」(コンテンツがガクッとずれること)を回避できる

CSSで縦横比を維持して要素を可変させる方法やレイアウトシフトを回避する方法を使ってみてください!