brunch

You can make anything
by writing

C.S.Lewis

by 점점 Mar 03. 2024

규칙적인 계층의 컬러 팔레트 시스템 제작 (1)

Lightness로 위계 설정하기


색상은 UXUI의 핵심 구성 요소다. 브랜드의 정체성을 구축하고 강화하기도 하며, 중요한 정보나 기능을 강조하여 고객이 핵심 콘텐츠와 기능을 더 빠르게 인식하도록 도울 수 있다. 그리고 이 모든 것의 기본이 되는 것이 색상 팔레트다. 지금 보는 이 글자는 물론이고 버튼의 배경, 테두리, 아이콘 색상 등 사이트에 보이는 UI는 대부분 기본 팔레트 시스템을 기반으로 작동한다. 

https://m3.material.io/styles/color/system/how-the-system-works
https://medium.com/@NateBaldwin/creating-a-flexible-design-token-taxonomy-for-intuits-design-system-



브랜드의 일관적인 경험을 높이려면 실제 프로덕트에 적용되어야 하는 것은 사용 목적을 명확히 한 시맨틱 컬러지만, 기본 팔레트가 있어야 시맨틱 컬러도 존재할 수 있기 때문에 체계적인 색상 계층을 구성하기 위하여 이런저런 테스트를 해보았다. 그러다 Lightness를 기반으로 색상 단계를 나누기로 했고, 토큰 스튜디오 플러그인을 사용하여 관리의 용이성을 높이는 시도도 해보았다.



목차

1. 색상 모델 (RGB, Hex code, HSB, HSL)

2. 색상 분류와 네이밍

3. 색상 토큰 추가 (토큰 스튜디오 플러그인 활용)

4. 색상 Document

5. 다크모드 적용

6. 피그마 베리어블 등록

(쓰다 보니 길어진 관계로 4~6은 2탄으로 작성 예정)



결과만 먼저 정리하자면 Lightness가 50인 색상 기준으로 팔레트의 0~100 단계가 자동으로 설정되도록 구성하였고, 색상 데이터도 피그마에서 바로 확인할 수 있도록 정리해 두었다. 이 도큐먼트는 플러그인과 연동되어 있어서 색상 정보가 변경될 경우 새로운 정보로 일괄 업데이트를 할 수 있다.

(GIF) 색상 팔레트 일괄 변경





색상 모델

디지털에서 색을 표현하는 방식은 다양하다. RGB, Hex code, HSB, HSL 등. 모든 UI의 기본이 되는 색상 계층이기 때문에 눈으로 보고 주관적으로 판단하는 것이 아니라 논리적이고 규칙적으로 구성하고 싶었다. 물론 시각적인 보정은 중요하다. 명확한 규칙을 적용해도 인간의 눈에는 왜곡되어 보일 때도 있기 때문에. 하지만 시각적 보정에 앞서 기본 작동 방식은 명확한 규칙으로 정렬하는 것을 목표로 삼았다.



