パフォーマンスに優れたパララックス

好まれも悪くも、パララックスは定着しつつあります。上手に使うと、 ウェブアプリに深みと繊細さを加えます。しかし問題は パフォーマンスの視差を損なうのは大変なことです。この記事では パフォーマンスと、それと同じくらい重要なこと サポートしています。

パララックスのイラスト。

要約

  • 視差アニメーションの作成にスクロール イベントや background-position を使用しないでください。
  • CSS の 3D 変換を使用して、より正確な視差効果を作成します。
  • Mobile Safari の場合は position: sticky を使用して、パララックス効果が表示されるようにします 反映されます。

ドロップイン ソリューションが必要な場合は、UI 要素のサンプルの GitHub リポジトリにアクセスし、 パララックス ヘルパー JS です。 パララックス スクローラーのライブデモを GitHub リポジトリ。

問題のパララクサー

まず、視差効果を上げる一般的な方法を 2 つ見てみましょう。 特に、AI の目的に適さない理由についてお話しします。

悪い例: スクロール イベントを使用する

視差の重要な要件は、スクロールと結合することです。 ページのスクロール位置、 パララックス要素の 位置が更新されますこれは簡単そうに聞こえますが、 最新のブラウザには、非同期に動作する機能が備わっています。これは、 イベントをスクロールできますほとんどのブラウザでは、スクロール イベントが 「ベスト エフォート」すべてのフレームで配信される保証はなく、 スクロール アニメーションです。

この重要な情報は、なぜ失敗を スクロール イベントに基づいて要素を移動する JavaScript ベースのソリューション: JavaScript では、視差が視差と同じになるとは限りません。 ページのスクロール位置。古いバージョンの Mobile Safari では、スクロール イベントは スクロールの最後に実際に配信されるため、 JavaScript ベースのスクロール効果。最近のバージョンでは、スクロール イベントが配信されます ただし、Chrome と同様に「ベスト エフォート」方式です。あります。もし メインスレッドが他の処理でビジー状態の場合、スクロール イベントは配信されません。 視差効果は失われます

悪い例: background-position を更新しています

避けたいもう一つの状況は、すべてのフレームでペイントすることです。多数のソリューション background-position を変更して視差効果を作成してみます。 ページの該当部分がスクロール時にブラウザによって再描画され、 アニメーションが著しくジャンクするほどのコストがかかる可能性があります。

視差効果を実現したいのであれば 加速プロパティとして適用できます 不透明度など)があり、スクロール イベントに依存しません。

3D の CSS

Scott KellumKeith Clark はどちらも、 CSS 3D を使用して視差動作を実現するなど、 そして、彼らが実質的に使用する手法は次のとおりです。

  • overflow-y: scroll でスクロールするように包含要素を設定する(おそらく overflow-x: hidden)。
  • 同じ要素に、perspective 値と perspective-origin 関数を適用します。 top left または 0 0 に設定。
  • その要素の子に対して、Z で平行移動を適用してから縮小する 画面上でのサイズに影響を与えずに視差効果を 発揮させることができます

このアプローチの CSS は次のようになります。

.container {
  width: 100%;
  height: 100%;
  overflow-x: hidden;
  overflow-y: scroll;
  perspective: 1px;
  perspective-origin: 0 0;
}

.parallax-child {
  transform-origin: 0 0;
  transform: translateZ(-2px) scale(3);
}

これは、次のような HTML のスニペットを前提としています。

<div class="container">
    <div class="parallax-child"></div>
</div>

視点のスケールの調整

子要素をプッシュバックすると、子要素に対する割合が 評価しますスケールアップの必要な量を計算し、 式: (視点 - 距離) / 視点最も可能性が高いのは 作成したサイズで表示されても 視差効果が見づらい場合は そのままにするのではなく、この方法でスケールアップする必要があります。

上記のコードの場合、視点は 1pxparallax-child の Z 距離は -2px です。つまり、この要素は 3x にスケールアップされます。ここには、コードに挿入された値が表示されます。 scale(3)

translateZ 値が適用されていないコンテンツについては、次のことができます。 ゼロに置換しますつまり、尺度は (視点 - 0) / 、つまり値が 1 になります。つまり、 できます。とても便利です。

このアプローチの仕組み

今回はこれを使用するので、なぜこれが機能するのかを明確にすることが重要です 説明します。スクロールは実質的に変換です。そのため、 accelerated;ほとんどの場合、GPU でレイヤを移動します。新しい 一般的なスクロールは、遠近感やスクロールという概念がない スクロール要素とその子要素を比較するときに、1 対 1 で発生します。 要素を 300px だけ下にスクロールすると、その子は上に変換されます。 同じ金額(300px)で差し引かれます。

ただし、スクロール要素に視点値を適用すると、混乱が生じます このプロセスに伴うスクロール変換を支える行列を変更します。 これで、300 ピクセルのスクロールで、子が 150 ピクセルしか移動しないようになりました。 選択した perspectivetranslateZ の値。要素に translateZ の値が 0 の場合、1:1(以前と同様)でスクロールされますが、子 視点原点から Z 方向に押し出されると、異なる位置でスクロールされます。 率です。最終的な結果: パララックス モーション。そして、非常に重要な点として、これは ブラウザ内部のスクロール機構の一部に自動的に 切り替わります。つまり、 scroll イベントをリッスンしたり、background-position を変更したりする必要はありません。

薬に包まれたハエ: モバイル サファリ

