Closed3

【スワイパー】画像ズームインアニメーション

kohei nemawarikohei nemawari

【Swiper 使用手順】

◎参考URL
https://skillhub.jp/blogs/371


公式のここを見る
◎レイアウトデモ
https://swiperjs.com/demos


参考URL:https://lightning-g3.hp1.work/full-screen-zoom-in-fade-slider/
◆まとめ◆
JavaScriptは、スライドが切り替わる前後のズームインの動きを調整し、スムーズな動きを作り出します。

CSS は、フェードイン・アウトのタイミングとズームインの速度を調整し、画像が自然にズームイン・アウトするように制御しています。

ドンっと切り替わる問題の解消:
前のスライドのアニメーションをリセットせず、ズームインを継続させることで、スライド切り替え時に画像が急に縮小する現象を防ぎました。
なぜスライド切り替え時に画像が「ドン」となるのか
原因:
アニメーションのリセット: スライドが切り替わる際、以前のコードでは前のスライドのアニメーションをリセットしていました。これにより、次のスライドに移行したとき、画像のスケールが初期状態に戻ってしまい、画面上で画像が急に縮小されるように見えていました。
対処法:
アニメーションをリセットしない: JavaScriptのslideChangeTransitionStartイベントで、前のスライドのアニメーションをリセットする処理を削除しました。これにより、ズームインアニメーションが継続し、スライドが切り替わっても画像が急に縮小することなく、スムーズに表示されます。

ーーーーーーーーーーーーーーーーー

画角の統一:
全ての画像の初期スケールをscale(1)に統一し、ズームインの範囲もscale(1)からscale(1.2)に統一することで、ズームイン開始前と完了後の画角の差異を解消しました。
スムーズな切り替えの実現:
アニメーション時間を12秒、スライドの切り替えを4秒に設定し、ズームインアニメーションがスライドをまたいで継続するようにしました。
アニメーションの開始タイミングを調整し、スライドが切り替わってすぐにズームインが始まるようにしました。

問題:
画角の不一致: 画像の初期スケールとズームイン後のスケールが異なるため、ズームインの開始時と終了時で画角が変わり、違和感が生じていました。
対処法:
画像の初期スケールを統一: CSSで全ての画像にtransform: scale(1);を設定し、画像の初期状態を等倍(スケール1)に統一しました。
ズームインの範囲を明確に設定:
@keyframes zoom-inで、アニメーションの開始と終了のスケールをscale(1)からscale(1.2)に設定しました。これにより、全ての画像が同じ範囲でズームインし、画角の不一致が解消されました。
ーーーーーーーーーーーーーーーーーーーーーーー
3. 理想URLのようにスムーズに切り替わるように調整した箇所
問題:
アニメーションのタイミングのずれ: スライドが切り替わった後、アニメーションが始まるまでに一呼吸置くような間があり、スムーズな切り替えになっていませんでした。
対処法:
アニメーションの開始タイミングを調整:
・JavaScriptのslideChangeTransitionEndイベントで、新しいスライドのアニメーションを即座に開始するようにしました。
・前のスライドのアニメーションをリセットせず、ズームインを継続させることで、スライド切り替え時の違和感を解消しました。

アニメーション時間の調整:
アニメーションの時間を12秒、スライドの切り替えを4秒に設定しました。これにより、ズームインアニメーションがスライドの切り替えをまたいで継続し、全体として滑らかな動きを実現しました。

ベースHTML
構造説明:

  1. hero-section: 全体を包むセクション。
  2. wrapper: コンテンツを包むラッパー。
  3. hero-content: ロゴやテキストを含む部分。
  4. swiper-container-4: スライダーのコンテナ。
  5. swiper-slide: 各スライドを表す。
 <!-- ヒーローセクション -->
<section class="hero-section">
    <div class="wrapper">
        <div class="hero-content">
            <div class="hero-inner-content">
                <img class="hero-logo" src="https://recure.life/wp-content/uploads/2022/08/gen_logo-1.png">
            </div>
            <div class="hero-inner-content">
                <h2>美と健康</h2>
                <p class="left">テキストテキストテキスト</p>
            </div>
        </div>
        <div class="swiper-wrap">
            <div class="swiper-container-4">
                <div class="swiper-wrapper">
                    <div class="swiper-slide">
                        <div class="slide-img">
                            <img src="https://recure.life/wp-content/uploads/2024/09/A7301016.jpg">
                        </div>
                        <div class="slide-text">テスト1</div>
                    </div>
                    <div class="swiper-slide">
                        <div class="slide-img">
                            <img src="https://recure.life/wp-content/uploads/2024/09/A7300539.jpg">
                        </div>
                        <div class="slide-text">テスト2</div>
                    </div>
                </div>
            </div>
        </div>
    </div>