일단 작동 방식을 테스트하기에 앞서, 자주 사용하는 Hex 기반으로 색상을 하나 선택했다. 그리고 좌측으로는 흰색(#FFF), 우측으로는 검정색(#000) 레이어를 투명도 20% 차이를 두고 5단계로 적용하여 팔레트의 위계를 구성해 보았다. 어떤 색상 모델의 규칙을 기준으로 하면 이런 균일한 팔레트를 설정할 수 있을지 확인해보기로 했다.

임시 계층 구성



RGB 

빛의 삼원색으로, 빨간색(Red), 초록색(Green), 파란색(Blue) 세 가지의 가산 혼합으로 표현한다. R, G, B 각 색상은 0~255 사이의 값으로 설정할 수 있고, 이를 통해 대략 1,670만 가지의 색상을 생성할 수 있다고 한다. 


RGB 모델로 명도를 계산해서 그레이스케일을 구성하는 내용을 본 적이 있었다. (R+G+B)/3으로 계산하여 Brightness를 구하고 일정한 Brightness 단계로 팔레트 간격이 유지되도록 설정한다고 한다. 사실 R, G, B 3가지 속성을 모두 컨트롤 해야 하므로 관리하기가 어려워 보였다. 보통 모니터를 처음 사면 명암이나 채도가 마음에 들지 않아서 화면 조절을 하게 되는데, 이때 RGB를 왔다 갔다 하며 방황했던 과거가 떠올랐다. 


어떤 색일까?


1번에서 5번까지는 쉽다. ① (0, 0, 0)은 빛이 없으니 검정색, ② (255 ,0, 0)는 R이 최대치이기 때문에 빨간색, ③(0, 255, 0)는 초록색, ④(0, 0, 255)는 파란색, ⑤(255, 255, 255)는 모든 빛이 최대치 빨간색. 


그런데 마지막 ⑥(26, 189, 230)을 봤을 때는 어떤 색상인지 바로 떠올릴 수 있는 사람은 거의 없을 것 같다R, G, B 중 하나의 색상만 값이 있지 않는 이상 다양하게 가산된 수치만 보고 색조나 채도, 명도를 파악하기는 너무 어려워 보였다. 그래서 RGB 기준은 포기.


예시 팔레트를 RGB로 표현한 값




Hex code

RGB를 16진수 형태로 변환한 값이다. #000000과 같은 식으로 표현할 수 있다. 16진수의 작동 방식을 간단히 적어 보면 0~9는 10진법과 동일하고, 10~15는 A~F로 하여 16자리(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F)로 표현하는 방법이다. 

ex. RGB(26, 186, 230)를 Hex code로 변환

R(26) = 26을 16으로 나눔 → 몫:1, 나머지:10 → 1A
G(186) = 186을 16으로 나눔 → 몫:11, 나머지:10 → BA
B(230) = 230을 16으로 나눔 → 몫:14, 나머지:6 → E6

따라서 RGB(26, 186, 230)를 hex로 변환하면 #1ABAE6


앞선 예시 팔레트를 Hex로 확인하면 이렇게 된다. 작동 규칙을 말로는 이해해도 내 머리로는 직관적으로 이해할 수 없기 때문에 이것도 포기.




HSB 

Hue (색조) : 색상의 종류로, 0°~360° 값으로 표현된다.

Saturation (채도) : 색의 강도. 채도가 낮으면 회색이 되고, 채도가 높으면 순수한 색상으로 표현된다.

Brightness (명도) : 색상의 밝기. 명도가 높으면 색이 밝아지고, 명도가 낮으면 어두워진다.



HSL

HSB에서 Brightnss 대신 Lightness로 표현하는 모델이다.

Hue (색조) : HSB와 동일

Saturation (채도) : HSB와 동일

Lightness (밝기) : HSB의 Brightness와는 달리 빛의 밝기라고 할 수 있다. 0은 검정, 50%는 순수한 채도, 100은 흰색이 된다.


HSB와 HSL의 색상 공간을 이미지로 보면 아래와 같다.


https://www.researchgate.net/figure/HSB-versus-HSL-color-space-Color-spaces-differ-in-terms-of-how-t



실제 디자인할 때 HSB와 HSL이 사용하는 컬러 피커의 차이다. 같은 색상에 대해서 Brightness, Lightness 값이 다른 것을 확인할 수 있다. Brightness는 아무리 높여도 명도가 밝아지지 않지만, Lightness는 최대로 줄이면 어두워지고, 높이면 흰색이 된다.

HSB와 HSL의 차이


테스트용 팔레트도 HSB와 HSL 각각 수치를 체크해보았다.


HSB는 Brightness만 조절해서는 명도가 높은 색상을 만들 수 없다. Saturation, Brightness 2가지 값을 조절해야 시각적 계층을 구분할 수 있다.


HSL은 Lightness 하나만 조절해도 시각적 위계를 갖는 팔레트를 구성할 수 있다. 결론적으로 하나의 기준으로 관리를 할 수 있다는 점에서 HSL을 택했다. 뿐만 아니라 RGB와 Hex와는 달리 ⓐHSL(268, 75, 50), ⓑHSL(268, 75, 60) 이라는 색상이 있다고 했을 때, 이 색상이 어떤 색상인지는 바로 떠올릴 수는 없더라도 Lightness가 ⓐ는 50, ⓑ는 60이기 때문에 ⓑ가 ⓐ보다 더 밝은 색상이라고 직관적으로 이해할 수 있는 것도 좋았다.





색상 분류 및 네이밍


세 가지 분류 (Brand, Basic, Static)

색상은 크게 brand, basic, static 3가지 그룹으로 분류했다. Brand는 브랜드의 정체성과 가치를 전달하는 색이다. 서비스에서 일관성을 높이고 중요한 요소를 강조하는 데 사용될 수 있다. 메인 색상인 primary가 반드시 존재하며 필요에 따라서 secondary, tertiary 색상이 포함될 수 있다. 

https://venngage.com/blog/brand-colors/



Basic은 red, blue, green, yellow, purple과 같은 기본적인 비주얼 색상이다. 성공, 경고, 주의와 같은 일반적인 의미와 감정을 전달하여 사용자와 의사소통 체계를 구축할 수 있으며, 데이터에서는 각 정보와의 시각적 계층을 강화해 주는 요소로 사용될 수도 있다. 브랜드에 따라서 채도를 낮추거나 높이는 식으로 변화를 줄 수 있다. 

https://spectrum.adobe.com/page/color-system/
https://carbondesignsystem.com/data-visualization/color-palettes/




Static은 테마 변경을 고려하여 어떤 테마에서든 변경되지 않는 색으로 사용하기 위해서 추가해 두었다. 기본적으로는 White, Black 두 가지 색상이 존재한다. 다크모드에서 예를 들어 설명하자면, Brand와 Basic은 모드가 변경되었을 때 배경색과의 대비가 유지되므로 밝았던 것은 어둡게, 어두웠던 것은 밝게 변경이 된다. Static의 경우에는 배경색과 무관하게 색상이 유지된다. 다크모드가 되었다고 라이트모드에서 어두웠던 그림자가 화이트 그림자가 되면 안 되기 때문에 고정된 색상도 반드시 필요해진다.





1차적으로 결정한 색상 그룹과 종류는 아래와 같다. 물론 서비스를 운영하다 보면 변경될 수도 있다.



단계

시각적 위계를 표현하기 위하여 팔레트 형식의 구성이 필요하다. 일반적으로 색상 뒤에 숫자를 붙여 각 색상 간의 차이를 표현해 준다. HSL에서 Lightness를 조절하여 팔레트를 구성할 예정이었고, Lightness를 10단위로 변경하여 0~100까지 시각적 계층을 나누어주면 아래와 같다. (명도가 낮은 색상보다 높은 색상에서 차이가 더 민감하기 때문에 95도 추가해 주었다.)


Lightness 수치를 색상 단계 표기로 유지할지 고민했지만, 일반적으로 낮은 수치에서 높은 수치로 올라가는 것이 강하다고 인지하기 때문에 100이 밝고 0이 어둡다면 사용할 때 헷갈릴 수도 있을 것 같았다. 결국 네이밍이라는 것은 서로 잘 이해하고 명확하게 소통하기 위함이기 때문에 상황에 맞게 변경하는 것을 좋을 것 같았다.


또한 나중에 opacity가 적용된 색상도 추후 추가할 예정이었고, opacity의 경우에는 0%는 완전 투명, 10%, 20%로 갈수록 점점 온전한 색으로 표현되는 방식이다. 따라서 다른 스타일 속성을 함께 고려했을 때 0이 밝고(배경색) 100으로 갈수록 대비가 높아지는 방식으로 사용하기로 했다. (Lightness)에서 (100-Lightness) 계산으로 변경했다. 


중요한 것은 '50'보다 '40'은 연하고 '60'은 강하다. '20은 배경색 대비 10보다 2배 강한 색' 이런 식으로 인지할 수 있는 수준이면 지금으로선 충분한 것 같았다.



최종 색상 네이밍

그룹과 색상 이름, 단계에 따라서 아래와 같이 최종 네이밍을 정했다.

f.color.{그룹}.{색상 명}.{계층}



이렇게 정한 파운데이션 색상 네이밍 규칙은 각 그룹과 색상에 따라 지정하면 된다.





색상 토큰 추가하기

디자인 시스템의 토큰은 피그마의 토큰 스튜디오 플러그인으로 관리를 하고 있다. 토큰 스튜디오를 사용하면 하나의 json 데이터를 프로덕트 디자이너는 피그마에, 개발자는 깃헙으로 받아서 사용하기 때문에 같은 스타일 정보를 유지하며 프로덕트를 관리 할 수 있어서 용이하다. 이건 나중에 기회가 되면 더 자세히 적어 보는 것으로.



1) default 색상 추가

