React CSS 변수 값 가져오기

외부에서 가져온 SVG 아이콘이나 컴포넌트 기반의 아이콘 라이브러리를 사용할 때, 프로젝트에서 미리 정의한 CSS 변수를 적용하는 것이 쉽지 않을 때가 있다. 예를 들어, className=”bg-primary”처럼 배경색을 적용하는 것은 가능하지만, fill이나 stroke 같은 SVG 속성에는 동일한 방식이 적용되지 않는다. 그리고 테마가 존재할 수 있다. 이 경우에 어떻게 변화를 감지하고, 어떻게 가져올 것인지 정리한다.

예시 CSS 코드

:root {
  --bg: #123456;
}

.dark {
  --bg: #030e18;
}

.light {
  --bg: #dbdbdb;
}

CSS 변수 값 가져오기

const rootStyle = getComputedStyle(document.documentElement);
const bg = rootStyle.getPropertyValue("--bg");

CSS 변수 변화 감지하고 다시 변수 값 가져오기

사실 하나의 컴포넌트에서만 사용할 것이면, 전역적으로 관리할 필요가 없고 이부분은 필요 없을 수 있다. 나에 경우에는 전역적으로 관리할 필요가 있었고, 특정 엘리먼트의 class값을 변화를 감지해서 state를 업데이트 해주는 로직을 작성했다.

import { create } from "zustand";

interface UseCSSStore {
  brand: string;
  foreground: string;
  secondary: string;
  border: string;
  trendUp: string;
  trendNeutral: string;
  trendDown: string;

  updateColors: (colors: Partial<typeof initialState>) => void;
}

const initialState = {
  brand: "",
  foreground: "",
  secondary: "",
  border: "",
  trendUp: "",
  trendNeutral: "",
  trendDown: "",
};

const useCSSProperty = create<UseCSSStore>(set => {
  return {
    ...initialState,
    updateColors: colors => {
      // 빈 문자열 또는 nullish 값을 제거한 새로운 객체 생성
      const filteredColors = Object.fromEntries(
        Object.entries(colors).filter(([_, value]) => value),
      );

      // 필터링된 객체만 상태에 적용
      set(filteredColors);
    },
  };
});

export function updateColors() {
  const rootStyle = getComputedStyle(document.documentElement);

  const { updateColors } = useCSSProperty.getState();

  updateColors({
    brand: rootStyle.getPropertyValue("--brand").trim(),
    foreground: rootStyle.getPropertyValue("--foreground").trim(),
    secondary: rootStyle.getPropertyValue("--secondary").trim(),
    border: rootStyle.getPropertyValue("--border").trim(),
    trendUp: rootStyle.getPropertyValue("--trend-up").trim(),
    trendNeutral: rootStyle.getPropertyValue("--trend-neutral").trim(),
    trendDown: rootStyle.getPropertyValue("--trend-down").trim(),
  });
}

export function useUpdateCSSPropertyStore() {
  useEffect(() => {
    const root = document.documentElement;
    const observer = new MutationObserver(updateColors);
    observer.observe(root, { attributes: true, attributeFilter: ["class"] });

    // 처음 한번 실행
    updateColors();
  }, []);
}

export default useCSSProperty;

useCSSProperty Zustand Store 정의

  • brand, foreground, secondary 등 CSS 변수 값을 저장하는 상태를 관리한다.
  • updateColors(colors) 함수로 CSS 변수 값을 업데이트할 수 있다.
  • 빈 문자열 또는 nullish(null 또는 undefined) 값을 제거하여 유효한 값만 저장한다.

updateColors() 함수

  • getComputedStyle(document.documentElement)을 사용해 현재 CSS 변수 값을 가져온다.
  • useCSSProperty.getState().updateColors({…})를 호출하여 Zustand Store를 업데이트한다.

useUpdateCSSPropertyStore() 커스텀 훅

  • MutationObserver를 사용하여 요소의 class 속성 변화를 감지한다.
  • 클래스가 변경되면 updateColors()를 실행하여 상태를 최신 CSS 변수 값으로 갱신한다.
  • useEffect 내에서 초기 실행 시 updateColors()를 한 번 호출하여 현재 상태를 설정한다.

Leave a Comment