Choose Higher Contrast Text Color

by ktsn

HTML

<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app">
  <ul>
    <li 
      v-for="(color, i) in colors" 
      :key="i" 
      :style="{ backgroundColor: toCssColor(color), color: textColor(color) }"
     >
      {{ toCssColor(color) }}
    </li>
  </ul>
</div>

CSS

ul,
li {
  margin: 0;
  padding: 0;
  list-style: none;
}

li {
  padding: 10px 20px;
}

JavaScript

new Vue({
  el: '#app',
  
  data() {
    const lightness = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
    const hue = [0, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300, 330]
    
    const colors = []
    hue.forEach(h => {
    	lightness.forEach(l => {
      	colors.push(hslToRgb(hsl(h, 1, l)))
      })
    })
    
    return {
    	colors
    }
  },
  
  methods: {
    toCssColor(color) {
    	const r = Math.round(color.red)
      const g = Math.round(color.green)
      const b = Math.round(color.blue)
      return `rgb(${r}, ${g}, ${b})`
    },
    
    textColor(background) {
    	// Procedure 1.
			const toRgbItem = item => {
        const i = item / 255
        return i <= 0.03928 ? i / 12.92 : Math.pow((i + 0.055) / 1.055, 2.4)
      }
      const R = toRgbItem(background.red)
      const G = toRgbItem(background.green)
      const B = toRgbItem(background.blue)
      const Lbg = 0.2126 * R + 0.7152 * G + 0.0722 * B
      
      // Procedure 2.
      // White or black can be text color
      // Relative luminance of white is 1, black is 0
      const Lw = 1
      const Lb = 0
      
      // Procedure 3.
      // White is always lighter than other colors
      // while black is always darker.
      const Cw = (Lw + 0.05) / (Lbg + 0.05)
      const Cb = (Lbg + 0.05) / (Lb + 0.05)
      
      // Use the color which the contrast is higher with background
      return Cw < Cb ? 'black' : 'white'
    }
  }
})

function hslToRgb(hsl) {
  const c = (1 - Math.abs(2 * hsl.lightness - 1) * hsl.sarturation)
  const h = hsl.hue / 60
  const x = c * (1 - Math.abs(h % 2 - 1))
  
  let rgb
	if (0 <= h && h <= 1) {
  	rgb = [c, x, 0]
  } else if (1 < h && h <= 2) {
  	rgb = [x, c, 0]
  } else if (2 < h && h <= 3) {
    rgb = [0, c, x]
  } else if (3 < h && h <= 4) {
    rgb = [0, x, c]
  } else if (4 < h && h <= 5) {
    rgb = [x, 0, c]
  } else if (5 < h && h <= 6) {
    rgb = [c, 0, x]
  } else {
    rgb = [0, 0, 0]
  }
  
  m = hsl.lightness - c / 2
  return {
   ...