Lightness가 50인 색상을 먼저 default로 추가해 주었다.

f.color.brand.primary.default





2) 0~100 팔레트 구성하기

그다음으로 default 토큰을 기반으로 0~100까지의 색상 토큰을 추가해야 한다. 


50

일단 50은 lightness가 50이라는 의미이기 때문에 default 색상을 그대로 참조한다. 기존에 등록된 토큰 네이밍을 '{토크명}' 중괄호로 감싸면 참조한다는 의미다. (자세히 알고 싶다면 Tokens studio docs를 참고)

50 토큰 추가




0~40, 60~100

그 후 플러그인의 Modify 기능(pro 버전에서만 사용 가능)을 사용하여 default 토큰을 참조로 넣고 0~40은 lighten, 60~100은 darken으로 변경하여 추가해야 한다. amount는 색상 밝기를 조절하는 값으로 0~1로 설정이 가능하며, default 토큰의 Lightness가 50이기 때문에 amount 0.1을 추가하면 lightness를 +/-5를 조절할 수 있다. 따라서 lightness을 10단위로 조절하고 싶다면 0.2를 더해서 추가하면 된다.


modify 설정
modify 설정

1. {f.color.brand.primary.default}를 참조
2. 0~40 = lighten,  60~100=darken으로 설정
3. hsl로 설정
4. amount : 0="1", 5="0.9", 10="0.8", 20="0.6", 30="0.4", 40="0.2", 60="0.2", 70="0.4", 80="0.6", 90="0.8", 100="1"



