参考サイトのように 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も追加することで意図した挙動になりました