</section>

1. WPで読み込む場合、functions.phpに下記を入れる

function enqueue_swiper_resources() {
    // SwiperのCSSファイルを読み込む
    wp_enqueue_style( 'swiper-css', 'https://unpkg.com/swiper@9/swiper-bundle.min.css', array(), null );
    
    // SwiperのJavaScriptファイルを読み込む
    wp_enqueue_script( 'swiper-js', 'https://unpkg.com/swiper@9/swiper-bundle.min.js', array(), null, true );
    
    // 子テーマのJavaScriptファイルを読み込む
    wp_enqueue_script( 'child-custom-js', get_stylesheet_directory_uri() . '/js/javascript.js', array('swiper-js'), null, true );
}
add_action( 'wp_enqueue_scripts', 'enqueue_swiper_resources' );

ーーーーーーーーーーーーーーーーーーーーーーーーー
2. JSファイルに下記記述を追加
JS説明
slideChangeTransitionStart:スライドが切り替わる前に、ズーム状態をリセットします。
つまり、スライドの画像を元の大きさに戻します。これにより、次のスライドで「急にズームが戻る」という不自然な動きが防げます。

slideChangeTransitionEnd:スライドが切り替わった後に、ズームインを少し遅れて開始します。
0.1秒遅らせてからズームインを開始することで、スライドが切り替わってから自然な形でズームが始まります。

・loop: true: スライダーを無限ループさせる。

・effect: 'fade': スライド切り替え時にフェード効果を適用。

・autoplay:

・delay: 4000: 4秒ごとにスライドを自動的に切り替える。

・disableOnInteraction: false: ユーザーが操作しても自動再生を停止しない。

・speed: 1200: スライドの切り替えに1.2秒かける。

・イベントハンドラon:

・initイベント:
スライダーが初期化されたときに、最初のスライドの画像にズームインアニメーションを適用。
・slideChangeTransitionStartイベント:
ここでは特に処理を行わない。前のスライドのアニメーションをリセットしないため、ズームインが継続する。

・slideChangeTransitionEndイベント:
新しいスライドの画像にズームインアニメーションを再度適用。

let swiperOption = {
    loop: true,
    effect: 'fade',
    autoplay: {
        delay: 4000, // スライドの切り替えは4秒ごと
        disableOnInteraction: false,
    },
    speed: 1200,  // スライド切り替え速度
    pagination: {
        el: '.swiper-pagination',
        clickable: true,
    },
    on: {
        init: function() {
            // 初期スライドのアニメーションを開始
            $('.swiper-slide-active img').css('animation', 'zoom-in 12s linear forwards');
        },
        slideChangeTransitionStart: function() {
            // 前のスライドのアニメーションをリセットせず、ズームインを継続。(!!ドンってなるのここ!!)
        },
        slideChangeTransitionEnd: function() {
            // 新しいスライドのアニメーションを開始
            $('.swiper-slide-active img').css('animation', 'zoom-in 12s linear forwards');
        }
    }
}
new Swiper('.swiper-container-4', swiperOption);

ーーーーーーーーーーーーーーーーーーーーーーーー
3. CSSにてアニメーションを追加
詳細説明:
.swiper-slideと.swiper-slide-activeでスライドのフェード効果を設定。非アクティブなスライドは透明(opacity: 0)、アクティブなスライドは不透明(opacity: 1)。

画像の初期設定:
width: 100%;とheight: 100%;で画像がコンテナ全体を覆うように設定。
object-fit: cover;で画像が縦横比を維持しながらコンテナを埋める。
object-position: center center;で画像の中央を表示。
transform: scale(1);で画像の初期スケールを1に設定。

ズームインアニメーションの適用:
アクティブなスライドの画像に対して、animation: zoom-in 12s linear forwards;を適用。
zoom-inというキーフレームを12秒間かけて実行し、線形(一定速度)でアニメーションを進行。

ズームインのキーフレーム定義:
from(0%)でtransform: scale(1);、to(100%)でtransform: scale(1.2);。
画像がスケール1から1.2へ12秒かけてゆっくり拡大。