위처럼 0~100 팔레트를 모두 등록하면 기본 작업은 끝이다. 0~100까지 default 토큰을 기반으로 작동하기 때문에 default 토큰의 색상만 바꿔줘도 팔레트 전체가 균일한 lightness를 유지하고 바뀌는 것을 확인할 수 있다. 앞으로 색상을 수정하더라도 0~100 색상을 직접적으로 건들지 않아도 된다.

default 토큰 변경






3) amount 토큰 추가

반복되는 값 변수로 변경하기


다른 색상의 팔레트도 동일하게 추가하기 전에 amount라는 부분이 직접적인 수치로 들어가 있어서 토큰으로 추가해 주기로 했다. 계속 반복되는 값이 있다면 가능한 토큰(변수)로 저장해두는 편이 좋다. 그래야 나중에 수정이 필요할 때 일일이 수정하는 노가다를 줄일 수 있다. 규칙적인 lightness를 설정했지만 추후 시각적인 보정이 필요한 경우가 생길 수 있으며, 이때에는 0.5를 0.45로 조정하는 등의 미세한 조정을 하게 될 수도 있어서 미리 준비를 해두기로 했다.


amount는 크게 2가지로 구분했다. 

1) f.color.amount.default.{0~100} = 기본적인 색상

2) f.color.amount.highSaturation.{0~100} = 채도가 높은 색상 (ex. 노랑, 연두 등)

(highSaturation이 정확한 표현인지는 애매하지만 일단 구분용으로 추가하고 나중에 더 적합한 네이밍을 찾으면 변경하기로 했다.)


일부 색상의 경우 기본적으로 채도가 높아서 웹 접근성 기준을 고려했을 때 다른 규칙으로 설정해야 할 경우가 생길 것 같았기 때문이다. 같은 Saturation, Lightness 값을 가져도 Hue에 따라서 채도를 빼서 확인하면 대비가 상당히 다른 것을 확인할 수 있다.

https://www.w3schools.com/colors/colors_picker.asp
https://uxdesign.cc/the-dark-yellow-problem-in-design-system-color-palettes-a0db1eedc99d




위에서 정한 규칙에 따라서 amount 토큰을 0, 5, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 각각 추가했고, 색상도 직접적인 수치에서 토큰을 참조하도록 변경했다.





4) 다른 색상 팔레트 추가하기

처음에 했던 방식을 반복할 필요 없이 기존에 만들어진 팔레트를 복사하여 네이밍만 수정해 주면 된다. 초반에 색상 네이밍 규칙을 정하고, 이것저것 참조하는 식으로 정리를 하는 것이 살짝 복잡해 보일 수는 있지만 앞단에서 작동 방식을 잘 정리해 두면 나중에 수정할 때 편하다는 장점이 있다. 


