이 예제는 4가지 다른 방법으로 배경색과 대비되는 텍스트 색상을 자동으로 계산하는 방법을 보여줍니다:
주요 방법들:
1. 명도 기반 흑백 대비 (추천)
배경색의 명도를 계산하여 밝으면 검은색, 어두우면 흰색 사용
가장 실용적이고 가독성이 좋음
2. 색상환 보색
색상환에서 정확히 반대편 색상 계산
시각적으로 강한 대비, 디자인 강조에 적합
3. RGB 반전
각 RGB 값을 255에서 빼서 반전
구현이 간단하지만 회색 계열에서 대비 부족
4. WCAG 기준 대비
웹 접근성 가이드라인 기준으로 최적 대비 계산
접근성을 고려한 가장 권장되는 방법
색상 선택기를 사용하거나 "랜덤 색상" 버튼을 클릭하여 각 방법의 차이점을 실시간으로 확인할 수 있습니다. 일반적인 웹사이트에서는 방법 1(명도 기반) 또는 **방법 4(WCAG 기준)**를 사용하는 것이 좋습니다.
주요 방법들:
1. 명도 기반 흑백 대비 (추천)
배경색의 명도를 계산하여 밝으면 검은색, 어두우면 흰색 사용
가장 실용적이고 가독성이 좋음
2. 색상환 보색
색상환에서 정확히 반대편 색상 계산
시각적으로 강한 대비, 디자인 강조에 적합
3. RGB 반전
각 RGB 값을 255에서 빼서 반전
구현이 간단하지만 회색 계열에서 대비 부족
4. WCAG 기준 대비
웹 접근성 가이드라인 기준으로 최적 대비 계산
접근성을 고려한 가장 권장되는 방법
색상 선택기를 사용하거나 "랜덤 색상" 버튼을 클릭하여 각 방법의 차이점을 실시간으로 확인할 수 있습니다. 일반적인 웹사이트에서는 방법 1(명도 기반) 또는 **방법 4(WCAG 기준)**를 사용하는 것이 좋습니다.
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>자동 보색 텍스트 색상</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
transition: all 0.3s ease;
}
.container {
max-width: 800px;
margin: 0 auto;
}
.demo-section {
margin: 20px 0;
padding: 20px;
border-radius: 8px;
transition: all 0.3s ease;
}
.color-picker {
margin: 10px 0;
}
.color-picker label {
display: inline-block;
width: 120px;
font-weight: bold;
}
.color-picker input[type="color"] {
width: 50px;
height: 30px;
border: none;
border-radius: 4px;
cursor: pointer;
}
.method-title {
font-size: 1.2em;
font-weight: bold;
margin-bottom: 10px;
border-bottom: 2px solid;
padding-bottom: 5px;
}
.explanation {
margin: 10px 0;
padding: 10px;
background-color: rgba(255, 255, 255, 0.1);
border-radius: 4px;
font-size: 0.9em;
}
button {
background-color: rgba(255, 255, 255, 0.2);
border: 1px solid rgba(255, 255, 255, 0.3);
color: inherit;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
margin: 5px;
transition: all 0.3s ease;
}
button:hover {
background-color: rgba(255, 255, 255, 0.3);
}
</style>
</head>
<body>
<div class="container">
<h1>자동 보색 텍스트 색상 지정</h1>
<div class="color-picker">
<label>배경색 선택:</label>
<input type="color" id="bgColorPicker" value="#3498db">
<button onclick="randomColor()">랜덤 색상</button>
</div>
<!-- 방법 1: 명도 기반 흑백 대비 -->
<div class="demo-section" id="method1">
<div class="method-title">방법 1: 명도 기반 흑백 대비</div>
<div class="explanation">
배경색의 명도를 계산하여 밝으면 검은색, 어두우면 흰색 텍스트를 사용합니다.
가장 실용적이고 가독성이 좋은 방법입니다.
</div>
<p>이 텍스트는 명도 기반으로 자동 조정됩니다.</p>
<button>버튼 예시</button>
</div>
<!-- 방법 2: 색상환 보색 -->
<div class="demo-section" id="method2">
<div class="method-title">방법 2: 색상환 보색</div>
<div class="explanation">
색상환에서 정확히 반대편에 위치한 보색을 계산합니다.
시각적으로 강한 대비를 만들지만 가독성은 떨어질 수 있습니다.
</div>
<p>이 텍스트는 색상환 보색으로 설정됩니다.</p>
<button>버튼 예시</button>
</div>
<!-- 방법 3: RGB 반전 -->
<div class="demo-section" id="method3">
<div class="method-title">방법 3: RGB 반전</div>
<div class="explanation">
각 RGB 값을 255에서 빼서 반전시킵니다.
간단하지만 회색 계열에서는 대비가 약할 수 있습니다.
</div>
<p>이 텍스트는 RGB 반전으로 설정됩니다.</p>
<button>버튼 예시</button>
</div>
<!-- 방법 4: 고급 대비 계산 -->
<div class="demo-section" id="method4">
<div class="method-title">방법 4: WCAG 기준 대비</div>
<div class="explanation">
WCAG(웹 접근성 가이드라인) 기준에 따라 최적의 대비를 계산합니다.
접근성을 고려한 가장 권장되는 방법입니다.
</div>
<p>이 텍스트는 WCAG 기준으로 최적화됩니다.</p>
<button>버튼 예시</button>
</div>
<div style="margin-top: 40px; padding: 20px; background-color: rgba(0,0,0,0.1); border-radius: 8px;">
<h3>사용 권장사항:</h3>
<ul>
<li><strong>웹사이트 일반 텍스트:</strong> 방법 1 (명도 기반) 또는 방법 4 (WCAG 기준)</li>
<li><strong>디자인 강조 요소:</strong> 방법 2 (색상환 보색)</li>
<li><strong>간단한 구현:</strong> 방법 3 (RGB 반전)</li>
</ul>
</div>
</div>
<script>
// 색상 변환 유틸리티 함수들
function hexToRgb(hex) {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
}
function rgbToHex(r, g, b) {
return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}
function rgbToHsl(r, g, b) {
r /= 255; g /= 255; b /= 255;
const max = Math.max(r, g, b), min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0;
} else {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return {h: h * 360, s: s * 100, l: l * 100};
}
function hslToRgb(h, s, l) {
h /= 360; s /= 100; l /= 100;
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
if (s === 0) {
return {r: l * 255, g: l * 255, b: l * 255};
}
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
return {
r: Math.round(hue2rgb(p, q, h + 1/3) * 255),
g: Math.round(hue2rgb(p, q, h) * 255),
b: Math.round(hue2rgb(p, q, h - 1/3) * 255)
};
}
// 방법 1: 명도 기반 흑백 대비
function getLuminanceContrastColor(bgColor) {
const rgb = hexToRgb(bgColor);
// 상대적 명도 계산 (ITU-R BT.709 표준)
const luminance = (0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b) / 255;
return luminance > 0.5 ? '#000000' : '#ffffff';
}
// 방법 2: 색상환 보색
function getComplementaryColor(bgColor) {
const rgb = hexToRgb(bgColor);
const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b);
const complementaryHue = (hsl.h + 180) % 360;
const complementaryRgb = hslToRgb(complementaryHue, hsl.s, hsl.l);
return rgbToHex(complementaryRgb.r, complementaryRgb.g, complementaryRgb.b);
}
// 방법 3: RGB 반전
function getInvertedColor(bgColor) {
const rgb = hexToRgb(bgColor);
const invertedRgb = {
r: 255 - rgb.r,
g: 255 - rgb.g,
b: 255 - rgb.b
};
return rgbToHex(invertedRgb.r, invertedRgb.g, invertedRgb.b);
}
// 방법 4: WCAG 기준 대비
function getWCAGContrastColor(bgColor) {
const rgb = hexToRgb(bgColor);
// 상대적 명도 계산 (WCAG 기준)
const getLuminance = (r, g, b) => {
const [rs, gs, bs] = [r, g, b].map(c => {
c = c / 255;
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
});
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
};
const bgLuminance = getLuminance(rgb.r, rgb.g, rgb.b);
const whiteContrast = (1 + 0.05) / (bgLuminance + 0.05);
const blackContrast = (bgLuminance + 0.05) / (0 + 0.05);
// 4.5:1 대비율 기준으로 판단
return whiteContrast > blackContrast ? '#ffffff' : '#000000';
}
// 색상 적용 함수
function applyColors(bgColor) {
document.body.style.backgroundColor = bgColor;
// 방법 1: 명도 기반
const method1 = document.getElementById('method1');
const luminanceColor = getLuminanceContrastColor(bgColor);
method1.style.backgroundColor = bgColor;
method1.style.color = luminanceColor;
method1.style.borderColor = luminanceColor;
// 방법 2: 색상환 보색
const method2 = document.getElementById('method2');
const complementaryColor = getComplementaryColor(bgColor);
method2.style.backgroundColor = bgColor;
method2.style.color = complementaryColor;
method2.style.borderColor = complementaryColor;
// 방법 3: RGB 반전
const method3 = document.getElementById('method3');
const invertedColor = getInvertedColor(bgColor);
method3.style.backgroundColor = bgColor;
method3.style.color = invertedColor;
method3.style.borderColor = invertedColor;
// 방법 4: WCAG 기준
const method4 = document.getElementById('method4');
const wcagColor = getWCAGContrastColor(bgColor);
method4.style.backgroundColor = bgColor;
method4.style.color = wcagColor;
method4.style.borderColor = wcagColor;
// 전체 텍스트 색상도 방법 1로 설정
document.body.style.color = luminanceColor;
}
// 랜덤 색상 생성
function randomColor() {
const colors = ['#e74c3c', '#3498db', '#2ecc71', '#f39c12', '#9b59b6', '#1abc9c', '#34495e', '#e67e22', '#95a5a6', '#7f8c8d'];
const randomIndex = Math.floor(Math.random() * colors.length);
const colorPicker = document.getElementById('bgColorPicker');
colorPicker.value = colors[randomIndex];
applyColors(colors[randomIndex]);
}
// 이벤트 리스너
document.getElementById('bgColorPicker').addEventListener('input', function(e) {
applyColors(e.target.value);
});
// 초기 색상 적용
applyColors('#3498db');
</script>
</body>
</html>



