Howler.js+audioSpriteで「BGMのON/OFF切り替え」「BGM切り替え 」「 イコライザーアニメーション」をつくってみよう

Howler.js+audioSpriteで「BGMのON/OFF切り替え」「BGM切り替え 」「 イコライザーアニメーション」をつくってみよう

はっちゃん

はっちゃん

こんにちは、フロントエンドエンジニアのはっちゃんです。

最近はブラウザでさまざまなことが再現できるようになりました。たとえば、WebサイトにBGMを入れたくなるときってありますよね? その場合は、当然サウンドのON/OFFの切り替え機能を作ってユーザーに配慮することが必要になります。

しかし、弊社には「期待を超えろ」というスローガンがあります。そのまま作ることは会社的にも個人的にもプライドが許しません。

そこで今回は、単なるサウンドのオン・オフ切り替え機能にとどまらず、それをさらにパワーアップさせた「サウンド ON/OFF + BGM切り替え + イコライザーアニメーション」を作ってみようと思います。

準備するもの

BGMのコントールに重宝するHowler.js

Howler.jsはさまざまな音楽ファイルのフォーマットを扱うことができ、再生のON/OFF、ストップ、ミュートなどを簡単に実装することができるのでおすすめです。詳しくは下記の公式サイトを参照ください。

公式サイト:https://howlerjs.com/

複数の音楽ファイルをひとまとめにできるaudioSprite

audioSpriteは、複数の音楽ファイルをひとつにまとめ、一度の読み込みで管理操作するテクニック。ffmpegというフリーソフトウェアのラッパーです。

Howler.jsとの互換性もあり、複数の音楽ファイルを管理するときは必須と言っても過言ではないでしょう。

公式サイト:https://github.com/tonistiigi/audiosprite

今回の実装は、事前に今回使用する音楽ファイルをひとまとめにして書き出しておく必要があります。詳しい使い方は以前シスコくんが書いてくれているのでご一読ください。

HTML、CSSコーディング

ではコーディングしていきましょう。

まずはサウンド切り替えスイッチとイコライザー。さくっと見た目だけ作ってしまいます。

HTML

<ul class="sound-select">
  <li>
    <input type="radio" id="sound-select-01" name="sound" data-sound="sound01" class="js-sound-select" checked>
    <label for="sound-select-01">01</label>
  </li>
  <li>
    <input type="radio" id="sound-select-02" name="sound" data-sound="sound02" class="js-sound-select">
    <label for="sound-select-02">02</label>
  </li>
  <li>
    <input type="radio" id="sound-select-03" name="sound" data-sound="sound03" class="js-sound-select">
    <label for="sound-select-03">03</label>
  </li>
</ul>


<div class="equalizer-wrap">
  <input id="equalizer-switch" type="checkbox">
  <label id="js-equalizer" for="equalizer-switch" class="equalizer">
    <span></span>
    <span></span>
    <span></span>
    <span></span>
    <span></span>
  </label>
</div>

CSS

