前回の記事で、円形の方向に回転する非常にクールな小さなスライダー (または、好みに応じて「カルーセル」) を作成しました。 今回は、ポラロイド画像を重ねてめくるようなものを作っていきます。
かっこいいでしょ? 解明すべきことがたくさんあるので、まだコードを見ないでください。 私に参加しませんか?
CSSスライダーシリーズ
基本的なセットアップ
このスライダーの HTML と CSS のほとんどは、前回作成した円形のものと似ています。 実際、まったく同じマークアップを使用しています。
これは、親を設定する基本的な CSS です。 .gallery
すべての画像が互いに積み重ねられているグリッドとしてのコンテナー:
.gallery {
display: grid;
width: 220px; /* controls the size */
}
.gallery > img {
grid-area: 1 / 1;
width: 100%;
aspect-ratio: 1;
object-fit: cover;
border: 10px solid #f2f2f2;
box-shadow: 0 0 4px #0007;
}
これまでのところ複雑なことは何もありません。 画像のポラロイド風のスタイルでも、私が使用しているのは一部です border
および box-shadow
. もっと上手にできるかもしれないので、これらの装飾的なスタイルで自由に遊んでみてください! 最も難しい部分であるアニメーションに焦点を当てます。
トリックは何ですか?
このスライダーのロジックは、画像の積み重ね順序に依存しています。 z-index
. すべての画像は同じで始まります z-index
値(2
) スタックの一番上に論理的に最後の画像を作成します。
最後の画像を右にスライドさせて、スタック内の次の画像を表示します。 次に、画像を減らします z-index
価値がある場合は、それをスライドしてデッキに戻します。 そしてそれ以来 z-index
値が残りの画像よりも小さい場合、スタック内の最後の画像になります。
これは、トリックを示す簡素化されたデモです。 画像にカーソルを合わせると、アニメーションがアクティブになります。
ここで、すべての画像に同じトリックを適用したと想像してください。 を使用している場合のパターンは次のとおりです。 :nth-child()
画像を区別する疑似セレクター:
- 最後の画像をスライドします(
N
)。 次の画像が表示されます (N - 1
). - 次の画像をスライドします(
N - 1
)。 次の画像が表示されます (N - 2
) - 次の画像をスライドします(
N - 2
)。 次の画像が表示されます (N - 3
) - (最初の画像に到達するまで同じプロセスを続けます)
- 最初の画像をスライドします(
1
)。 最後の画像(N
) が再び表示されます。
それが私たちの無限スライダーです!
アニメーションの分析
前回の記事を覚えていれば、私はアニメーションを XNUMX つだけ定義し、各イメージを制御するために遅延を使用して再生しました。 ここでも同じことを行います。 まず、アニメーションのタイムラインを視覚化してみましょう。 XNUMX つの画像から始めて、後で任意の数に一般化します (N
) 画像の。
アニメーションは、「右にスライド」、「左にスライド」、「動かない」の XNUMX つの部分に分かれています。 各画像間の遅延は簡単に識別できます。 最初の画像が 0s
、期間は等しい 6s
、その後、XNUMX番目のものはで始まります -2s
そして三つ目は -4s
.
.gallery > img:nth-child(2) { animation-delay: -2s; } /* -1 * 6s / 3 */
.gallery > img:nth-child(3) { animation-delay: -4s; } /* -2 * 6s / 3 */
また、「動かない」部分がアニメーション全体の XNUMX 分の XNUMX を占めていることもわかります (2*100%/3
) 一方、「右にスライド」と「左にスライド」の部分は合わせて XNUMX 分の XNUMX を占めます。 100%/6
アニメーション全体の。
アニメーション キーフレームは次のように記述できます。
@keyframes slide {
0% { transform: translateX(0%); }
16.67% { transform: translateX(120%); }
33.34% { transform: translateX(0%); }
100% { transform: translateX(0%); }
}
それ 120%
任意の値です。 よりも大きなものが必要でした 100%
. 画像は、残りの画像から右にスライドする必要があります。 そのためには、少なくとも移動する必要があります 100%
そのサイズの。 だから私は行った 120%
—余分なスペースを得るために。
今、私たちは考慮する必要があります z-index
. 画像を更新する必要があることを忘れないでください z-index
値 After 山の右側にスライドし、 スライドさせて山の一番下に戻します。
@keyframes slide {
0% { transform: translateX(0%); z-index: 2; }
16.66% { transform: translateX(120%); z-index: 2; }
16.67% { transform: translateX(120%); z-index: 1; } /* we update the z-order here */
33.34% { transform: translateX(0%); z-index: 1; }
100% { transform: translateX(0% ); z-index: 1; }
}
XNUMX つの状態を定義する代わりに、 16.67%
(100%/6
) タイムラインのポイントでは、ほぼ同じポイントで XNUMX つの状態を定義しています (16.66%
および 16.67%
) どこ z-index
画像をスライドしてデッキに戻す前に、値が減少します。
これらをすべてまとめると、次のようになります。
うーん、スライド部分は問題ないようですが、重ね順がバラバラ! 一番上の画像が後ろに移動しているのでアニメーションはうまく始まります...しかし、後続の画像はそれに追随しません。 お気付きのように、シーケンスの XNUMX 番目の画像は、次の画像がその上で点滅する前に、スタックの一番上に戻ります。
我々は密接にフォローする必要があります z-index
変化します。 最初に、持っているすべての画像は z-index: 2
. つまり、積み上げ順序は…
Our eyes 👀 --> 3rd (2) | 2nd (2) | 1st (2)
XNUMX 番目の画像をスライドして更新します z-index
この注文を取得するには:
Our eyes 👀 --> 2nd (2) | 1st (2) | 3rd (1)
XNUMX 番目のものでも同じことを行います。
Our eyes 👀 --> 1st (2) | 3rd (1) | 2nd (1)
…そして最初のもの:
Our eyes 👀 --> 3rd (1) | 2nd (1) | 1st (1)
私たちはそれを行い、すべてがうまくいっているようです。 しかし、実際にはそうではありません。 最初の画像が後ろに移動すると、XNUMX 番目の画像が別の反復を開始します。 z-index: 2
:
Our eyes 👀 --> 3rd (2) | 2nd (1) | 1st (1)
そのため、実際にはすべての画像が z-index: 2
まったく! 画像が動いていない場合 (つまり、アニメーションの「動かない」部分)、 z-index
is 1
. XNUMX 番目の画像をスライドして更新すると、 z-index
からの値 2
〜へ 1
、それは上に残ります! すべての画像が同じ場合 z-index
、ソース順序の最後の画像 (この場合は XNUMX 番目の画像) がスタックの一番上にあります。 XNUMX 番目の画像をスライドすると、次のようになります。
Our eyes 👀 --> 3rd (1) | 2nd (1) | 1st (1)
XNUMX 番目の画像はまだ一番上にあり、その直後に XNUMX 番目の画像のアニメーションが再開したときに XNUMX 番目の画像を一番上に移動します。 z-index: 2
:
Our eyes 👀 --> 2nd (2) | 3rd (1) | 1st (1)
スライドすると、次のようになります。
Our eyes 👀 --> 3rd (1) | 2nd (1) | 1st (1)
次に、最初の画像が一番上にジャンプします。
Our eyes 👀 --> 1st(2) | 3rd (1) | 2nd (1)
わかりました、私は迷っています。 それでは、すべてのロジックが間違っていますか?
私は知っています、それは混乱しています。 しかし、私たちの論理は完全に間違っているわけではありません。 アニメーションを少し修正するだけで、すべてが思いどおりに機能します。 トリックは、正しくリセットすることです z-index
.
XNUMX 番目の画像が一番上にある状況を考えてみましょう。
Our eyes 👀 --> 3rd (2) | 2nd (1) | 1st (1)
XNUMX番目の画像をスライドさせて変更することがわかりました z-index
それを上に保ちます。 私たちがする必要があるのは、 z-index
XNUMX番目の画像の。 したがって、XNUMX 番目の画像をデッキからスライドさせる前に、 z-index
XNUMX番目の画像の 2
.
つまり、リセットします z-index
アニメーションが終了する前の XNUMX 番目のイメージの。
緑のプラス記号は増加を表します z-index
〜へ 2
、赤いマイナス記号は z-index: 1
. XNUMX番目の画像はから始まります z-index: 2
、次にそれを更新します 1
デッキから滑り落ちるとき。 しかし、最初の画像がデッキから滑り落ちる前に、 z-index
XNUMX 番目の画像の 2
. これにより、両方の画像が同じであることを確認します z-index
、しかしそれでも、XNUMX 番目のものは DOM で後で表示されるため、一番上に残ります。 しかし、XNUMX番目の画像スライドの後、 z-index
更新されると一番下に移動します。
アニメーションの XNUMX 分の XNUMX で、それに応じてキーフレームを更新しましょう。
@keyframes slide {
0% { transform: translateX(0%); z-index: 2; }
16.66% { transform: translateX(120%); z-index: 2; }
16.67% { transform: translateX(120%); z-index: 1; } /* we update the z-order here */
33.34% { transform: translateX(0%); z-index: 1; }
66.33% { transform: translateX(0%); z-index: 1; }
66.34% { transform: translateX(0%); z-index: 2; } /* and also here */
100% { transform: translateX(0%); z-index: 2; }
}
少し良くなったが、まだではない 非常に そこの。 別の問題があります…
いや、これは終わらない!
この問題は最後の画像が関係している場合にのみ発生するため、キーフレームを再度変更するつもりはありません。 最後の画像を修正するための「特別な」キーフレーム アニメーションを作成できます。
最初の画像が一番上にある場合、次のような状況になります。
Our eyes 👀 --> 1st (2) | 3rd (1) | 2nd (1)
以前に行った調整を考慮すると、最初の画像がスライドする前に XNUMX 番目の画像が一番上にジャンプします。 この状況でのみ発生するのは、最初の画像の後に移動する次の画像が last DOM で上位の画像。 残りの画像は問題ありません。 N
をタップし、その後、 N - 1
、それから行きます 3
〜へ 2
, 2
〜へ 1
…しかし、私たちはから行きます 1
〜へ N
.
それを避けるために、最後の画像に次のキーフレームを使用します。
@keyframes slide-last {
0% { transform: translateX(0%); z-index: 2;}
16.66% { transform: translateX(120%); z-index: 2; }
16.67% { transform: translateX(120%); z-index: 1; } /* we update the z-order here */
33.34% { transform: translateX(0%); z-index: 1; }
83.33% { transform: translateX(0%); z-index: 1; }
83.34% { transform: translateX(0%); z-index: 2; } /* and also here */
100% { transform: translateX(0%); z-index: 2; }
}
リセットします z-index
最初の画像がパイルから外れたときの値は、アニメーションによって (5 分の 6 ではなく) XNUMX/XNUMX になります。 したがって、ジャンプは見られません。
多田! 無限スライダーが完成しました! 最終的なコードは次のとおりです。
.gallery > img {
animation: slide 6s infinite;
}
.gallery > img:last-child {
animation-name: slide-last;
}
.gallery > img:nth-child(2) { animation-delay: -2s; }
.gallery > img:nth-child(3) { animation-delay: -4s; }
@keyframes slide {
0% { transform: translateX(0%); z-index: 2; }
16.66% { transform: translateX(120%); z-index: 2; }
16.67% { transform: translateX(120%); z-index: 1; }
33.34% { transform: translateX(0%); z-index: 1; }
66.33% { transform: translateX(0%); z-index: 1; }
66.34% { transform: translateX(0%); z-index: 2; }
100% { transform: translateX(0%); z-index: 2; }
}
@keyframes slide-last {
0% { transform: translateX(0%); z-index: 2; }
16.66% { transform: translateX(120%); z-index: 2; }
16.67% { transform: translateX(120%); z-index: 1; }
33.34% { transform: translateX(0%); z-index: 1; }
83.33% { transform: translateX(0%); z-index: 1; }
83.34% { transform: translateX(0%); z-index: 2; }
100% { transform: translateX(0%); z-index: 2; }
}
任意の数の画像をサポート
アニメーションが XNUMX つの画像に対して機能するようになったので、任意の数に対して機能するようにしましょう (N
) 画像の。 しかし、最初に、冗長性を避けるためにアニメーションを分割することで、作業を少し最適化できます。
.gallery > img {
z-index: 2;
animation:
slide 6s infinite,
z-order 6s infinite steps(1);
}
.gallery > img:last-child {
animation-name: slide, z-order-last;
}
.gallery > img:nth-child(2) { animation-delay: -2s; }
.gallery > img:nth-child(3) { animation-delay: -4s; }
@keyframes slide {
16.67% { transform: translateX(120%); }
33.33% { transform: translateX(0%); }
}
@keyframes z-order {
16.67%,
33.33% { z-index: 1; }
66.33% { z-index: 2; }
}
@keyframes z-order-last {
16.67%,
33.33% { z-index: 1; }
83.33% { z-index: 2; }
}
コードが大幅に減りました! スライド部分のアニメーションとスライド部分のアニメーションを作成します。 z-index
更新します。 使用することに注意してください steps(1)
z-index
アニメーション。 急に変えたいから z-index
滑らかな動きが必要なスライド アニメーションとは異なります。
コードが読みやすく保守しやすくなったので、任意の数の画像をサポートする方法を理解するためのより良いビューが得られました。 アニメーションの遅延とキーフレームのパーセンテージを更新する必要があります。 前回の記事で作成したのとまったく同じループを使用して、円形スライダーで複数の画像をサポートできるため、遅延は簡単です。
@for $i from 2 to ($n + 1) {
.gallery > img:nth-child(#{$i}) {
animation-delay: calc(#{(1 - $i)/$n}*6s);
}
}
これは、バニラの CSS から Sass に移行していることを意味します。 次に、タイムラインがどのようにスケールするかを想像する必要があります。 N
画像。 アニメーションは XNUMX つのフェーズで発生することを忘れないでください。
「右にスライド」と「左にスライド」の後、残りの画像がシーケンスを通過するまで、画像をそのままにしておく必要があります。 そのため、「動かない」部分は (N - 1
)「右にスライド」および「左にスライド」として。 そして、XNUMX回の繰り返しで、 N
画像がスライドします。 したがって、「右にスライド」と「左にスライド」はどちらも 100%/N
アニメーション タイムライン全体の画像は山から離れてスライドします (100%/N)/2
でスライドして戻ります 100%/N
.
これを変更できます。
@keyframes slide {
16.67% { transform: translateX(120%); }
33.33% { transform: translateX(0%); }
}
…これに:
@keyframes slide {
#{50/$n}% { transform: translateX(120%); }
#{100/$n}% { transform: translateX(0%); }
}
交換すれば N
3
、 我々が得る 16.67%
および 33.33%
あるとき 3
スタック内の画像。 これは、次のスタック順序と同じロジックです。
@keyframes z-order {
#{50/$n}%,
#{100/$n}% { z-index: 1; }
66.33% { z-index: 2; }
}
まだ更新する必要があります 66.33%
点。 それは、画像がリセットされる場所であるはずです z-index
アニメ終了前。 同時に、次の画像がスライドし始めます。 スライド部分がかかるので 100%/N
、リセットはで発生する必要があります 100% - 100%/N
:
@keyframes z-order {
#{50/$n}%,
#{100/$n}% { z-index: 1; }
#{100 - 100/$n}% { z-index: 2; }
}
しかし、私たちのために z-order-last
アニメーションが機能するようにするには、シーケンスの少し後で行う必要があります。 最後の画像に対して行った修正を覚えていますか? をリセットする z-index
値は、最初の画像が滑り始めたときではなく、山から出たときに発生する必要があります。 ここのキーフレームでも同じ理由を使用できます。
@keyframes z-order-last {
#{50/$n}%,
#{100/$n}% { z-index: 1; }
#{100 - 50/$n}% { z-index: 2; }
}
完了です! XNUMX つの画像を使用すると、次のようになります。
回転のタッチを追加して、物事を少し派手にすることができます。
私がしたのは追加だけです rotate(var(--r))
transform
財産。 ループの中で、 --r
はランダムな角度で定義されます:
@for $i from 1 to ($n + 1) {
.gallery > img:nth-child(#{$i}) {
--r: #{(-20 + random(40))*1deg}; /* a random angle between -20deg and 20deg */
}
}
一部の画像がスタックの後ろにジャンプするのを見ることができるため、ローテーションによって小さな不具合が発生しますが、大した問題ではありません。
包み込む
すべて z-index
仕事は大きなバランスをとる行為でしたよね? この演習の前にスタックの順序がどのように機能するかわからなかった場合は、おそらく今の方がはるかに優れたアイデアを持っているでしょう! 説明がわかりにくい場合は、記事をもう一度読んで、もう一度お読みになることを強くお勧めします。 鉛筆と紙で物事をマッピングする. トリックをよりよく理解するために、さまざまな数の画像を使用してアニメーションの各ステップを説明してみてください。
前回は、いくつかのジオメトリ トリックを使用して、完全なシーケンスの後に回転して最初の画像に戻る円形のスライダーを作成しました。 今回は、同様のトリックを使用して達成しました z-index
. どちらの場合も、連続したアニメーションをシミュレートするために画像を複製したり、計算を支援するために JavaScript を使用したりしませんでした。
次回は3Dスライダーを作っていきます。 乞うご期待!