background-attachment fixedを使って、背景を固定してパララックスのような動きをすることがあるかと思います。
しかし、background-attachment fixedはスマホで動きません。
正しくは、「background-attachment fixedと、background-size coverを同時に使うとバグって動かなくなる」となっているようです。これは公式でバグとして認識されているみたいです。
バグだからと言って実装しないわけにはいかないので、やっていきましょう。
よくある擬似要素を使った方法の落とし穴
間違いとまではいきませんが、擬似要素を使った方法には欠点が多く使える状況が限定的で実際のWebサイト制作には正直使えない….
多くのブログで紹介されている擬似要素を使った方法のコードはこちら。
スマホ時のみこちらのコードを有効にして、z-index -1を使うことで擬似的に背景として扱っています。
hoge::before{
content:’’;
display:block;
position:fixed;
top:0;
left:0;
z-index:-1;
width:100%;
height:100vh;
background: url(ここに画像のパス) no-repeat center / cover;
}
一見すると背景固定表示ができているように見えますが、実制作で使う際の欠点は主に3点。
- position fixedの背景はページ全体をついて回るので、ページ全体に影響を及ぼす
- 背景色を使っているコンテンツの一部にといった使い方はできない
- ページ内に複数背景固定があった場合は、それぞれがついてくる状態なので使い物にならない
ページ内に一箇所だけ、かつ、背景色と一緒に使わない、かつ、ページ全体への影響を気にしないという状況だったら使えるかも。。。。いや、そんなのめんどくさい!
jsで細かく制御すればいけなくない場面も多いですが、工数どんだけかかるの?ってお話になっちゃいます。
詳しくは実際に使ってみるととてもわかります。
【本題】スマホで背景固定する方法
私が色々試した結果、ネットではどんだけ調べても出てこなかったのでぜひ試してみてください。
まずはHTMLはこちら。PC時は、普段どおりの背景固定を使ってください。( 2022年5月:picture要素とsouce要素を使ったレスポンシブイメージを使えばPC,SPどちらもいけます。コードの書き換えはまた今度やっておきます 2023年9月 picture要素に書き換えました)「__attachment」からなるdivの塊をHTML上に書いておきます。PCではdisplay noneとかで消しておいてください。
<div class="hoge">
<div class="hoge__attachment">
<picture class="hoge__attachment__clip">
<source srcset="PCで固定したい画像のパス" media="(min-width: 769px)" width="" height="" />
<img src="スマホで固定したい画像のパス" alt="" width="" height="" loading="lazy" />
</picture>
</div>
</div>
CSSはこちら。
重要な部分だけ解説しますので、細かい値は調整する際に試してみてください。
hogeには、表示したい高さを指定します。
そして、画像はposition fixedを使って画面に固定させます。
※ 2022年5月:使いやすいように少しコードを調整しています
.hoge{
height: 表示したい高さを指定;
&__attachment{
position: absolute;
left: 0;
top: 0;
display: block;
height: 100%;
width: 100%;
&__clip{
display: block;
position: relative;
overflow: hidden;
clip-path: inset(0 0 0 0);
height: 100%;
}
img{
position: fixed;
width: 100%;
min-height: 100vh;
height: auto;
left: 0;
top: 0;
pointer-events: none;
}
}
}
一番大事なのが、clipの部分。
overflow hiddenはぶっちゃけ意味なかったような….気が…ちょうど使ってた案件で必要だったので入れただけなので必要なければ消してください。
今回使っているposition fixedは、overflow hiddenが効きません。
代わりに「clip-path」を使ってoverflow hiddenと同じ挙動をさせます。
&__clip{
position: relative;
overflow: hidden;
clip-path: inset(0 0 0 0);
height: 100%;
}
「clip-path inset(0 0 0 0)」は要素を矩形にトリミングする方法です。
これだと、position fixedでも問題なくトリミングが可能です。
注意点
この方法では、コード中のdivにtransformを使うと動かなくなります。
transformを使ったアニメーションの際は、今回の方法ではなくabsoluteを使いましょう。
まとめ
この方法だったら、背景固定がページ内に複数あっても使えますし、背景色の影響も受けませんし、必要なdivの中で動作が完結するのでページへの影響もありません。
終わってみると単純な仕組みでした。