primary 팔레트를 복제하여 이름을 secondary로 변경하여 생성해 준다. 단순히 복제만 했기 때문에 네이밍만 바뀌었을 뿐 색상은 primary와 동일하다.

secondary 팔레트 복제



f.color.brand.secondary.default 색상을 변경해 준다.

secondary.default 색상 변경


default 색상을 변경했음에도 팔레트가 변경되지 않는 이유는 primary 데이터를 그대로 복제해서 secondary.0~100 팔레트는 여전히 primary.default를 참조하고 있기 때문이다. 이 참조를 다시 secondary로 변경해 줘야 한다.

primary > secondary로 모두 변경되어야 하는 부분



토큰을 하나씩 edit을 눌러서 변경하면 힘드니 json 모드로 변경하여 일괄 변경을 해준다. secondary 하위 영역에서 'primary' 키워드를 선택하고 ctrl+D를 눌러서 변경이 필요한 부분을 연속 선택해 준 후에 'primary' → 'secondary'로 단어를 모두 바꿔준다. 정보 변경 후 'save json' 버튼을 누르면 secondary 팔레트가 secondary.default 기준으로 변경되는 것을 확인할 수 있다. 모두 다 선택해서 변경하면 안 되는 이유는 primary 팔레트는 primary로 유지되어야 하기 때문이다.

토큰 스튜디오 json 모드
참조 정보 일괄 변경
단축키
1) 단어 모두 선택 : ctrl+shift+L
2) 아래로 개별 선택 : ctrl+D



다른 색상들도 위처럼 ⓐ 복제하고 → ⓑ default 색상 바꾸고 → ⓒ json에서 참조 변수를 일괄 변경해 주는 식으로 추가하면 빠르게 추가할 수 있다. 궁금해서 녹화하면서 진행해 보았는데 팔레트 하나를 만드는 데 33초 정도 걸렸다. 도큐먼트까지 정리하는 데에는 1분 정도가 걸린다.



네이밍 규칙 유의해서 변경

f.color{group}.{colorName}.{hierarchy}


데이터를 변경할 때 유의할 점은 primary와 secondary는 brand라는 상위 집합={group}이 동일하기 때문에 그대로 유지했지만, 다른 그룹을 복제해서 수정할 경우에는 네이밍 규칙이 다른 부분까지 고려해서 변경을 해줘야 한다.


1) 같은 집합의 팔레트 복제 후 변경

f.color.brand.primery.{0~100} → f.color.brand.secondary.{0~100}


2) 다른 집합의 팔레트 복제 후 변경

f.color.brand.primery.{0~100} → f.color.basic.gray.{0~100}






마무리

토큰 스튜디오를 활용하여 HSL의 Lightness 기준으로 색상의 위계를 나누고 쉽게 변경하거나 확장할 수 있도록 구성을 해보았다. 물론 색상 모델마다 장단점이 있고 목적에 맞는 디테일한 설정을 고려한다면 더 좋은 방식이 있을 수는 있지만, 디자인 시스템을 구축하면서 가장 중요하게 생각했던 부분은 규칙과 시스템화였다. 가능하면 반복 작업과 노가다를 줄일 수 있는 방법을 고안하고 싶었다. 디자인 시스템도 결국 서비스가 발전하면서 계속 바뀔 수 있는 부분이기 때문에 쉽게 변경할 수 있게 구성을 해두어야 추후 업데이트가 용이할 것 같았기 때문이다.


여기까지는 아주 기본적인 작동 방식만 기록을 해두었고, 사실상 시각적 보정 및 다크모드와 같은 테마, 시맨틱 컬러 등을 고려하면 더 세부적인 조절이 필요하긴 하다. 쓰다 보니 또 길어지는 것 같아서 나머지 부분들을 시간이 될 때 더 기록을 해두고 싶다.

다크모드 등 테마 변경

디자인 토큰 도큐먼트 생성 및 업데이트 싱크

피그마 베리어블로 일괄 등록하기

시맨틱 컬러

깃헙 연동 후 json 푸시, 개발자와의 협업 등

...


브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari