Memorandum 

  1. Home
  2. Memorandum
  3. Detail

動画実装のベストプラクティス2023

videoタグで動画を実装する時のベストプラクティス(たぶん)2023。

HTMLはこんな感じで、JavaScriptを使用してvideoタグを生成し挿入するやり方です。
代替画像や動画が始まったかときを監視するので、videoタグの生成自体もJavaScriptで行います。

<section class="home-kv"></section>
const root = './';

const playVideo = {
    kv        : document.querySelector('.home-kv'),
    sourcePc  : root + 'assets/video/pv-pc.mp4',
    sourceSp  : root + 'assets/video/pv-sp.mp4',
    img       : root + 'assets/img/home/kv_bg.jpg',
    videoClass: 'home-kv__video',
    imgClass  : 'home-kv__bg',
    init: function(){
        const _this = playVideo;

        if( document.querySelector('.' + _this.videoClass) ){
            return false;
        }

        _this.setVariable();
        _this.createVideo();
        _this.onPlaying();
    },
    setVariable: function(){
        const _this = playVideo;

        /* ---------- sourse ---------- */
        if( navigator.userAgent.match(/(iPhone|Android)/) ){
            _this.source = _this.sourceSp;
        } else{
            _this.source = _this.sourcePc;
        }
    },
    createVideo: function(){
        const _this = playVideo;

        const videoTag = '<video muted webkit-playsinline playsinline loop preload="auto" type="video/mp4" src="' + _this.source + '" class="c-objectfit-video '+ _this.videoClass +'"></video>';
        _this.kv.insertAdjacentHTML('beforeend', videoTag );

        _this.video = document.querySelector('.' + _this.videoClass);


        /* ---------- 低電力モードなら画像に代替 ---------- */
        _this.video.play()
        .then(() => {
        })
        .catch((error) => {
            const img = '<img src="'+ _this.img +'" alt="" decoding="async" class="c-objectfit -cover '+ _this.imgClass +'">';
            _this.kv.insertAdjacentHTML('beforeend', img );
            _this.kv.removeChild( _this.video );
            _this.kv.classList.add('type-img');
        });
    },
    onPlaying: function(){
        const _this = playVideo;

        /* ---------- playing ---------- */
        const onPlaying = function(){
            _this.kv.classList.add('is-shown');
            _this.video.classList.add('is-shown');
            _this.video.removeEventListener('playing',onPlaying);
        }
        _this.video.addEventListener('playing',onPlaying);
    }
}

window.addEventListener('DOMContentLoaded',function(){
    playVideo.init();
});

ポイント1: userAgentを使用して動画を振り分ける

パフォーマンスや再生品質の向上の為、閲覧環境によって、適切な動画を提供することが重要です。
JavaScriptのuserAgentを使って、閲覧者のデバイスやブラウザ情報を取得し、適切な動画ファイルを振り分けます。

setVariable: function(){
    const _this = playVideo;

    /* ---------- sourse ---------- */
    if( navigator.userAgent.match(/(iPhone|Android)/) ){
        _this.source = _this.sourceSp;
    } else{
        _this.source = _this.sourcePc;
    }
 },

ポイント2: playingイベントを利用して動画に開始クラスを付与する

動画の再生を開始した時に特定のクラスを追加することで、カスタムスタイルを適用したり、アニメーションを開始したりすることができます。
playingイベントを監視し、動画が再生された瞬間に開始クラスを付与する方法が効果的です。

onPlaying: function(){
    const _this = playVideo;

    /* ---------- playing ---------- */
    const onPlaying = function(){
        _this.kv.classList.add('is-shown');
        _this.video.classList.add('is-shown');
        _this.video.removeEventListener('playing',onPlaying);
    }
    _this.video.addEventListener('playing',onPlaying);
}

ポイント3: 自動再生がブロックされる場合の処理

iPhoneの低電力モードなどの状況では、動画の自動再生がブロックされることがあります。
その場合、再生アイコンが中央に表示され不恰好です。
この問題を回避するために、video.play().catch((error) => {のようなコードを使用して、動画が再生されない場合にはvideoタグを削除し、代替画像を表示するようにしています。

/* ---------- 低電力モードなら画像に代替 ---------- */
_this.video.play()
.then(() => {
})
.catch((error) => {
    const img = '<img src="'+ _this.img +'" alt="" decoding="async" class="c-objectfit -cover '+ _this.imgClass +'">';
    _this.kv.insertAdjacentHTML('beforeend', img );
    _this.kv.removeChild( _this.video );
    _this.kv.classList.add('type-img');
});