polished의 lighten, darken 을 구현해보기.til

Universe·2023년 3월 27일
0

☀️

polished 라이브러리에는 lighten, darken 이라는 기능이 있다.
특정 색상을 가중치만큼 밝게, 혹은 어둡게 만들어주는 기능인데,
단지 색상 코드를 바꿔주는 기능을 위해서 라이브러리를 설치하는 것 보다
직접 구현해보고 싶어서 시작한 유틸함수 만들기.




🌕

lighten: (color, amount) => {
  if (!color) return;
    const r = Math.round(parseInt(color.slice(1, 3), 16) * (1 + amount));
    const g = Math.round(parseInt(color.slice(3, 5), 16) * (1 + amount));
    const b = Math.round(parseInt(color.slice(5, 7), 16) * (1 + amount));
  return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;

ver 1.0

  1. color 로 색상 HEX 값을 받아와서
  2. string.slice로 gb에 해당하는 문자열을 16진수 숫자로 변환한 후
  3. 가중치를 곱하는 로직.

아주 간단하게 완성했다고 생각했다.

그러나 가중치를 곱한 값이 255를 초과하는 경우,
그러니까 rgb 값의 상한선을 초과하는 경우 16진수 값이 세자리 수가 되어버려
정상적인 색상 코드를 리턴하지 않는 버그가 있다.
그래서 상한선을 255로 두고 넘어간다면 255로 고정할 수 있도록 로직을 수정했다.

lighten: (color, amount) => {
    if (!color) return;
    const r = Math.min(
      255,
      Math.round(parseInt(color.slice(1, 3), 16) * (1 + amount))
    );
    const g = Math.min(
      255,
      Math.round(parseInt(color.slice(3, 5), 16) * (1 + amount))
    );
    const b = Math.min(
      255,
      Math.round(parseInt(color.slice(5, 7), 16) * (1 + amount))
    );

    return `#${r.toString(16)}${g.toString(16)}${b.toString(16)}`;
  },

ver 2.0

위의 로직에서 가중치를 곱할 때 Math.min 메소드로 255를 초과할 수 없게 임계설정.
원리는 Math.min 은 주어진 인자값들 중 가장 작은 숫자를 반환하므로
255 보다 큰 값이 인자로 입력되면 255를 반환하도록 하는 것.

그러나 이 로직에도 문제점이 있다.
예를들어 가중치가 계산된 숫자가 16진수로 '0A' 같은 경우 toString 메소드는 'A'만 반환한다.
그러면 정상적으로 코드를 출력하지 않으므로 강제로 두자리 숫자로 고정해주어야 한다.

lighten: (color, amount) => {
    if (!color) return;
    const r = Math.min(
      255,
      Math.round(parseInt(color.slice(1, 3), 16) * (1 + amount))
    );
    const g = Math.min(
      255,
      Math.round(parseInt(color.slice(3, 5), 16) * (1 + amount))
    );
    const b = Math.min(
      255,
      Math.round(parseInt(color.slice(5, 7), 16) * (1 + amount))
    );

    const rHex = r.toString(16).padStart(2, "0");
    const gHex = g.toString(16).padStart(2, "0");
    const bHex = b.toString(16).padStart(2, "0");

    return `#${rHex}${gHex}${bHex}`;
  },

ver 3.0

padStart(2,'0') 메소드로 toString 으로 'A'를 리턴하더라도 '0A' 두 자리 숫자로
고정시켜주었다.

이 로직은 항상 6자리의 HEX 색상 코드를 반환하게 됐다. 🥰
조금 더 리펙토링 해보면,
lighten, darken 로직의 padStart 로직은 겹치는 부분이 많아서 하나의 함수로 만들어 주었다.

const rgbToHex = (r, g, b) => {
  const rHex = r.toString(16).padStart(2, "0");
  const gHex = g.toString(16).padStart(2, "0");
  const bHex = b.toString(16).padStart(2, "0");

  return `#${rHex}${gHex}${bHex}`;
};

export const transColor = {
  lighten: (color, amount) => {
    if (!color) return;
    const r = Math.min(
      255,
      Math.round(parseInt(color.slice(1, 3), 16) * (1 + amount))
    );
    const g = Math.min(
      255,
      Math.round(parseInt(color.slice(3, 5), 16) * (1 + amount))
    );
    const b = Math.min(
      255,
      Math.round(parseInt(color.slice(5, 7), 16) * (1 + amount))
    );

    return rgbToHex(r, g, b);
  },

  darken: (color, amount) => {
    if (!color) return;
    const r = Math.min(
      255,
      Math.round(parseInt(color.slice(1, 3), 16) * (1 - amount))
    );
    const g = Math.min(
      255,
      Math.round(parseInt(color.slice(3, 5), 16) * (1 - amount))
    );
    const b = Math.min(
      255,
      Math.round(parseInt(color.slice(5, 7), 16) * (1 - amount))
    );

    return rgbToHex(r, g, b);
  },
};

완성!




⭐️

그러나 아쉽게도 polished 라이브러리의 lighten, darken 과 비교했을 때
눈에띄는 차이가 있었다.
그건 색상의 코드가 아닌 HSL (색상, 채도, 명도)를 변경하는 로직을 사용하기 때문인데
밝기를 조절하는 측면에서 봤을 때는 이쪽이 조금 더 정확하다는 것이다.
이 부분도 직접 구현해볼까 해서 관련 레퍼런스를 찾아봤는데
이해할 수 없는 수학적인 계산 로직이 너무 많고,
하고싶은 공부만 할 수 없는 실전 프로젝트 특성상 시간적 여유가 부족하다고 판단해서
아쉽지만 일단은 마무리하기로 했다.
흠, 아쉽군
나중에 시간이 되면 관련 레퍼런스를 보고 직접 구현해보면 재밌을 것 같다.

profile
Always, we are friend 🧡

0개의 댓글