参考サイトのように Slick の current-slide
を使ってキャプションをアニメーション表示させようとしました。しかし、初回ロード時はアニメーションが反映されず、突如表示されてしまいます。具体的には
- 画面表示 (初回ロード時、リロード時) のスライド1枚目のキャプションのみアニメーションが発火しない
- 2週目以降はスライド1枚目のキャプションもアニメーションが発火する
という状態です。そこで、初回ロード時にもアニメーションさせる方法を模索しました。
コード (現象確認)
まずは現象を確認するためのコードを。
html
<ul class="slider defaultSlider">
<li class="slider_first">
<p class="caption">1枚目</p>
<div class="slider_imgWrapper">
<img src="https://placehold.jp/24/ff9100/db0303/1200x800.jpg">
</div>
</li>
<li class="slider_second">
<p class="caption">2枚目</p>
<div class="slider_imgWrapper">
<img src="https://placehold.jp/24/ff9100/db0303/1200x800.jpg">
</div>
</li>
<li class="slider_last">
<p class="caption">3枚目</p>
<div class="slider_imgWrapper">
<img src="https://placehold.jp/24/ff9100/db0303/1200x800.jpg">
</div>
</li>
</ul>
例えばこんな Slick のカルーセルを用意します。
JavaScript
$(() => {
//slick
const $slider = $('.slider');
$slider.slick({
autoplay: true,
autoplaySpeed: 5000
});
});
css(Scss)
@charset "utf-8";
//slick
.slider {
overflow: hidden;
position: relative;
height: calc(100vw / 1200px * 800px);
max-height: 80vh;
z-index: 1;
li {
img {
width: 100%;
}
}
}
$transition-speed: .3s;
$transition-delay: .5s;
.defaultSlider .slick-slide .caption {
opacity: 0;
transition: opacity $transition-speed ease;
}
.defaultSlider .slick-current .caption {
opacity: 1;
transition-delay: $transition-delay;
}
これで動作を確認すると、初回ロード時やリロード時といった最初の表示のときのみ transition
アニメーション が発火せず、ただキャプションが表示されるだけになってしまいます。
そこで以下のように改修。具体的には、初回ロード時等の一度限りで @keyframes
アニメーション を用いて transition
アニメーション を再現することにしました。
コード (改修後)
HTML と JavaScript はそのまま。
css(Scss)
@charset "utf-8";
//slick
.slider {
overflow: hidden;
position: relative;
height: calc(100vw / 1200px * 800px);
max-height: 80vh;
z-index: 1;
li {
img {
width: 100%;
}
}
}
$transition-speed: .3s;
$transition-delay: .5s;
/* 初回ロード時のみ Slick の transition アニメーションが効かないため、独自にcss @keyframes で同じ transition アニメーションを指定 */
@keyframes firstLoadFade {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.ingenuitySlider .slider_first .caption {
opacity: 0;
animation: firstLoadFade $transition-speed ease $transition-delay 1 normal none running;
}
.ingenuitySlider .slick-slide .caption {
opacity: 0;
transition: opacity $transition-speed ease, visibility $transition-speed ease;
}
.ingenuitySlider .slick-current .caption {
opacity: 1;
transition-delay: $transition-delay;
}
肝は2点。
@keyframes
アニメーション のプロパティ:- 1回限りなので
1 normal none running
指定
- 1回限りなので
transition
アニメーション で指定するプロパティ:- アニメーション対象を最小限にするために
opacity
,visibility
を指定
- アニメーション対象を最小限にするために
余談
改修に至るまでいくつか試行錯誤した結果をついでに書き記しておきます。
- JavaScript側で処理:
- Slick のイベントの
init
を使おうと思ったのですが、上手く反応しなかったので没- 最初
init
イベント が発火している様子がなく、理由を探ったらイベントへのバインド ($slider.on('init', function () { /* 処理 */ });
) は$slider.slick({ /* 処理 */ });
より前に行っていないとダメなようでした - その後、「初回だけ」の処理のために
init
で色々処理をして、それが次のスライドに切り替わる(少なくともカルーセルが1週するまでの間)にはフックやスタイルを外さなければならないため、チェーンメソッドが長くなりそうな雰囲気がしたため没にafterChange
は「前のスライド」を引数で持ってくることはできなさそうだった、というのも没になった点
- 最初
- Slick のイベントの
- css側で処理:
slick-initialized
クラス でのプロパティ指定は特に効果なしtransition
アニメーション で指定するプロパティについて、最初はall
を指定していましたが、font-size
等関係ない部分もアニメーションが効いてしまうため、最小限の指定となるようにopacity
のみを指定- しかし、
opacity
のみでは@keyframes
アニメーション が動作せず、最初の状況と同じ状態になってしまいました。調査した結果、visibility
も追加することで意図した挙動になりました