🎨

背景色に合わせて文字色を自動変更する

2023/01/02に公開

原色大辞典さんのように、背景色に合わせて文字色のスタイルを自動的に変更したかったのでメモ
Reactで書いてますが、環境に合わせて適宜読み替えてください

方法1 (失敗)

背景色と同じ文字色を適用し、文字色をfilterで反転させます

<div style={{ width: 'fit-content', backgroundColor: '#000', padding: '8px'  }}>
  <span style={{
    color: '#000',
   filter: 'invert(100%) grayscale(100%) contrast(100)',
  }}>テスト</span>
</div>

これでほとんど対応できますが、invert()が効かない中間色のグレーはテキストが見づらくなります

方法2 (成功)

自分の感覚だと、RGBでいう各値が118~136の間のグレーだとテキストが見づらくなるので、その時のみは文字色を白色にするように調整しました
その判定の過程で、Hexの16進数のカラーコードからRGBの10進数のカラーコードに変換しています

<div style={{ backgroundColor: '#808080', padding: '8px' }}>
  <span style={getTextStyle('#808080')}>テスト</span>
</div>
/**
 * HexをRGBに変換する
 */
export const convertHexToRGB = (hex: string) => {
  if (hex.slice(0, 1) !== '#') {
    throw new Error('Hex must start with #')
  }
  if (hex.length !== 4 && hex.length !== 7) {
    throw new Error('Hex must be 4 or 7 characters')
  }

  const hex6Digits =
    hex.length == 4
      ? '#' +
        hex.slice(1, 2) +
        hex.slice(1, 2) +
        hex.slice(2, 3) +
        hex.slice(2, 3) +
        hex.slice(3, 4) +
        hex.slice(3, 4)
      : hex

  return [hex6Digits.slice(1, 3), hex6Digits.slice(3, 5), hex6Digits.slice(5, 7)].map((color) =>
    parseInt(color, 16)
  )
}

/**
 * 背景色に合わせた文字色のスタイルを返す
 */
export const getTextStyle = (backgroundColor: string) => {
  const [red, green, blue] = convertHexToRGB(backgroundColor)

  if (red > 118 && red < 136 && green > 118 && green < 136 && blue > 118 && blue < 136) {
    return {
      color: '#fff',
    }
  }
  return {
    color: backgroundColor,
    filter: 'invert(100%) grayscale(100%) contrast(100)',
  }
}

その他

厳密にやるのであれば、この記事のように閾値を測ってやるのが良さそうです
自分の用途では問題がなかったので、現状これでいいかなと思ってます
https://zenn.dev/mryhryki/articles/2020-11-12-hatena-background-color

参考

https://blanktar.jp/blog/2020/11/css-automate-foreground-text-color
https://gokansoichiro.com/blog/css-mix-blend-mode/
https://lab.syncer.jp/Web/JavaScript/Snippet/61/

Discussion

ログインするとコメントできます