색상 팔레트 생성기
베이스 색상에서 보색, 유사색, 삼색, 사색 배색 팔레트 생성
베이스 색상
배색 유형
생성된 팔레트
색상 팔레트란?
색상 팔레트는 디자인에서 함께 사용하도록 선택된 고정된 색상 집합입니다. 브랜드, 웹사이트, 일러스트레이션을 위한 베이스 색상 하나를 선택했을 때, 그 옆에 잘 어울리는 보조 색상이 필요합니다. 색상 팔레트 생성은 색채 이론의 규칙, 특히 표준 HSL 색상환의 기하학적 관계를 적용하여 이 선택을 자동화합니다.
HSL(색조, 채도, 명도) 색상환은 360도 원형으로 색조를 배열합니다. 빨간색은 0도, 초록색은 120도, 파란색은 240도에 위치합니다. 모든 색상 배색 유형은 베이스 색상으로부터 특정 각도 거리에서 색조를 선택하는 방식으로 작동합니다. 예를 들어 보색은 180도 반대편에 있는 두 색상을 사용합니다. 유사색은 양쪽으로 30도 이내의 색상을 선택합니다. 이러한 기하학적 규칙은 선택된 색조가 한 영역에 집중되지 않고 색상환 전체에 분산되므로 균형 잡힌 조합을 만들어냅니다.
이 도구는 임의의 hex 색상을 입력받아 HSL로 변환하고, 선택된 배색 유형이 정의하는 각도만큼 색조를 회전시킨 후 결과를 다시 hex로 변환합니다. 보색, 유사색, 삼색, 분할 보색, 사색, 단색 등 여섯 가지 배색 유형을 지원합니다. 각 유형은 2~5개의 색상을 출력합니다.
이 색상 팔레트 생성기를 사용하는 이유
시행착오를 통해 어울리는 색상을 고르는 것은 느리고 일관성이 없습니다. 팔레트 생성기는 색채 이론 규칙을 즉시 적용하여 어떤 출발점에서도 수학적으로 균형 잡힌 결과를 제공합니다.
색상 팔레트 생성기 활용 사례
색상 배색 유형 비교
모든 배색 유형은 HSL 색상환에서 베이스 색상으로부터의 색조 회전 각도를 기반으로 색상을 선택합니다. 아래 표는 각 유형, 생성 색상 수, 회전 각도, 가장 적합한 디자인 상황을 정리합니다.
| 배색 유형 | 색상 수 | 색조 각도 | 적합한 용도 |
|---|---|---|---|
| Complementary | 2 | 180 | High contrast, call-to-action buttons |
| Analogous | 3 | -30, 0, +30 | Harmonious, low-tension backgrounds |
| Triadic | 3 | 0, 120, 240 | Balanced variety, dashboards |
| Split-Complementary | 3 | 0, 150, 210 | Softer contrast than complementary |
| Tetradic (Rectangle) | 4 | 0, 90, 180, 270 | Rich palettes, complex UIs |
| Monochromatic | 5 | Same hue, varied lightness | Subtle, single-brand pages |
HSL 색상환 회전 원리
이 도구의 모든 팔레트 생성은 HSL 색상 모델을 기반으로 합니다. 세 가지 축을 이해하면 베이스 색상이 각 배색 유형에서 어떻게 변환될지 예측할 수 있습니다.
코드 예제
HSL 변환과 색조 회전을 사용하여 프로그래밍 방식으로 색상 팔레트를 생성하세요.
// Generate a complementary color by rotating hue 180 degrees
function hexToHsl(hex) {
let r = parseInt(hex.slice(1,3), 16) / 255;
let g = parseInt(hex.slice(3,5), 16) / 255;
let b = parseInt(hex.slice(5,7), 16) / 255;
const max = Math.max(r,g,b), min = Math.min(r,g,b);
let h = 0, s = 0, l = (max + min) / 2;
if (max !== min) {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
if (max === r) h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
else if (max === g) h = ((b - r) / d + 2) / 6;
else h = ((r - g) / d + 4) / 6;
}
return [Math.round(h * 360), Math.round(s * 100), Math.round(l * 100)];
}
function hslToHex(h, s, l) {
s /= 100; l /= 100;
const a = s * Math.min(l, 1 - l);
const f = n => {
const k = (n + h / 30) % 12;
return Math.round(255 * (l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1))));
};
return '#' + [f(0), f(8), f(4)].map(v => v.toString(16).padStart(2, '0')).join('');
}
const base = '#6366f1';
const [h, s, l] = hexToHsl(base);
const comp = hslToHex((h + 180) % 360, s, l);
console.log(comp); // → "#f1ee63"import colorsys
def hex_to_hsl(hex_color: str):
r, g, b = (int(hex_color[i:i+2], 16) / 255 for i in (1, 3, 5))
h, l, s = colorsys.rgb_to_hls(r, g, b)
return round(h * 360), round(s * 100), round(l * 100)
def hsl_to_hex(h: int, s: int, l: int) -> str:
r, g, b = colorsys.hls_to_rgb(h / 360, l / 100, s / 100)
return '#{:02x}{:02x}{:02x}'.format(round(r * 255), round(g * 255), round(b * 255))
def complementary(hex_color: str) -> str:
h, s, l = hex_to_hsl(hex_color)
return hsl_to_hex((h + 180) % 360, s, l)
def triadic(hex_color: str) -> list[str]:
h, s, l = hex_to_hsl(hex_color)
return [hex_color, hsl_to_hex((h + 120) % 360, s, l), hsl_to_hex((h + 240) % 360, s, l)]
print(complementary('#6366f1')) # → #f1ee63
print(triadic('#6366f1')) # → ['#6366f1', '#66f163', '#f16366']package main
import (
"fmt"
"math"
)
func hexToHSL(hex string) (float64, float64, float64) {
var r, g, b uint8
fmt.Sscanf(hex, "#%02x%02x%02x", &r, &g, &b)
rf, gf, bf := float64(r)/255, float64(g)/255, float64(b)/255
max := math.Max(rf, math.Max(gf, bf))
min := math.Min(rf, math.Min(gf, bf))
l := (max + min) / 2
if max == min {
return 0, 0, l * 100
}
d := max - min
s := d / (2 - max - min)
if l <= 0.5 {
s = d / (max + min)
}
var h float64
switch max {
case rf:
h = (gf - bf) / d
if gf < bf { h += 6 }
case gf:
h = (bf-rf)/d + 2
case bf:
h = (rf-gf)/d + 4
}
return h * 60, s * 100, l * 100
}
func hslToHex(h, s, l float64) string {
s /= 100; l /= 100
a := s * math.Min(l, 1-l)
f := func(n float64) uint8 {
k := math.Mod(n+h/30, 12)
return uint8(255 * (l - a*math.Max(-1, math.Min(math.Min(k-3, 9-k), 1))))
}
return fmt.Sprintf("#%02x%02x%02x", f(0), f(8), f(4))
}
func main() {
h, s, l := hexToHSL("#6366f1")
comp := hslToHex(math.Mod(h+180, 360), s, l)
fmt.Println(comp) // → #f1ee63
}