パララックス効果をスマホでも実装する(CSSのみ)

ロッチくん
ロッチくん

パララックス効果を実装できるCSSプロパティ、background-attachment: fixed;はiOSのSafariでは使えないからスマホでは諦めるしかないのかニャ。。

はじめに

パララックス効果を簡単に実装できるCSSプロパティとして background-attachment: fixed;があります。
しかし iOS の Safari ではこちらが使えません。厳密にいうと background-size: cover; との併用が問題になるようですが、パララックスでは画像を画面いっぱいに表示させるケースが多いので、こちらの併用ができないのは致命的になります。
今回はスマホでもパラックス効果のあるページを実装する、background-size: cover;の代用できるプロパティと実装方法の解説になります。

パララックスの効果は大きな画面上でよく映える演出技法であると思うので、スマホではこの演出をあきらめるというのは案外実務でもあります。他の技法でもスプリットにして画面を2等分にする手法なども同様で、無理にPCとスマホの見せ方を揃えなくても最適な魅せ方を選択すべきでしょう。

ただ今回どうしてもスマホでも実装させたいとの依頼があり色々調べて実践することにしました。

どのような手法があるか

調べると何個か手法はみつかりました。JSを使った複雑な手法やパララックスのライブラリ等ももちろんあるのですが、そこまで手間をかけずにCSSだけでできるシンプルな方法がないかで今回探してみました。

一番よく見かけたのは、::before など疑似要素に背景画像を指定し、position: fixed; で固定させ、 z-index: -1; にして他のコンテンツよりも下の値を指定するもの。ただしこのやり方では複数のパララックス画像を設置させることが困難です(JSなどでなんとかできるかもしれませんが、効果を得るための費用対効果が見合わないように思えます)。

また、 position: sticky; を使って固定化するやりかたもよく見かけました。こちらなら複数のパララックス画像を設置することもできます。ただこちらだと一つの section 内に背景画像と背景を透過させたテキスト部分を併せ持つ今回実装したいページが難しく感じ、結局今回紹介する clip-path で一つに重なった背景画像を切り抜いて一枚ずつ固定するやりかたで、一番background-attachment: fixed; で実装させていたページに近い形を再現できたと感じています。

前置きが長くなりました。今回のデモサイトはこちらです。もちろんスマホにも対応もしています。

コード

HTML

<div class="wrapper">
    <header>
      <div class="headerInner">
        <h1>LOGO</h1>
      </div>
    </header>
    <div class="container">
      <section>
          <div class="sectionInner">
              <div id="imageBg01" class="imageBg"></div>
              <div class="cntFrame">
                  <h2>見出し1</h2>
                  <P>ここにテキストが入ります。ここにテキストが入ります。ここにテキストが入ります。ここにテキストが入ります。ここにテキストが入ります。ここにテキストが入ります。</P>
              </div>
          </div>
      </section>
      <section>
          <div class="sectionInner">
              <div id="imageBg02" class="imageBg"></div>
              <div class="cntFrame">
                  <h2>見出し2</h2>
                  <P>ここにテキストが入ります。ここにテキストが入ります。ここにテキストが入ります。ここにテキストが入ります。ここにテキストが入ります。ここにテキストが入ります。</P>
              </div>
          </div>
      </section>
      <section>
          <div class="sectionInner">
              <div id="imageBg03" class="imageBg"></div>
              <div class="cntFrame">
                  <h2>見出し3</h2>
                  <P>ここにテキストが入ります。ここにテキストが入ります。ここにテキストが入ります。ここにテキストが入ります。ここにテキストが入ります。ここにテキストが入ります。</P>
              </div>
          </div>
      </section>
    </div>
    <footer>
      <div class="footerInner">
        <p>FOOTER</p>
      </div>
    </footer>
</div>

CSS

.wrapper {
  width: 100%;
}
header {
  width: 100%;
  height: 60px;
}
.headerInner {
  max-width: 1000px;
  margin: 0 auto;
  height: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}
h1 {
  font-size: 20px;
  color: #333;
  font-weight: bold;
}
.container {
  width: 100%;
}
section {
  position: relative;
  width: 100%;
  height: 200vh;
}
section .sectionInner {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  clip: rect(auto, auto, auto, auto); /* これで背景を切り抜く */
}
section .imageBg {
  position: fixed;
  top: 0;
  left: 0;
  z-index: -1;
  display: block;
  width: 100%;
  height: 100vh;
  background-size: cover;
  background-position: center;
}
section #imageBg01 {
  background-image: url(./images/imageBg01.jpg);
}
section #imageBg02 {
  background-image: url(./images/imageBg02.jpg);
}
section #imageBg03 {
  background-image: url(./images/imageBg03.jpg);
}
section div.cntFrame {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  width: 100%;
  height: 100vh;
  padding: 0 100px;
  margin-top: 100vh;
  background: rgba(255,255,255,.8);
  color: #111;
}
section div.cntFrame h2 {
  font-size: 20px;
  font-weight: bold;
  margin-bottom: 2em;;
}
footer {
  width: 100%;
  height: 100px;
  background-color: #333;
}
.footerInner {
  max-width: 1000px;
  height: 100%;
  margin: 0 auto;
  display: flex;
  justify-content: center;
  align-items: center;
}
.footerInner p {
  color: #fff;
  font-size: 20px;
  font-weight: bold;
}

@media (max-width: 768px) {
  section div.cntFrame {
    padding: 0 15px;
  }
  section #imageBg01 {
    background-position: 20% top;
  }
  section #imageBg02 {
    background-position: 20% top;
  }
  section #imageBg03 {
    background-position: 62% top;
  }
}

ちょこっと解説

まず背景画像は「position: fixed;」で絶対位置で固定しておきます。この状態だとすべての画像が重なっていて最後の背景画像だけが表示されている状態になります。

そこで登場するのが今回の「position: fixed;」した背景画像を取り囲む「.sectionInner」です。
こちらに指定されたCSSのプロパティ「clip-path: inset(0 0 0 0);」で要素を矩形にトリミングし、「.sectionInner」内の要素で背景画像を切り抜くことで一枚一枚固定表示することが可能となりました。
clip-pathのくわしい解説はこちらをご覧ください。

これでスマホにも対応できるパララックスが実装できました。

コメント

タイトルとURLをコピーしました