@import url(https://fonts.googleapis.com/css?family=Text+Me+One);

li {
  list-style: none;
}

.sound-select {
  display: flex;
  justify-content: center;
  padding: 85px 0 60px;
  > li {
    padding: 0 40px;
    label {
      display: block;
      font-family: 'Text Me One', sans-serif;
      font-size: 60px;
    }
  }
}

input[type=radio] {
  display: none;
}
.mute-switch {
  padding-left: 30px;
}
.equalizer-wrap {
  margin: 0 auto;
  width: 82px;
}
.equalizer {
  display: block;
  position: relative;
  width: 77px;
  height: 2px;
  padding: 10px 0;
  backface-visibility: hidden;
  span {
    position: absolute;
    top: 50%;
    transform: translateY(-50%) scale(1);
    transform-origin: center;
    height: 2px;
    width: 2px;
    background-color: #000;
    backface-visibility: hidden;
    &:nth-child(1) {
      left: 0;
      height: 8px;
      width: 77px;
      transition: height 0.2s,
      width 0.2s 0.2s;
    }
    &:nth-child(2) {
      height: 25px;
      left: 0;
      animation: equalizer 0.1s linear forwards;
    }
    &:nth-child(3) {
      height: 30px;
      left: 25px;
      animation: equalizer 0.1s linear forwards;
    }
    &:nth-child(4) {
      height: 50px;
      left: 50px;
      animation: equalizer 0.1s linear forwards;
    }
    &:nth-child(5) {
      height: 30px;
      left: 75px;
      animation: equalizer 0.1s linear forwards;
    }
  }
}
input[type=checkbox] {
  display: none;
  &:checked + label {
    width: 77px;
    height: 2px;
    span {
      width: 2px;
      transition: height 0.3s;
      &:nth-child(1) {
        transition: height 0.1s 0.1s,
        width 0.2s;
      }
      &:nth-child(2) {
        transform: translateY(-50%) scaleY(.1);
        animation: equalizer 0.8s linear infinite;
        animation-delay: 0.2s;
      }
      &:nth-child(3) {
        transform: translateY(-50%) scaleY(.15);
        animation: equalizer 0.8s linear infinite;
        animation-delay: 0.4s;
      }
      &:nth-child(4) {
        transform: translateY(-50%) scaleY(.1);
        animation: equalizer 0.8s linear infinite;
        animation-delay: 0.6s;
      }
      &:nth-child(5) {
        transform: translateY(-50%) scaleY(.15);
        animation: equalizer 0.8s linear infinite;
        animation-delay: 0.8s;
      }
    }
  }
}

@keyframes equalizer {
  0% { transform: translateY(-50%) scaleY(1); }
  100% { transform: translateY(-50%) scaleY(.15);}
}

JSコーディング

それではJSで機能を実装していきます。

作る前に、必要なイベント、関数を洗い出しておきましょう。

  • Howler.jsサウンドファイルの読み込み
    • 読み込み直後に実行する処理
  • イベント
    • サウンド切り替え
    • ミュート切り替え

あとはこれにそってコードをガンガン描いていくだけです!

// サウンドファイルの読み込み
let soundId = 'sound01';
let sound = new Howl(
  {
    src: ['https://82mou.github.io/src/sound/blog201809/sound.mp3', 'https://82mou.github.io/src/sound/blog201809/sound.ogg'],
    preload: true,
    autoplay: false,
    loop: true,
    volume: 1,
    sprite: {
      sound01: [0, 64055.98639455782],
      sound02: [66000, 518608.979591],
      sound03: [586000, 196231.836734]
    },
    onload: function () {
      sound.mute(true);
      sound.play(soundId);
    },
    onend: function () {}
  }
);

// イベント
// サウンド切り替え
let clickHandler = function(target) {
  soundId = target;
  sound.pause();
  sound.play(soundId);
}

let soundSelectTargets = document.querySelectorAll('.js-sound-select');
for (let i = 0; i < soundSelectTargets.length; i++) { var soundSelectTarget = soundSelectTargets[i]; soundSelectTarget.addEventListener('click', (e) => {
    clickHandler(e.currentTarget.dataset['sound']);
  }, false);
}

// ミュート切り替え
let equalizerInput = document.querySelector('#equalizer-switch'),
    equalizerLabel = document.querySelector('#js-equalizer');

equalizerLabel.addEventListener('click', changeHandler, false);

function changeHandler() {
  let isChecked = equalizerInput.checked;
  if(isChecked) {
    sound.mute(true);
  } else {
    sound.mute(false);
  }
}

完成

操作方法
サウンド切り替え・・・番号をクリック
ON/OFF切り替え・・・イコライザーをクリック

See the Pen howler.js + equalizer by k_hatsushi (@hatsushi_kazuya) on CodePen.

BGMを思いのままにコントロールできるようになりました。これでBGM付きWebサイト制作はばっちりですね!

まとめ

いかがでしたか? 冒頭でも書いたとおり、最近はブラウザでさまざまなことが再現できるようになり、フロントエンドに求められるものがとっても増えてきています。

ひとつずつしっかり理解して汎用性のあるコードを作り、新しいことにどんどん挑戦していけたらサイコーですね! はっちゃんでした。

LIGにWeb制作について相談してみる!

LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。

Webサイト制作の実績・料金を見る

この記事のシェア数

はっちゃん
はっちゃん フロントエンドエンジニア / 蓮子 和也

フロントエンドエンジニアのはっちゃんです。 雰囲気の良いチーム作りをしていけるよう頑張ります。 たまに外人に間違えられますが、鹿児島と千葉のハーフです。

このメンバーの記事をもっと読む
それいけ!フロントエンド | 213 articles
デザイン力×グローバルな開発体制でDXをトータル支援
お問い合わせ 会社概要DL