엉망진창인 컬러 체계를 개편해보자.
디자인 시스템을 실제 개발에 적용하면서 기존 컬러 체계에 큰 문제가 있다는 것을 깨달았다.
더 문제가 커지기 전에 이를 한 번 다듬고 가야겠다는 생각으로 컬러 체계를 다시 정립하기로 했다.
기존 컬러 체계의 문제점
기존에 사용하고 있던 컬러 체계는 위와 같다.
이 컬러 체계는 크게 베이직 컬러의 모음인 컬러 팔레트와
베이직 컬러 중 자주 사용되고 핵심적인 컬러들을 모아 의미를 부여한 시멘틱 컬러로 구분된다.
시멘틱 컬러는 각 컬러마다 라이트/다크 모드 쌍을 가지고 있다.
이를 통해서 tailwind에서 dark:와 같은 속성을 사용하지 않고 편하게 개발할 수 있을 것이라 기대했었다.
그런데, 실제 개발에 들어가보니 이 컬러 체계에는 여러가지 문제점이 있었다.
1. 시멘틱 컬러에 정의되지 않은 컬러들이 UI 상에서 사용됨
기존 컬러 체계에서 시멘틱 컬러는 자주 사용되어 일반화가 가능하며 재사용이 가능한 컬러들을 모아서 의미를 붙여두는 방식이었다.
때문에 하나의 컴포넌트만을 위해서 사용되는 컬러들을 시멘틱 컬러로 정의하기는 애매하다고 생각, 시멘틱 컬러를 부여하지 않았다.
(대표적으로, 투자 의견 컴포넌트의 가로 막대바의 배경과 내부 바 컬러, 복잡한 라인 차트의 추가 차트 색상인 분홍색과 초록색)
문제는 실제 개발에 들어가면서 이런 베이직 컬러들과 시멘틱 컬러들이 코드 상에 혼재되기 시작했다는 점이다.
<div className="text-primary bg-blue-500 dark: bg-blue-700"></div>
위와 같이 두 가지 컬러 코드가 혼재되기 시작하면서
primary로 지정한 컬러는 라이트/다크 모드 변환이 자동으로 이루어지는데
그렇지 않은 컬러들에 대해서는 따로 dark: 태그를 사용해주어야하는 문제가 생겼다.
시멘틱 컬러를 사용함으로써 오히려 혼란스러워져 생산성이 떨어지는 결과가 나왔다.
2. 시멘틱 컬러 체계에 존재하는 컬러지만, 라이트/다크 모드가 기존 시멘틱 체계와 일치하지 않음
시멘틱 컬러에 포함되는 컬러들이지만, 라이트/다크 컬러 체계를 따르지 않는 컬러들도 생겨났다.
위의 흐르는 주식 배너가 대표적인데,
위 주식 배너의 배경, 텍스트 컬러들은 기존 시멘틱 컬러 팔레트에 포함이 되어있었지만 다크모드에서도 동일한 색상을 유지한다.
이를 해결하기 위해서는 시멘틱 컬러에 설정되어 있는 컬러를 따로 베이직 컬러에서 불러와 사용해야했다.
즉, 동일한 컬러를 한 쪽에서는 시멘틱 컬러로, 다른 쪽에서는 베이직 컬러로 불러오는 것이다.
이는 추후 유지보수 시 문제가 될 가능성이 다분했다.
3. 상태에 대한 체계가 존재하지 않음
컴포넌트에는 다양한 상태가 존재한다.
Frontend의 State가 아니라 UI가 사용자와 상호작용하는 상태를 말하는 것인데,
대표적으로 button이라는 컴포넌트에는 hover, focus, pressed(active), disabed와 같은 상태가 존재한다.
문제는 시멘틱 컬러에는 이런 상태에 대한 체계가 존재하지 않아서 베이직 컬러를 사용해야했다는 점이다.
결국 1번과 동일한 문제가 발생한 것인데,
배경은 시멘틱 컬러로 설정해놓고 hover 상태들은 베이직 컬러로 설정하게되면서 파편화가 일어났다.
<button className="bg-primary hover:bg-600 dark:hover:bg-blue-400">버튼</button>
또, 상태에 대한 일정한 규칙이 존재하지 않아서 어떤 상태에 어떤 컬러를 불러와야하는지에 대한 정의도 존재하지 않았다.
디자인 시스템이지만 컬러부터 규칙적이지 않게 된 것이다.
4. 접근성 무시
기존에 만들었던 시멘틱 컬러들은 접근성을 고려하지 않고 지정된 컬러들이었다.
때문에 컬러 체계를 개편하면서 접근성에 대한 고려 역시 들어가야했다.
어떤 해결 방법이 있을까?
개발 초입에 들어섰을 뿐인데 문제점이 우수수 나오자 추후 유지보수가 두려워지는 지경이 이르렀다.
나는 근본적인 원인이 디자인 시스템의 컬러 체계에 있음을 깨닫고, 컬러 체계를 개편하기 위한 방법들을 고민해봤다.
기존 컬러 체계의 가장 큰 문제점은 코드 상에서 서로 다른 컬러 계층의 색상들을 불러와 사용한다는 점이다.
컬러를 토큰화 하기 위해서는 크게 4가지의 과정을 거치는데
Hex Code(#5845F5)에 컬러와 밝기로 이름을 붙이는 Basic Color(purple-500),
Basic Color에서 컬러에 의미를 부여하는 Semantic Color(color-action, primary),
그리고 마지막으로 Semantic Color에 컴포넌트에서 실제로 사용하는 맥락을 담아 이름을 붙이는
Context Color(color-background-button)의 과정을 거친다.
(물론 이 단계가 정답은 아니기 때문에 꼭 모든 단계를 거칠 필요는 없다.)
디자인 토큰을 개발에 편하게 적용하기 위해서는 한 단계의 계층에서만 컬러 코드를 가져오는 것이 가장 좋은데,
(그래야 일정한 규칙으로 코드를 작성하기 좋다.)
나의 경우는 시멘틱 컬러가 UI 상의 모든 컬러와 상태를 포용하지 못해서
베이직 컬러의 코드를 다시 불러와야하는 문제가 있었던 것이다.
즉, 이 문제를 해결하려면 불러오는 컬러의 계층을 한 단계로 한정하면 되는데
컬러 토큰에는 3가지 계층이 있으니 해결 방법에도 3가지가 있었다.
1. Basic Color를 그대로 코드에 불러와 사용
근본적으로 tailwind 시스템이 작동하는 방식이다.
디자인 토큰들을 흩뿌려놓고 이를 불러와 조합해서 디자인을 만들어내는 방식이다보니
가장 tailwind스러운 방식이면서 가장 간단한 해결법이었다.
단, 컴포넌트에서 컬러를 직접 불러와 사용해야하기 때문에 실수가 발생할 확률이 높았고,
다크 모드 대응 시에 각 색깔 별로 매칭되는 컬러 조합을 색상별로 상태별로 찾거나 외워야한다는 단점이 있다.
또, tailwind 특성 상 다크모드를 지정하는게 일반 색상이 아닌 hover와 같은 상태에 대해서도 일일이 지정을 해주어야했기 때문에
가장 긴 className을 가지게 된다.
2. Semantic Color를 체계적으로 확장해서 UI상의 모든 컬러와 상태를 포용하도록 수정
시멘틱 컬러 체계가 모든 컬러를 수용하지 못하는 것이 문제이므로
시멘틱 컬러 체계를 확장해서 모든 컬러를 수용할 수 있도록 만든다.
체계가 정립만 된다면, 라이트 다크 모드 별로 색상 묶음을 별도로 관리해 재사용하기 때문에 재사용성도 높고 굉장히 깔끔하다.
단, 체계를 정립하는게 쉽지가 않다. 정립한다고 해도 Context Color에 비해서 유연성이 떨어지는 면이 있다.
3. Context Color를 통해 컴포넌트별, 상황별로 사용하는 색상 클래스를 모두 작성
시간은 매우 오래 걸리지만 내가 CDD 기반으로 즉, 컴포넌트 단위로 개발을 진행한다는 점에서 의외로 나쁘지 않은 방법이었다.
실제로 쏘카의 디자인 시스템이 비슷한 맥락에서 이런 방식으로 해결을 하기도 했다. (참고)
단, 컴포넌트 별로 색상 클래스를 모두 다 선언해야한다는 점에서 색상이라는 디자인 토큰의 재사용성이 매우 떨어진다.
각 컴포넌트만을 위한 클래스를 작성해야하는데 이는 컬러라는 토큰의 재사용성이 컴포넌트의 재사용성과 같아진다는 것이다.
(테일윈드스러운게 뭔진 모르겠지만 내가 생각하기에 테일윈드스러운 방법은 아니다.)
또, 아무리 CDD 기반으로 한다고해도 그때 그때 색상 클래스를 작성한다는게 수고로운 일인 것 맞으며,
컴포넌트 기반으로 클래스를 만들기 때문에 컴포넌트가 늘어나면 클래스의 개수도 늘어난다는 단점이 있다.
위와 같은 세 가지 해결법 중에서 어떤 것을 선택할까 고민을 했었다.
각 방법 모두 장, 단점을 가지고 있었기 때문에 내가 생각하는 가장 이상적인 방법을 고민했었다.
그 중 2번이 프로젝트 규모도 작거니와 처음에만 고생한다면,
라이트/다크 모드에 대한 색상 묶음 관리가 용이하고 재사용성이라는 측면에서도 3번보다 좋을 것 같아 2번으로 결정했다.
Material UI
나는 디자이너가 아니기 때문에 디자인 시스템을 보면서 따라하는게 최선이었다.
(그래도 디자이너 분들이 보기에는 미흡하겠지만)
많은 디자인 시스템들을 봐봤으나 시멘틱 컬러를 어떤 체계를 가지고 확장하면 좋을지 제대로 인사이트를 주는 시스템이 없었다.
그러나 구글의 Material UI의 컬러 시스템을 봤고 그 때 이거다 싶어 이 체계를 가져와 재정립하기로 마음을 먹었다.
내가 이해한 바로 Material UI의 컬러 체계는 아주 간단히 말해 아래와 같은 형태로 구성된다.
유채색과 무채색으로 Accent 컬러와 Neutral 컬러를 구분한 뒤,
Accent 컬러에서는 라이트/다크 모드에 따라 변하는 가변 색(Dynamic)과 모드에 관계 없이 변하지 않는 고정 색(Fixed)이 있다.
또 이 색들은, 기본적인 Main 색과 덜 중요한 컨텐츠를 나타내는 비슷한 계열의 색인 추가 색(Container) 1개를 제공한다.
마지막으로 컴포넌트의 배경을 의미하는 색과 그 컴포넌트 위에 올라가는 글자, 아이콘의 색인 콘텐츠 색(On) 색이 있다.
Neutral 컬러도 비슷한데,
영역의 배경으로 깔리는 밑바탕 색(Surface)과 선 색(Outline)으로 구분된다.
Surface 색상은 가장 밑에 깔리는 기본 밑바탕 색과 그 위에 깔리는 추가 색(Container) 여러 개를 제공한다.
또한, 각 UI의 상태 색상을 정의하는 규칙 역시 아래처럼 존재한다.
Content와 Background 사이에 State Layer를 넣고, 이 State Layer의 불투명도를 조절하여 상태를 나타낸다.
개편하기
이런 Material UI의 방식을 차용하여, 기존 컬러 체계의 문제점들을 해결해보자.
1. 시멘틱 컬러에 정의되지 않은 컬러들이 UI 상에서 사용됨
UI 상에 사용되는 컬러 중 시멘틱 컬러에 정의되지 않은 컬러는
대표적으로 빈도 차트의 바 배경과 막대 색상, 그리고 복잡한 차트의 부가 차트 색상이 있었다.
Material UI에서는 이렇게 주된 컬러와 별개의 컬러 중 유채색에 해당하는 컬러는 Custom Color로 정의하여 사용한다.
이 커스텀 컬러 역시 주 색과 보조 색, 그리고 배경 색과 컨텐츠 색을 제공한다.
이를 활용해서 나 역시 Paimary 색상인 파란색이 아닌 경우 Custom Color를 통해 시멘틱 컬러로 명명해주었다.
그리고 무채색의 경우에는, Material UI에서 사용되는 예를 참고하여 Surface Container에 추가해주었다.
대표적인 예로 위에 있는 Material UI의 막대 차트 비슷한 UI를 보면
막대 차트 배경색의 경우 밑바탕 위에 올라가는 배경색이므로 surface container로 분류했다.
그 결과 아래와 같이 배경색을 정할 수 있었다.
2. 시멘틱 컬러 체계에 존재하는 컬러지만, 라이트/다크 모드가 기존 시멘틱 체계와 일치하지 않음
이 경우에는 Fixed Color를 선언하여 해결했다.
3. 상태에 대한 체계가 존재하지 않음
상태에 대한 체계는 컨텐츠 컬러(On)을 별도로 정의하는 것에서 아이디어를 얻었다.
나 역시도 State Layer를 사용하되, 위에 올라가는 컨텐츠 컬러를 받아서 이를 불투명도를 적용해 덮어서 상태를 나타내기로 했다.
파란색 Text Button에서 hover, active 배경 색상이 파란 색으로 나타나는게 자연스럽기 때문이라는 생각에 이렇게 정했다.
4. 접근성 무시
Material UI에서는 접근성 가이드라인을 아래와 같이 제시해주고 있다.
텍스트 외 디자인 요소 | 최소 3:1의 명도 대비 |
큰 텍스트(18px 이상 or Bold 14px 이상) | 최소 3:1의 명도 대비 |
일반 텍스트 | 최소 4.5:1의 명도 대비 |
이는 WCAG 2.0에서 규정하는 웹 접근성 가이드라인과 동일하다.
단, 조금 더 상세한 예제를 들어 설명해주고 있다.
컴포넌트 배경색과 컴포넌트 컨텐츠색(On)은 4.5:1의 명도 대비를 지켜야한다.
Surface 색과 컴포넌트 배경색은 3:1의 명도 대비를 지켜야한다.
이런 식으로 말이다. 나도 이 규정에 맞춰서 색상 조합을 만들었다.
명도 대비는 WebAIM 사이트를 통해 체크해주었다.
이를 통해 웹 접근성을 고려해서 색상 팔레트를 개선할 수 있었다.
결론
위와 같은 절차를 고쳐 최종 컬러 팔레트와 시멘틱 컬러들이 나왔다.
이제 이 색상들을 tailwind로 옮겨서 작성하면 시멘틱 컬러 계층으로만 개발할 수 있는 환경이 마련될 것이다.
Reference
Color system – Material Design 3
The color system handles the variability of dynamically changing color schemes that arise as user inputs change.
m3.material.io
States – Material Design 3
States are visual indicators used to communicate the status of a component or interactive element
m3.material.io
'토이프로젝트 > chistock' 카테고리의 다른 글
다형성 컴포넌트 개발에 대한 고민 기록 (1) | 2023.11.11 |
---|---|
아토믹 디자인 도입기 (0) | 2023.07.17 |
디자인 작업 완료 (0) | 2023.07.17 |
디자인 작업과 API에 관해 (0) | 2023.07.13 |
치스톡 프로젝트 재개 (0) | 2023.07.12 |