
Webサイトのメインビジュアルやコンテンツ紹介で、ひときわ目を引くスライダー表現を取り入れたいと感じたことはありませんか。
本記事では、センターのスライドが大きく表示され、前後にいくにつれてスライドが小さくなっていく、奥行き感のあるパララックス風スライダーをご紹介します。
視覚的な立体感が生まれ、シンプルな構成でも印象に残る表現が可能です。
「こういったスライダーを自分のサイトでも実装してみたい」「仕組みや考え方を知りたい」という方に向けて、実際に動きを確認できるデモも用意しています。
同じようなスライダーを作りたいと考えている方に向けて、実装のポイントや考え方をあわせてご紹介します。
目次
今回作成するスライダー

センターに表示されるスライドを大きく見せ、前後に配置されるスライドほど徐々に小さくなっていく構成のスライダーです。
中央に視線が集まりやすく、スライド同士のサイズ差によって奥行き感のあるパララックス風の表現を実現しています。
シンプルなスライダーでありながら、動きのある印象的なビジュアルを演出できるため、メインビジュアルやコンテンツのアイキャッチとしても活用しやすいのが特徴です。
デモはこちらです。
奥行き感のあるパララックス風のスライダー デモ
事前準備
今回使用するスライダープラグインは、swiperです。
詳しい組み込み方などは、以下のブログで紹介しているのでご覧ください。
【最新】Swiperの使い方・カスタマイズを解説!サンプルやオプション15個付き ー基礎から応用までー
作成の手順
最終的なコードはこちらです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | <div class="swiper demo-swiper"> <div class="swiper-wrapper"> <div class="swiper-slide"> <div class="card"> <div class="img"> <img src="/img/slide-img01.jpg.webp" alt=""> </div> <p class="slide-ttl">TITLE</p> </div> </div> <div class="swiper-slide"> <div class="card"> <div class="img"> <img src="/img/slide-img02.jpg.webp" alt=""> </div> <p class="slide-ttl">TITLE</p> </div> </div> <div class="swiper-slide"> <div class="card"> <div class="img"> <img src="/img/slide-img03.jpg.webp" alt=""> </div> <p class="slide-ttl">TITLE</p> </div> </div> <div class="swiper-slide"> <div class="card"> <div class="img"> <img src="/img/slide-img01.jpg.webp" alt=""> </div> <p class="slide-ttl">TITLE</p> </div> </div> <div class="swiper-slide"> <div class="card"> <div class="img"> <img src="/img/slide-img02.jpg.webp" alt=""> </div> <p class="slide-ttl">TITLE</p> </div> </div> <div class="swiper-slide"> <div class="card"> <div class="img"> <img src="/img/slide-img03.jpg.webp" alt=""> </div> <p class="slide-ttl">TITLE</p> </div> </div> </div> <div class="swiper-pagination"> </div> <div class="swiper-button-wrap"> <div class="swiper-button-prev"> </div> <div class="swiper-button-next"> </div> </div> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | .img { border-radius: 20px; -webkit-box-shadow: 0 4px 10px rgba(43, 146, 150, 0.25); box-shadow: 0 4px 10px rgba(43, 146, 150, 0.25); overflow: hidden; position: relative; } .img img { -o-object-fit: cover; object-fit: cover; width: 100%; } .slide-ttl { font-size: 35px; font-weight: bold; line-height: 1; margin-top: 20px; text-align: center; } /* スライド */ .swiper-wrapper { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-box-align: center; -webkit-align-items: center; -ms-flex-align: center; align-items: center; will-change: transform; -webkit-backface-visibility: hidden; backface-visibility: hidden; } .swiper-slide { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-box-align: center; -webkit-align-items: center; -ms-flex-align: center; align-items: center; -webkit-box-pack: center; -webkit-justify-content: center; -ms-flex-pack: center; justify-content: center; padding-inline: 30px; -webkit-transition: 0.7s; transition: 0.7s; width: clamp(280px, 100vw - 20px, 500px); } /* ページネーション */ .swiper-pagination { -webkit-box-pack: center; -webkit-justify-content: center; -ms-flex-pack: center; justify-content: center; display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-flex-wrap: wrap; -ms-flex-wrap: wrap; flex-wrap: wrap; gap: 10px; margin-top: 50px; } .swiper-pagination .swiper-pagination-bullet { cursor: pointer; border: 1px solid #2B9296; border-radius: 100px; background: #fff; height: 10px; width: 30px; -webkit-transition: 0.3s ease-in-out; transition: 0.3s ease-in-out; } .swiper-pagination .swiper-pagination-bullet:hover { background: #2B9296; -webkit-transition: 0.3s ease-in-out; transition: 0.3s ease-in-out; } .swiper-pagination .swiper-pagination-bullet-active { background: #2B9296; } /* 前へ次へボタン */ .swiper-button-wrap { -webkit-box-align: center; -webkit-align-items: center; -ms-flex-align: center; align-items: center; display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; -webkit-flex-wrap: wrap; -ms-flex-wrap: wrap; flex-wrap: wrap; gap: 20px; -webkit-box-pack: center; -webkit-justify-content: center; -ms-flex-pack: center; justify-content: center; margin-top: 30px; } .swiper-button-prev, .swiper-button-next { background: #2B9296; border: 1px solid #2B9296; border-radius: 100px; cursor: pointer; height: 54px; width: 54px; position: relative; -webkit-transition: 0.3s ease-in-out; transition: 0.3s ease-in-out; } .swiper-button-prev::before, .swiper-button-next::before { background: #fff; content: ""; -webkit-mask-image: url(../img/arrow.svg); mask-image: url(../img/arrow.svg); -webkit-mask-size: contain; mask-size: contain; -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat; -webkit-mask-position: center; mask-position: center; height: 21px; width: 13px; position: absolute; top: 0; left: 0; bottom: 0; right: 0; margin: auto; -webkit-transition: 0.3s ease-in-out; transition: 0.3s ease-in-out; } .swiper-button-prev::before { left: -2px; } .swiper-button-next::before { right: -2px; -webkit-transform: scale(-1, 1); transform: scale(-1, 1); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | $(function () { // 端末幅でスケール段階を返す function tierScales() { const w = window.innerWidth; if (w < 768) return { min: 1, mid: 1, max: 1 }; // SPは全部1 return { min: 0.7, mid: 0.85, max: 1 }; // PC } // SP時のパララックスscale切替(任意) function setParallaxScaleAttr() { const isSP = window.innerWidth < 768; $('.demo-swiper .card').attr( 'data-swiper-parallax-scale', isSP ? '1' : '0.85' ); } const swiper = new Swiper('.demo-swiper', { slidesPerView: 'auto', centeredSlides: true, speed: 500, loop: true, parallax: true, roundLengths: true, loopAdditionalSlides: 10, watchSlidesProgress: true, pagination: { el: '.demo-swiper .swiper-pagination', clickable: true, type: 'bullets', }, navigation: { nextEl: '.demo-swiper .swiper-button-next', prevEl: '.demo-swiper .swiper-button-prev', }, on: { init(swiper) { swiper.updateSlidesProgress(); swiper.setTranslate(swiper.translate); setParallaxScaleAttr(); }, setTranslate(swiper) { const { min, mid, max } = tierScales(); $(swiper.slides).each(function () { const p = this.progress; // 中央=0, 右+1, 左-1 const ap = Math.abs(p); let scale; const card = $(this).find('.card'); if (ap <= 0) scale = max; else if (ap < 1) scale = max - (max - mid) * ap; // 0→1で 1→0.85 else if (ap < 2) scale = mid - (mid - min) * (ap - 1); // 1→2で 0.85→0.6 else scale = min; let origin = 'center left'; if (!(p < 0)) { origin = 'center right'; } card.css({ 'transform': `scale(${scale})`, 'transform-origin': origin, 'z-index': String(1000 - Math.round(ap * 100)), }); }); }, setTransition(swiper, duration) { $(swiper.slides).css('transition-duration', `${duration}ms`); }, resize(swiper) { swiper.updateSlidesProgress(); swiper.setTranslate(swiper.translate); setParallaxScaleAttr(); } } }); }); |
それぞれ段階を踏んで細かく説明していきます。
基本のスライダー
まず始めに普通のスライダーを作成します。
HTML構造の詳しい説明は以下のブログで紹介しているので、ご覧ください。
【最新】Swiperの使い方・カスタマイズを解説!サンプルやオプション15個付き ー基礎から応用までー
jQuery
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | $(function(){ const mySwiper = new Swiper('.swiper', { slidesPerView: 'auto', centeredSlides: true, speed: 500, loop: true, parallax: true, roundLengths: true, loopAdditionalSlides: 10, watchSlidesProgress: true, pagination: { el: '.demo-swiper .swiper-pagination', clickable: true, type: 'bullets', }, navigation: { nextEl: '.demo-swiper .swiper-button-next', prevEl: '.demo-swiper .swiper-button-prev', }, }); }); |
スライドの横幅は後々CSSで指定するため、autoを設定します。
CSS
CSSで必要なコードは以下の部分です。
※説明に必要な部分のみ抜粋しています。
1 2 3 4 5 | .swiper-slide { width: clamp(280px, calc(100vw - 20px), 500px); } |
デザインの自由度が上がるので、スライドの幅はCSSで指定しています。
これで普通のスライダーが完成です。
通常スライダーのデモ
中央から前後のスライドが縮小していくスライダー
ここから本題のスライダーを作成する手順に入っていきます。
奥行き感のあるパララックス風のスライダーを作成するのに必要な記述は以下の二点です。
スケールに関する関数
イベントの登録
スケールに関する関数
まず、中央のスライドから前後のスライドが小さくなっていくためのスケールに関する関数を作成します。
1 2 3 4 5 6 7 | function tierScales() { const w = window.innerWidth; if (w < 768) return { min: 1, mid: 1, max: 1 }; // SPは全部1 return { min: 0.7, mid: 0.85, max: 1 }; // PC } |
この関数は、画面幅に応じてスケール値を返すための関数です。
中央のスライドを大きく、前後のスライドを小さくすると奥行き感のあるパララックス風が実装出来ます。
1 2 3 | const w = window.innerWidth; |
現在閲覧しているブラウザの横幅を取得します。
こちらは、PCとSPで動きや縮小率を変えるための判定用です。
1 2 3 4 | if (w < 768) return { min: 1, mid: 1, max: 1 }; return { min: 0.7, mid: 0.85, max: 1 }; |
横幅でスマホかどうかを判定します。
始めのreturnはSPでのスケール値の設定です。
スマホでは、画面が狭くあまり奥行き感を表現出来ないため、縮小なしとしてmin/mid/maxを全て1にします。
次のreturnではPCのスケール値を設定しています。
max : 1
中央のスライドを100%のサイズ(縮小なし)
mid : 0.85
中央から直前直後のスライドを85%のサイズにする。
min : 0.7
直前直後のスライドよりさらに端のスライドを70%のサイズにする。
中央を100%とした時、段階を踏んで縮小させていくことで、奥行き感を出せます。
SP時のパララックススケール切替
先程の『スケールに関する関数』と似た目的で、パララックス用の scale 属性を SP/PC で切り替える関数です。
これが無いと後々スライドを移動した際にカクついてしまいます。
1 2 3 4 5 6 7 8 9 | function setParallaxScaleAttr() { const isSP = window.innerWidth < 768; $('.demo-swiper .card').attr( 'data-swiper-parallax-scale', isSP ? '1' : '0.85' ); } |
SPの画面幅を判断して、スケール値を100%か85%に切り替えます。
イベントの登録
実際にイベントを登録していきます。
全体のコードは以下です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | on: { init(swiper) { swiper.updateSlidesProgress(); swiper.setTranslate(swiper.translate); setParallaxScaleAttr(); }, setTranslate(swiper) { const { min, mid, max } = tierScales(); $(swiper.slides).each(function () { const p = this.progress; // 中央=0, 右+1, 左-1 const ap = Math.abs(p); let scale; const card = $(this).find('.card'); if (ap <= 0) scale = max; else if (ap < 1) scale = max - (max - mid) * ap; // 0→1で 1→0.85 else if (ap < 2) scale = mid - (mid - min) * (ap - 1); // 1→2で 0.85→0.6 else scale = min; let origin = 'center left'; if (!(p < 0)) { origin = 'center right'; } card.css({ 'transform': `scale(${scale})`, 'transform-origin': origin, 'z-index': String(1000 - Math.round(ap * 100)), }); }); }, setTransition(swiper, duration) { $(swiper.slides).css('transition-duration', `${duration}ms`); }, resize(swiper) { swiper.updateSlidesProgress(); swiper.setTranslate(swiper.translate); setParallaxScaleAttr(); } } |
上から順に説明します。
初期化時の処理
1 2 3 4 5 6 7 | init(swiper) { swiper.updateSlidesProgress(); swiper.setTranslate(swiper.translate); setParallaxScaleAttr(); }, |
スライダーが最初に作られた瞬間の処理です。
最後のsetParallaxScaleAttr();は、SP時のパララックススケール切替を呼び出しています。
swiper.updateSlidesProgress();
各スライドに位置情報(progress値)を計算して保存します。
progressはSwiperが各スライドに自動的に付与する数値で、「そのスライドが画面中央からどれだけ離れているか」を表します。

Swiperは内部で各スライドの位置を管理していますが、初期状態ではprogressが未計算です。
この関数を呼ぶことで、後続の処理でthis.progressを使えるようになります。
内部的にはこのようなイメージです。
1 2 3 4 5 6 | swiper.slides.forEach((slide, index) => { const offset = index - swiper.activeIndex; // 中央からの距離 slide.progress = offset; // 各スライドに保存 }); |
swiper.setTranslate(swiper.translate);
setTranslateイベントハンドラーを手動で呼び出すことで、初期状態のスケール適用を実行します。
swiper.translateはSwiperのスライド全体が現在どれだけ移動しているかを表す数値(ピクセル単位)です。

スライド実行中の処理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | setTranslate(swiper) { const { min, mid, max } = tierScales(); $(swiper.slides).each(function () { const p = this.progress; // 中央=0, 右+1, 左-1 const ap = Math.abs(p); let scale; const card = $(this).find('.card'); if (ap <= 0) scale = max; else if (ap < 1) scale = max - (max - mid) * ap; // 0→1で 1→0.85 else if (ap < 2) scale = mid - (mid - min) * (ap - 1); // 1→2で 0.85→0.6 else scale = min; let origin = 'center left'; if (!(p < 0)) { origin = 'center right'; } card.css({ 'transform': `scale(${scale})`, 'transform-origin': origin, 'z-index': String(1000 - Math.round(ap * 100)), }); }); }, |
スライドが動くたびに実行される部分です。
各スライドの位置に応じて拡大縮小を行います。
実行されるタイミングは以下の4つです。
スワイプ中(指を動かしている間)
慣性スクロール中
slideTo()などのメソッド実行時
init内で手動呼び出ししたとき
スライダーが動いている間は連続的に実行されます。
1 2 3 | const { min, mid, max } = tierScales(); |
スケール値の準備です。
事前にスケールに関する関数で作成している関数を呼び出します。
ループ処理
ループ処理内の説明していきます。
変数の宣言
1 2 3 4 5 6 | const p = this.progress; // 中央=0, 右+1, 左-1 const ap = Math.abs(p); let scale; const card = $(this).find('.card'); |
上記のコードはそれぞれ以下を意味します。
const p = this.progress;
現在のスライドが画面中央からどれだけ離れているかを判断するために必要な変数を宣言しています。
const ap = Math.abs(p);
progressの絶対値を取得(※符号を無視)しています。
Math.abs()は、数値から符号(+/-)を取り外して、絶対値を返すメソッドです。
理由1: 左右対称の処理 ⇒ 同じ距離なら同じサイズにするため
理由2: 距離の計算 ⇒ 方向問わず中央から2つ離れている
let scale;
スケール値を格納する変数を宣言(初期値なし)しています。
const card = $(this).find(‘.card’);
現在のスライド内の.card要素を取得するための変数を宣言しています。
実際にスケールを変えるのは、slide要素ではなく、その中のcard要素のため必要です。
※slide要素をスケールしてしまうとスライダーの挙動が崩れてしまうため、中に入れ込んでいる要素をスケールするようにしてください。
スケールの計算
続いてスケールの計算に必要な核心部分です。
1 2 3 4 5 6 | if (ap <= 0) scale = max; else if (ap < 1) scale = max - (max - mid) * ap; // 0→1で 1→0.85 else if (ap < 2) scale = mid - (mid - min) * (ap - 1); // 1→2で 0.85→0.6 else scale = min; |
if文でどのようにスケールを計算するかを分岐させています。
if (ap <= 0) scale = max;
ap(絶対値)が0以下なら、100%(基準のサイズ)にする分岐です。
else if (ap < 1) scale = max - (max - mid) * ap;
ap(絶対値)が1以下なら、スケールを小さくする分岐です。

else if (ap < 2) scale = mid - (mid - min) * (ap - 1);
ap(絶対値)が2以下なら、スケールをさらに小さくする分岐です。

else scale = min;
ap(絶対値)が2以上なら、スケールを一番小さいサイズで固定にする分岐です。
これで中央のスライドが一番大きく、両端に行くにつれて小さくなっていくスライダーが実装できます。
スケールの基準点の調整
次にスケールの基準点について調整します。
1 2 3 4 5 6 7 8 9 10 11 12 | let origin = 'center left'; if (!(p < 0)) { origin = 'center right'; } card.css({ 'transform': `scale(${scale})`, 'transform-origin': origin, 'z-index': String(1000 - Math.round(ap * 100)), }); |
まず、基準点を格納した変数を宣言します。
上下中央なのは同じですが、スライドの現在位置が0より小さい場合は、右を基準にします。
先程のif文で計算された変数『scale』は、transformとして使用します。
変数『origin』は、card要素のtransform-originに使用します。
z-indexは、奥行き感のあるパララックス風を表現するために、中央が一番前に来るようにします。
基準を1,000とし、スライドの位置によって変わる絶対値×100で出た数値と計算したものをz-indexとして登録します。
z-indexは整数で指定するのが一般的なので、小数点が出ても問題ないようにMath.round( )で囲んでおきます。
数値を最も近い整数に四捨五入するJavaScriptのメソッド
アニメーションの速度
1 2 3 4 5 | setTransition(swiper, duration) { $(swiper.slides).css('transition-duration', `${duration}ms`); }, |
スライドを切り替える時のスピードを設定する処理です。
画面リサイズ時の処理
1 2 3 4 5 6 7 | resize(swiper) { swiper.updateSlidesProgress(); swiper.setTranslate(swiper.translate); setParallaxScaleAttr(); } |
処理的には、初期化時の処理と同じです。
画面サイズが変わった時に再度読み込み直し、スムーズにスライダーを生成しなおします。
完成
奥行き感のあるパララックス風のスライダーの完成です。
奥行き感のあるパララックス風のスライダー デモ
まとめ
今回は、センターのスライドを大きく表示し、前後にいくにつれてスライドが小さくなる奥行き感のあるパララックス風スライダーについてご紹介しました。
スライドのサイズに変化をつけることで、シンプルな構成でも立体感や動きのある表現が可能になります。
実装自体は基本的なスライダーをベースにしつつ、少し工夫を加えるだけで、視覚的に印象に残るUIを作ることができます。
「いつものスライダーに少し変化を加えたい」「目を引くビジュアル表現を取り入れたい」という方は、ぜひ今回の内容を参考にしてみてください。
デモを確認しながら調整することで、自分のサイトやデザインに合った表現へとカスタマイズできると思います。
今回ご紹介したスライダーが、スライダー表現を検討する際のヒントになれば幸いです。
エンジニア新卒採用2027でも奥行き感のあるパララックス風のスライダーを実装しているので、参考にご覧ください。
先輩社員の声





