TOP » WEB » javascript » swiper.jsでスマホアプリのようなUIを実装する
swiper.jsでスマホアプリのようなUIを実装する

swiper.jsでスマホアプリのようなUIを実装する

スマホアプリのようなUIをWEBサイトにも実装したい

最近PWAに対応したサイトを作成した際にUIを極力スマホアプリっぽくして欲しいといわれた時に実装した方法を備忘録も兼ねて紹介しようと思います。

先方の要望としてはスマホアプリでよく見るような横並びのカテゴリー別メニューがあり、メニューをタップするかメニュー下のコンテンツ部分を左右にスワイプすることでページ遷移せずに内容を切り替えたいということらしい。

よく見るかと言われればそうでもないような気もするが、確かに何度かその手のUIにはお目にかかったことがあると思います。
簡易的なものになりますが、つまりはこういう感じですね。

デモページ

メニューと該当するコンテンツが連動していて、コンテンツを切り替えるとメニューも一緒に選択中のメニューへとスライドして、ユーザーに今なにを選択しているのか分かりやすくしています。

swiper.jsでスライダー化

要はメニュー部分とコンテンツ部分を2つのスライダーに分けて、その動きを連動するようにしているだけの話です。
今回そのスライダーを実装するのに「Swiper」というjavascriptのスライダーを使用しました。

Swiper

Swiperはjqueryに依存しないため、Swiper単品で動作させることができます。また画像の遅延読み込みや3Dエフェクトだったりパララックス効果だったり、様々なオプションを使用することができる高機能スライダーで、およそスライダーで使用したい機能は揃っているんじゃないでしょうか。
今回それらの高機能なオプションをほとんど使っていないので紹介はできないですが、サイトに各機能のデモページも用意されているので気になる人は確認してみるといいですね。

Swiper

必要なファイルの読み込み

それではまずSwiperを使うにあたって必要なファイルを読み込ませます。

Swiperのjsファイルとcssファイルをサイトからgithub経由でダウンロードしてくるか、CDNで読み込むこともできます。
ここはお好きな方法で読み込んでください。

ちなみに冒頭でSwiperはjqueryを使用しないでも動くと書きましたが、今回は処理の一環で使ってます。なのでCDNでjqueryも併せて読み込んでいます。
あと上記では「swiper.min.js」もhead内で読み込んでいますが、本当は</body>直前に読み込ませる方が良いでしょう。

メニュー部分の用意

Swiperが読み込めたら次にメニュー部分となるhtmlを用意します。
Swiperはメインの囲みとなる「swiper-container」とスライダーを内包するための「swiper-wrapper」、スライダー要素となる「swiper-slide」の3つの要素で成り立っています。
これらを踏まえてメニュー部分となるスライドを下記のようにします。

「swiper-container」にもう一つ「swiper-navigation」というクラスを指定していますが、これはコンテンツ部分となるもう一つのスライダーと差別化するためのクラスなので、別に任意の名前でも大丈夫です。
また1つ目の「swiper-slide」には選択中を表す「selected」のクラスを指定します。
Swiperはデフォルトで選択中のスライドに対して「swiper-slide-active」というクラスがつきますが、今回メニュー部分のスライドに対して設定するオプション「freeMode」を指定している場合、選択中というよりは画面左端に来ている要素に対して「swiper-slide-active」がつくようで、左端に寄せようがない最後の方のメニュー対しては「swiper-slide-active」が付けられないのでデフォルトとは別に選択中を表すクラス「selected」を1つ目の「swipe-slide」に指定しています。

htmlの用意ができたらSwiperの設定をしていきます。
次の記述をhead内か外部jsファイルとして読み込みます。

まずスライダーの高さを正確に取得するために、window.onloadで全てのhtmlの読み込み終わってから処理を開始します。(公式ではこの方法は推奨しませんとありますが…)
最初に現在選択中のスライドに対して「selected」を付与する関数「setCurrentSlide」を定義しておきます。

