fumi WEB フミウェブ

お見積もり・ご相談はこちら

fumi Blog

コーディング中心に活動中のフリーランス、
fumicaのブログ。
日々取得した技術や勉強の記録をまとめています。

Swiperの高さがガクつく原因と解決方法

Swiperで高さを揃える方法

LP制作などでよく使われるカード型スライダーを作ると、

テキスト量が違うせいで高さがバラバラになり、スライドした時にガクつく現象が起きます。

今回はjavascriptを使用して「一番高いスライドに合わせて全体を調整する」方法について解説します。

Swiper初期化(autoHightは使わない)

const swiper = new Swiper('.item-color__slider .swiper', {
  loop: false,
  autoHeight: false, // 高さ固定するので必ずオフ
});

今回はjavascriptを使用するためautoHightはオフにします。

なぜautoHightを切るのか?

自動で高さを揃えてくれそうなautoHeight: trueですが、実際の挙動は以下になります。

  • 「今表示しているスライドの高さ」に毎回合わせる
  • スライド切り替えのたびに wrapper の高さが変わる

つまり、

高さが違うスライドがある時点でガクつく設計です。

今回やりたいのは

一番高いスライドに全スライドを合わせて固定

真逆の挙動をしてしまうため、autoHeightはオフにしましょう。

javascriptで最大高さを取得する

以下のコードをSwiper設定用コードの、var swiper = new Swiper(‘.swiper’, { ~  });次に記載してください。

function setSlideHeight() {
  //全スライドを取得
  const slides = document.querySelectorAll(
    '.item-color__slider .swiper-slide'
  );

  let maxHeight = 0;

  slides.forEach(slide => {
    slide.style.height = 'auto'; // 一度リセット
    const h = slide.offsetHeight;// 一番高いスライドを探す
    if (h > maxHeight) maxHeight = h;
  });

  slides.forEach(slide => {
    slide.style.height = maxHeight + 'px';// 全スライドに同じ高さを設定
  });
}

// 初回
setSlideHeight();
// 画像読み込み後
window.addEventListener('load', setSlideHeight);
// リサイズ対応
window.addEventListener('resize', setSlideHeight);

コード解説

簡単にコードについて解説します。

全スライドを取得

const slides = document.querySelectorAll(...)

高さを揃えたい対象を取得。

いったん高さをリセット

slide.style.height = 'auto';

前回計算された高さを解除しないと、正しい高さが取れません。

一番高いスライドを探す

const h = slide.offsetHeight;

offsetHeight で実際の高さを取得し、最大値を保存します。

全スライドに同じ高さを設定

slide.style.height = maxHeight + 'px';

最後に一番高いスライドに合わせて、全スライドの高さを設定します。

これでスライド切替時に高さが変わらなくなります。

最後に、実行タイミングを設定(重要)

setSlideHeight();
window.addEventListener('load', setSlideHeight);
window.addEventListener('resize', setSlideHeight);

なぜ必要なのか

未設定の場合、以下の挙動になります。

  • 画像読み込み後に高さが変わる
  • リサイズで改行が変わる
  • 初期表示でガクつく

そのため、
load と resize で再計算します。

必ず 1ページに1回だけSwiper初期化の後に実行してください。

CSS側の最低限設定

.swiper-slide {
  height: auto;
}

.card {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.cardheight:100% を付けることで固定されたスライド高さに追従させます。

HTMLは以下を想定してます。

<!-- スライダー -->
<div class="swiper">
    <div class="swiper-wrapper">
    <!-- 1枚目 -->
        <div class="swiper-slide">
            <div class="card">
                <!-- 画像 -->
                <div class="card__img">
                    <img src="./images/card-1.png" alt="">
                </div>
                 <!-- タイトル+テキスト -->
                <div class="card__text">
                    <h3 class="card-title">タイトル</h3>
                    <div class="item-color__detail__text">
                        <p>テキスト</p>
                    </div>
                </div>
            </div>
        </div>
        <!-- 2枚目以降省略 -->
        </div>
    </div><!-- swiper-wrapper -->
</div><!-- swiper -->

Swiperでbreakpoints設定をしている場合は注意

breakpointsで768: { … }などとレスポンシブ設定している場合は上記のコードでは高さが可変にならないので、以下のコードを使用してください。

function setSlideHeight() {
    const slides = document.querySelectorAll('.swiper .swiper-slide');

    // ① いったん完全リセット
    slides.forEach(slide => {
        slide.style.height = '';
    });

    let maxHeight = 0;

    // ② 最大高さ取得
    slides.forEach(slide => {
        const h = slide.offsetHeight;
        if (h > maxHeight) maxHeight = h;
    });

    // ③ 再設定
    slides.forEach(slide => {
        slide.style.height = maxHeight + 'px';
    });
}

/* ===== ここから変更 ===== */
/* 初回(画像読み込み後) */
window.addEventListener('load', function () {
    setSlideHeight();
});

/* リサイズ */
let resizeTimer;
window.addEventListener('resize', function () {
    clearTimeout(resizeTimer);
    resizeTimer = setTimeout(function () {
        setSlideHeight();
    }, 250);
});

/* breakpoint変更時にも再計算 */
swiper.on('breakpoint', function () {
    setSlideHeight();
});

変更したところ

function setSlideHeight() {・・・}の後のコードをbreakpoint仕様に変更しています。

swiper.on('breakpoint', function () {
    setSlideHeight();
});

このコードがポイントで、Swiperがレイアウトを変えた直後に高さを再計算するようになります。

まとめ

  • autoHeightは使わない
  • 最大高さを取得して固定する
  • load / resize で再計算する
  • Swiper初期化の後に実行する

LPのカード型スライダーでは、この方法が一番安定します。

FV(ファーストビュー)系のスライダーにも必要?

FV系は高さ固定されているため、JSで計算する意味がないため、ほぼ不要です。

不要なスライダー
  • 高さは vh / aspect-ratio / 固定比率
  • テキスト量で高さが変わらない
  • 画像・動画主役
このJSが必要なスライダー
  • カード型
  • スライドによってテキスト量が違う
  • 商品・料金・比較

今回のコードはFVスライダーには不要、カード型スライダー向けと覚えておきましょう。

今までカード型スライダーの高さが揃わないとき、

  • min-heightで無理やり調整
  • autoHeight: trueを設定してみる
  • height:100% を親子で連打

などの試行錯誤を繰り返していましたが、いつもSwiperの内部計算に負けがちでした。

「一番高いスライドに全員を合わせる」
これはSwiperは自動では絶対にやってくれないみたいです。

今回のJSを最後に追加するだけでスライドの挙動が安定したので、カード型スライダーSwiper作業のハードルがだいぶ下がったのではないかと思います。

Swiperは完成してからの設定が本作業なため、今後もハマったポイントと対処方法をメモして出来る限り負担を減らしたいですね。