이 예제는 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>