現在、もっともポピュラーでカスタマイズ性が高く実装が簡単な、レスポンシブ対応のスライドショーjQueryモジュールである「slick.js」。
弊社にて提供中のWordPressテーマ「DigiPress」シリーズの次期テーマには、トップページのスライダーに動画を含めることが要件としてあるため、今回はそんな人気のスライドショーモジュール「slick.js」を利用して、画像だけでなくYouTube、Vimeo、さらにHTML5のvideo要素の動画もスライドとして含める方法を、次期リリース予定のテーマ向けに考えてみました。
今回のデモで動画スライドを含めたスライドショーを実装する要件は以下です。
スライドに動画を含める要件
- 動画は、YouTube、Vimeo、video要素のムービーを含めることができる
- 動画スライドが表示された際は、自動再生させる
- 動画スライドが非アクティブになった際は、一時停止する(複数の動画を同時に再生させない、無駄な通信負荷をしないため)
- 音声はミュート(再生時に音を出さない)
- YouTubeとVimeoは再生開始位置を指定できる
- レスポンシブに対応(常に動画の中心を基点に伸縮する)
これらの要件を満たす動画スライドを含めた「slick.js」のスライドショーの完成デモがこちら。
See the Pen Slick Slider with auto play YouTube, Vimeo and HTML5 video by digistate (@digistate) on CodePen.
このスライダーを実装するための要点を以下に解説します。
下準備
まずは大前提、「slick.js」を利用するために必要jQuery、そして「slick.js」本体を読み込んでおきます。
CSSは、最低限のslick.min.cssだけを読み込みます。
CSS
CSSはhead
セクション内に「slick.min.css」を定義します。
<head> : <link href="slick.min.css" media="screen" rel="stylesheet" type="text/css" /> : </head>
Javascript
Javascriptは、</body>
の前にjquery.min.jsとslick.min.jsを挿入します。
<script src="jquery.min.js"></script> <script src="slick.min.js"></script>
CDN経由であれば、以下のようにします。
<link href="//cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.css" media="screen" rel="stylesheet" type="text/css" />
<script src="//code.jquery.com/jquery-2.2.4.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.js"></script>
jQueryのCDNはこちら、slick.jsのCDNはこちら。
HTMLの構成
スライダー部分のHTMLの大まかな構成は、以下のようにしています。
<section class="main-slider"> <div class="item"> <!-- スライドコンテンツ(イメージまたはビデオ) --> </div> <div class="item"> <!-- スライドコンテンツ(イメージまたはビデオ) --> </div> : </section>
.main-slider
が「slick.js」でスライダー化の対象とするメインのセクションです。
その中にある、.item
セレクタのdiv要素が、それぞれのスライドとなる部分です。
画像スライドの場合
画像スライドの場合は、以下のHTML構成をベースとします。
<div class="item image"> <figure> <div class="slide-image slide-media" style="background-image:url(画像URL);"> <img data-lazy="画像URL" class="image-entity" /> </div> </figure> </div>
画像スライドの場合は、.item
セレクタのdiv要素に.image
セレクタも付けておきます。
figure
要素内で画像(img
)を挿入していますが、 今回のスライダーのデモではフルワイドでスライダーの高さは表示幅(ビューポート)に比例して可変するリキッドレイアウトとしており、画像の中心を基点としてレスポンシブ表示になるようにすることと、「slick.js」のlazyLoadオプションで、スライドショーの画像要素がロードされたことを検出させるため、img
要素自体はありますがCSSで見えないようにしています。
実際の画像は、img
要素を括っている.slide-image
セレクタのdiv要素のbackground-image
で表示しています。
Vimeoの埋め込み動画スライドの場合
Vimeoの埋め込みコード(iframe)をスライドコンテンツとするには以下のようにします。
<div class="item vimeo" data-video-start="再生開始秒数"> <iframe class="embed-player slide-media" src="https://player.vimeo.com/video/動画ID?api=1&byline=0&portrait=0&title=0&background=1&mute=1&loop=1&autoplay=0" width="980" height="520" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> </div>
Vimeoの動画スライドの場合は、.item
セレクタのdiv要素に.vimeo
セレクタも付けておきます。
Vimeoの動画パラメータ
Vimeoのiframe
コードでは、src
属性に動画URLと共に様々なパラメータを付けて埋め込みプレイヤーや動画の再生条件を指定できます。
今回のスライダーで利用するパラメータは以下を指定しています。
- api=1 : APIを利用
- byline=0 : 動画の投稿者を非表示
- portrait=0 : Vimeoロゴを非表示
- title=0 : 動画タイトルを非表示
- background=1 : 再生ボタンやシークバーなどのコントローラーを非表示
- mute=1 : 消音で動画を再生
- loop=1 : ループ再生
- autoplay=0 : 自動再生しない
URLは以下の書式になり、あとはスライドに表示したい動画のIDを指定するだけで使いまわしができます。
https://player.vimeo.com/video/動画ID?api=1&byline=0&portrait=0&title=0&background=1&mute=1&loop=1&autoplay=0
再生開始位置(秒数)の指定
特定の位置から動画の再生を開始したい場合は、Vimeoでは先述のURLの引数に #t
というパラメータに時間の値を含めれば指定の位置から再生できるのですが、なぜか他のパラメータが動作しなくなってしまうため、再生開始位置の指定はAPI(postMessage)を利用します。
HTMLでは、後述するJavascriptで再生開始位置を取得できるよう、data属性に動画の先頭からの経過秒数を必要に応じて指定します。
<div class="item vimeo" data-video-start="再生開始秒数">
YouTubeの埋め込み動画スライドの場合
YouTubeの埋め込みコード(iframe)をスライドコンテンツとするには以下のようにします。
<div class="item youtube"> <iframe class="embed-player slide-media" src="https://www.youtube.com/embed/動画ID?enablejsapi=1&controls=0&fs=0&iv_load_policy=3&rel=0&showinfo=0&loop=1&playlist=動画ID&start=再生開始秒数" width="980" height="520" frameborder="0" allowfullscreen></iframe> </div>
YouTubeの動画スライドの場合は、.item
セレクタのdiv要素に.youtube
セレクタも付けておきます。
YouTubeの動画パラメータ
Vimeoと同様に、YouTubeのiframe
コードにも、src
属性に動画URLと共に様々なパラメータを付けて埋め込みプレイヤーや動画の再生条件を指定できます。
今回のスライダーで利用するパラメータは以下を指定しています。
- enablejsapi=1 : APIを利用
- fs=0 : 全画面表示ボタンを非表示
- iv_load_policy=3 : 動画アノテーションを非表示
- rel=0 : 関連動画を非表示
- showinfo=0 : 動画のタイトルや投稿者情報を非表示
- loop=1 : ループ再生
- playlist=動画ID : loopパラメータでループ再生する際は、playlistパラメータに同じ動画IDを指定
- start=再生開始秒数 : 動画の再生開始位置(動画の先頭からの経過秒数)
URLは以下の書式になり、あとはスライドに表示したい動画のIDを指定するだけで使いまわしができます。
https://www.youtube.com/embed/動画ID?enablejsapi=1&controls=0&fs=0&iv_load_policy=3&rel=0&showinfo=0&loop=1&playlist=動画ID&start=再生開始秒数
HTML5 video要素の動画スライドの場合
サーバー上にある動画ファイルをHTML5のvideo要素としてスライドコンテンツとするには以下のようにします。
<div class="item video"> <video class="slide-video slide-media" loop muted preload="metadata" poster="プレイヤーを表示できない場合の代替表示画像URL"> <source src="mp4ムービーファイルのURL" type="video/mp4" /> </video> </div>
video要素には、webmとmp4の両方のフォーマットのファイルを指定することが一般的ですが、現在の主要なブラウザ環境ではmp4だけ指定しておけば再生できるため、webm形式の指定はしていません。
video要素のパラメータ
video要素には、以下の属性を指定しています。
- loop : ループ再生
- muted : 消音で動画を再生
- preload=”metadata” : ページ表示時、動画のメタデータのみを読み込み(動画をバックグラウンドで読み込ませない)
- poster=”プレイヤーを表示できない場合の代替表示画像URL”
動画スライドに関するCSS
iframe
内に表示される埋め込み動画については、CSSでレイアウトを制御できないため、後述のJavascriptで制御します。
video
要素の動画については、以下のCSSで表示エリアに常にフィットさせると同時に、動画の中心を基点にしてアスペクト比を保持してレスポンシブ表示にできます。
.slick-slide video { display: block; position: absolute; top: 50%; left: 50%; min-width: 100%; min-height: 100%; width: auto; height: auto; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%); }
上記のCSSによって、スライダーの表示エリアがどのように伸縮しても、常にエリアの中心(top:50%, left:50%)がvideo要素の原点となり、CSSのtransform
パラメータで動画自身を左(X)と上(Y)に-50%移動することで、動画の中心を常に基点としてレスポンシブ表示するようにしています。
このCSSの手法はよく利用される方法で、画像(img)の場合でも利用できます。
Javascript(jQuery)
「slick.js」を利用するので、スライダー自体の生成と制御はとても簡単です。
スライダーの生成
スライダーのメイン要素である.main-slider
セレクタをslick.jsに対象として渡してあげる、ごくシンプルなslickスライダーの生成です。
$(".main-slider").slick({ autoplaySpeed:4000, // スライド表示時間 speed:600, // スライドの切り替え時間 lazyLoad:"progressive", // バックグラウンドでスライド画像をロード arrows:false, dots:true });
その他、指定できるスライダーのパラメータについてはこちら。
slickスライダーイベント
slickスライダーのイベントのうち、今回利用するのは、スライダーの初期化が完了した際に発生する init
イベント、スライドが切り替わる直前に発生する beforeChange
イベント、スライドが切り替わった直後に発生する afterChange
イベントです。
スライダーの初期化完了時のイベント
スライダーの初期化が完了した際は、まずは対象のスライダーを取得し、別途用意している動画の再生と一時停止をする処理(playPauseVideo)に対して再生を指示し、現在のスライダー表示エリアに対するiframeの埋め込み動画の表示サイズと位置を決定する処理(resizePlayer)を実行します。
$(".main-slider").on("init", function(slick){ // スライダーオブジェクトを取得 slick = $(slick.currentTarget); // 動画スライドの再生(1枚目のスライドが動画である場合) setTimeout(function(){ playPauseVideo(slick,"play"); }, 1000); // iframeの埋め込み動画の表示サイズと位置を決定 resizePlayer(iframes, 16/9); });
スライドが切り替わる直前のイベント
スライドが切り替わる際には、動画スライドの場合は再生状態を解除し、一時停止させます。
$(".main-slider").on("beforeChange", function(event, slick) { slick = $(slick.$slider); // 現在の動画スライドに対して一時停止させる(カレントが動画スライドである場合) playPauseVideo(slick,"pause"); });
スライドが切り替わった直後のイベント
スライドが切り替わった際には、動画スライドの場合は一時停止を解除し、途中から再び再生を開始させます。
$(".main-slider").on("afterChange", function(event, slick) { slick = $(slick.$slider); // 現在の動画スライドに対して再生を開始(カレントが動画スライドである場合) playPauseVideo(slick,"play"); });
iframeの埋め込み動画のサイズと位置を調整するための関数
VimeoとYouTubeのiframe要素による埋め込み動画の位置と表示サイズは、スライダーの表示サイズに合わせて上下左右に余白部分がでないように動画を伸縮させるため、専用の関数(resizePlayer)をつくります。
function resizePlayer(iframes, ratio) { if (!iframes[0]) return; var win = $(".main-slider"), width = win.width(), playerWidth, height = win.height(), playerHeight, ratio = ratio || 16/9; iframes.each(function(){ var current = $(this); if (width / ratio < height) { playerWidth = Math.ceil(height * ratio); current.width(playerWidth).height(height).css({ left: (width - playerWidth) / 2, top: 0 }); } else { playerHeight = Math.ceil(width / ratio); current.width(width).height(playerHeight).css({ left: 0, top: (height - playerHeight) / 2 }); } }); }
この関数は、スライダーが初期化されたときと、ブラウザのウィンドウサイズが変更(リサイズイベント)されたときに呼び出します。
再生/一時停止用の関数をつくる
slickスライダーの各イベントで呼び出している、動画の再生と一時停止を行うメイン関数(playPauseVideo)をつくります。
この関数の1番目の引数にはスライダー本体のオブジェクトを、2番目には再生か一時停止かを指示するフラグ(play/pause)を指定します。
function playPauseVideo(slick, control){ var currentSlide, slideType, startTime, player, video; // 現在のスライドを取得 currentSlide = slick.find(".slick-current"); // 現在のスライドのclass属性に指定の値から2番目のセレクタ(スライドのタイプ)を取得 slideType = currentSlide.attr("class").split(" ")[1]; // iframeオブジェクトを取得 player = currentSlide.find("iframe").get(0); // 再生開始位置(data-video-start)を取得(vimeoのみ) startTime = currentSlide.data("video-start"); if (slideType === "vimeo") { // 現在のスライドがVimeoの場合 switch (control) { case "play": // 再生処理 break; case "pause": // 一時停止処理 break; } } else if (slideType === "youtube") { // 現在のスライドがYouTubeの場合 switch (control) { case "play": // 再生処理 break; case "pause": // 一時停止処理 break; } } else if (slideType === "video") { // 現在のスライドがvideoの場合 // videoオブジェクトを取得 video = currentSlide.children("video").get(0); if (video != null) { if (control === "play"){ // 再生 video.play(); } else { // 一時停止 video.pause(); } } } }
再生/一時停止の指示をAPI経由でPOSTする関数
再生と一時停止をAPIにPOSTする処理は、VimeoとYouTube共通で利用可能な関数(postMessageToPlayer)として別途用意しています。
function postMessageToPlayer(player, command){ if (player == null || command == null) return; player.contentWindow.postMessage(JSON.stringify(command), "*"); }
Vimeoの再生処理
Vimeoの場合、URLパラメータに再生開始位置(#t)を指定すると他のパラメータが解釈されなくなるため、指定(data-video-start
)がある場合はAPI経由で再生開始位置をセットします。
その後、API経由で再生を開始します。
// 再生開始位置の指定があり、初めて再生を行う場合のみ if (startTime != null && !currentSlide.hasClass('started')) { currentSlide.addClass('started'); // 再生開始位置をセット postMessageToPlayer(player, { "method": "setCurrentTime", "value" : startTime }); } // 再生開始 postMessageToPlayer(player, { "method": "play", "value" : 1 });
Vimeoの一時停止処理
VimeoのAPIに一時停止を指示する際は、method
は pause
を指定します。
postMessageToPlayer(player, { "method": "pause", "value": 1 });
その他、VimeoのPlayer APIで指定できるメソッドの種類はこちら。
YouTubeの再生処理
YouTubeの場合、URLパラメータにミュートの指定ができないため、再生を開始する前にAPI経由でミュートを指示してから再生を開始します。
postMessageToPlayer(player, { "event": "command", "func": "mute" // ミュート }); postMessageToPlayer(player, { "event": "command", "func": "playVideo" // 再生 });
YouTubeの一時停止処理
一時停止する際は、pauseVideo を指示します。
postMessageToPlayer(player, { "event": "command", "func": "pauseVideo" });
その他、YouTube Player APIによるコマンドについてはこちら。
video要素の再生/一時停止処理
video要素の場合は、video.play()
で再生、video.pause()
で一時停止です。シンプル。
随分、ざっくりと解説しましたが、以上のHTML、CSS、Javascriptの構成によって、slickスライダーにVimeoとYouTubeのiframe埋め込みプレイヤーと、HTML5 のvideo要素の動画をスライドとして組み込んで自動再生させることができました。
おまけ
スライダーのトランジションはフェードイン・アウトにして、すべてのスライド画像が読み込まれた時点でスライドショーを自動で開始させた場合のデモはこちら。
See the Pen Slick Slider with auto play YouTube, Vimeo and HTML5 video (Fade-in/out) by digistate (@digistate) on CodePen.
slick sliderよりも高機能でjQuery不要の「Swiper.js」のサンプルコードも公開しています。