すべての効果には注意点があります。変換で重要な点の一つは、 子要素の 3D 効果が保持されます。変数に 視点を持つ要素とその視差のある子の間の階層構造 3D 視点は「平坦化」され、効果が失われます。

<div class="container">
    <div class="parallax-container">
    <div class="parallax-child"></div>
    </div>
</div>

上記の HTML では、.parallax-container は新しく、実質的には perspective 値をフラット化すると、視差効果が失われます。ソリューション ほとんどの場合は、次のように transform-style: preserve-3d を追加します。 要素に追加され、3D 効果(視点など)が伝播していきます。 ツリーの上位で適用されます。

.parallax-container {
  transform-style: preserve-3d;
}

しかし、Mobile Safari の場合は、もう少し複雑です。 コンテナ要素への overflow-y: scroll の適用は技術的には機能しますが、 スクロール要素をフリングするためのコストがかかります。解決策は、 -webkit-overflow-scrolling: touch。ただし、perspective もフラット化されます。 視差が生じることもないです

段階的な機能強化という観点では、これは あります。あらゆる状況で視差を取れない場合でもアプリは動作しますが、 回避策を見つけられると助かります

position: sticky が助けになります!

実際、position: sticky 形式のヘルプがあります。これは、 要素を「固定」できるようにする移動することもできます。 表示されます。他のほとんどのモデルと同様に、仕様はかなり大きいですが、 次の場所にある小さな宝石:

一見すると大したことではないように思えるかもしれませんが、 要素のスティッキネスについて、 計算: 「オフセットは最も近い祖先を参照して計算されます スクロール ボックスを使用する」をご覧ください。つまり、スティッキー要素を移動する距離です。 (別の要素またはビューポートにアタッチされているように見えるようにするため)は、 他の変換が適用されるであって、適用後では計算されません。つまり 先ほどのスクロールの例と同様に、オフセットが計算され 300 ピクセルで、視点(またはその他の変換)を使用する新たな機会がある 300px のオフセット値を 固定表示に適用する前に あります。

視差要素に position: -webkit-sticky を適用すると、次のようになります。 実質的に「逆方向」に-webkit-overflow-scrolling: touch のフラット化効果これにより、視差要素が最も近い スクロール ボックス(この場合は .container)を持つ祖先が表示されます。その後、 以前と同様に、.parallax-containerperspective 値を適用します。 計算されたスクロール オフセットを変更し、視差効果を作成します。

<div class="container">
    <div class="parallax-container">
    <div class="parallax-child"></div>
    </div>
</div>
.container {
  overflow-y: scroll;
  -webkit-overflow-scrolling: touch;
}

.parallax-container {
  perspective: 1px;
}

.parallax-child {
  position: -webkit-sticky;
  top: 0px;
  transform: translate(-2px) scale(3);
}

これにより Mobile Safari の視差効果が復元されました。これはすべてすばらしいニュースです。 。

スティッキー ポジショニングの注意点

違いはありますが、position: sticky によって変更されます。 視差メカニクスです固定配置では、要素を スクロール コンテナが対象になりますが、固定されていないバージョンには調整されません。つまり、 固定された視差は、次の視差のない視差の逆になります。

  • position: sticky では、要素が z=0 に近づくほど z=0 に近づくほど小さくなります ムーブ。
  • position: stickyない場合は、要素が z=0 に近づくほど大きいほど 動きます。

少し抽象的な印象がある方は、Robert Flack のデモをご覧ください。 スティッキーがある場合とない場合で要素の動作がどのように異なるかを示す 考えていますこの違いを確認するには、Chrome Canary(バージョン 56)が必要です。 または Safari を使用してください。

パララックス視点のスクリーンショット

Robert Flack によるデモ position: sticky は視差スクロールに影響します。

さまざまなバグと回避策

ですが 他の機能と同様に ダメージやダメージが残りやすいため 平滑化:

  • スティッキー サポートに一貫性がない。サポートは、 Chrome、Edge は完全にサポートされておらず、Firefox ではスティッキーが視点変換と組み合わされると描画バグが発生します。このような position: sticky-webkit- プレフィックス付きバージョンなど)を必要に応じて使用(Mobile Safari の場合) のみです。
  • 「効果が上がる」わけではない使用できます。Edge は、Deployment の 通常は問題ありませんが、この場合は例外を スクロール中に視点の変化を検出できないようにします。この問題を解決するには これは固定位置の要素です。これは Edge を OS 以外のスクロール方法に切り替えるように見えるためです。 視点の変化を確実に考慮する必要があります
  • 「ページのコンテンツが巨大になってしまいました。」多くのブラウザが コンテンツの大きさを決める際の参考になりますが 残念ながら Chrome と Safari では 視点を考慮しないでください。まず たとえばある要素に 3 倍のスケールが適用されると スクロールバーなどを表示できます。要素が perspective が適用されました。この問題は次の方法で回避できます。 (transform-origin: bottom right を使用して)要素をスケーリングします。これは、サイズが大きすぎる要素が拡大し、 「除外地域」スクロール可能な領域の左側(通常は左上)に配置されます。スクロール可能 除外地域のコンテンツを表示またはスクロールすることはできません。

まとめ

パララックスは、よく考えて使用すると楽しい効果になります。ご覧のとおり、この画像には スクロールと連動し、ブラウザをまたいだ高パフォーマンスで実装できます。 数学的な計算処理が少し必要になります。 用意されているため、小さなヘルパー ライブラリを とサンプル(UI 要素のサンプルに関する GitHub リポジトリにあります)をご覧ください。

ぜひプレイして、ご意見をお寄せください。