次にSwiperの初期化を行ないます。
「new Swiper」の第一引数にメニューとなる要素のクラス「.swiper-navigation」を指定して、第二引数でオプションを指定します。
指定するオプションは以下の通りです。

  • slidesPerView…画面内に見せるスライドの数を指定します。今回は数を指定させないので「’auto’」とします。
  • freeMode…スライドがスライダー単位ではなくなる?とりあえずfalseとします。
  • loop…スライドをループさせるかどうか。メニューループさせちゃうとすごく分かりづらくなっちゃうので今回はfalseとします。
  • autoplay…勝手にスライドされたら困るのでこれもfalseです。

これでメニュー部分のSwipeの初期化は完了です。
次にメニュースライド1つ1つに対してクリックした時の処理を指定します。

「swiperNavigation.slides.each」で内包するスライド全てに対して「on(“click”,function())」でクリックした時に最初に定義した関数「setCurrentSlide」を実行する処理を指定します。

あとはcssで見た目を整えるんですが、「.swiper-navigation .swiper-slide」には必ず「width: auto;」としておきましょう。
そうしないとメニュースライド1つ1つが画面幅一杯になってしまいます。

今回は以下のようなcssを設定しています。

これでメニュー部分は以下のような感じに仕上がります。

デモページ2

ちゃんとクリックで選択中のスライドに「selected」が付与されていますか?

コンテンツ部分の用意

メニューのスライダーが完成したので次はそれに連動させるコンテンツ部分のスライダーを作成していきます。
先ほどの「swiper-navigation」の直下に次のhtmlを追加します。

今度のスライダーには「swiper-container」に対して「swiper-contents」のクラスを付与しています。
またコンテンツ部分は画面の1つのスライドしか表示させないので選択中のクラスを表す「selected」は不要です。

それではメニューと同じようにコンテンツ部分に対してもSwipeの初期化の記述をしていきましょう。
先ほどのscriptに追加でonload内に以下の記述をします。

今度のSwiperには以下のオプションを指定します。

  • loop…メニュー部分と同じです。ループさせる必要はないのでfalseとします。
  • autoHeight…trueとすると現在選択中の要素の高さに囲みの高さを合わせます。

次にコンテンツスライダーをスライドさせた時にメニューのスライドも同期してスライドするためのイベントを登録します。
Swiperにはスライドさせた時のイベント「slideChange」が用意されているので、onメソッドに指定します。
現在処理中のスライドのインデックス番号を取得してそれをメニュースライドと同じインデックス番号のスライダーに対して「setCurrentSlide」関数を実行して「selected」を切り替えます。
そしてメニュースライドを指す「swiperNavigation」に対して「slideTo」メソッドを実行して同じインデックス番号のスライダーにスライドさせます。

今の状態だとコンテンツ部をスライドさせた時はメニューと同期できていますが、逆にメニューを選択した時のコンテンツとの同期ができていません。
なので「ele.on(“click”,…)」の末尾に下記の処理を追加します。

これでメニューとコンテンツ部分の同期ができたので完成となります。

デモページ3

【おまけ】要素が追加されて囲み要素の高さが変わった際の対応

例えば下記の記事のように要素を後から追加した場合、囲み要素の高さからはみ出してしまい、はみ出した部分が切れた状態になってしまいます。

下記のデモに要素を追加するボタンを用意したので、実際に確認してみてください。1回ボタンを押すとボタンが見切れてしまい、2回も押そうものなら完全に隠れてしまうことが分かると思います。

デモページ4

なので、要素が追加された時点でSwiperに再計算をしてもらうようにする必要があります。
そんな時は「update」メソッドを使うことで解決します。
「prepend」で要素を追加した後に「swiperContents.update()」とするだけです。

デモページ5

どうでしょう、今度は見切れなくなったと思います。

最終コード

最後に最終的なコードを掲載しておきますので何かのお役に立てれば幸いです。