パララックス効果があるタイプ

こういうヘッダーだと、パララックス効果をつけてみたくなるものです。ウィンドウ幅いっぱいのヘッダー画像にパララックス効果をつけたいときのためのメモです。ここではCSSのtransformプロパティを利用して、パララックス効果を作ります。

パララックスの作り方

JavaScriptでパララックス効果を再現する場合、ウィンドウのスクロール位置に合わせて、transform: translateY()を使って要素の位置をちょっとずつズラして表現してます。※このブログの記事ヘッダー部分参照(2018.10現在)
一方CSSだけで作るパララックス効果は、実際にtransform: translateZ()を使って要素を画面の奥にズラして、本当に奥行きを使ってパララックスを表現します。

CSSでパララックス効果を作る方法について、詳しくは下記記事を参照のこと。
動くCSSのためのメモ。パララックス(2014.6.5)

スクロールする要素を作る

CSSのパララックスは、いつものウィンドウのスクロールでは出来なくて、スクロールする要素を別途用意しなくちゃいけません。
ここでは#wrapper要素の中身をスクロールするようにします。要素のサイズを固定して、overflowプロパティでautoを指定すれば、その要素の中身がはみ出す場合にスクロールバーが表示されるようになります。

#wrapper {
	position: absolute;
	overflow: auto;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	︙

-webkit-overflow-scrolling: touchは、iPhoneでの慣性スクロールを有効にするための指定。
さらに、will-change: scroll-positionを指定することで、スクロール可能なコンテンツのレンダリングの最適化が図れます。

	︙
	-webkit-overflow-scrolling: touch;
	will-change: scroll-position;
	︙

そしてパララックスの要、perspectiveプロパティで、その子要素に指定した3Dを伴う変形の奥行きを指定します。

	︙
	perspective: 200px;
}

will-changeプロパティについて、詳しくは以下の記事を参照のこと。

要素を奥に移動する

あとは、パララックス効果をつけたい要素を、transformプロパティで、手前or奥へ移動させればよいです。

まずはページタイトル。もともと、要素の中央に配置するためにtranslateY(-50%)が指定してあったので、それを残しつつ、translateZ()も指定しなくちゃいけません。そんな時は、(x, y, z)をまとめて指定できるtranslate3dで指定しましょう。3つめの値がz方向への移動の指定で、正の値が手前へ、負の値が奥への移動を表します。単位はpxを使います。

header h1 {
	transform: translate3d(0, -50%, -100px) scale(1.5);
	︙

その際、奥へ移動するときの消失点(#wrapper要素のperspective-origin)が、ウィンドウ中央になっているため、100px奥へ移動した分、表示位置が下に下がって見えてしまいます。そこで、ページタイトル自体の、変形するときの原点transform-origin)を適宜指定して、header要素の中央に表示されるように調整しています。ここではx方向に50%、y方向に25vhの位置を指定。

	︙
	transform-origin: 50% 25vh;
}

img要素にも、同じ要領で奥への移動と、transform-originプロパティの調整をすれば、できあがり!

header figure img {
	︙
	min-width: 66.6666vh;
	transform-origin: 50% 100%;
	transform: translate3d(-50%, -50%, -50px) scale(1.26);
}

scale(1.26)の指定は、ほんとはscale(1.25)なのですけれど、スクロールバーが常に表示されてるタイプのデバイス(Windowsとか)の場合、その幅分、ウィンドウ幅vh単位の値とに誤差が出てしまうみたいなので、img要素を若干header要素からはみ出すくらい大きめに拡大しています。

背景画像として表示するタイプでもパララックス

header要素にbackgroundプロパティで指定したままでは、パララックス効果を作るのは難しいため、header要素に::before擬似要素を使って、それに背景画像を表示させて、パララックス効果を作ります。

※::after擬似要素は、半透明のスクリーントーンの表示に使っているので、::before擬似要素を使います。

header::before {
	content: "";
	display: block;
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	background: url(../img/background.jpg) center / cover;
	︙

パララックス効果のための指定は、img要素で表示するタイプのとほとんど同じですけれど、画面めいっぱい表示background-size: coverでできているので、transformの指定は、translateZ()scale()の調整だけでよいですね;)

	︙
	transform-origin: 50% 100%;
	transform: translateZ(-50px) scale(1.26);
}

Safari、Firefox、IEで表現できるパララックス

SafariやFirefox、IE/Edgeでは、perspectiveプロパティを指定した直接の子要素のみ、奥行きが適用されるようです。
そのため、今回のように、#wrapper要素にperspectiveプロパティを指定して、その子要素のheader要素の中の、figure要素の中の、img要素に指定した奥行きは、表現されません…¦(

下記サンプルのように、#wrapper要素の直接の子要素であるheader要素自体を奥に移動してのパララックス効果は表現できました。

※IE/Edgeではスムーズにスライドしませんが、奥行きは適用されてる様子が伺えます…。

Safari、Firefox、IEでもChromeと同じ感じにパララックスする

HTMLを以下のように書き換えれば、Chromeと同じ感じのパララックス効果をつけれそうです。figure要素をheader要素から出して、スクロールコンテナである#wrapper要素の直下に移動してみました。

<header>
	<h1>Halfscreen Photo Header</h1>
</header>
<figure>
	<img src="img/background.jpg" alt="" width="1024" height="768">
	<figcaption class="caption">license</figcaption>
</figure>

CSSもそれに合わせて修正します。
タイトル自体(h1要素)には奥行きが適用されないので、タイトルを奥へ移動するには、header要素ごと移動します。
figure要素をheader要素の外に出したため、figure要素の高さはheader要素と同じく50vhに指定。そして、奥へ移動するのはimg要素ではなく、figure要素です。

header {
	︙
	height: 50vh;
	transform-origin: 50% 100%;
	transform: translateZ(-100px) scale(1.5);
}
figure {
	︙
	height: 50vh;
	margin: 0;
	transform-origin: 50% 100%;
	transform: translateZ(-50px) scale(1.26);
}

Safariだけ、ページタイトルが表示されないですね…。
ここでは、header要素にtranslateZ(-100px)、figure要素にtranslateZ(-50px)しているため、header要素の方が奥にあるということで、figure要素の裏に隠れちゃってるみたいです。z-indexプロパティも効かないです。
たしかに、物理的に奥にあるのだから、こちらの方が自然なのだけれど…

Safariでできるパララックス効果

そんなわけで、Safariでもきちんと表示されるように、物理的に自然なカタチで、画像が一番奥、タイトルを画像の手前に配置するようにしました。

header {
	︙
	transform: translateZ(-50px) scale(1.25);
}
figure {
	︙
	transform: translateZ(-100px) scale(1.51);
}