Blogブログ

css

2024.11.13

メインカラーが決まったら-webデザインの色の配色・背景色と文字色、コントラスト比についての解説。

カラーパレットとコントラスト比チェック:コードの詳細解説

以下は、今回完成したカラーパレットとコントラスト比チェックのHTML・JavaScriptコードについて、各部分を詳細に解説したものです。


<!DOCTYPE html>
<html lang="ja">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>カラーパレットとコントラスト比チェック</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      background-color: #f5f5f5;
      padding: 20px;
    }

    .container {
      max-width: 800px;
      margin: 0 auto;
    }

    .section {
      margin: 20px 0;
    }

    .palette-block {
      display: flex;
      flex-wrap: wrap;
      gap: 10px;
      justify-content: space-around;
    }

    .color-block {
      width: 100px;
      height: 120px;
      display: flex;
      align-items: center;
      justify-content: center;
      flex-direction: column;
      border-radius: 8px;
      transition: background-color 0.3s, color 0.3s;
      text-align: center;
      padding: 5px;
    }

    .error-message {
      font-size: 10px;
      color: red;
      margin-top: 5px;
      text-align: center;
      visibility: hidden;
    }

    input[type="color"],
    input[type="text"] {
      width: 100%;
      height: 40px;
      margin: 5px 0;
      padding: 5px;
      box-sizing: border-box;
    }
  </style>
</head>

