IT일상

javascript에서 RGB ↔ HSL 변환하기 본문

프론트엔드

javascript에서 RGB ↔ HSL 변환하기

solo5star 2023. 4. 30. 00:17
리뉴얼 된 블로그로 보기: https://solo5star.dev/posts/41/

 

먼저, "#ffffff" 16진수 표현을 RGB로 변환하기

/**
 * @param {string} hexColor #ffffff 와 같이 16진수 형태로 작성된 색상 문자열
 * @returns {[number, number, number]} R, G, B 배열 (0 ~ 255)
 */
function hexColorToRGB(hexColor) {
  const rgb = hexColor.startsWith('#') ? hexColor.slice(1) : hexColor;
  const [r, g, b] = [rgb.slice(0, 2), rgb.slice(2, 4), rgb.slice(4, 6)].map((hex) => Number.parseInt(hex, 16));

  return [r, g, b];
}

"#ffffff" 같은 식의 16진수로 표현된 색상 문자열을 R, G, B 배열로 변환합니다.

 

 

RGB를 HSL로 변환하기

/**
 * 출처: https://www.30secondsofcode.org/js/s/rgb-to-hsl/
 * 
 * @param {[number, number, number]} rgb R, G, B 값 배열
 * @returns {[number, number, number]} H, S, L 값 배열
 */
function rgbToHSL(rgb) {
  const r = rgb[0] / 255;
  const g = rgb[1] / 255;
  const b = rgb[2] / 255;
  const l = Math.max(r, g, b);
  const s = l - Math.min(r, g, b);

  const h = s
    ? l === r
      ? (g - b) / s
      : l === g
      ? 2 + (b - r) / s
      : 4 + (r - g) / s
    : 0;
  return [
    60 * h < 0 ? 60 * h + 360 : 60 * h,
    100 * (s ? (l <= 0.5 ? s / (2 * l - s) : s / (2 - (2 * l - s))) : 0),
    (100 * (2 * l - s)) / 2,
  ];
}

※ 소스코드의 출처는 https://www.30secondsofcode.org/js/s/rgb-to-hsl/ 입니다.

 

RGB 배열을 HSL 배열로 변환합니다. 잘 동작하는 것을 확인할 수 있습니다.

 

 

HSL을 RGB로 변환하기

/**
 * 출처: https://www.30secondsofcode.org/js/s/hsl-to-rgb/
 *
 * @param {[number, number, number]} hsl H, S, L 값 배열
 * @returns {[number, number, number]} R, G, B 값 배열
 */
function hslToRGB(hsl) {
  const h = hsl[0];
  const s = hsl[1] / 100;
  const l = hsl[2] / 100;
  const k = (n) => (n + h / 30) % 12;
  const a = s * Math.min(l, 1 - l);
  const f = (n) =>
    l - a * Math.max(-1, Math.min(k(n) - 3, Math.min(9 - k(n), 1)));
  return [255 * f(0), 255 * f(8), 255 * f(4)];
}

※ 소스코드의 출처는 https://www.30secondsofcode.org/js/s/hsl-to-rgb/ 입니다.

다시 RGB를 HSL로 변환합니다. 변환이 문제없는 것을 잘 검증할 수 있었습니다.

 

 

HSL을 문자열로

브라우저에서 HSL 문자열을 나타내는 방법은 간단합니다.

/**
 * @param {[number, number, number]} hsl H, S, L 값 배열
 * @returns {string} hsl(h, s%, l%) 로 표현된 문자열
 */
function stringifyHSL(hsl) {
  const [h, s, l] = hsl;
  return `hsl(${h}, ${s}%, ${l}%)`;
}

잘 나오지만 불필요한 소숫점까지 찍히는 것을 볼 수 있습니다.

 

 

HSL 값 정규화하기

/**
 * @param {[number, number, number]} hsl H, S, L 값 배열
 * @returns {[number, number, number]} 정규화된 H, S, L 값 배열
 */
function normalizeHSL(hsl) {
  const [h, s, l] = hsl;
  return [
    ((Math.round(h) % 360) + 360) % 360, // 0 ~ 360, positive modulo
    Math.max(0, Math.min(100, Math.round(s))), // 0 ~ 100
    Math.max(0, Math.min(100, Math.round(l))), // 0 ~ 100
  ];
}

hsl 배열의 값이 항상 아래와 같이 나오도록 해주는 함수를 만듭니다.

 

* H: 0 ≤ H < 360

* S: 0 ≤ S ≤ 100

* L: 0 ≤ L ≤ 100

 

 

브라우저에서 사용

<body>
  <div class="color-form">
    <p id="color-name"></p>
    <div class="color"></div>
  </div>
</body>

<script>
function setColor(color) {
  document.getElementById('color-name').innerText = color;
  document.getElementById('color-name').style.color = color;
  document.querySelector('.color').style.backgroundColor = color;
}

setColor([
  hexColorToRGB,
  rgbToHSL,
  normalizeHSL,
  stringifyHSL,
].reduce((acc, pipe) => pipe(acc), '#ecb127'));
</script>

잘 동작합니다. 실제로 hsl(42, 84%, 54%) 로 설정했음에도 브라우저에서는 rgb로 변환되어 표시되는 모습을 볼 수 있습니다.

Comments