ニュースアプリなどでよく見られる「スワイプでタブ切り替えができるメニュー」を実装する方法をご紹介したいと思います。
今回使用する「Swiper」の基本的な使用方法については、下記記事を参考にしてください。
スマホアプリ風メニューの機能とデモ
様々な方法があるかとは思いますが、今回実装するにあたっての求める機能は以下の通りとしております。
- タブ切り替え機能(スワイプでスライドし、タップすると切り替わる)。
- コンテンツ部分をスワイプするとタブが切り替わる。
- タブによって高さをautoにする。
- アクティブな(タップした)メニューにcssを適用する。
- タップしたメニューを見やすいように少し移動させる。
このような機能を実装してみたいと思います。
こちらが完成したデモです。
スライダーは「Swiper」を使用
スライダーには、jQueryを使わない人気スライダー「Swiper」を使用します。
理由は「とにかく簡単」に実装ができ、「オプションが豊富」であることからSwiperを使用すれば簡単にできるのではないかと考えたためです。
早速、設定をしていきます。
Swiperを使えるようにする
SwiperはCDNを利用できますので、下記を読み込んでいきます。
<link rel="stylesheet" href="https://unpkg.com/swiper@7/swiper-bundle.min.css" />
<script src="https://unpkg.com/swiper@7/swiper-bundle.min.js"></script>
※この記事では、執筆時の最新バージョン「v7.4.1」で作成されています。最新版の読み込み先を確認する場合は、下記記事をご確認ください。
HTMLを設定
続いては、HTML部分を記述していきます。
必要なのは、タブ切り替えに必要な「メニュー」部分とメニューを押したときに切り替わる「コンテンツ」部分です。
今回は、「Swiper」のデモ一覧から実装したい機能に最も近かった「Thumbs Gallery」のHTML部分をカスタマイズして使用しています。
<div class="container">
<!-- メニュー部分 -->
<div class="swiper tab-menu">
<div class="swiper-wrapper">
<div class="swiper-slide">トップ</div>
<div class="swiper-slide">ランキング</div>
<div class="swiper-slide">国内</div>
<div class="swiper-slide">エンタメ</div>
<div class="swiper-slide">スポーツ</div>
<div class="swiper-slide">経済</div>
</div>
<!-- コンテンツ部分 -->
<div class="swiper tab-contents">
<div class="swiper-wrapper">
<div class="swiper-slide">トップ</div>
<div class="swiper-slide">ランキング</div>
<div class="swiper-slide">国内</div>
<div class="swiper-slide">エンタメ</div>
<div class="swiper-slide">スポーツ</div>
<div class="swiper-slide">経済</div>
</div>
</div>
Swiperを初期化して使用できるようにする
次に、jsでSwiperの初期化をしていきます。
<script>
//初期化
const galleryThumbs = new Swiper('.tab-menu', {
spaceBetween: 20,
slidesPerView: 'auto',
freeMode: false,
watchSlidesVisibility: true,
watchSlidesProgress: true,
});
const galleryTop = new Swiper('.tab-contents', {
autoHeight: true,
thumbs: {
swiper: galleryThumbs
}
});
</script>
いくつかオプションについて説明していきます。
slidesPerView: 'auto',
この部分は、画面上にいくつスライドを表示するかという設定です。メニュー部分は、何個という設定ではなく一覧表示したいので’auto’を設定しています。
watchSlidesVisibility: true,
watchSlidesProgress: true,
この部分は、「watchSlidesVisibility」でスライドの進行状況を計算し、「watchSlidesProgress」で「swiper-slide-visibleクラス」が付与されます。
thumbs: {
swiper: galleryThumbs
}
この部分でメニュー部分とコンテンツ部分が紐づきます。
CSSを設定
次はCSSを設定していきます。
.container {
max-width: 375px;
margin: 30px auto;
border: 1px solid #CCC;
}
.swiper{
margin: 0 auto 30px;
}
.tab-menu {
background: #f5f5f5;
border-bottom: 1px solid #CCC;
}
.tab-menu .swiper-slide {
width: auto;
padding: 10px 0;
}
.tab-contents {
margin: 30px auto;
}
必要なのは、「.tab-menu .swiper-slide」の「width:auto」です。
こちらは、メニューの一つ一つの幅を設定しています。
その他のCSSに関しては、必須ではないので適宜変更してください。
ここまでのデモはこちらです。
アクティブなメニューの装飾を変更したい
ここまでの設定では、メニューをタップもしくはクリックした際に、メニューの色やボーダーが変化しない為、どのメニューが選択されているか分かりにくいですよね。
そこで、メニューが選択されたら色と太さ、そして下線を付けてみたいと思います。
slideActiveClassオプションを利用する
Swiperには、予め「slideActiveClass」というアクティブなスライドにクラスを付与するというオプションが用意されていますので、こちらを利用します。
「watchSlidesProgress: true,」の下に追加します。
watchSlidesVisibility: true,
watchSlidesProgress: true,
//こちらを追加//
slideActiveClass: 'swiper-slide-active'
});
これでアクティブなメニューに「swiper-lide-active」クラスが付与されますので、CSSを設定していきます。
.tab-contents {
margin: 30px auto;
}
/*こちらに追加*/
.swiper-slide-thumb-active {
border-bottom: 2px solid rgb(9, 8, 53);
color: rgb(9, 8, 53) !important;
font-weight: bold;
}
これでアクティブなメニューに装飾することができました。
タップした時にスライドに合わせてメニューに動きをつける
ここまでで、ほとんど機能としては完成ですが、メニューをタップした際に、コンテンツに合わせてメニューも少しだけ移動させることでよりアプリっぽさを出します。
考え方としては、「メニューをタップした時に、アクティブなコンテンツの位置にスライドを移動させる」イベントを設定するといった感じです。
slideActiveClass: 'swiper-slide-active'
});
//ここから追加
galleryThumbs.on('tap', function () {
const current = galleryTop.activeIndex;
galleryThumbs.slideTo(current, 500, true);
});
Swiperのtapイベントを「メニュー」に設定し、アクティブなコンテンツのインデックス番号を変数「current」にセット。そして、「slideTo」メソッドで位置を変更しています。
これで、すべての設定が完了となります。
完成形
完成形は以下の様になります。
HTML
<div class="container">
<!-- Swiper -->
<div class="swiper tab-menu">
<div class="swiper-wrapper">
<div class="swiper-slide">トップ</div>
<div class="swiper-slide">ランキング</div>
<div class="swiper-slide">国内</div>
<div class="swiper-slide">エンタメ</div>
<div class="swiper-slide">スポーツ</div>
<div class="swiper-slide">経済</div>
</div>
</div>
<div class="swiper tab-contents">
<div class="swiper-wrapper">
<div class="swiper-slide">トップ</div>
<div class="swiper-slide">ランキング</div>
<div class="swiper-slide">国内</div>
<div class="swiper-slide">エンタメ</div>
<div class="swiper-slide">スポーツ</div>
<div class="swiper-slide">経済</div>
</div>
</div>
</div>
JS
<script>
const galleryThumbs = new Swiper('.tab-menu', {
spaceBetween: 20,
slidesPerView: 'auto',
watchSlidesVisibility: true,
watchSlidesProgress: true,
slideActiveClass: 'swiper-slide-active'
});
galleryThumbs.on('tap', function () {
const current = galleryTop.activeIndex;
galleryThumbs.slideTo(current, 500, true);
});
const galleryTop = new Swiper('.tab-contents', {
autoHeight: true,
thumbs: {
swiper: galleryThumbs
}
});
</script>
CSS
.container {
max-width: 375px;
margin: 30px auto;
border: 1px solid #CCC;
}
.swiper {
margin: 0 auto 30px;
}
.tab-menu {
border-bottom: 1px solid #CCC;
}
.tab-menu .swiper-slide {
width: auto;
padding: 10px 0;
}
.tab-contents {
margin: 30px auto;
}
.swiper-slide-thumb-active {
border-bottom: 2px solid rgb(9, 8, 53);
color: rgb(9, 8, 53) !important;
font-weight: bold;
}
補足
コンテンツ部分の「autoHeight: auto,」を設定することでコンテンツの高さをautoにしています。
こちらを設定しない場合、最も高さのあるコンテンツにすべてのコンテンツの高さが揃います。もし高さを可変にしたくない場合は、こちらの記述を削除してください。
まとめ
スマホアプリ風のスワイプやタップでのタブ切り替えメニューを作成してみました。
とにかく「Swiper」の機能の多さに感銘を受けました。