<body>

  <div class="container">
    <div class="section">
      <div>メインカラーのpick</div>
      <input type="color" id="main-color" value="#3498db">
    </div>

    <div class="section">
      <div>文字色のpick</div>
      <input type="color" id="text-color" value="#ffffff">
    </div>

    <div class="section">
      <div>コントラスト比の入力</div>
      <input type="text" id="contrast-threshold" value="4.5">
    </div>

    <div class="section">
      <div>補色カラーパレット</div>
      <div class="palette-block" id="complementary-palette"></div>
    </div>

    <div class="section">
      <div>分割補色カラーパレット</div>
      <div class="palette-block" id="split-complementary-palette"></div>
    </div>

    <div class="section">
      <div>トライアドカラーパレット</div>
      <div class="palette-block" id="triadic-palette"></div>
    </div>

    <div class="section">
      <div>モノクロマティックカラーパレット</div>
      <div class="palette-block" id="monochromatic-palette"></div>
    </div>
  </div>

  <script>
    const textColorPicker = document.getElementById('text-color');
    const contrastThresholdInput = document.getElementById('contrast-threshold');
    const complementaryPalette = document.getElementById('complementary-palette');
    const splitComplementaryPalette = document.getElementById('split-complementary-palette');
    const triadicPalette = document.getElementById('triadic-palette');
    const monochromaticPalette = document.getElementById('monochromatic-palette');

    function hexToRgb(hex) {
      const bigint = parseInt(hex.slice(1), 16);
      return [(bigint >> 16) & 255, (bigint >> 8) & 255, bigint & 255];
    }

    function rgbToHex([r, g, b]) {
      return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase()}`;
    }

    function luminance(r, g, b) {
      const a = [r, g, b].map(v => {
        v /= 255;
        return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
      });
      return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
    }

    function contrastRatio(rgb1, rgb2) {
      const lum1 = luminance(...rgb1) + 0.05;
      const lum2 = luminance(...rgb2) + 0.05;
      return lum1 > lum2 ? lum1 / lum2 : lum2 / lum1;
    }

    function createColorBlock(color) {
      const blockWrapper = document.createElement('div');

      const block = document.createElement('div');
      block.className = 'color-block';
      block.style.backgroundColor = color;

      const colorText = document.createElement('span');
      colorText.innerHTML = `<span style="color: ${textColorPicker.value}">テキスト</span>`;

      const colorPicker = document.createElement('input');
      colorPicker.type = 'color';
      colorPicker.value = color;

      const errorMessage = document.createElement('div');
      errorMessage.className = 'error-message';
      errorMessage.textContent = 'コントラスト比が合いません';

      block.appendChild(colorText);
      block.appendChild(colorPicker);
      blockWrapper.appendChild(block);
      blockWrapper.appendChild(errorMessage);

      colorPicker.addEventListener('input', () => {
        const newColor = colorPicker.value;
        block.style.backgroundColor = newColor;
        updateBlockColor(blockWrapper, newColor);
      });

      updateBlockColor(blockWrapper, color);
      return blockWrapper;
    }

    function updateBlockColor(wrapper, bgColorHex) {
      const bgColor = hexToRgb(bgColorHex);
      const textColor = hexToRgb(textColorPicker.value);
      const ratio = contrastRatio(bgColor, textColor);
      const threshold = parseFloat(contrastThresholdInput.value) || 4.5;

      const errorMessage = wrapper.querySelector('.error-message');
      if (ratio < threshold) {
        errorMessage.style.visibility = 'visible';
      } else {
        errorMessage.style.visibility = 'hidden';
      }
    }

    function displayPalette(element, colors) {
      element.innerHTML = '';
      colors.forEach(color => {
        const block = createColorBlock(color);
        element.appendChild(block);
      });
    }

    function generateComplementaryColor(hex) {
      const [r, g, b] = hexToRgb(hex);
      return rgbToHex([255 - r, 255 - g, 255 - b]);
    }

    function generateSplitComplementaryColors(hex) {
      const [r, g, b] = hexToRgb(hex);
      return [rgbToHex([r, 255 - g, b]), rgbToHex([255 - r, g, 255 - b])];
    }

    function generateTriadicColors(hex) {
      const [r, g, b] = hexToRgb(hex);
      return [rgbToHex([b, r, g]), rgbToHex([g, b, r])];
    }

    function generateMonochromaticColors(hex) {
      const [r, g, b] = hexToRgb(hex);
      return [rgbToHex([r * 0.8, g * 0.8, b * 0.8]), rgbToHex([r * 1.2, g * 1.2, b * 1.2])];
    }

    function updatePalettes() {
      const mainColor = document.getElementById('main-color').value;
      displayPalette(complementaryPalette, [generateComplementaryColor(mainColor)]);
      displayPalette(splitComplementaryPalette, generateSplitComplementaryColors(mainColor));
      displayPalette(triadicPalette, generateTriadicColors(mainColor));
      displayPalette(monochromaticPalette, generateMonochromaticColors(mainColor));
    }

    document.getElementById('main-color').addEventListener('input', updatePalettes);
    textColorPicker.addEventListener('input', updatePalettes);
    contrastThresholdInput.addEventListener('input', updatePalettes);
    updatePalettes(); // 初期化
  </script>

</body>

</html>


目次

  1. HTML構造の解説
  2. CSSスタイルの解説
  3. JavaScriptの機能解説
  4. イベントリスナーの仕組み
  5. コントラスト比チェックの詳細
  6. 動作の流れ

1. HTML構造の解説

HTML部分は、UIとして「メインカラー」「文字色」「コントラスト閾値」を入力するセクションと、補色・分割補色・トライアド・モノクロマティックのカラーパレットを表示するための各ブロックを用意しています。

重要なHTML部分

<div class="container">
  <div class="section">
    <div>メインカラーのpick</div>
    <input type="color" id="main-color" value="#3498db">
  </div>

  <div class="section">
    <div>文字色のpick</div>
    <input type="color" id="text-color" value="#ffffff">
  </div>

  <div class="section">
    <div>コントラスト比の入力</div>
    <input type="text" id="contrast-threshold" value="4.5">
  </div>

  <div class="section">
    <div>補色カラーパレット</div>
    <div class="palette-block" id="complementary-palette"></div>
  </div>
</div>

解説

  • input タグ:メインカラー、文字色、コントラスト閾値をそれぞれ input フィールドで取得しています。
  • パレットブロック:各カラーパレット(補色、分割補色、トライアド、モノクロマティック)が、<div class="palette-block"> の中で色ブロックとして表示されます。

2. CSSスタイルの解説

このコードでは、ブロックの見た目を整え、エラーメッセージのスタイルも設定しています。

重要なCSS部分

.color-block {
width: 100px;
height: 120px;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
border-radius: 8px;
transition: background-color 0.3s, color 0.3s;
text-align: center;
padding: 5px;
}

.error-message {
font-size: 10px;
color: red;
margin-top: 5px;
text-align: center;
visibility: hidden;
}

解説

.color-block:各色ブロックは100×120ピクセルの正方形で、色が変わるとスムーズに変>化するように transition を適用しています。

.error-message:エラーメッセージは初期状態で隠されており、コントラスト比が閾値を

下回ると表示されます。

~                          


3. JavaScriptの機能解説

JavaScriptの部分では、ユーザーが入力した色やコントラスト閾値に応じて色ブロックを更新し、コントラスト比を計算する機能を実装しています。

重要な関数の解説
hexToRgb 関数

function hexToRgb(hex) {
const bigint = parseInt(hex.slice(1), 16);
return [(bigint >> 16) & 255, (bigint >> 8) & 255, bigint & 255];
}
  • 役割:16進カラーコードをRGB形式に変換します。


contrastRatio 関数

function contrastRatio(rgb1, rgb2) {
  const lum1 = luminance(...rgb1) + 0.05;
  const lum2 = luminance(...rgb2) + 0.05;
  return lum1 > lum2 ? lum1 / lum2 : lum2 / lum1;
}
  • 役割:2つの色のRGB値からコントラスト比を計算します。
  const errorMessage = wrapper.querySelector('.error-message');
if (ratio < threshold) {
errorMessage.style.visibility = 'visible';
} else {
errorMessage.style.visibility = 'hidden';
 }
}

役割:ブロックごとに背景色と文字色のコントラスト比を計算し、閾値を下回る場合にエラーメッセージを表示します。

4. イベントリスナーの仕組み

ユーザーの入力に応じてリアルタイムで色を更新するため、各入力フィールドにイベントリスナーを設定しています。

イベントリスナーの設定

document.getElementById('main-color').addEventListener('input', updatePalettes);
textColorPicker.addEventListener('input', updatePalettes);
contrastThresholdInput.addEventListener('input', updatePalettes);

役割:メインカラー、文字色、コントラスト閾値が変更されるたびに updatePalettes() 関数を呼び出し、色ブロックとコントラスト比を再計算します。

5. コントラスト比チェックの詳細

コントラスト比の計算:contrastRatio 関数が2つのRGB色のコントラスト比を計算します。

閾値チェック:updateBlockColor 関数でコントラスト比が閾値より低い場合にエラーメッセージが表示されます。

6. 動作の流れ

初期化:

ページが読み込まれた際、updatePalettes() 関数が実行され、各パレットが初期状態で表示されます。

ユーザー入力の検知:

メインカラーや文字色が変更されるたびに、パレット内の色がリアルタイムで更新されます。

コントラスト比チェック:

各ブロックごとにコントラスト比を計算し、閾値を満たさない場合にはエラーメッセージが表示されます。

まとめ

このコードは、カラーパレットを使ってメインカラーと文字色の組み合わせを確認し、リアルタイムでコントラスト比が適切かどうかを判定する機能を実装しています。ユ>ーザーが自由に色を変更でき、入力されたコントラスト閾値に応じたチェックが行われます。視認性を確保するために、エラーメッセージは各色ブロックの外に表示される>ように工夫されています。

これにより、UIデザイナーが色の選定に役立つツールとして活用できるようになっています。

結果はこれ

メインカラーのpick
文字色のpick
コントラスト比の入力
補色カラーパレット
分割補色カラーパレット
トライアドカラーパレット
モノクロマティックカラーパレット