スクロールや変化に応じて背景色を取得してハンバーガーメニューの色を動的に変化させる方法

javascript

スマホ対応などでグローバルナビゲーションを格納しハンバーガーメニューで開閉させるといった実装は一般的によくありますが、ハンバーガーメニューを固定で配置した際にスクロース位置によって、見にくくてなるといったことはないでしょうか?
今回は、この悩みを解消するために、ハンバーガーメニューの背景の色の明るさを判別してハンバーガーメニューの色を動的に変化させる方法をご紹介します。

背景色を動的に取得してハンバーガーメニューに反映させる方法

ハンバーガーメニューを目立つようにするには、ハンバーガーメニューが表示されている部分の背景色を動的に取得して結果を反映させる必要があります。
まずは、次のソースをご確認ください。

<div id="hamburger_menu"></div>
#hamburger_menu{
position: fixed;
top:10;
left:10;
widht:50px;
heighjt:50px;
}
#hamburger_menu.dark-color{
background: #fff;
}
#hamburger_menu.light-color{
background: #000;
}
<script>
// 特定の領域のスクリーンショットを取得して平均色を計算する関数
function calculateAverageColor() {
  var targetElement = document.querySelector('#hamburger_menu');
  var elementRect = targetElement.getBoundingClientRect();
  var x = elementRect.left + window.pageXOffset;
  var y = elementRect.top + window.pageYOffset;
  var width = elementRect.width;
  var height = elementRect.height;

  html2canvas(document.body).then(function (canvas) {
    var context = canvas.getContext('2d');
    var imageData = context.getImageData(x, y, width, height);
    var data = imageData.data;
    var totalRed = 0;
    var totalGreen = 0;
    var totalBlue = 0;

    for (var i = 0; i < data.length; i += 4) {
      totalRed += data[i];
      totalGreen += data[i + 1];
      totalBlue += data[i + 2];
    }

    var pixelCount = width * height;
    var averageRed = Math.round(totalRed / pixelCount);
    var averageGreen = Math.round(totalGreen / pixelCount);
    var averageBlue = Math.round(totalBlue / pixelCount);

    var averageColor = 'rgb(' + averageRed + ', ' + averageGreen + ', ' + averageBlue + ')';

    // 平均色に基づいてクラスを追加・削除
    var targetClass = isDarkColor(averageColor) ? 'dark-color' : 'light-color';
    targetElement.classList.add(targetClass);
    targetElement.classList.remove(targetClass === 'dark-color' ? 'light-color' : 'dark-color');
  });
}

// 色が暗いかどうかを判定する関数
function isDarkColor(color) {
  // カラーをRGBの各値に分解
  var rgb = color.replace(/[^\d,]/g, '').split(',');

  // RGB値を0-255の範囲に正規化して明るさを計算
  var brightness = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;

  // 明るさが128未満なら暗い色と判定
  return brightness < 128;
}

// スクロールイベントとリサイズイベントで平均色を再計算
window.addEventListener('scroll', calculateAverageColor);
window.addEventListener('resize', calculateAverageColor);

// 初回の平均色計算を実行
calculateAverageColor()
</script>

上記のコードでは、#hamburger_menuをハンバーガーメニューに見立てています。今回はなじみのある3本線のデザインではなく仮でただの正方形として配置します。
#hamburger_menu に対して、スクロールとリサイズのイベントに基づいて背景色を動的に切り替える機能を実装しています。

まず、#hamburger_menu のスタイルが定義されています。これにより、要素が固定されてページ上の特定の位置に配置され、幅と高さが50ピクセルに設定されます。また、.dark-color.light-color のクラスも定義され、それぞれ異なる背景色を持ちます。

calculateAverageColor() 関数は、指定された要素の範囲内のスクリーンショットを取得し、その範囲の平均色を計算します。html2canvas ライブラリを使用してページ全体のスクリーンショットを取得し、指定した要素の位置とサイズを基に必要な領域を切り抜きます。その後、各ピクセルのRGB値を合計し、平均値を計算します。

isDarkColor() 関数は、与えられた色が暗い色かどうかを判定します。RGB値を取得し、明るさを計算して、明るさが128未満の場合には暗い色と判定します。
スクロールイベントとリサイズイベントのハンドラには、calculateAverageColor() 関数が登録されています。つまり、スクロールやウィンドウのサイズ変更が発生するたびに平均色を再計算します。これにより、要素の表示範囲が変わった場合でも正確な平均色を取得できます。

また、初回の平均色計算を行うために、calculateAverageColor() 関数が直接呼び出されています。

以上のコードを使用することで、#hamburger_menu の背景色がスクロールやリサイズに応じて適切に切り替わるようになります。平均色に基づいて .dark-color.light-color のクラスが追加され、対応する背景色が適用されます。