Webサイトでスライダー(カルーセル)を実装する際、「スマホではスライダーを表示したいが、PCでは静的なレイアウトにしたい」といったニーズはよくあります。今回は、Swiperと window.matchMedia を組み合わせて、画面サイズに応じて動的にSwiperの有効・無効を切り替える方法を段階的に解説します。
実装のゴール
| 画面幅 | 表示レイアウト | Swiperの動作 |
|---|---|---|
| 768px未満 | スライダー表示(Swiper有効) | 有効 |
| 768px以上 | 横並びの静的レイアウト | 無効 |
1. 基本の構成:Swiperを画面幅で切り替える
まずは、スマホでSwiperを有効化し、PCでは破棄する基本の実装です。
HTML(Swiperの構造)
<div class="swiper-container js-my-swiper">
<div class="swiper-wrapper">
<div class="swiper-slide">スライド1</div>
<div class="swiper-slide">スライド2</div>
<div class="swiper-slide">スライド3</div>
</div>
</div>JavaScript
let mySwiper = null;
const mediaQuery = window.matchMedia('(max-width: 767px)');
function initSwiper() {
if (!mySwiper) {
mySwiper = new Swiper('.js-my-swiper', {
slidesPerView: 1,
spaceBetween: 10,
loop: true,
});
}
}
function destroySwiper() {
if (mySwiper) {
mySwiper.destroy(true, true);
mySwiper = null;
}
}
function handleBreakpoint(e) {
if (e.matches)
initSwiper();
} else {
destroySwiper();
}
}
handleBreakpoint(mediaQuery);
mediaQuery.addEventListener('change', handleBreakpoint);2. PCでは静的レイアウトに切り替える
Swiperだけでなく、PCでは静的な横並びのブロックにレイアウトを切り替える例です。
HTML(Swiperと静的レイアウトを両方用意)
<!-- スライダー:スマホ用 -->
<div class="swiper-container js-my-swiper" data-role="slider">
<div class="swiper-wrapper">
<div class="swiper-slide">アイテム1</div>
<div class="swiper-slide">アイテム2</div>
<div class="swiper-slide">アイテム3</div>
</div>
</div>
<!-- 静的レイアウト:PC用 -->
<div class="static-layout" data-role="static">
<div class="item">アイテム1</div>
<div class="item">アイテム2</div>
<div class="item">アイテム3</div>
</div>CSS(表示の切り替え)
[data-role="slider"],
[data-role="static"] {
display: none;
}
@media (max-width: 767px) {
[data-role="slider"] {
display: block;
}
}
@media (min-width: 768px) {
[data-role="static"] {
display: flex;
gap: 16px;
}
.static-layout .item {
flex: 1;
background: #eee;
padding: 16px;
text-align: center;
}
}
3. HTMLを共通化してJSで動的に切り替える
HTML構造をSwiper用と静的レイアウト用に分けると、同じデータを重複して書くことになるというデメリットがあります。これを避けるために、共通のアイテムリストから、JSでSwiper構造/静的構造に変換する方法を紹介します。
HTML(共通のリストのみ)
<div id="item-container">
<div class="item">アイテム1</div>
<div class="item">アイテム2</div>
<div class="item">アイテム3</div>
</div>CSS(共通アイテムと静的レイアウト用)
.item {
background: #eee;
padding: 16px;
text-align: center;
}
.static-layout {
display: flex;
gap: 16px;
}
.swiper-container {
width: 100%;
}
JavaScript(DOM変換とSwiper初期化)
let mySwiper = null;
const container = document.getElementById('item-container');
const mediaQuery = window.matchMedia('(max-width: 767px)');
let currentLayout = null;
function setupSwiperLayout() {
if (currentLayout === 'swiper') return;
const wrapper = document.createElement('div');
wrapper.classList.add('swiper-wrapper');
[...container.children].forEach((item) => {
const slide = document.createElement('div');
slide.classList.add('swiper-slide');
slide.appendChild(item);
wrapper.appendChild(slide);
});
container.innerHTML = '';
const swiperEl = document.createElement('div');
swiperEl.classList.add('swiper-container');
swiperEl.appendChild(wrapper);
container.appendChild(swiperEl);
mySwiper = new Swiper('.swiper-container', {
slidesPerView: 1.2,
spaceBetween: 10,
loop: true,
});
currentLayout = 'swiper';
}
function setupStaticLayout() {
if (currentLayout === 'static') return;
if (mySwiper) {
mySwiper.destroy(true, true);
mySwiper = null;
}
const items = [];
container.querySelectorAll('.swiper-slide .item').forEach((item) => {
items.push(item);
});
container.innerHTML = '';
const staticLayout = document.createElement('div');
staticLayout.classList.add('static-layout');
items.forEach((item) => staticLayout.appendChild(item));
container.appendChild(staticLayout);
currentLayout = 'static';
}
function handleResize(e) {
if (e.matches) {
setupSwiperLayout();
} else {
setupStaticLayout();
}
}
handleResize(mediaQuery);
mediaQuery.addEventListener('change', handleResize);