非アクティブなスライドの画像のスケールをリセット:
非アクティブなスライドの画像は常にtransform: scale(1);でスケール1を維持。

/* 新ファーストビュー テスト -----------------------*/
.page-id-15048 .wrapper {
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.page-id-15048 .slide {
    max-width: 800px;
    width: 100%;
    height: auto;
}
.page-id-15048 .metaslider img {
    max-width: 700px !important;
    height: 580px !important; 
    object-fit: cover;
    width: 100%;
}
.page-id-15048 .hero-logo {
    max-width: 400px;
}
.hero-content {
    max-width: 400px;
    width: 100%;
}
.hero-inner-content {
    text-align: center;
}
.hero-section .left {
    text-align: left;
}

.swiper-wrap {
    margin: 0 calc(52% - 50vw);
    max-width: 57vw;
    position: relative;
    overflow: hidden;
}

.slide-text {
    position: absolute;
    top: 50%;
    left: 50%;
    font-size: 3vw;
    font-family: serif;
    font-weight: bold;
    text-shadow: 2px 2px 8px #000;
    color: #fff;
    transform: translate(-50%, -50%);
}

/* スライド全体にフェード効果を適用 */
.swiper-slide {
    opacity: 0;
    transition: opacity 1.2s ease-in-out;
}

.swiper-slide-active {
    opacity: 1;
}

* 画像の初期設定を統一 */
.swiper-slide img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center center;
    transform: scale(1);
}

/* アクティブなスライドの画像にズームインアニメーションを適用 */
.swiper-slide-active img {
    animation: zoom-in 12s linear forwards;
}

/* ズームインのキーフレーム */
@keyframes zoom-in {
    0% {
        transform: scale(1.1);
    }
    100% {
        transform: scale(1.2);
    }
}
/* 非アクティブなスライドの画像のスケールをリセット */
.swiper-slide:not(.swiper-slide-active) img {
    transform: scale(1);
}
kohei nemawarikohei nemawari

画像のループ

	<div class="scroll-infinity">
<div class="scroll-infinity__wrap">
  <ul class="scroll-infinity__list scroll-infinity__list--left">
    <li class="scroll-infinity__item"><img src="sample.png" /></li>                        
    <li class="scroll-infinity__item"><img src="sample.png" /></li>
    <li class="scroll-infinity__item"><img src="sample.png" /></li>
    <li class="scroll-infinity__item"><img src="sample.png" /></li>
    <li class="scroll-infinity__item"><img src="sample.png" /></li>
    <li class="scroll-infinity__item"><img src="sample.png" /></li>
  </ul>
  <ul class="scroll-infinity__list scroll-infinity__list--left">
    <li class="scroll-infinity__item"><img src="sample.png" /></li>                        
    <li class="scroll-infinity__item"><img src="sample.png" /></li>
    <li class="scroll-infinity__item"><img src="sample.png" /></li>
    <li class="scroll-infinity__item"><img src="sample.png" /></li>
    <li class="scroll-infinity__item"><img src="sample.png" /></li>
    <li class="scroll-infinity__item"><img src="sample.png" /></li>
  </ul>
</div>
</div>
@keyframes infinity-scroll-left {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-100%);
  }
}

.scroll-infinity__wrap {
  display: flex;
  overflow: hidden;
}

.scroll-infinity__list {
  display: flex;
  list-style: none;
  margin: 0;
  padding: 0;
  animation: infinity-scroll-left 15s infinite linear;
  /* リスト全体の幅を確保するため、リスト1と2の内容を連続で移動 */
  width: calc(100vw * 2);
}

.scroll-infinity__item {
  flex-shrink: 0;
  width: calc(100vw / 4); /* 各アイテムの幅 */
}

.scroll-infinity__item img {
  width: 80%;
  padding: 3rem ;
}

https://rita-plus.com/blog/css-animation-scroll-infinity/

kohei nemawarikohei nemawari

スワイパー 両端が映らない

おそらくV9以降のバグなので、以下のページを参考にswiperのバージョンをV8に変更する。
https://zenn.dev/muuuurai/articles/f84d6c22e1a8c2


◎loop指定時に余白ができてしまう(コピーが追い付かない)問題は
以下の回答にあるように、Swiperの仕様っぽいです。

このスクラップは2024/09/25にクローズされました