1. 소개
이 섹션은 규범적이지 않습니다.
테스트
이 섹션은 규범적이지 않으며, 테스트가 필요하지 않습니다.
이 모듈은 작성자가 요소의 텍스트 콘텐츠의 전경색과 불투명도를 지정할 수 있도록 하는 CSS 속성을 설명합니다. 또한 CSS <color> 값 유형을 자세히 설명합니다.
이 모듈은 CSS1, CSS2, 및 CSS Color 3에 이미 존재하는 색상 관련 속성과 값을 정의할 뿐만 아니라, 새로운 속성과 값도 정의합니다.
특히, sRGB 이외의 색상 공간에서 색상을 지정할 수 있도록 합니다. 이전에는 sRGB 색역 외부의 더 포화된 색상을 CSS에서 사용할 수 없었으며, 디스플레이 장치가 이를 지원하더라도 사용할 수 없었습니다.
초안 구현 보고서를 사용할 수 있습니다.
1.1. 값 정의
이 명세서는 CSS 속성 정의 관례를 [CSS2]에서 따르며, 값 정의 구문을 [CSS-VALUES-3]에서 사용합니다. 이 명세서에 정의되지 않은 값 타입은 CSS 값과 단위 [CSS-VALUES-3]에서 정의됩니다. 다른 CSS 모듈과의 조합으로 이러한 값 타입의 정의가 확장될 수 있습니다.
정의에 나열된 속성별 값 외에도, 이 명세에서 정의된 모든 속성은 CSS-wide 키워드를 속성 값으로 허용합니다. 가독성을 위해 이를 명시적으로 반복하지 않았습니다.
2. 색상 용어
테스트
이 섹션은 이후에 사용될 정의를 제공합니다. 테스트는 필요하지 않습니다.
색상은 빛이나 빛으로 조명된 물체에 대한 인간의 시각적 인식에 대한 정의(숫자 또는 텍스트)입니다. 인간 색각에 대한 객관적 연구는 색채학이라고 합니다.
물리적 물체의 색상은 각 가시 파장에서 반사되는 빛의 양과 (동일하게, 각 파장에서의 빛의 양) 조명을 제공하는 빛의 실제 색상에 따라 달라집니다. 분광광도계에 의해 측정됩니다.
빛을 방출하는 물체의 색상 (컴퓨터 화면의 색상을 포함)은 각 가시 파장에서 방출되는 빛의 양에 따라 달라집니다. 분광복사계에 의해 측정됩니다.
두 물체가 스펙트럼이 다르지만, 여전히 동일한 물리적 감각을 만들어내는 경우, 우리는 그것들이 동일한 색상을 가지고 있다고 말합니다. 스펙트럼을 CIE XYZ (세 숫자)로 변환하여 두 색상이 동일한지 계산할 수 있습니다.
색상 공간은 기본 색채학적 모델과 관련하여 색상을 체계적으로 조직하는 것입니다. 이를 통해 해당 색상 공간 내의 모든 색상에 대해 명확하고 객관적으로 측정 가능한 의미를 제공합니다. 이는 동일한 색상이 여러 색상 공간에서 표현되거나, 한 색상 공간에서 다른 색상 공간으로 변환되더라도 여전히 동일하게 보일 수 있음을 의미합니다.
한 잎을 분광광도계로 측정한 결과, lch(51.2345% 21.2 130) 색상이며, 이는 lab(51.2345% -13.6271 16.2401)으로 표현됩니다.
이 동일한 색상은 여러 색상 공간에서 다음과 같이 표현될 수 있습니다:
color ( sRGB0.41587 0.503670 0.36664 ); color ( display-p30.43313 0.50108 0.37950 ); color ( a98-rgb0.44091 0.49971 0.37408 ); color ( prophoto-rgb0.36589 0.41717 0.31333 ); color ( rec20200.42210 0.47580 0.35605 );
가산 색상 공간은 좌표계가 광 강도에 대해 선형인 공간을 의미합니다. CIE XYZ 색상 공간은 가산 색상 공간입니다. XYZ의 Y 구성 요소는 휘도이며, 단위 면적당 광 강도, 즉 '얼마나 밝은지'를 나타냅니다. 휘도는 cd/m²(칸델라 매 제곱미터)로 측정되며, 흔히 니트(nits)라고도 합니다.
가산 색상 공간에서는 색상 혼합을 정확히 예측할 수 있는 계산이 가능합니다. 대부분의 RGB 공간은 가산적이지 않은데, 이는 구성 요소들이 감마로 인코딩되었기 때문입니다. 이 감마 인코딩을 해제하면 선형 조명 값이 생성됩니다.
두 개의 서로 다른 색상의 스포트라이트가 무대 위를 비춘다고 가정하면, 하나는 측정된 값이 color(xyz 0.15 0.24 0.17) 이고, 다른 하나는 color(xyz 0.11 0.06 0.06)인 경우, 두 색상의 광선이 겹칠 때 혼합된 색상은 XYZ 구성 값의 합계, 즉 color(xyz 0.26 0.30 0.23)이 될 것이라고 정확히 예측할 수 있습니다.
색도는 밝기 요소가 제거된 색상 측정입니다. 위에서 언급된 동일한 조명 예에서, 하나의 조명이 가진 u',v' 색도는 (0.2537, 0.5268)이며, 두 조명이 있을 때에도 색도는 동일합니다 (같은 색상이지만, 더 밝아졌을 뿐입니다).
색도는 가산적이므로, 혼합의 색도(그러나 결과 밝기는 제외)를 정확하게 예측할 수 있습니다. 색도는 2차원이기 때문에, 색도 혼합을 예측하기 위해 색도 다이어그램에 쉽게 표현할 수 있습니다. 임의의 두 색상을 혼합할 수 있으며, 결과 색상은 다이어그램에서 두 색상을 연결하는 선 위에 위치하게 됩니다. 세 가지 색상은 평면을 형성하며, 결과 색상은 다이어그램에서 이들이 형성하는 삼각형 내부에 위치하게 됩니다.
따라서 RGB 색상 공간이 선형화되면 가산적이 되며, 빨강, 초록, 파랑 기본 색상의 색도와 백색점 (모든 기본 색상이 최대 강도로 결합될 때 형성되는 색상)의 색도로 색역이 정의됩니다.
대부분의 색상 공간은 몇 가지 주광을 모사한 백색점 중 하나를 사용하며, 이는 해당 블랙바디 라디에이터의 상관 색온도(CCT) [Understanding_CCT]로 명명됩니다. 예를 들어, D65는 상관 색온도가 6500 켈빈 (실제로는 6504, 플랑크 상수 값이 색상이 처음 정의된 이후 변경되었기 때문)인 주광 백색점입니다.
누적 왕복 오류를 방지하기 위해, 동일한 색도 값이 계산의 모든 곳에서 일관되게 사용되는 것이 중요합니다. 따라서, 최대 호환성을 위해, 이 명세에서는 다음 두 가지 표준 주광 모사 백색점이 정의됩니다:
| 이름 | x | y | CCT |
|---|---|---|---|
| D50 | 0.345700 | 0.358500 | 5003K |
| D65 | 0.312700 | 0.329000 | 6504K |
측정된 물리적 특성 (사용된 기본 색상의 색도와, 주어진 입력 세트에 대한 반응으로 생성된 색상 등)이 색상 공간 또는 색상 생성 장치에 대해 알려진 경우, 이를 특성화(characterized)되었다고 합니다.
추가로 장치가 백색점, 회색의 중립성, 톤 응답의 예측 가능성과 일관성 같은 보정 목표를 충족하도록 조정된 경우, 이를 보정(calibrated)되었다고 합니다.
실제 물리적 장치는 아직 인간 눈이 볼 수 있는 모든 색상을 생성할 수 없습니다. 특정 장치가 생성할 수 있는 색상의 범위를 색역(gamut)이라 하며, (감마와 혼동하지 마십시오). 색역이 제한된 장치는 무지개에서 볼 수 있는 것과 같은 매우 포화된 색상을 생성할 수 없습니다.
다른 색상 공간의 색역은 표현할 수 있는 색상의 부피(큐빅 Lab 단위)를 비교하여 확인할 수 있습니다. 다음 표는 CSS에서 사용할 수 있는 미리 정의된 색상 공간을 조사합니다.
| 색상 공간 | 부피 (백만 Lab 단위) |
|---|---|
| sRGB | 0.820 |
| display-p3 | 1.233 |
| a98-rgb | 1.310 |
| prophoto-rgb | 2.896 |
| rec2020 | 2.042 |
CSS의 색상은 유효하지 않은 색상이거나, 각 구문 형식에 대해 아래에 설명된 대로, 유효한 색상입니다.
유효하지 않은 색상이 아닌 모든 색상은 유효한 색상입니다.
유효한 색상은 여전히 출력 장치 (화면, 프로젝터, 프린터 등)가 생성할 수 있는 색상 범위를 벗어날 수 있습니다.
이를 색역 외(out of gamut)라고 합니다.
각 유효한 색상은 특정 출력 장치(화면 또는 프린터)에 대해 색역 내(in-gamut)이거나, 색역 외(out of gamut)입니다.
이는 display-p3로 표현했을 때, 하나 이상의 좌표가 1.0보다 크거나 0.0보다 작기 때문입니다:color ( prophoto-rgb0.88 0.45 0.10 )
이 색상은 유효하며, 예를 들어 그라디언트 정지점으로 사용할 수 있지만, 표시를 위해 CSS 색역 매핑이 필요하며, 비슷하게 보이지만 채도가 낮은(덜 포화된) 색상을 생성합니다.color ( display-p31.0844 0.43 0.1 )
3. CSS에서 색상 적용
3.1. 접근성과 색상으로 정보 전달
테스트
이 섹션은 작성 지침을 제공합니다. 테스트는 필요하지 않습니다.
색상은 문서에 중요한 정보를 추가하고 가독성을 높일 수 있지만, 색상만으로 중요한 정보를 전달해서는 안 됩니다. 작성자는 문서에서 색상을 사용할 때 W3C 웹 콘텐츠 접근성 가이드라인 [WCAG21]을 고려해야 합니다.
1.4.1 색상 사용: 색상은 정보를 전달하거나, 작업을 나타내거나, 반응을 유도하거나, 시각적 요소를 구별하는 데 유일한 시각적 수단으로 사용되지 않습니다
3.2. 전경색: color 속성
| 이름: | color |
|---|---|
| 값: | <color> |
| 초기값: | CanvasText |
| 적용 대상: | 모든 요소 및 텍스트 |
| 상속 여부: | 예 |
| 퍼센트: | N/A |
| 계산된 값: | 계산된 색상, 색상 값 해결 참조 |
| 정규 순서: | 문법에 따름 |
| 애니메이션 유형: | 계산된 값 유형에 따라 |
테스트
이 속성은 요소의 주요 전경색을 지정합니다. 이는 텍스트 콘텐츠의 채우기 색상으로 사용되며, 추가적으로 사용된 값을 지정하여 currentcolor로 해석됩니다. 이는 이 전경색에 대한 간접 참조를 허용하며, border-color 및 text-emphasis-color와 같은 다양한 다른 색상 속성의 초기값에 영향을 미칩니다.
- <color>
- 지정된 <color>로 주요 전경색을 설정합니다.
em{ color : lime; } /* color keyword */ em{ color : rgb ( 0 255 0 ); } /* RGB range 0-255 */ em{ color : rgb ( 0 % 100 % 0 % ); } /* RGB range 0%-100% */ em{ color : color ( sRGB0 1 0 ); } /* sRGB range 0.0-1.0 */
이 속성이 텍스트에 적용될 때, 알파 구성 요소를 포함하여,
"색상 글리프"(일부 글꼴의 이모지 등)에는 영향을 미치지 않습니다.
이러한 글리프는 내장 팔레트로 색상이 지정됩니다.
그러나 일부 색상 글꼴은 컨텍스트 "전경색"을 참조할 수 있으며,
예를 들어 OpenType의 COLR 테이블에서 0xFFFF 팔레트 항목
또는 SVG-in-OpenType의 context-fill 값을 통해 가능합니다.
이러한 경우, 전경색은 이 속성에 의해 설정되며,
currentcolor 값 설정과 동일합니다.
3.3. 투명도: opacity 속성
Opacity는 후처리 작업으로 볼 수 있습니다. 개념적으로, 요소(자식 요소 포함)가 RGBA 오프스크린 이미지로 렌더링된 후, opacity 설정은 오프스크린 렌더링을 현재 합성 렌더링에 어떻게 혼합할지 지정합니다. 자세한 내용은 단순 알파 합성을 참고하세요.
| 이름: | opacity |
|---|---|
| 값: | <opacity-value> |
| 초기값: | 1 |
| 적용 대상: | 모든 요소 |
| 상속: | 아님 |
| 백분율: | [0,1] 범위로 매핑 |
| 계산값: | 지정된 숫자, [0,1] 범위로 클램핑 |
| 정식 순서: | 문법에 따라 |
| 애니메이션 유형: | 계산값 유형 기준 |
테스트
- clip-opacity-out-of-flow.html (실시간 테스트) (소스)
- t32-opacity-basic-0.0-a.xht (실시간 테스트) (소스)
- t32-opacity-basic-0.6-a.xht (실시간 테스트) (소스)
- t32-opacity-basic-1.0-a.xht (실시간 테스트) (소스)
- t32-opacity-clamping-0.0-b.xht (실시간 테스트) (소스)
- t32-opacity-clamping-1.0-b.xht (실시간 테스트) (소스)
- t32-opacity-offscreen-b.xht (실시간 테스트) (소스)
- t32-opacity-offscreen-multiple-boxes-1-c.xht (실시간 테스트) (소스)
- t32-opacity-offscreen-multiple-boxes-2-c.xht (실시간 테스트) (소스)
- t32-opacity-offscreen-with-alpha-c.xht (실시간 테스트) (소스)
- t32-opacity-zorder-c.xht (실시간 테스트) (소스)
- opacity-computed.html (실시간 테스트) (소스)
- opacity-valid.html (실시간 테스트) (소스)
- opacity-invalid.html (실시간 테스트) (소스)
- composited-filters-under-opacity.html (실시간 테스트) (소스)
- filters-under-will-change-opacity.html (실시간 테스트) (소스)
- color-composition.html (실시간 테스트) (소스)
- opacity-interpolation.html (실시간 테스트) (소스)
- canvas-change-opacity.html (실시간 테스트) (소스)
- opacity-animation-ending-correctly-001.html (실시간 테스트) (소스)
- opacity-animation-ending-correctly-002.html (실시간 테스트) (소스)
- <opacity-value>
-
요소에 적용될 투명도입니다.
결과 투명도는 특정 색상이 아니라
전체 요소에 적용됩니다.
[0,1] 범위를 벗어나는 opacity 값도 잘못된 것은 아니며, 지정된 값으로는 보존되지만 계산 값에서는 [0, 1] 범위로 클램핑됩니다.
CSS에서 opacity는 <opacity-value> 문법으로 표시되며, 예를 들어 opacity 속성에서 사용됩니다.
<opacity-value> = <number> | <percentage>
<number>로 표현될 때, 값의 유효 범위는 0(완전 투명)을 나타내며 1(완전 불투명)을 나타냅니다. 또한 <percentage>로도 작성할 수 있으며, 이는 동일한 <number>로 계산됩니다(0%는 0, 100%는 1).
opacity 속성은 지정된 투명도를 요소 전체에 적용하며, 내용도 포함하고, 각 자손 요소에 개별적으로 적용하는 것이 아닙니다. 예를 들어, 불투명한 자식이 요소의 배경 일부를 가리는 경우 opacity가 1보다 작아도 계속 가리지만, 요소와 자식 전체는 아래 페이지를 투명하게 보여줍니다.
또한 요소의 모든 문자에 대응하는 글리프도 전체로 처리되며, 겹치는 부분이 있어도 투명도가 더 높아지지 않습니다.
각 글리프마다 개별 투명도가 필요하다면, opacity 속성 대신 알파값이 포함된 색상 값을 사용하면 됩니다.
박스의 opacity가 1보다 작으면 자식 요소에 대해 스태킹 컨텍스트가 생성됩니다. (이는 자식 내용이 z축에서 박스 외부 내용과 섞이지 않도록 방지합니다.)
또한 z-index 속성이 박스에 적용될 경우 auto 값은 해당 요소에서 0으로 처리되고, 그렇지 않으면 부모 스태킹 컨텍스트 내에서 스택 레벨 0인 포지셔닝된 요소와 동일한 레이어에 그려집니다 (즉, z-index:0인 포지셔닝된 요소처럼).
스태킹 컨텍스트에 대한 자세한 내용은 9.9절과 부록 E, [CSS2] 를 참고하세요.
SVG 요소에는 이러한 z-순서 규칙이 적용되지 않습니다. SVG는 자체 렌더링 모델([SVG11], 3장)을 따르기 때문입니다.
opacity 속성의 값은 히트 테스트에는 영향을 주지 않습니다.
3.4. 태그된 이미지의 색 공간
태그된 이미지란 이미지 포맷에 따라 명시적으로 색상 프로파일이 지정된 이미지를 말합니다. 이는 보통 International Color Consortium (ICC) 프로파일 [ICC]을 포함하여 이루어집니다.
예를 들어 JPEG [JPEG], PNG [PNG], TIFF [TIFF] 모두 ICC 프로파일을 내장하는 방법을 명시합니다.
이미지 포맷은 간결함을 위해 다른 동등한 방식도 사용할 수 있습니다.
예를 들어, PNG는 sRGB 청크를 통해, sRGB 색 공간에 있음을 명시적으로 태그할 수 있으며, sRGB ICC 프로파일을 포함하지 않아도 됩니다.
마찬가지로, PNG는 cICP 청크를 통해 Display P3, BT.2100 HLG 등 다양한 SDR 또는 HDR 색 공간에 속함을 명시적으로 태그하는 간결한 방법을 제공합니다. 이때 ICC 프로파일을 포함하지 않아도 됩니다.
태그된 RGB 이미지와, RGB 변환 방식(예: YCbCr)을 사용하는 태그된 이미지의 경우 색상 프로파일 또는 기타 식별 정보가 유효하다면, 지정된 색 공간에 있는 것으로 간주해야 합니다.
테스트
예를 들어, Display P3 모니터가 있는 시스템에서 실행되는 브라우저가 ITU Rec BT.2020 [Rec.2020] 색 공간으로 태그된 JPEG 이미지를 표시할 때, 색상을 ITU Rec BT.2020에서 Display P3로 변환하여 올바르게 표시해야 합니다. ITU Rec BT.2020 값을 Display P3 값으로 간주해서는 안 되며, 그렇게 하면 잘못된 색상이 출력됩니다.
색상 프로파일이나 기타 식별 정보가 잘못된 경우, 이미지는 태그되지 않은 이미지에 대해 설명된 대로 처리됩니다.
3.5. 태그되지 않은 색상의 색 공간
호환성을 위해 HTML에서 지정한 색상과 태그되지 않은 이미지는 별도로 지정하지 않는 한 sRGB 색 공간([SRGB])에 있는 것으로 간주해야 합니다.
태그되지 않은 이미지란 이미지 포맷에 따라 명시적으로 색상 프로파일이 지정되지 않은 이미지를 말합니다.
이 규칙은 태그되지 않은 비디오에는 적용되지 않습니다. 태그되지 않은 비디오는 ITU가 정의한 색 공간에 있는 것으로 추정해야 합니다.
-
720p 미만에서는 Recommendation ITU-R BT.601 [ITU-R-BT.601]
-
720p에서는 SMPTE ST 296(709와 동일한 색도) [SMPTE296]
-
1080p에서는 Recommendation ITU-R BT.709 [ITU-R-BT.709]
-
4k(UHDTV) 이상에서는 SDR 비디오에 대해 ITU-R BT.2020 [Rec.2020]을 사용합니다.
4. 색상 표현: <color> 타입
테스트
이 절에서는 타입을 설명하며, 해당 타입이 사용되는 부분에서 주로 테스트됩니다.
CSS에서 색상은 색상 공간의 축을 나타내는 색상 컴포넌트(채널) 목록으로 표현됩니다. 각 컴포넌트는 최소값과 최대값을 가지며, 그 사이의 어떤 값도 가질 수 있습니다. 또한 모든 색상에는 얼마나 투명한지, 즉 배경이 얼마나 비치는지를 나타내는 알파 컴포넌트가 동반됩니다.
CSS에서는 색상 값을 지정하기 위한 여러 가지 문법이 있습니다:
-
RGB 및 알파 컴포넌트를 16진수로 표현하는 sRGB 16진수 색상 표기법
-
다양한 색상 공간과 좌표계를 사용할 수 있는 색상 함수
-
상수 이름이 지정된 색상 키워드
-
변수 <system-color> 키워드와 currentColor 키워드.
색상 함수는 CSS 함수형 표기법을 사용하여 다양한 색상 공간에서 색상을 컴포넌트 좌표로 표현합니다. 일부는 실린더 극 좌표 색상 모델을 사용하며, 색상을 <hue> 각도, 중심축(밝기, 즉 검정~흰색), 반지름(채도 또는 크로마, 중성 회색에서의 거리)으로 지정합니다. 나머지는 직교 좌표 색상 모델을 사용하며, 색상을 세 개의 직교 축으로 지정합니다.
Level 4에서 제공되는 색상 함수는 다음과 같습니다.
-
rgb() 및 rgba() 별칭은 (16진수 색상 표기법과 같이) 빨강/초록/파랑/알파 구성 요소로 sRGB 색상을 직접 지정합니다.
-
hsl() 및 hsla() 별칭은 HSL 원통좌표계를 사용하여 색상, 채도, 명도를 통해 sRGB 색상을 지정합니다.
-
lab()는 CIE LAB 직교좌표계를 사용하여 CIE 명도와 a, b축 색상좌표(빨강/초록, 노랑/파랑)를 통해 CIELAB 색상을 지정합니다.
-
lch()는 CIE LCH 원통좌표계를 사용하여 CIE 명도, 채도, 색상으로 CIELAB 색상을 지정합니다.
-
oklab()는 Oklab 직교좌표계를 사용하여 Oklab 명도와 a, b축 색상좌표(빨강/초록, 노랑/파랑)를 통해 Oklab 색상을 지정합니다.
-
oklch()는 OkLCh 원통좌표계를 사용하여 Oklab 명도, 채도, 색상으로 Oklab 색상을 지정합니다.
-
color()는 sRGB, 선형광 sRGB, Display P3, 선형광 Display P3, A98 RGB, ProPhoto RGB, ITU-R BT.2020-2, 그리고 CIE XYZ 등 다양한 색 공간의 색상을 지정할 수 있게 합니다.
다른 명세에서 쉽게 참고할 수 있도록, 불투명 검정은 rgb(0 0 0 / 100%) 색상으로 정의되고, 투명 검정은 동일한 색상이지만 완전히 투명—즉, rgb(0 0 0 / 0%)입니다.
테스트
4.1. <color> 문법
테스트
이 절은 이후에 사용되는 정의를 제공하므로 테스트가 필요하지 않습니다.
CSS의 색상은 <color> 타입으로 표현됩니다:
<color> = <color-base> | currentColor | <system-color> <color-base> = <hex-color> | <color-function> | <named-color> | transparent <color-function> = <rgb () > | <rgba () > | <hsl () > | <hsla () > | <hwb () > | <lab () > | <lch () > | <oklab () > | <oklch () > | <color () >
절대 색상은 <color> 중 계산된 값이 절대 색도 해석을 가지는 경우를 의미합니다. 즉, 값이 다음에 해당하지 않습니다:
-
currentColor (이는 color 속성 값에 따라 달라짐)
-
<system-color> (이는 색상 모드에 따라 달라짐)
sRGB로 해석되는 색상은 다음과 같습니다:
레거시 색상 문법을 지원하는 함수는 다음과 같습니다:
<hsl()>, <hsla()>, <hwb()>, <lch()>, <oklch()> 색상 함수는 실린더 극 좌표 색상 표현방식이며 <hue> 각도를 사용합니다; 그 외의 색상 함수는 직교 좌표 색상 표현방식을 사용합니다.
4.1.1. 모던(공백 구분) 색상 함수 문법
이 명세에서 처음 정의된 모든 절대 색상 함수형 형식은 모던 색상 문법을 사용합니다. 즉:
-
색상 컴포넌트는 공백으로 구분됨
-
선택적 알파 항목은 슬래시("/")로 구분됨
-
직렬화 시 최소 요구 정밀도가 정의되며, 컴포넌트당 8비트보다 높을 수 있음
-
<percentage>와 <number>를 자유롭게 혼합해서 사용할 수 있음
4.1.2. 레거시(쉼표 구분) 색상 함수 문법
웹 호환성을 위해, rgb(), rgba(), hsl(), hsla()의 문법(이전 명세에서 정의된)은 레거시 색상 문법도 지원하며, 차이점은 다음과 같습니다:
-
색상 컴포넌트가 쉼표로 구분됨(공백이 앞뒤에 올 수 있음)
-
불투명하지 않은 경우 별도 표기법 사용 (예: hsla()는 hsl() 대신 사용) 알파 항목도 쉼표로 구분됨(앞뒤에 공백이 올 수 있음)
-
최소 요구 정밀도가 더 낮으며, 컴포넌트당 8비트
-
none 값은 허용되지 않음
-
색상 컴포넌트는 모두 <percentage> 또는 모두 <number>로 지정해야 하며, 혼합할 수 없음.
이 명세 및 이후 레벨에서 도입된 색상 함수에는 웹 호환성 문제가 없는 경우 레거시 색상 문법은 유효하지 않습니다.
4.2. 색상에서 투명도 표현: <alpha-value> 문법
테스트
이 절은 이후에 사용되는 정의를 제공하므로 테스트가 필요하지 않습니다.
<alpha-value> = <number> | <percentage>
별도로 지정하지 않는 한, 색상의 <alpha-value> 컴포넌트는 생략 시 100%로 기본 설정됩니다. [0,1] 범위를 벗어난 값도 잘못된 것은 아니지만, 파싱된 값 단계에서 해당 범위로 클램핑됩니다.
4.3. 실린더 좌표 색상각 표현: <hue> 문법
테스트
이 절은 이후에 사용되는 정의를 제공하므로 테스트가 필요하지 않습니다.
색상각(hue)은 색상 원의 각도로 표현됩니다 (무지개를 원으로 휘어놓고, 보라색을 보라~빨강 사이에 추가한 것).
<hue> = <number> | <angle>
이 값은 매우 자주 도 단위(degree)로 주어지므로, 인자(argument)를 숫자로도 지정할 수 있는데, 이 경우 숫자는 도(degree) 단위로 해석되며 정규 단위입니다.
이 숫자는 [0,360) 범위로 정규화(normalize)됩니다.
hsl(360 0 0)에서는 <hue> 컴포넌트가 0도(degree)로 정규화됩니다.
hsl(calc(-infinity) 0 0) 또는 hsl(calc(infinity) 0 0)의 경우, <hue> 컴포넌트 역시 0도(degree)로 정규화됩니다.
참고: 특정 색상에 대응하는 각도와 간격은 색상 공간에 따라 달라집니다. 예를 들어, sRGB 색상 공간을 사용하는 HSL 및 HWB에서는 sRGB 녹색이 120도입니다. LCH에서는 sRGB 녹색이 134.39도, display-p3 녹색은 136.01도, a98-rgb 녹색은 145.97도, prophoto-rgb 녹색은 141.04도입니다 (각 색상 공간마다 녹색의 색조가 다르기 때문입니다).
<hue> 컴포넌트는 무효(powerless)가 되는 경우가 가장 많습니다; 색상이 중심 무채색 축에 충분히 가까우면 무효인 hue 컴포넌트가 됩니다.
4.4. “누락된” 색상 컴포넌트와 none 키워드
특정 경우에, 색상은 하나 이상의 누락된 색상 구성 요소를 가질 수 있습니다.
이 명세에서는 일부 색상(hue 기반 보간으로 인한 white 등)에서 자동으로 발생합니다; 다른 명세에서는 추가적인 상황에서 컴포넌트가 자동으로 누락될 수 있음을 정의할 수 있습니다.
명시적으로 지정할 수도 있는데, 색상 함수의 컴포넌트에 none 키워드를 지정하면 됩니다. 모든 색상 함수는 (레거시 색상 문법을 사용하는 함수를 제외하고) 어떤 컴포넌트라도 none으로 지정할 수 있습니다.
이 기능은 신중하게 사용해야 하며, 원하는 효과가 있을 때만 사용하는 것이 좋습니다.
테스트
- color-computed-color-function.html (실시간 테스트) (소스)
- color-computed-hsl.html (실시간 테스트) (소스)
- color-computed-hwb.html (실시간 테스트) (소스)
- color-computed-lab.html (실시간 테스트) (소스)
- color-computed-relative-color.html (실시간 테스트) (소스)
- color-computed-rgb.html (실시간 테스트) (소스)
- color-invalid-hsl.html (실시간 테스트) (소스)
- color-invalid-rgb.html (실시간 테스트) (소스)
- color-valid-color-function.html (실시간 테스트) (소스)
- color-valid-color-mix-function.html (실시간 테스트) (소스)
- color-valid-hsl.html (실시간 테스트) (소스)
- color-valid-hwb.html (실시간 테스트) (소스)
- color-valid-lab.html (실시간 테스트) (소스)
- color-valid-relative-color.html (실시간 테스트) (소스)
- color-valid-rgb.html (실시간 테스트) (소스)
누락된 컴포넌트가 두 색상을 합치는 상황(예: 색상 보간)에서 어떻게 처리되는지는 § 13.2 누락된 컴포넌트와의 보간를 참고하세요.
그 외의 모든 경우에는 누락된 컴포넌트는 해당 컴포넌트의 단위에 맞는 0값으로 동작합니다: 0, 0%, 0deg. 이는 색상을 직접 렌더링하거나, 다른 색상 공간으로 변환하거나, 색상 컴포넌트 값을 연산할 때 등 모두 포함됩니다.
누락된 컴포넌트가 있는 색상을 직렬화하거나 저자(author)에게 직접 보여줄 경우, 레거시 색상 문법에서는 해당 컴포넌트를 0값으로 표현하고, 그렇지 않은 경우에는 none 키워드로 표현합니다.
결과는 초록과 흰색이 실제로 섞인 것처럼 보이게 되며, 만약 white의 hue가 0deg로 기본 처리된다면 붉게 보일 수도 있습니다.
예를 들어 어떤 색이든 "그레이스케일"로 애니메이션하려면, oklch(none 0 none)과 보간하면 됩니다. 이렇게 하면 시작 색상의 hue와 밝기는 그대로 두고, chroma만 0으로 애니메이션되어 일정 밝기의 회색으로, 애니메이션 내내 hue가 일정하게 유지됩니다.
이걸 수동으로 하려면 시작 색상의 hue와 밝기를 일일이 맞춰야 합니다.
4.4.1. “무효” 색상 컴포넌트
개별 색상 문법에서는, 특정 상황에서 해당 문법의 컴포넌트가 무효 색상 컴포넌트가 될 수 있다고 규정할 수 있습니다. 이는 해당 컴포넌트의 값이 렌더링된 색상에 영향을 주지 않음을 의미합니다; 어떤 값을 주더라도 화면에 표시되는 색상은 동일합니다.
예를 들어, hsl()에서, 채도(saturation) 컴포넌트가 0%일 때 hue 컴포넌트는 무효가 됩니다; 0% 채도는 회색조를 의미하며, hue가 전혀 없는 색상이므로, 0deg든 180deg든, 또는 어떤 각도든 결과는 완전히 동일합니다.
무효 컴포넌트를 수동으로 지정하면, 평소처럼 동작하며; 무효라는 사실이 동작에 영향을 주지 않습니다.
하지만 색상 공간 변환으로 색상이 자동 생성되는 경우, 변환 결과의 무효 컴포넌트는 변환 과정에서 나온 값 대신 누락됨으로 설정해야 합니다.
색상 공간 변환을 실린더 극 좌표 색상 공간으로 할 때, 사용자 에이전트는 chroma(또는 hsl에서의 채도 등 색상도 측정치)가 해당 색상 공간에서 규정된 epsilon(ε)보다 작으면 hue 컴포넌트를 무효로 처리해야 합니다. 예를 들어, 회색을 oklch()로 변환하면 수치 오차로 인해 chroma가 정확히 0%가 아니라 매우 작게 나올 수 있는데, 이 경우 hue 컴포넌트는 무효가 됩니다.
4.5. <color> 값 파싱하기
테스트
이 절은 다른 곳에서 참조되는 정의를 제공하므로 테스트가 필요하지 않습니다.
참고: 이 알고리즘은 CSS <color> 값을 CSS 스타일시트나 CSSOM 인터페이스에서 파싱하기 위한 것이 아니라, HTML 속성이나 Canvas 인터페이스 등 다른 곳에서 사용하기 위한 것입니다.
5. sRGB 색상
CSS에서 sRGB 색상 공간의 색상은 빨강, 초록, 파랑 값의 삼중값(triplet)으로 표현되며, sRGB 색상 공간의 한 점을 식별합니다 [SRGB]. 이 색상 공간은 국제적으로 인정받는 장치 독립적 색상 공간으로, 컴퓨터 화면에 표시될 색상을 지정할 때 유용하며, 프린터와 같은 다른 종류의 장치에 색상을 지정할 때도 유용합니다.
CSS는 또한 sRGB가 아닌 색상 공간도 사용할 수 있도록 허용합니다. 자세한 내용은 § 10 미리 정의된 색상 공간을 참고하세요.
CSS에서는 sRGB 색상을 직접 지정하는 여러 방법을 제공합니다: 16진수 색상, rgb()/rgba() 색상 함수, hsl()/hsla() 색상 함수, hwb() 색상 함수, 이름이 지정된 색상, 그리고 transparent 키워드입니다.
5.1. RGB 함수: rgb() 및 rgba()
rgb() 및 rgba() 함수는 r, g, b(빨강, 초록, 파랑) 컴포넌트를 직접 지정하여 sRGB 색상을 정의합니다. 문법은 다음과 같습니다:
rgb () =[ <legacy-rgb-syntax> | <modern-rgb-syntax>] rgba () =[ <legacy-rgba-syntax> | <modern-rgba-syntax>] <legacy-rgb-syntax> =rgb ( <percentage>#{ 3 } , <alpha-value>?) |rgb ( <number>#{ 3 } , <alpha-value>?) <legacy-rgba-syntax> =rgba ( <percentage>#{ 3 } , <alpha-value>?) |rgba ( <number>#{ 3 } , <alpha-value>?) <modern-rgb-syntax> =rgb ( [ <number> | <percentage> | none] { 3 } [ /[ <alpha-value> | none] ] ?) <modern-rgba-syntax> =rgba ( [ <number> | <percentage> | none] { 3 } [ /[ <alpha-value> | none] ] ?)
| 백분율 | r, g, b 값에 허용됨 |
|---|---|
| 백분율 기준 범위 | r, g, b: 0% = 0.0, 100% = 255.0 alpha: 0% = 0.0, 100% = 1.0 |
테스트
- rgb-001.html (실시간 테스트) (소스)
- rgb-002.html (실시간 테스트) (소스)
- rgb-003.html (실시간 테스트) (소스)
- rgb-004.html (실시간 테스트) (소스)
- rgb-005.html (실시간 테스트) (소스)
- rgb-006.html (실시간 테스트) (소스)
- rgb-007.html (실시간 테스트) (소스)
- rgb-008.html (실시간 테스트) (소스)
- out-of-gamut-legacy-rgb.html (실시간 테스트) (소스)
- color-valid.html (실시간 테스트) (소스)
- color-computed-rgb.html (실시간 테스트) (소스)
- color-invalid-rgb.html (실시간 테스트) (소스)
- color-valid-rgb.html (실시간 테스트) (소스)
처음 세 인자는 각각 r, g, b(빨강, 초록, 파랑) 색상 컴포넌트를 지정합니다. 0%는 해당 sRGB 색상 컴포넌트의 최소값을, 100%는 최대값을 나타냅니다.
색상 컴포넌트의 백분율 기준 범위는 많은 그래픽 엔진이 색상 컴포넌트를 내부적으로 한 바이트(0~255 정수)로 저장했던 역사적 사실에서 유래했습니다. 구현체는 저자가 작성하거나 계산한 컴포넌트의 정밀도를 최대한 존중해야 합니다. 만약 불가능하다면, 컴포넌트는 +∞ 방향으로 반올림되어야 합니다.
마지막 인자인 <alpha-value>는 색상의 알파값을 지정합니다. 생략 시 기본값은 100%입니다.
테스트
이 범위를 벗어난 값도 잘못된 것은 아니지만, 파싱 시점에 여기 정의된 범위로 클램핑됩니다.
역사적 이유로 rgb() 및 rgba()는 레거시 색상 문법도 지원합니다.
테스트
5.2. RGB 16진수 표기법: #RRGGBB
CSS 16진수 색상 표기법은 sRGB 색상을 각 컴포넌트를 16진수 숫자로 지정할 수 있게 해줍니다. 이는 색상을 컴퓨터 코드에서 직접 쓸 때 자주 사용하는 방식과 유사합니다. rgb() 표기법보다 더 짧게 쓸 수 있습니다.
<hex-color>의 문법은 3, 4, 6, 8자리 16진수로 이루어진 <hash-token> 토큰입니다. 즉, 16진수 색상은 해시 문자 "#" 뒤에 0~9 또는 a~f(대소문자 구분 없음, #00ff00과 #00FF00은 동일)를 나열해 작성합니다.
16진수 자릿수에 따라 RGB 색상으로 해석하는 방법이 달라집니다:
- 6자리
- 첫 두 자리는 16진수로 해석해 빨강 컴포넌트를 지정합니다. 00은 최소값, ff(10진수 255)는 최대값입니다. 다음 두 자리는 초록, 마지막 두 자리는 파랑 컴포넌트를 지정하며, 알파값은 완전히 불투명입니다.
- 8자리
- 첫 6자리는 6자리 표기법과 동일하게 해석합니다. 마지막 두 자리는 16진수로 해석해 알파값을 지정하며, 00은 완전 투명, ff는 완전 불투명입니다.
- 3자리
- 6자리 표기법을 짧게 만든 방식입니다. 첫 자리는 빨강 컴포넌트, 0은 최소, f는 최대값입니다. 다음 두 자리는 초록, 파랑을 같은 방식으로 지정하며, 알파값은 완전히 불투명입니다.
- 4자리
- 8자리 표기법을 짧게 만든 것으로, 3자리 표기법과 마찬가지로 "확장"됩니다. 첫 자리는 빨강 컴포넌트, 0은 최소, f는 최대값, 다음 세 자리는 초록, 파랑, 알파 컴포넌트를 각각 지정합니다.
테스트
- hex-001.html (실시간 테스트) (소스)
- hex-002.html (실시간 테스트) (소스)
- hex-003.html (실시간 테스트) (소스)
- hex-004.html (실시간 테스트) (소스)
- border-bottom-color.xht (실시간 테스트) (소스)
- border-left-color.xht (실시간 테스트) (소스)
- border-right-color.xht (실시간 테스트) (소스)
- border-top-color.xht (실시간 테스트) (소스)
- color-valid.html (실시간 테스트) (소스)
- color-computed-hex-color.html (실시간 테스트) (소스)
- color-invalid-hex-color.html (실시간 테스트) (소스)
6. 색상 키워드
다양한 숫자 문법 <color> 외에도, CSS는 여러 색상 키워드 집합을 정의하며, 상황에 따라 쓰일 수 있습니다—각각 장점과 용도가 있습니다.
6.1. 이름이 지정된 색상
CSS는 이름이 지정된 색상을 다수 정의하여, 자주 쓰이는 색상을 더 쉽게 작성하고 읽을 수 있도록 합니다. <named-color>는 <ident>로 작성되며, <color>가 허용되는 모든 곳에서 사용할 수 있습니다. CSS에서 정의한 <ident>처럼, 모든 키워드는 ASCII 대소문자 구분 없이 인식됩니다.
이 이름들은 sRGB 색상으로 해석됩니다.
CSS의 이름이 지정된 색상 중 16개는 원래 VGA 팔레트에서 비롯되었고, HTML에도 채택되었습니다: aqua, black, blue, fuchsia, gray, green, lime, maroon, navy, olive, purple, red, silver, teal, white, yellow. 나머지 대부분은 Unix 계열 시스템에서 콘솔 색상을 지정할 때 사용된 X11 색상 시스템의 한 버전에서 유래했고, 이후 SVG로 채택되었습니다.
참고: 이들 색상 이름이 여기에서 표준화된 것은 좋아서가 아니라, 수십 년간 널리 쓰이고 구현되어왔기 때문이며, 표준은 현실을 반영해야 합니다. 실제로 각 이름이 어떤 색상일지 상상하기 어려운 경우가 많으므로(아래 목록 참고), sRGB 색상 볼륨 전체에 이름이 고르게 분포되어 있지 않고, 이름 간에도 일관성이 없습니다 ( darkgray는 gray보다 더 밝고, lightpink는 pink보다 더 어둡습니다), 그리고 일부 이름( indianred 등)은 논란이 있는 경우도 있습니다. 따라서 사용을 권장하지 않습니다.
(transparent, currentcolor는 별도 섹션에서 정의되어 있습니다.)
아래 표는 모든 불투명 이름 색상을, 다른 색상 표기법으로 동등하게 지정한 값을 제시합니다.
| 이름 | 숫자 표기 | 색상 이름 | 16진수 rgb | 10진수 |
|---|---|---|---|---|
| aliceblue | #f0f8ff | 240 248 255 | ||
| antiquewhite | #faebd7 | 250 235 215 | ||
| aqua | #00ffff | 0 255 255 | ||
| aquamarine | #7fffd4 | 127 255 212 | ||
| azure | #f0ffff | 240 255 255 | ||
| beige | #f5f5dc | 245 245 220 | ||
| bisque | #ffe4c4 | 255 228 196 | ||
| black | #000000 | 0 0 0 | ||
| blanchedalmond | #ffebcd | 255 235 205 | ||
| blue | #0000ff | 0 0 255 | ||
| blueviolet | #8a2be2 | 138 43 226 | ||
| brown | #a52a2a | 165 42 42 | ||
| burlywood | #deb887 | 222 184 135 | ||
| cadetblue | #5f9ea0 | 95 158 160 | ||
| chartreuse | #7fff00 | 127 255 0 | ||
| chocolate | #d2691e | 210 105 30 | ||
| coral | #ff7f50 | 255 127 80 | ||
| cornflowerblue | #6495ed | 100 149 237 | ||
| cornsilk | #fff8dc | 255 248 220 | ||
| crimson | #dc143c | 220 20 60 | ||
| cyan | #00ffff | 0 255 255 | ||
| darkblue | #00008b | 0 0 139 | ||
| darkcyan | #008b8b | 0 139 139 | ||
| darkgoldenrod | #b8860b | 184 134 11 | ||
| darkgray | #a9a9a9 | 169 169 169 | ||
| darkgreen | #006400 | 0 100 0 | ||
| darkgrey | #a9a9a9 | 169 169 169 | ||
| darkkhaki | #bdb76b | 189 183 107 | ||
| darkmagenta | #8b008b | 139 0 139 | ||
| darkolivegreen | #556b2f | 85 107 47 | ||
| darkorange | #ff8c00 | 255 140 0 | ||
| darkorchid | #9932cc | 153 50 204 | ||
| darkred | #8b0000 | 139 0 0 | ||
| darksalmon | #e9967a | 233 150 122 | ||
| darkseagreen | #8fbc8f | 143 188 143 | ||
| darkslateblue | #483d8b | 72 61 139 | ||
| darkslategray | #2f4f4f | 47 79 79 | ||
| darkslategrey | #2f4f4f | 47 79 79 | ||
| darkturquoise | #00ced1 | 0 206 209 | ||
| darkviolet | #9400d3 | 148 0 211 | ||
| deeppink | #ff1493 | 255 20 147 | ||
| deepskyblue | #00bfff | 0 191 255 | ||
| dimgray | #696969 | 105 105 105 | ||
| dimgrey | #696969 | 105 105 105 | ||
| dodgerblue | #1e90ff | 30 144 255 | ||
| firebrick | #b22222 | 178 34 34 | ||
| floralwhite | #fffaf0 | 255 250 240 | ||
| forestgreen | #228b22 | 34 139 34 | ||
| fuchsia | #ff00ff | 255 0 255 | ||
| gainsboro | #dcdcdc | 220 220 220 | ||
| ghostwhite | #f8f8ff | 248 248 255 | ||
| gold | #ffd700 | 255 215 0 | ||
| goldenrod | #daa520 | 218 165 32 | ||
| gray | #808080 | 128 128 128 | ||
| green | #008000 | 0 128 0 | ||
| greenyellow | #adff2f | 173 255 47 | ||
| grey | #808080 | 128 128 128 | ||
| honeydew | #f0fff0 | 240 255 240 | ||
| hotpink | #ff69b4 | 255 105 180 | ||
| indianred | #cd5c5c | 205 92 92 | ||
| indigo | #4b0082 | 75 0 130 | ||
| ivory | #fffff0 | 255 255 240 | ||
| khaki | #f0e68c | 240 230 140 | ||
| lavender | #e6e6fa | 230 230 250 | ||
| lavenderblush | #fff0f5 | 255 240 245 | ||
| lawngreen | #7cfc00 | 124 252 0 | ||
| lemonchiffon | #fffacd | 255 250 205 | ||
| lightblue | #add8e6 | 173 216 230 | ||
| lightcoral | #f08080 | 240 128 128 | ||
| lightcyan | #e0ffff | 224 255 255 | ||
| lightgoldenrodyellow | #fafad2 | 250 250 210 | ||
| lightgray | #d3d3d3 | 211 211 211 | ||
| lightgreen | #90ee90 | 144 238 144 | ||
| lightgrey | #d3d3d3 | 211 211 211 | ||
| lightpink | #ffb6c1 | 255 182 193 | ||
| lightsalmon | #ffa07a | 255 160 122 | ||
| lightseagreen | #20b2aa | 32 178 170 | ||
| lightskyblue | #87cefa | 135 206 250 | ||
| lightslategray | #778899 | 119 136 153 | ||
| lightslategrey | #778899 | 119 136 153 | ||
| lightsteelblue | #b0c4de | 176 196 222 | ||
| lightyellow | #ffffe0 | 255 255 224 | ||
| lime | #00ff00 | 0 255 0 | ||
| limegreen | #32cd32 | 50 205 50 | ||
| linen | #faf0e6 | 250 240 230 | ||
| magenta | #ff00ff | 255 0 255 | ||
| maroon | #800000 | 128 0 0 | ||
| mediumaquamarine | #66cdaa | 102 205 170 | ||
| mediumblue | #0000cd | 0 0 205 | ||
| mediumorchid | #ba55d3 | 186 85 211 | ||
| mediumpurple | #9370db | 147 112 219 | ||
| mediumseagreen | #3cb371 | 60 179 113 | ||
| mediumslateblue | #7b68ee | 123 104 238 | ||
| mediumspringgreen | #00fa9a | 0 250 154 | ||
| mediumturquoise | #48d1cc | 72 209 204 | ||
| mediumvioletred | #c71585 | 199 21 133 | ||
| midnightblue | #191970 | 25 25 112 | ||
| mintcream | #f5fffa | 245 255 250 | ||
| mistyrose | #ffe4e1 | 255 228 225 | ||
| moccasin | #ffe4b5 | 255 228 181 | ||
| navajowhite | #ffdead | 255 222 173 | ||
| navy | #000080 | 0 0 128 | ||
| oldlace | #fdf5e6 | 253 245 230 | ||
| olive | #808000 | 128 128 0 | ||
| olivedrab | #6b8e23 | 107 142 35 | ||
| orange | #ffa500 | 255 165 0 | ||
| orangered | #ff4500 | 255 69 0 | ||
| orchid | #da70d6 | 218 112 214 | ||
| palegoldenrod | #eee8aa | 238 232 170 | ||
| palegreen | #98fb98 | 152 251 152 | ||
| paleturquoise | #afeeee | 175 238 238 | ||
| palevioletred | #db7093 | 219 112 147 | ||
| papayawhip | #ffefd5 | 255 239 213 | ||
| peachpuff | #ffdab9 | 255 218 185 | ||
| peru | #cd853f | 205 133 63 | ||
| pink | #ffc0cb | 255 192 203 | ||
| plum | #dda0dd | 221 160 221 | ||
| powderblue | #b0e0e6 | 176 224 230 | ||
| purple | #800080 | 128 0 128 | ||
| rebeccapurple | #663399 | 102 51 153 | ||
| red | #ff0000 | 255 0 0 | ||
| rosybrown | #bc8f8f | 188 143 143 | ||
| royalblue | #4169e1 | 65 105 225 | ||
| saddlebrown | #8b4513 | 139 69 19 | ||
| salmon | #fa8072 | 250 128 114 | ||
| sandybrown | #f4a460 | 244 164 96 | ||
| seagreen | #2e8b57 | 46 139 87 | ||
| seashell | #fff5ee | 255 245 238 | ||
| sienna | #a0522d | 160 82 45 | ||
| silver | #c0c0c0 | 192 192 192 | ||
| skyblue | #87ceeb | 135 206 235 | ||
| slateblue | #6a5acd | 106 90 205 | ||
| slategray | #708090 | 112 128 144 | ||
| slategrey | #708090 | 112 128 144 | ||
| snow | #fffafa | 255 250 250 | ||
| springgreen | #00ff7f | 0 255 127 | ||
| steelblue | #4682b4 | 70 130 180 | ||
| tan | #d2b48c | 210 180 140 | ||
| teal | #008080 | 0 128 128 | ||
| thistle | #d8bfd8 | 216 191 216 | ||
| tomato | #ff6347 | 255 99 71 | ||
| turquoise | #40e0d0 | 64 224 208 | ||
| violet | #ee82ee | 238 130 238 | ||
| wheat | #f5deb3 | 245 222 179 | ||
| white | #ffffff | 255 255 255 | ||
| whitesmoke | #f5f5f5 | 245 245 245 | ||
| yellow | #ffff00 | 255 255 0 | ||
| yellowgreen | #9acd32 | 154 205 50 |
참고: 이 색상 목록과 정의는 SVG 1.1에 정의된 이름이 지정된 색상 목록의 상위 집합입니다.
역사적 이유로, 이를 X11 색상 집합이라고도 합니다.참고: X11 색상 시스템의 역사는 흥미롭고, Alex Sexton의 “Peachpuffs and Lemonchiffons” 강연에서 훌륭하게 요약되었습니다.
테스트
6.2. 시스템 색상
일반적으로, <system-color> 키워드는 기본 색상 선택을 반영합니다(사용자, 브라우저 또는 운영체제에서 설정). 이러한 이유로 주로 브라우저 기본 스타일 시트에서 사용됩니다.
가독성을 유지하기 위해, <system-color> 키워드는 사용된 색상 체계에도 반응합니다.
가독성이 좋은 링크 텍스트
가독성이 나쁜 링크 텍스트
가독성이 좋은 링크 텍스트
하지만, 강제 색상 모드에서는, 대부분의 페이지 색상이 사용자가 선택한 제한된 팔레트로 강제 적용됩니다. 관련 내용은 CSS Color Adjustment 1 § 5.2 강제 색상 모드 팔레트를 참고하세요. <system-color> 키워드는 이러한 사용자 지정 색상을 노출하여 페이지의 나머지 부분이 제한된 팔레트와 일관성 있게 동작하도록 합니다.
forced-colors 미디어 특성이 active일 때, 작성자는 반드시 <system-color> 키워드를 CSS Color Adjustment 1 § 3.1 강제 색상 모드에 영향을 받는 속성에 나열된 속성이 아닌 다른 속성의 색상 값으로 사용하여, 페이지 전반의 가독성과 일관성을 보장하고 사용자가 강제한 색상과 페이지 지정 색상이 뒤섞이는 현상을 피해야 합니다.
테스트
<system-color> 키워드의 값이 브라우저에서 제공되는 경우 (운영체제 기본값 또는 사용자가 선택한 값이 아닌 경우), 브라우저는 매칭되는 전경/배경 조합이 최소 WCAG AA 대비를 만족하도록 해야 합니다. 단, 사용자의 취향(고대비 또는 저대비 여부)이 브라우저 환경설정, 사용자 스타일시트 또는 OS 기본값 변경을 통해 설정된 경우, 이 요구사항보다 우선 적용되어야 합니다.
작성자는 언제든지 이러한 키워드를 사용할 수 있습니다. 단, 반드시 매칭되는 배경-전경 조합으로 색상을 지정하여 적절한 대비를 확보해야 하며, 매칭되지 않는 조합(예: Canvas와 ButtonText) 간의 특정 대비 관계는 보장되지 않습니다.
<system-color> 키워드는 다음과 같이 정의됩니다:
- AccentColor
- 강조된 사용자 인터페이스 컨트롤의 배경입니다.
- AccentColorText
- 강조된 사용자 인터페이스 컨트롤의 텍스트입니다.
- ActiveText
- 활성 링크의 텍스트. 밝은 배경에서는 전통적으로 빨간색입니다.
- ButtonBorder
- 푸시 버튼의 기본 테두리 색상입니다.
- ButtonFace
- 푸시 버튼의 표면 배경 색상입니다.
- ButtonText
- 푸시 버튼의 텍스트입니다.
- Canvas
- 애플리케이션 콘텐츠나 문서의 배경입니다.
- CanvasText
- 애플리케이션 콘텐츠나 문서의 텍스트입니다.
- Field
- 입력 필드의 배경입니다.
- FieldText
- 입력 필드의 텍스트입니다.
- GrayText
- 비활성화된 텍스트. (종종, 그러나 반드시, 회색임.)
- Highlight
- 선택된 텍스트의 배경(예: ::selection에서).
- HighlightText
- 선택된 텍스트의 텍스트입니다.
- LinkText
- 비활성, 미방문 링크의 텍스트. 밝은 배경에서는 전통적으로 파란색입니다.
- Mark
- 특별히 강조(mark)된 텍스트의 배경
(예: HTML
mark요소). - MarkText
- 특별히 강조된 텍스트
(예: HTML
mark요소). - SelectedItem
- 선택된 항목의 배경(예: 체크박스에서 선택된 항목).
- SelectedItemText
- 선택된 항목의 텍스트입니다.
- VisitedText
- 방문한 링크의 텍스트. 밝은 배경에서는 전통적으로 보라색입니다.
테스트
참고: 다른 키워드처럼, 이 이름들은 ASCII 대소문자 구분 없이 인식됩니다. 가독성을 위해 혼합 대소문자로 표기합니다.
특정 시스템 UI 개념이 없는 시스템에서는, 지정된 값은 존재하는 가장 비슷한 시스템 색상 값으로 매핑되어야 합니다. 다음 시스템 색상 쌍은 읽기 쉬운 배경-전경 색상 조합을 형성해야 합니다:
-
Canvas 배경과 CanvasText, LinkText, VisitedText, ActiveText 전경.
-
Canvas 배경과 ButtonBorder 테두리 및 인접 색상 Canvas
-
ButtonFace 배경과 ButtonText 전경.
-
ButtonFace 또는 Field 배경과 ButtonBorder 테두리, 인접 색상 Canvas
-
Highlight 배경과 HighlightText 전경.
-
SelectedItem 배경과 SelectedItemText 전경.
-
AccentColor 배경과 AccentColorText 전경.
또한, GrayText는 어떤 배경에서도 읽을 수 있어야 하지만, 명도비 평가는 낮을 수 있습니다.
위젯 강조 색상 스타일과 일관성을 유지하기 위해, AccentColor 값은 accent-color에서 가져옵니다. 단, 강제 색상 모드가 활성화된 경우는 제외합니다. AccentColorText 값은 AccentColor에 대한 대비되는 전경색에서 가져오며, 위젯 강조 색상 스타일에 대해 설명된 방식과 같습니다.
Canvas와 CanvasText: CanvasText
Canvas와 LinkText: LinkText
Canvas와 VisitedText: VisitedText
Canvas와 ActiveText: ActiveText
Canvas와 GrayText: GrayText
Canvas와 ButtonBorder 및 인접 Canvas: CanvasTextAdjacent
ButtonFace와 ButtonText: ButtonText
ButtonFace와 ButtonText 및 ButtonBorder: ButtonText
ButtonFace와 GrayText: GrayText
Field와 FieldText: FieldText
Field와 GrayText: GrayText
Mark와 MarkText: MarkText
Mark와 GrayText: GrayText
Highlight와 HighlightText: HighlightText
Highlight와 GrayText: GrayText
SelectedItem과 SelectedItemText: SelectedItemText
AccentColor와 AccentColorText: AccentColorText
AccentColor와 GrayText: GrayText
이전 CSS 버전에서는 추가 <system-color>도 정의했으나, 현재는 폐지되었습니다. 자세한 내용은 부록 A: 폐지된 CSS 시스템 색상을 참고하세요.
참고: <system-color>는 § 22 개인정보 보호 고려사항 및 § 20 보안 고려사항에서 설명한 바와 같이 개인정보 및 보안 위험이 있습니다.
사용자 에이전트는, 지문 채취 등 개인정보·보안 위험을 완화하기 위해, 시스템 색상 사용 값에 대해 사용자의 맞춤화나 테마 선택을 반영하지 않는 고정 값을 반환하도록 선택할 수 있습니다.
6.3. transparent 키워드
transparent 키워드는 투명한 검정을 지정합니다. 이는 <named-color>의 일종입니다.
테스트
6.4. currentcolor 키워드
currentcolor 키워드는 같은 요소의 color 속성 값을 나타냅니다. <named-color>와 달리, sRGB에만 제한되지 않습니다; 값은 어떤 <color>여도 됩니다. 사용된 값은 색상값 해석에 의해 결정됩니다.
테스트
- border-color-currentcolor.html (실시간 테스트) (소스)
- color-mix-currentcolor-nested-for-color-property.html (실시간 테스트) (소스)
- currentcolor-001.html (실시간 테스트) (소스)
- currentcolor-002.html (실시간 테스트) (소스)
- currentcolor-003.html (실시간 테스트) (소스)
- currentcolor-004.html (실시간 테스트) (소스)
- currentcolor-visited-fallback.html (실시간 테스트) (소스)
- color-valid.html (실시간 테스트) (소스)
.foo{ color : red; background-color : currentcolor; }
이는 다음과 동일합니다:
.foo{ color : red; background-color : red; }
< p >< em > Some< strong > really</ strong > emphasized text.</ em > < style > p { color : black ; } em { text-emphasis : dot ; } strong { color : red ; } </ style >

위 예시에서는 강조 마크가 "Some"과 "emphasized text"에는 검정색, "really"에는 빨강입니다.
참고: CSS에서 여러 단어로 된 키워드는 보통 하이픈으로 단어를 구분합니다. currentcolor는 그렇지 않은데, (잠시 숨 고르고) 원래 SVG에서 속성값 "current-color"로, 일반적인 CSS 표기 규칙에 따라 도입됐기 때문입니다. 이후(다른 모든 속성 및 값과 함께) 표시 속성과 속성값, 그리고 속성이 되었는데, 이는 XSLT 생성이 더 쉬워지기 위함이었습니다. 그 다음, 모든 표시 속성이 하이픈에서 camelCase로 변경됐는데, 이는 DOM에서 하이픈이 "마이너스"로 인식되는 문제 때문이었습니다. 그런데 이렇게 바뀌면서 CSS 관례를 따르지 않게 되었고, 이미 CSS의 일부이던 모든 속성 및 값은 다시 하이픈 표기로 환원됐습니다! currentcolor는 그 때 CSS의 일부가 아니어서 camelCase 형태로 남았습니다. 이후 CSS에서 이를 채택하게 되었고, 이 시점에서는 대소문자가 중요하지 않게 되었는데, CSS 키워드는 ASCII 대소문자 구분 없이 처리되기 때문입니다.
7. HSL 색상: hsl() 및 hsla() 함수
색상을 지정하는 RGB 시스템은 기계와 그래픽 라이브러리에는 편리하지만, 사람이 직관적으로 이해하기에는 매우 어렵다고 여겨집니다. 예를 들어, RGB 색상을 어떻게 조정해야 같은 색상의 더 밝은 변형이 나오는지 쉽게 알 수 없습니다.
다른 색상 체계도 여러 가지가 있습니다. 그 중 하나가 HSL [HSL] 색상 체계이며, 더 직관적으로 사용할 수 있지만, 여전히 RGB 색상으로 쉽게 변환됩니다.
HSL 색상은 색상각(hue), 채도(saturation), 명도(lightness) 삼중값으로 지정됩니다. hsl() 및 hsla() 함수의 문법은 다음과 같습니다:
hsl () =[ <legacy-hsl-syntax> | <modern-hsl-syntax>] hsla () =[ <legacy-hsla-syntax> | <modern-hsla-syntax>] <modern-hsl-syntax> =hsl ( [ <hue> | none] [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ /[ <alpha-value> | none] ] ?) <modern-hsla-syntax> =hsla ( [ <hue> | none] [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ /[ <alpha-value> | none] ] ?) <legacy-hsl-syntax> =hsl ( <hue>, <percentage>, <percentage>, <alpha-value>?) <legacy-hsla-syntax> =hsla ( <hue>, <percentage>, <percentage>, <alpha-value>?)
| 백분율 | S와 L에 허용됨 |
|---|---|
| 백분율 기준 범위 | S와 L: 0% = 0.0, 100% = 100.0 |
| 무효(hue) ε | S <= 0.001 |
테스트
- hsl-001.html (실시간 테스트) (소스)
- hsl-002.html (실시간 테스트) (소스)
- hsl-003.html (실시간 테스트) (소스)
- hsl-004.html (실시간 테스트) (소스)
- hsl-005.html (실시간 테스트) (소스)
- hsl-006.html (실시간 테스트) (소스)
- hsl-007.html (실시간 테스트) (소스)
- hsl-008.html (실시간 테스트) (소스)
- hsl-clamp-negative-saturation.html (실시간 테스트) (소스)
- background-color-hsl-001.html (실시간 테스트) (소스)
- background-color-hsl-002.html (실시간 테스트) (소스)
- background-color-hsl-003.html (실시간 테스트) (소스)
- background-color-hsl-004.html (실시간 테스트) (소스)
- color-computed-hsl.html (실시간 테스트) (소스)
- color-invalid-hsl.html (실시간 테스트) (소스)
- color-valid-hsl.html (실시간 테스트) (소스)
첫 번째 인자는 색상각(hue)을 지정합니다.
HSL(HWB도 동일)에서 0deg는 sRGB 원색 빨강을 나타내며 (360deg, 720deg 등도 마찬가지), 나머지 hue들은 원을 따라 분포합니다. 120deg는 sRGB 원색 초록, 240deg는 sRGB 원색 파랑 등입니다.
다음 두 인자는 각각 채도(saturation)와 명도(lightness)입니다. 채도의 경우 100% 또는 100이 완전히 채도된 밝은 색이고, 0% 또는 0이 완전히 무채색의 회색입니다. 명도의 경우 50% 또는 50이 "일반적인" 색, 100% 또는 100이 흰색, 0% 또는 0이 검정입니다.
역사적 이유로, 채도가 0% 미만이면 파싱 시점에 0%로 클램핑되어, sRGB 색상 변환 전에 적용됩니다.
마지막 인자는 색상의 알파 컴포넌트입니다. rgb() 함수의 네 번째 인자와 동일하게 해석됩니다. 생략 시 기본값은 100%입니다.
HSL 색상은 sRGB로 해석됩니다.
HSL 색상의 채도가 0% 또는 0이면, hue 컴포넌트는 무효(powerless)가 됩니다.
HSL의 장점은 RGB보다 직관적이라는 점입니다: 사람들이 원하는 색상을 대략적으로 예측하여 쉽게 조정할 수 있습니다.
hsl ( 120 deg 100 % 50 % ) lime greenhsl ( 120 deg 100 % 25 % ) dark greenhsl ( 120 deg 100 % 75 % ) light greenhsl ( 120 deg 75 % 85 % ) pastel green
HSL의 단점은 OKLCh에 비해 hue 조작 시 시각적 명도가 달라지고, hue 간 간격이 고르지 않다는 점입니다.
따라서 HSL에서는 hue를 고정하고 채도와 명도만 바꿔서 색상 세트를 만들기가 sRGB 컴포넌트 값을 직접 조작하는 것보다 쉽지만, 명도(lightness)는 감마 보정된 빨강, 초록, 파랑 컴포넌트의 평균이기 때문에 hue에 따라 시각적으로 느끼는 명도와 일치하지 않습니다.
OKLCh에서는 sRGB 파랑이 oklch(0.452 0.313 264.1)이고, sRGB 노랑은 oklch(0.968 0.211 109.8)입니다. OKLCh의 명도값(0.452와 0.968)이 실제 시각적 밝기를 잘 반영합니다.
HSL의 hue 각도는 시각적으로 균일하지 않습니다; 색상들이 어떤 영역에서는 몰려 있고 다른 영역에서는 넓게 퍼져 보입니다.
OKLCh에서는 oklch(0.533 0.26 262.6)와 oklch(0.462 0.306 268.9) 두 색상은 hue 차이가 268.9 - 262.6 = 6.3deg이고, 두 번째 쌍 oklch(0.882 0.181 94.24)와 oklch(0.91 0.245 129.9)는 hue 차이가 129.9 - 94.24 = 35.66deg로, 시각적 색상차를 잘 반영합니다.
역사적 이유로 hsl() 및 hsla()는 레거시 색상 문법도 지원합니다.
테스트
- hsla-001.html (실시간 테스트) (소스)
- hsla-002.html (실시간 테스트) (소스)
- hsla-003.html (실시간 테스트) (소스)
- hsla-004.html (실시간 테스트) (소스)
- hsla-005.html (실시간 테스트) (소스)
- hsla-006.html (실시간 테스트) (소스)
- hsla-007.html (실시간 테스트) (소스)
- hsla-008.html (실시간 테스트) (소스)
- hsla-clamp-negative-saturation.html (실시간 테스트) (소스)
- color-valid.html (실시간 테스트) (소스)
7.1. HSL 색상을 sRGB로 변환하기
HSL 색상을 sRGB로 변환하는 것은 수학적으로 간단합니다. 아래는 변환 알고리즘의 자바스크립트 샘플 구현입니다. 색상의 빨강, 초록, 파랑 컴포넌트를 나타내는 세 숫자 배열을 반환하며, sRGB 영역 내의 색상일 경우 값은 [0, 1] 범위입니다.
이 코드에서는 음수 채도에 대한 파싱 시점 클램핑이 이미 적용되었다고 가정합니다.
/** * @param {number} hue - Hue as degrees 0..360 * @param {number} sat - Saturation in reference range [0,100] * @param {number} light - Lightness in reference range [0,100] * @return {number[]} Array of sRGB components; in-gamut colors in range [0..1] */ function hslToRgb( hue, sat, light) { sat/= 100 ; light/= 100 ; function f( n) { let k= ( n+ hue/ 30 ) % 12 ; let a= sat* Math. min( light, 1 - light); return light- a* Math. max( - 1 , Math. min( k- 3 , 9 - k, 1 )); } return [ f( 0 ), f( 8 ), f( 4 )]; }
7.2. sRGB 색상을 HSL로 변환하기
반대로 변환하는 과정도 비슷하게 진행됩니다.
sRGB 영역을 벗어난 색상에서 중간 단계에서 음수 채도가 나올 수 있는데, 이를 처리하기 위해 특별한 주의를 기울입니다.
/** * @param {number} red - Red component 0..1 * @param {number} green - Green component 0..1 * @param {number} blue - Blue component 0..1 * @return {number[]} Array of HSL values: Hue as degrees 0..360, Saturation and Lightness in reference range [0,100] */ function rgbToHsl( red, green, blue) { let max= Math. max( red, green, blue); let min= Math. min( red, green, blue); let [ hue, sat, light] = [ NaN , 0 , ( min+ max) / 2 ]; let d= max- min; let epsilon= 1 / 100000 ; // max Sat is 1, in this code if ( d!== 0 ) { sat= ( light=== 0 || light=== 1 ) ? 0 : ( max- light) / Math. min( light, 1 - light); switch ( max) { case red: hue= ( green- blue) / d+ ( green< blue? 6 : 0 ); break ; case green: hue= ( blue- red) / d+ 2 ; break ; case blue: hue= ( red- green) / d+ 4 ; } hue= hue* 60 ; } // 아주 sRGB 영역을 벗어난 색상은 음수 채도를 만들 수 있음 // 이 경우 hue에 180을 더하고 양수 채도를 사용함 // 참고: https://github.com/w3c/csswg-drafts/issues/9222 if ( sat< 0 ) { hue+= 180 ; sat= Math. abs( sat); } if ( hue>= 360 ) { hue-= 360 ; } if ( sat<= epsilon) { hue= NaN ; } return [ hue, sat* 100 , light* 100 ]; }
7.3. HSL 색상 예시
이 절은 규범적이지 않습니다.
테스트
이 절은 규범적이지 않으므로, 테스트가 필요하지 않습니다.
아래 표는 다양한 HSL 색상을 보여줍니다. 각 표는 한 가지 색상각(hue)을 대표하며, 30° 간격으로 선택된 대표적인 "핵심" 색상: 빨강, 노랑, 초록, 시안, 파랑, 마젠타, 그리고 그 사이의 6가지 중간색을 나타냅니다.
각 표에서 X축은 채도(saturation), Y축은 명도(lightness)를 나타냅니다.
| 0° 빨강 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 30° 빨강-노랑(=오렌지) | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 60° 노랑 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 90° 노랑-초록 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 120° 초록 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 150° 초록-시안 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 180° 시안 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 210° 시안-파랑 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 240° 파랑 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 270° 파랑-마젠타 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 300° 마젠타 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
| 330° 마젠타-빨강 | ||||||
|---|---|---|---|---|---|---|
| 100% | 80% | 60% | 40% | 20% | 0% | |
| 100% | ||||||
| 90% | ||||||
| 80% | ||||||
| 70% | ||||||
| 60% | ||||||
| 50% | ||||||
| 40% | ||||||
| 30% | ||||||
| 20% | ||||||
| 10% | ||||||
| 0% | ||||||
8. HWB 색상: hwb() 함수
HWB(Hue-Whiteness-Blackness의 약자) [HWB]는 sRGB 색상을 지정하는 또 다른 방법으로, HSL과 비슷하지만, 사람에게 더 직관적으로 다가오는 경우가 많습니다. 색상을 기준이 되는 hue로 시작해서, 그에 혼합할 하양(whiteness)과 검정(blackness)의 정도를 지정하여 색을 만듭니다.
많은 컬러 피커가 HWB 색상 시스템을 기반으로 하는데, 그만큼 직관적이기 때문입니다.
HWB 색상은 sRGB로 해석됩니다.
< input type = "color" > 를
활성화할 때 나타납니다.
바깥쪽 휠로 hue를 선택하고,
안쪽 삼각형을 클릭하여 백색(whiteness)과 흑색(blackness)의 상대적 비율을 선택합니다.
hwb() 함수의 문법은 다음과 같습니다:
hwb () =hwb ( [ <hue> | none] [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ /[ <alpha-value> | none] ] ?)
| 백분율 | W와 B에 허용됨 |
|---|---|
| 백분율 기준 범위 | W와 B: 0% = 0.0, 100% = 100.0 |
| 무효(hue) ε | W + B >= 99.999 |
첫 번째 인자는 hue(색상각)를 지정하며, hsl()과 완전히 동일하게 정의됩니다; 즉, 동일한 단점(hue 균일성 등)이 있습니다.
두 번째 인자는 혼합할 백색의 양을, 0%(백색 없음)부터 100%(전부 백색)까지 백분율로 지정합니다. 세 번째 인자는 혼합할 흑색의 양을, 0%(흑색 없음)부터 100%(전부 흑색)까지 백분율로 지정합니다.
이 범위를 벗어나는 값도 잘못된 것은 아닙니다; hue가 [0,360) 범위를 벗어나면 그 범위로 정규화되고, 백색과 흑색의 합이 100% 이상이면 아래 설명처럼 무채색(achromatic) 색상이 생성됩니다.
결과 색상은 개념적으로 선택한 hue의 페인트, 백색 페인트, 흑색 페인트를 각 백분율만큼 혼합한 것이라 생각하면 됩니다.
white+black의 합이 100% 이상이면, 이는 무채색(achromatic) 색상, 즉 회색의 한 종류를 의미합니다; sRGB로 변환될 때 R, G, B 값이 모두 같으며 그 값은 white / (white + black)입니다.
무채색 HWB 색상은 선택한 hue의 흔적이 남아 있지 않습니다. 이 경우 hue 컴포넌트는 무효(powerless)입니다.
네 번째 인자는 색상의 알파 컴포넌트입니다. rgb() 함수의 네 번째 인자와 동일하게 해석됩니다. 생략 시 기본값은 100%입니다.
hwb는 이 명세에서 새로 도입된 것이므로 Web 호환성 문제가 없으며, hwb()는 레거시 색상 문법(모든 인자를 쉼표로 구분하는 방식)을 지원하지 않습니다. hwb() 안에 쉼표를 사용하면 오류입니다.
테스트
8.1. HWB 색상을 sRGB로 변환하기
HWB 색상을 sRGB로 변환하는 것은 간단하며, HSL을 RGB로 변환하는 방법과 유사합니다. 아래 Javascript 구현은 먼저 백색과 흑색 컴포넌트를 정규화하여 합이 100%를 넘지 않도록 처리합니다.
/** * @param {number} hue - Hue as degrees 0..360 * @param {number} white - Whiteness in reference range [0,100] * @param {number} black - Blackness in reference range [0,100] * @return {number[]} Array of RGB components 0..1 */ function hwbToRgb( hue, white, black) { white/= 100 ; black/= 100 ; if ( white+ black>= 1 ) { let gray= white/ ( white+ black); return [ gray, gray, gray]; } let rgb= hslToRgb( hue, 100 , 50 ); for ( let i= 0 ; i< 3 ; i++ ) { rgb[ i] *= ( 1 - white- black); rgb[ i] += white; } return rgb; }
8.2. sRGB 색상을 HWB로 변환하기
반대로 변환하는 과정도 비슷하게 진행됩니다.
/** * @param {number} red - Red component 0..1 * @param {number} green - Green component 0..1 * @param {number} blue - Blue component 0..1 * @return {number} Hue as degrees 0..360 */ function rgbToHue( red, green, blue) { // rgbToHsl과 유사하지만, 채도와 명도는 계산하지 않고, // 음수 채도 가능성은 무시함. let max= Math. max( red, green, blue); let min= Math. min( red, green, blue); let hue= NaN ; let d= max- min; if ( d!== 0 ) { switch ( max) { case red: hue= ( green- blue) / d+ ( green< blue? 6 : 0 ); break ; case green: hue= ( blue- red) / d+ 2 ; break ; case blue: hue= ( red- green) / d+ 4 ; } hue*= 60 ; } if ( hue>= 360 ) { hue-= 360 ; } return hue; } /** * @param {number} red - Red component 0..1 * @param {number} green - Green component 0..1 * @param {number} blue - Blue component 0..1 * @return {number[]} Array of HWB values: Hue as degrees 0..360, Whiteness and Blackness in reference range [0,100] */ function rgbToHwb( red, green, blue) { let epsilon= 1 / 100000 ; // 100 곱셈에 대한 오차 보정 var hue= rgbToHue( red, green, blue); var white= Math. min( red, green, blue); var black= 1 - Math. max( red, green, blue); if ( white+ black>= 1 - epsilon) { hue= NaN ; } return ([ hue, white* 100 , black* 100 ]); }
8.3. HWB 색상 예시
이 절은 규범적이지 않습니다.
테스트
이 절은 규범적이지 않으므로, 테스트가 필요하지 않습니다.
| 0° 빨강 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 30° 빨강-노랑(오렌지) | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 60° 노랑 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 90° 노랑-초록 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 120° 초록 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 150° 초록-시안 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 180° 시안 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 210° 시안-파랑 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 240° 파랑 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 270° 파랑-마젠타 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 300° 마젠타 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
| 330° 마젠타-빨강 | ||||||
|---|---|---|---|---|---|---|
| W\B | 0% | 20% | 40% | 60% | 80% | 100% |
| 0% | ||||||
| 20% | ||||||
| 40% | ||||||
| 60% | ||||||
| 80% | ||||||
| 100% | ||||||
9. 디바이스 독립 색상: CIE Lab 및 LCH, Oklab 및 OKLCh
9.1. CIE Lab 및 LCH
이 절은 규범적이지 않습니다.
테스트
이 절은 규범적이지 않으므로, 테스트가 필요하지 않습니다.
물리적 색상 측정값은 일반적으로 CIE L*a*b* [CIELAB] 색상 공간으로 표현합니다. 1976년 CIE에서 만든 것으로, 흔히 Lab이라고 부릅니다. 디바이스 간 색상 변환에서도 중간 단계로 Lab을 사용할 수 있습니다. 인간 시각 실험을 바탕으로 만들어졌으며, Lab은 사람이 볼 수 있는 전체 색 영역을 나타냅니다.
Lab은 중심에 명도(Lightness, L) 축이 있는 직교 좌표계입니다. 이 값은 보통 단위 없는 숫자로 기록되며, CSS와의 호환성을 위해 백분율로도 쓸 수 있습니다. 100%는 L 값 100, 1.0이 아닙니다. L=0% 또는 0은 깊은 검정(빛 없음), L=100% 또는 100은 확산된 흰색입니다.
편리하게도 L=50% 또는 50은 중간 회색이고, L 값의 증가가 시각적으로 고르게 분포됩니다: Lab 색상 공간은 시각적으로 균등하도록 설계되었습니다.
a, b 축은 색상(hue)을 나타냅니다; a 축 양수는 보라빛이 도는 빨강, 음수는 보색인 초록입니다. b 축 양수는 노랑, 음수는 보색인 파랑/보라입니다. 채도가 낮은 색은 a, b 값이 작고 L 축에 가까우며, 채도가 높은 색은 L 축에서 멀리 떨어집니다.
조명(illuminant)은 D50 흰색이며, 표준화된 주광 스펙트럼(색온도 5000K)입니다. 완전 확산 반사체에 반사된 빛을 기준으로 하며, 맑은 날 햇빛 색상과 비슷합니다. D50은 ICC 색상 변환의 프로파일 접속 공간, Lab 편집을 지원하는 이미지 편집기의 기준, 측색기나 분광방사계의 Lab 측정에서도 사용됩니다.
다른 기준점에서 지정된 색상을 변환하는 것은 색상 적응 변환(chromatic adaptation transform)이라고 하며, 새로운 조명 환경에 눈이 적응할 때의 변화를 모델링합니다. 선형 브래드포드 알고리즘 [ICC](원래 브래드포드 알고리즘 [Bradford-CAT]의 단순화 버전)는 업계 표준 색상 적응 변환으로, 행렬 곱셈만으로 쉽게 계산할 수 있습니다.
CIE LCH는 Lab과 동일한 L 축을 가지며, 극좌표계 C(채도, chroma)와 H(색상각, hue)를 사용합니다. 즉, 원통 좌표계입니다. C는 L 축에서의 거리이며, H는 a 축 양수에서 b 축 양수 방향으로의 각도입니다.
참고: Lab 및 LCH의 L 축은 HSL의 L 축과 혼동하면 안 됩니다. 예를 들어, HSL에서는 sRGB 파랑(#00F)과 노랑(#FF0)이 L 값 50%로 같지만, 실제로 파란색이 훨씬 더 어둡습니다. Lab에서는 더 명확하게 구별됩니다: sRGB 파랑은 lab(29.567% 68.298 -112.0294), sRGB 노랑은 lab(97.607% -15.753 93.388)입니다. Lab과 LCH에서 두 색의 L 값이 같으면, 시각적으로도 밝기가 동일합니다. HSL 및 관련 RGB 극좌표 모델은 LCH가 Lab에 준 혜택을 RGB에 적용하려고 만들어졌지만, 정확도는 많이 떨어집니다.
CIE Lab 및 LCH는 널리 사용되지만, 몇 가지 문제가 알려져 있습니다. 특히:
- 색상선(hue linearity)
- 파란색 영역(LCH Hue 270°~330°)에서 실제 색상선이 예측과 다릅니다. 같은 hue, 다른 채도의 파란색을 그리면 중성축에서 직선이 아니라 곡선이 됩니다. 즉, 채도가 낮아질수록 보랏빛이 나타납니다.
- 색상 균등(hue uniformity)
- LCH의 hue는 대체로 고르게 분포하지만, (HSL, HWB보다 훨씬 우수) 완벽하지는 않습니다.
- 높은 채도에서의 과예측(over-prediction of high Chroma differences)
- 높은 채도 색상에서 채도 변화가 중성색보다 덜 눈에 띕니다.
이러한 문제는 균등한 색상 그라데이션, 색상 공간 간 영역 매핑, 두 색상 간 시각적 차이 계산 등에 영향을 미칩니다.
이를 보완하기 위해, 두 색상 간 시각적 차이를 계산하는 공식(ΔE)이 점점 더 정확해지고(복잡해짐) 있습니다. 현행 업계 표준 공식인 ΔE 2000은 Lab과 LCH의 일부 문제를 잘 완화합니다. 샘플 구현은 § 20.1 ΔE2000에 있습니다.
하지만 색상선 곡률 문제까지 해결되진 않습니다.
9.2. Oklab 및 OKLCh
이 절은 규범적이지 않습니다.
테스트
이 절은 규범적이지 않으므로, 테스트가 필요하지 않습니다.
최근 Oklab이라는 개선된 Lab 계열 색상 공간이 개발되었습니다 [Oklab]. 극좌표 버전은 OKLCh라고 부릅니다. 방대한 데이터셋에서 시각적으로 유사한 색상을 수치적으로 최적화하여 만들어졌으며, 기존 CIE LCH보다 색상선, 색상 균등성, 채도 균등성이 개선되었습니다.
CIE Lab과 마찬가지로 중심 명도 L 축이 있으며, 보통 [0,1] 범위의 단위 없는 숫자로 표기합니다; CSS와의 호환성을 위해 백분율로도 쓸 수 있습니다. 100%는 L 값 1.0입니다. L=0% 또는 0.0은 깊은 검정, L=100% 또는 1.0은 확산된 흰색입니다.
참고: CIE Lab이 확산 흰색 적응을 전제로 하는 것과 달리, Oklab은 정의된 색상에 적응한다고 가정하여 스케일 불변성을 지향합니다.
CIE Lab과 같이 a, b 축은 색상(hue)을 나타냅니다; a 축 양수는 보라빛이 도는 빨강, 음수는 보색인 초록, b 축 양수는 노랑, 음수는 보색인 파랑/보라입니다.
조명은 D65로, 대부분의 RGB 색상 공간과 동일한 기준점입니다.
OKLCh는 Oklab과 같은 L 축을 가지며, 극좌표계 C(채도)와 H(색상각)를 사용합니다.
참고: CIE LCH에서 Chroma가 200 이상까지 갈 수 있는 것과 달리, OKLCh의 Chroma 값은 보통 0.5 정도까지입니다. 색상각(hue angle)은 두 모델 간 대체로 비슷하지만, 정확히 일치하진 않습니다.
Oklab이 CIE Lab보다 시각적으로 더 균등하므로, 색상 차이 계산이 3차원 공간 거리(루트의 제곱 합)로 간단합니다. 매우 단순하지만, 샘플 구현은 § 20.2 ΔEOK에 있습니다.
9.3. Lab 및 LCH 지정: lab() 및 lch() 함수 표기법
CSS에서는 색상을 Lab 및 LCH로 직접 표현할 수 있습니다.
lab () =lab ( [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ /[ <alpha-value> | none] ] ?)
| 백분율 | L, a, b에 허용됨 |
|---|---|
| 백분율 기준 범위 | L: 0% = 0.0, 100% = 100.0 a, b: -100% = -125, 100% = 125 |
테스트
- lab-001.html (실시간 테스트) (소스)
- lab-002.html (실시간 테스트) (소스)
- lab-003.html (실시간 테스트) (소스)
- lab-004.html (실시간 테스트) (소스)
- lab-005.html (실시간 테스트) (소스)
- lab-006.html (실시간 테스트) (소스)
- lab-007.html (실시간 테스트) (소스)
- lab-008.html (실시간 테스트) (소스)
- lab-l-over-100-1.html (실시간 테스트) (소스)
- lab-l-over-100-2.html (실시간 테스트) (소스)
- color-valid.html (실시간 테스트) (소스)
- color-computed-lab.html (실시간 테스트) (소스)
- color-invalid-lab.html (실시간 테스트) (소스)
- color-valid-lab.html (실시간 테스트) (소스)
Lab에서는 첫 번째 인자가 CIE 명도(Lightness, L)를 지정합니다. 이 값은 0% 또는 0에서 100% 또는 100까지의 숫자입니다. 0% 또는 0 미만 값은 파싱 시점에 0%로 클램핑되어야 하며, 100% 또는 100 초과 값도 파싱 시점에 100%로 클램핑됩니다.
두 번째와 세 번째 인자는 Lab 색 공간에서 "a" 축과 "b" 축을 따라 측정한 거리입니다. 이는 앞 절에서 설명된 대로입니다. 이 값들은 부호가 있으며 (양수와 음수 모두 허용함) 이론적으로는 범위가 없습니다 (그러나 실제 색상에서는 ±160을 넘지 않습니다).
네 번째 <alpha-value> 구성요소는 선택 사항이며, 슬래시로 구분되고, 알파 채널을 나타냅니다.
Lab 색상(클램핑 후)의 명도가 0% 또는 100%일 경우, 그 색상은 각각 검정 또는 흰색으로 표시됩니다. 이는 디스플레이에 대한 색 공간 매핑 때문입니다.
lab ( 29.2345 % 39.3825 20.0664 ); lab ( 52.2345 40.1645 59.9971 ); lab ( 60.2345 -5.3654 58.956 ); lab ( 62.2345 % -34.9638 47.7721 ); lab ( 67.5345 -8.6911 -41.6019 ); lab ( 29.69 % 44.888 % -29.04 % )
lch () =lch ( [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ <hue> | none] [ /[ <alpha-value> | none] ] ?)
| 백분율 | L, C에 허용됨 |
|---|---|
| 백분율 기준 범위 | L: 0% = 0.0, 100% = 100.0 C: 0% = 0, 100% = 150 |
| 무효(hue) ε | C <= 0.0015 |
테스트
- lch-001.html (실시간 테스트) (소스)
- lch-002.html (실시간 테스트) (소스)
- lch-003.html (실시간 테스트) (소스)
- lch-004.html (실시간 테스트) (소스)
- lch-005.html (실시간 테스트) (소스)
- lch-006.html (실시간 테스트) (소스)
- lch-007.html (실시간 테스트) (소스)
- lch-008.html (실시간 테스트) (소스)
- lch-009.html (실시간 테스트) (소스)
- lch-010.html (실시간 테스트) (소스)
- lch-l-over-100-1.html (실시간 테스트) (소스)
- lch-l-over-100-2.html (실시간 테스트) (소스)
- color-valid.html (실시간 테스트) (소스)
CIE LCH에서 첫 번째 인자는 CIE 명도 L을 지정하며, lab()의 명도 인자와 동일하게 해석됩니다.
두 번째 인자는 채도 C이며, ("색의 양"을 대략적으로 나타냄). 최소 유효값은 0이고, 최대값은 이론적으로 무제한이지만 실제로는 230을 넘지 않습니다. 음수 값이 제공되면 파싱 시점에 0으로 클램핑됩니다.
세 번째 인자는 색상각 H입니다. <hue> 인자와 유사하게 해석되지만, hsl()처럼 각도와 색상 매핑이 동일하지는 않고, 시각적으로 고르게 분포됩니다. 0deg는 a 축 양(보라빛 빨강)을 가리키며, (360deg, 720deg 등도 같음) 90deg는 b 축 양(겨자 노랑), 180deg는 a 축 음(초록빛 시안), 270deg는 b 축 음(하늘 파랑)입니다.
옵션으로 네 번째 <alpha-value> 컴포넌트가 있으며, 슬래시로 구분되어, 알파 컴포넌트를 나타냅니다.
LCH 색상의 채도(C)가 0%이면 hue 컴포넌트는 무효(powerless)입니다. LCH 색상의 명도(L)가 클램핑 후 0% 또는 100%이면, 색상은 검정 또는 흰색으로 표시됩니다(디스플레이 영역 매핑 결과).
lch ( 29.2345 % 44.2 27 ); lch ( 52.2345 % 72.2 56.2 ); lch ( 60.2345 59.2 95.2 ); lch ( 62.2345 % 59.2 126.2 ); lch ( 67.5345 % 42.5 258.2 ); lch ( 29.69 % 45.553 % 327.1 )
lab 및 lch는 이 명세에서 새로 도입된 것이므로 Web 호환성 문제가 없으며, lab() 및 lch()는 레거시 색상 문법(모든 인자를 쉼표로 구분하는 방식)을 지원하지 않습니다. 이 함수들에서 쉼표를 사용하면 오류입니다.
9.4. Oklab 및 OKLCh 지정: oklab() 및 oklch() 함수 표기법
CSS에서는 색상을 Oklab 및 OKLCh로 직접 표현할 수 있습니다.
oklab () =oklab ( [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ /[ <alpha-value> | none] ] ?)
| 백분율 | L, a, b에 허용됨 |
|---|---|
| 백분율 기준 범위 | L: 0% = 0.0, 100% = 1.0 a, b: -100% = -0.4, 100% = 0.4 |
테스트
- oklab-001.html (실시간 테스트) (소스)
- oklab-002.html (실시간 테스트) (소스)
- oklab-003.html (실시간 테스트) (소스)
- oklab-004.html (실시간 테스트) (소스)
- oklab-005.html (실시간 테스트) (소스)
- oklab-006.html (실시간 테스트) (소스)
- oklab-007.html (실시간 테스트) (소스)
- oklab-008.html (실시간 테스트) (소스)
- oklab-009.html (실시간 테스트) (소스)
- oklab-l-almost-0.html (실시간 테스트) (소스)
- oklab-l-almost-1.html (실시간 테스트) (소스)
- oklab-l-over-1-1.html (실시간 테스트) (소스)
- oklab-l-over-1-2.html (실시간 테스트) (소스)
- color-valid.html (실시간 테스트) (소스)
Oklab에서 첫 번째 인자는 Oklab 명도를 지정합니다. 이 값은 0% 또는 0에서 100% 또는 1.0 범위입니다.
0% 또는 0.0 미만 값은 파싱 시점에 0%로 클램핑되어야 하며, 100% 또는 1.0 초과 값은 파싱 시점에 100%로 클램핑됩니다.
두 번째, 세 번째 인자는 Oklab 색상 공간의 "a", "b" 축 방향 거리이며, 앞 절에서 설명한 바와 같습니다. 이 값들은 부호 있는 값(양수, 음수 모두 허용)이고, 이론적으로 제한이 없지만(실제로는 ±0.5를 넘지 않음) 실무에서는 범위 내에서 사용됩니다.
슬래시(/)로 구분되는 선택적 네 번째 <alpha-value> 컴포넌트가 있으며, 이는 알파 컴포넌트를 나타냅니다.
Oklab 색상의 명도가 0% 또는 0, 혹은 100% 또는 1.0인 경우, 색상은 각각 검정 또는 흰색으로 표시됩니다. 이는 디스플레이 색역 매핑(gamut mapping)에 의해 결정됩니다.
oklab ( 40.101 % 0.1147 0.0453 ); oklab ( 59.686 % 0.1009 0.1192 ); oklab ( 0.65125 -0.0320 0.1274 ); oklab ( 66.016 % -0.1084 0.1114 ); oklab ( 72.322 % -0.0465 -0.1150 ); oklab ( 42.1 % 41 % -25 % )
oklch () =oklch ( [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ <hue> | none] [ /[ <alpha-value> | none] ] ?)
| 퍼센트 값 허용 | L 및 C에 허용됨 |
|---|---|
| 퍼센트 기준 범위 | L: 0% = 0.0, 100% = 1.0 C: 0% = 0.0, 100% = 0.4 |
| Powerless hue ε | C <= 0.000004 |
테스트
- oklch-001.html (실시간 테스트) (소스)
- oklch-002.html (실시간 테스트) (소스)
- oklch-003.html (실시간 테스트) (소스)
- oklch-004.html (실시간 테스트) (소스)
- oklch-005.html (실시간 테스트) (소스)
- oklch-006.html (실시간 테스트) (소스)
- oklch-007.html (실시간 테스트) (소스)
- oklch-008.html (실시간 테스트) (소스)
- oklch-009.html (실시간 테스트) (소스)
- oklch-010.html (실시간 테스트) (소스)
- oklch-011.html (실시간 테스트) (소스)
- oklch-l-almost-0.html (실시간 테스트) (소스)
- oklch-l-almost-1.html (실시간 테스트) (소스)
- oklch-l-over-1-1.html (실시간 테스트) (소스)
- oklch-l-over-1-2.html (실시간 테스트) (소스)
- color-valid.html (실시간 테스트) (소스)
OkLCh에서 첫 번째 인자는 OkLCh 명도 L을 지정하며, oklab()의 명도 인자와 동일하게 해석됩니다.
두 번째 인자는 채도 C입니다. 최소 유효값은 0이고, 최대값은 이론적으로 제한이 없으나 실제로는 0.5를 넘지 않습니다. 음수 값이 입력되면, 파싱 시점에 0으로 클램핑됩니다.
세 번째 인자는 색상각 H입니다. <hue> 인자처럼 hsl(), lch()와 유사하게 해석되지만 각도가 같은 방식으로 색상에 매핑되지는 않습니다. 0deg는 양의 "a"축(자주빛 붉은색)을 향하고, (360deg, 720deg 등도 마찬가지) 90deg는 양의 "b"축(겨자 노란색)을 향합니다. 180deg는 음의 "a"축(녹청색)을, 270deg는 음의 "b"축(하늘색)을 가리킵니다.
네 번째 <alpha-value> 구성요소는 선택적이며, 슬래시로 구분되고, 알파 구성요소를 나타냅니다.
OkLCh 색상의 채도가 0% 또는 0이면 색상 구성요소는 비활성입니다. OkLCh 색상의 명도가 0% 또는 0, 혹은 100% 또는 1.0이면, 해당 색상은 각각 검정 또는 흰색으로 표시됩니다. 이는 디스플레이로 색 공간 매핑되기 때문입니다.
oklch ( 40.101 % 0.12332 21.555 ); oklch ( 59.686 % 0.15619 49.7694 ); oklch ( 0.65125 0.13138 104.097 ); oklch ( 0.66016 0.15546 134.231 ); oklch ( 72.322 % 0.12403 247.996 ); oklch ( 42.1 % 48.25 % 328.4 )
oklab 또는 oklch는 이 명세의 이 레벨에서 새롭게 도입된 것이므로 웹 호환성 문제가 없습니다. oklab()와 oklch()는 모든 인자를 쉼표로 구분하는 레거시 색상 문법을 지원하지 않습니다. 이 함수 내에서 쉼표를 사용하면 오류입니다.
9.5. Lab 또는 Oklab 색상을 LCH 또는 OkLCh 색상으로 변환하기
극좌표 형태로의 변환은 매우 간단합니다:
- C = sqrt(a^2 + b^2)
- if (C > epsilon) H = atan2(b, a) 그렇지 않으면 H는 missing
- L은 그대로
a와 b 값이 매우 작을 때(Chroma가 0에 근접할 경우), 시각적으로 색상이 중성축에 위치해 변하지 않더라도, 값이 조금만 변화해도 색상각이 심하게 흔들리며 사실상 임의로 표시될 수 있습니다. CSS에서는 이런 경우 색상 정보가 비활성으로 간주되며, LCH 또는 OkLCh로 변환할 때 값 없음(missing)으로 처리됩니다. CSS가 아닌 환경에서는 NaN 등으로 해당 값을 표현할 수 있습니다.
9.6. LCH 또는 OkLCh 색상을 Lab 또는 Oklab 색상으로 변환하기
직교좌표 형태로의 변환도 매우 간단합니다:
- H가 missing이면, a = b = 0
-
그렇지 않으면,
- a = C cos(H)
- b = C sin(H)
- L은 그대로
10. 미리 정의된 색상 공간
CSS는 여러 미리 정의된 색상 공간을 제공합니다. 대표적으로 display-p3 [Display-P3]가 있으며, 이는 최신 광색역 모니터에서 일반적인 넓은 색상 영역입니다. prophoto-rgb는 사진가들이 널리 사용하며, rec2020 [Rec.2020]는 방송 산업 표준으로, 실세계의 거의 모든 색상을 표현할 수 있는 초광색역 공간입니다.
10.1. 미리 정의된 색상 지정: color() 함수
color() 함수는 색상을 특정 명시된 색상 공간에서 지정할 수 있게 해줍니다(대부분의 다른 색상 함수가 암묵적으로 sRGB를 사용하는 것과 달리). 문법은 다음과 같습니다:
color () =color ( <colorspace-params>[ /[ <alpha-value> | none] ] ?) <colorspace-params> =[ <predefined-rgb-params> | <xyz-params>] <predefined-rgb-params> = <predefined-rgb>[ <number> | <percentage> | none] { 3 } <predefined-rgb> = srgb | srgb-linear | display-p3 | a98-rgb | prophoto-rgb | rec2020 <xyz-params> = <xyz-space>[ <number> | <percentage> | none] { 3 } <xyz-space> = xyz | xyz-d50 | xyz-d65
테스트
color 함수는 특정 명시적 색상 공간에서 색상 파라미터를 받습니다.
아래 설명된 대로 잘못된 색상이거나, 유효한 색상일 수 있습니다.
파라미터 형식은 다음과 같습니다:
-
<ident>는 미리 정의된 색상 공간 중 하나입니다(예: display-p3). 개별 미리 정의된 색상 공간은 <number> 또는 <percentage> 또는 두 가지 모두 사용 가능 여부를 제한할 수 있습니다.
<ident>가 존재하지 않는 색상 공간을 지정하면(미리 정의된 색상 공간과 일치하지 않으면) 해당 인자는 잘못된 색상으로 처리됩니다.
-
해당 색상 공간의 3개 파라미터(RGB 또는 XYZ 값).
색상 영역을 벗어난(out of gamut) 색상의 컴포넌트 값은 0 혹은 0% 미만, 1 혹은 100% 초과일 수 있습니다. 이런 값은 잘못된 것이 아니라, 중간 연산에서 유지됩니다; 디스플레이에서는 css gamut mapping(상대적 컬러리메트릭 방식)으로 실제 값이 0/0%~1/100% 범위로 맞춰집니다.
-
옵션으로 슬래시로 구분된 <alpha-value>.
color()는 이번 현행 표준 단계에서 새로 도입된 것이므로 웹 호환성 문제가 없으며, color()는 모든 인자를 쉼표로 구분하는 레거시 색상 문법(legacy color syntax)을 지원하지 않습니다. 이 함수에서 쉼표를 사용하면 오류입니다.
색상이 잘못된 색상이거나 색상 영역을 벗어난(out of gamut) 색상인 경우 표시할 수 없습니다.
지정한 색상이 표시할 수 있습니다라면, (즉 잘못된 색상도 아니고 색상 영역을 벗어난 색상도 아니면) 이것이 color() 함수의 실제 값(actual value)입니다.
지정한 색상이 유효한 색상이지만 표시할 수 없는 색상이면, 실제 값은 지정한 색상을 css gamut mapping을 거쳐 디스플레이에 맞게 변환한 값입니다.
색상이 잘못된 색상이면, 사용 값(used value)은 불투명 검정입니다.
LCH 좌표계에서는 이 색상은 다음과 같습니다color ( rec20200.42053 0.979780 0.00579 );
display-p3 색 공간에서는 이 색상은 다음과 같습니다lch ( 85.9017 % 166.116 138.207 );
그리고 display-p3 범위를 벗어납니다 (red와 blue가 음수이고, green은 1보다 큽니다). display-p3 화면을 사용할 경우, 이 색상은:color ( display-p3-0.350289 1.00707 -0.144209 );
- 유효
- 가시영역 (rec.2020에서)
- 가시영역 아님 (사용자 디스플레이에서)
- 따라서 표시할 수 없음
color ( profoto-rgb0.4835 0.9167 0.2188 )
10.2. 미리 정의된 sRGB 색상 공간: sRGB 키워드
아래에서 정의하는 sRGB 미리 정의된 색상 공간은 레거시 sRGB 색상(예: rgb())에 사용되는 것과 동일합니다.
- srgb
-
srgb
[SRGB]
색상 공간은 숫자 3개 파라미터를 받으며,
각각 빨강, 초록, 파랑 컴포넌트입니다.
영역 내 색상은 세 컴포넌트 모두 [0, 1] 범위에 있습니다.
기준백색점은 D65입니다.
[SRGB] 에서는 인코딩(encoding)과 일반(typical) 두 가지 시청 조건을 규정하는데, [ICC]에서는 색상 변환 및 최적 시청에 인코딩 조건(아래 표)을 사용할 것을 권장합니다.
sRGB는 CSS의 기본 색상 공간이며, 모든 레거시 색상 함수에서 사용됩니다.
주요 특성은 다음과 같습니다:
x y 빨강 색도 0.640 0.330 초록 색도 0.300 0.600 파랑 색도 0.150 0.060 백색 색도 D65 전달 함수 아래 참고 백색 휘도 80.0 cd/m2 검정 휘도 0.20 cd/m2 이미지 상태 디스플레이 기준(display-referred) 백분율 R, G, B에 허용됨 백분율 기준 범위 R,G,B: 0% = 0.0, 100% = 1.0
c는 감마 인코딩된 빨강, 초록, 파랑 컴포넌트입니다. cl은 해당 선형광(linear-light) 컴포넌트입니다.let sign= c< 0 ? - 1 : 1 ; let abs= Math. abs( c); if ( abs<= 0.04045 ) { cl= c/ 12.92 ; } else { cl= sign* ( Math. pow(( abs+ 0.055 ) / 1.055 , 2.4 )); } LCH에서 sRGB 색상 공간의 시각화. 원색(primary)과 2차색(secondary)을 표시.
테스트
10.3. 미리 정의된 선형광 sRGB 색상 공간: srgb-linear 키워드
sRGB-linear 미리 정의된 색상 공간은 srgb와 동일하나 전달 함수가 선형광(linear-light, 감마 인코딩 없음)이라는 점만 다릅니다.
- srgb-linear
-
srgb-linear [SRGB]
색상 공간은 숫자 3개 파라미터를 받으며,
각각 빨강, 초록, 파랑 컴포넌트입니다.
영역 내 색상은 세 컴포넌트 모두 [0, 1] 범위에 있습니다.
기준백색점은 D65입니다.
주요 특성은 다음과 같습니다:
x y 빨강 색도 0.640 0.330 초록 색도 0.300 0.600 파랑 색도 0.150 0.060 백색 색도 D65 전달 함수 단순히 입력값(cl=c), 아래 참고 백색 휘도 80.0 cd/m2 검정 휘도 0.20 cd/m2 이미지 상태 디스플레이 기준(display-referred) 백분율 R, G, B에 허용됨 백분율 기준 범위 R,G,B: 0% = 0.0, 100% = 1.0 cl
c는 빨강, 초록, 파랑 컴포넌트입니다. cl은 해당 선형광 컴포넌트(동일값)입니다.= c; 밴딩(banding) 현상을 방지하려면 더 높은 정밀도가 srgb-linear에 필요하며, srgb보다 더 높아야 합니다.
테스트
10.4. 미리 정의된 Display P3 색상 공간: display-p3 키워드
- display-p3
-
display-p3 [Display-P3] 색상 공간은 숫자 3개 파라미터를 받으며,
각각 빨강, 초록, 파랑 컴포넌트입니다.
영역 내 색상은 세 컴포넌트 모두 [0, 1] 범위에 있습니다.
[DCI-P3]와
동일한 주요 색도(primary chromaticities)를 사용하지만,
D65 기준백색점과 sRGB와 동일한 전달 곡선을 사용합니다.
최신 디스플레이, TV, 노트북과 스마트폰 화면은 display-p3 영역의 모든 색상 또는 거의 모든 색상을 표시할 수 있습니다.
주요 특성은 다음과 같습니다:
x y 빨강 색도 0.680 0.320 초록 색도 0.265 0.690 파랑 색도 0.150 0.060 백색 색도 D65 전달 함수 srgb와 동일 백색 휘도 80.0 cd/m2 검정 휘도 0.80 cd/m2 이미지 상태 디스플레이 기준(display-referred) 백분율 R, G, B에 허용됨 백분율 기준 범위 R,G,B: 0% = 0.0, 100% = 1.0 LCH에서 P3 색상 공간의 시각화. 원색(primary)과 2차색(secondary)을 표시. (표시된 색상은 sRGB로 표시되어 정확한 색상은 아님) 비교를 위해 sRGB의 원색과 2차색도 점선 원으로 함께 표시. P3 원색은 더 높은 채도를 가짐.
테스트
- predefined-005.html (실시간 테스트) (소스)
- predefined-006.html (실시간 테스트) (소스)
- display-p3-001.html (실시간 테스트) (소스)
- display-p3-002.html (실시간 테스트) (소스)
- display-p3-003.html (실시간 테스트) (소스)
- display-p3-004.html (실시간 테스트) (소스)
- display-p3-005.html (실시간 테스트) (소스)
- display-p3-006.html (실시간 테스트) (소스)
- 2d.color.space.p3.fillText.html (실시간 테스트) (소스)
- 2d.color.space.p3.fillText.shadow.html (실시간 테스트) (소스)
- 2d.color.space.p3.strokeText.html (실시간 테스트) (소스)
- 2d.color.space.p3.to.p3.html (실시간 테스트) (소스)
- 2d.color.space.p3.to.srgb.html (실시간 테스트) (소스)
- 2d.color.space.p3.toBlob.p3.canvas.html (실시간 테스트) (소스)
- 2d.color.space.p3.toBlob.with.putImageData.html (실시간 테스트) (소스)
- 2d.color.space.p3.toDataURL.jpeg.p3.canvas.html (실시간 테스트) (소스)
- 2d.color.space.p3.toDataURL.p3.canvas.html (실시간 테스트) (소스)
- 2d.color.space.p3.toDataURL.with.putImageData.html (실시간 테스트) (소스)
10.5. 미리 정의된 선형광 Display P3 색 공간: display-p3-linear 키워드
display-p3-linear 미리 정의된 색 공간은 display-p3와 동일하지만 전달 함수(transfer function)가 선형광(감마 인코딩 없음)이라는 점이 다릅니다.
다음과 같은 특성을 갖고 있습니다:
| x | y | |
| 적색 색좌표 | 0.680 | 0.320 |
|---|---|---|
| 녹색 색좌표 | 0.265 | 0.690 |
| 청색 색좌표 | 0.150 | 0.060 |
| 백색 색좌표 | D65 | |
| 전달 함수 | unity, 아래 참고 | |
| 백색 휘도 | 80.0 cd/m2 | |
| 흑색 휘도 | 0.80 cd/m2 | |
| 이미지 상태 | 디스플레이 기준 | |
| 퍼센트값 | R, G, B에 허용 | |
| 퍼센트 참조 범위 | R,G,B: 0% = 0.0, 100% = 1.0 | |
cl= c;
c는 빨강, 초록, 파랑 구성요소이며, cl은 해당 선형광 구성요소로, 동일합니다.
밴딩(banding) 현상을 방지하기 위해, display-p3-linear은 더 높은 정밀도가 필요합니다 display-p3보다.
color ( display-p30.591 0.123 0.264 ) color ( display-p3-linear0.3081 0.014 0.0567 )
테스트
10.6. 미리 정의된 A98 RGB 색 공간: a98-rgb 키워드
- a98-rgb
-
a98-rgb 색 공간은
빨강, 녹색, 파랑 색상 요소를 나타내는
3개의 숫자 인자를 받습니다.
가시영역(in-gamut) 색상은 3개 구성요소가 모두 [0, 1] 범위에 있습니다.
전달 곡선은 감마 함수로서,
1/2.2에 가깝지만 정확히 같지는 않습니다.
다음과 같은 특성을 갖고 있습니다:
x y 적색 색좌표 0.6400 0.3300 녹색 색좌표 0.2100 0.7100 청색 색좌표 0.1500 0.0600 백색 색좌표 D65 전달 함수 256/563 백색 휘도 160.0 cd/m2 흑색 휘도 0.5557 cd/m2 이미지 상태 디스플레이 기준 퍼센트값 R, G, B에 허용 퍼센트 참조 범위 R,G,B: 0% = 0.0, 100% = 1.0 A98 색 공간의 LCH 시각화. 기본색(primary)과 보조색(secondary)이 표시되어 있으며 (단, sRGB로 나타나 실제 색상과는 다름) 비교를 위해 sRGB 기본색과 보조색도 점선 원으로 나타냅니다. a98 기본색은 채도가 더 높으며, 특히 노랑, 초록, 청록에서 두드러집니다.
테스트
10.7. 미리 정의된 ProPhoto RGB 색 공간: prophoto-rgb 키워드
- prophoto-rgb
-
prophoto-rgb 색상 공간은 숫자 3개 파라미터를 받으며,
각각 빨강, 초록, 파랑 컴포넌트입니다.
영역 내 색상은 세 컴포넌트 모두 [0, 1] 범위에 있습니다.
전달 곡선은
감마 함수(지수 1/1.8)이며,
검정 근처에서는 선형 구간이 있습니다.
기준백색점은 D50로, CIE Lab과 동일합니다. 따라서,
CIE Lab 변환 시 색상 적응 변환 단계가 필요 없습니다.
ProPhoto RGB 공간은 초포화(hyper-saturated)로, 실제로 구현 불가능한 원색(primary)을 사용합니다. 넓은 색상 영역을 허용하고, 특히 톤 조정 시 색상 변화(hue shift)를 최소화하기 위해 이런 선택이 이루어졌습니다. 디지털 사진에서 원본 이미지의 넓은 색역 보관(archival)용으로 자주 쓰이는 색상 공간입니다. prophoto-rgb 색상 공간을 사용하면 CSS에서 해당 RGB값을 가진 이미지와 정확히 일치하는 색상을 지정할 수 있습니다.
ProPhoto RGB 공간은 원래 코닥(Kodak)에서 개발되었으며, [Wolfe]에 설명되어 있습니다. ISO에서 [ROMM],[ROMM-RGB]로 표준화되었습니다.
백색 휘도(white luminance)는 범위로 주어지며, 플레어(화면 반사)로 인해 검정 휘도(black luminance)는 전체의 0.5%~1.0%입니다.
주요 특성은 다음과 같습니다:
x y 빨강 색도 0.734699 0.265301 초록 색도 0.159597 0.840403 파랑 색도 0.036598 0.000105 백색 색도 D50 전달 함수 아래 참고 백색 휘도 160.0~640.0 cd/m2 검정 휘도 본문 참고 이미지 상태 디스플레이 기준(display-referred) 백분율 R, G, B에 허용됨 백분율 기준 범위 R,G,B: 0% = 0.0, 100% = 1.0
c는 감마 인코딩된 빨강, 초록, 파랑 컴포넌트입니다. cl은 해당 선형광(linear-light) 컴포넌트입니다.const E= 16 / 512 ; let sign= c< 0 ? - 1 : 1 ; let abs= Math. abs( c); if ( abs<= E) { cl= c/ 16 ; } else { cl= sign* Math. pow( c, 1.8 ); } LCH에서 prophoto-rgb 색상 공간의 시각화. 원색(primary)과 2차색(secondary)을 표시. (표시된 색상은 sRGB로 표시되어 정확한 색상은 아님) 비교를 위해 sRGB의 원색과 2차색도 점선 원으로 함께 표시. prophoto-rgb 원색과 2차색은 훨씬 높은 채도를 가지나, 이 초광색역의 많은 부분은 물리적으로 실현 불가능한 색상입니다.
테스트
10.8. 미리 정의된 ITU-R BT.2020-2 색상 공간: rec2020 키워드
- rec2020
-
rec2020 [Rec.2020]
색 공간은 빨강, 녹색, 파랑 색상값을 나타내는 3개의 숫자 인자를 받습니다.
가시영역 색상(in-gamut)은 세 구성요소가 모두 [0, 1] 범위에 위치합니다
(비디오 용어로는 "풀-레인지" 입니다).
ITU Reference 2020은
초고화질(UHD), 4K 및 8K TV에서 사용됩니다.
기본색(primary)은 실제로 구현 가능하지만, 스펙트럼 곡선에 매우 인접해 있으므로 구현이 어렵습니다.
현재 디스플레이는 rec2020 전체 색 영역을 구현하지 못합니다. 시간이 지나면서 디스플레이 발전에 따라 커버리지가 점점 증가할 것으로 기대됩니다.
다음 특성을 가지고 있습니다:
x y 적색 색좌표 0.708 0.292 녹색 색좌표 0.170 0.797 청색 색좌표 0.131 0.046 백색 색좌표 D65 전달 함수 감마 2.40, [REC_BT.1886]에서 정의 이미지 상태 디스플레이 기준 퍼센트값 R, G, B에 허용 퍼센트 참조 범위 R,G,B: 0% = 0.0, 100% = 1.0 rec2020 색 공간의 LCH 시각화. 기본색(primary)과 보조색(secondary)이 표시되어 있습니다 (단, sRGB로 나타난 것이며 실제 색상과는 다릅니다). 비교를 위해 sRGB 기본색과 보조색도 점선 원으로 표시됩니다. rec2020 기본색은 훨씬 더 높은 채도를 갖고 있습니다.
테스트
10.9. 미리 정의된 CIE XYZ 색상 공간: xyz-d50, xyz-d65, xyz 키워드
- xyz-d50, xyz-d65, xyz
-
xyz 색상
공간은 숫자 3개 파라미터를 받으며,
각각 X, Y, Z 값을 의미합니다.
CIE XYZ [COLORIMETRY] 색상 공간을 나타내며,
확산 백색(diffuse white)의 휘도(Y)가 1.0이
되도록 스케일링됩니다.
필요하다면 기준백색점(reference white)에 맞게 색상 적응이 이루어집니다.
xyz-d50의 기준백색점은 D50이고, xyz-d65 및 xyz는 D65입니다.
1.0/100%를 초과하는 값도 허용되며 클램핑하지 않아야 합니다. Y 값이 1.0을 넘으면 확산 백색보다 더 밝은 색상을 나타냅니다. 0/0% 미만 값은 드물지만 색상 적응(chromatic adaptation) 결과로 나타날 수 있으며, 역시 클램핑하지 않아야 합니다.
주요 특성은 다음과 같습니다:
백분율 X,Y,Z에 허용됨 백분율 기준 범위 X,Y,Z: 0% = 0.0, 100% = 1.0
테스트
- predefined-016.html (실시간 테스트) (소스)
- xyz-001.html (실시간 테스트) (소스)
- xyz-002.html (실시간 테스트) (소스)
- xyz-003.html (실시간 테스트) (소스)
- xyz-004.html (실시간 테스트) (소스)
- xyz-005.html (실시간 테스트) (소스)
- xyz-d50-001.html (실시간 테스트) (소스)
- xyz-d50-002.html (실시간 테스트) (소스)
- xyz-d50-003.html (실시간 테스트) (소스)
- xyz-d50-004.html (실시간 테스트) (소스)
- xyz-d50-005.html (실시간 테스트) (소스)
- xyz-d65-001.html (실시간 테스트) (소스)
- xyz-d65-002.html (실시간 테스트) (소스)
- xyz-d65-003.html (실시간 테스트) (소스)
- xyz-d65-004.html (실시간 테스트) (소스)
- xyz-d65-005.html (실시간 테스트) (소스)
- color-valid.html (실시간 테스트) (소스)
10.10. 미리 정의된 색상 공간을 Lab 또는 Oklab으로 변환
모든 미리 정의된 RGB 색상 공간에서 Lab으로 변환하려면 여러 단계를 거쳐야 하며, 실제로 첫 단계만 비선형이고 나머지는 선형 계산이므로 통합할 수 있습니다.
- 감마 인코딩된 RGB를 선형광(Linear-light) RGB로 변환(감마 인코딩 해제)
- 선형 RGB를 CIE XYZ로 변환
- 필요한 경우 D65 백색점 (sRGB, display-p3, a98-rgb, rec2020에서 사용)의 색상을 Lab에서 사용하는 D50 백색점으로 선형 브래드포드 변환(Bradford transform)을 통해 변환합니다. prophoto-rgb는 이미 D50 백색점을 갖고 있습니다.
- D50에 맞춘 XYZ를 Lab으로 변환
Oklab으로 변환도 유사하지만, 색상 순응 단계(백색점 변환)는 prophoto-rgb에만 필요합니다.
- 감마 인코딩된 RGB를 선형광 RGB로 변환(감마 인코딩 해제)
- 선형 RGB를 CIE XYZ로 변환
- 필요한 경우 D50 백색점 (prophoto-rgb에서 사용)의 색상을 Oklab에서 사용하는 D65 백색점으로 선형 브래드포드 변환을 통해 변환합니다.
- D65에 맞춘 XYZ를 Oklab으로 변환
이 변환에 대한 샘플 JavaScript 코드는 § 19 색상 변환 샘플 코드에 있습니다.
10.11. Lab 또는 Oklab을 미리 정의된 RGB 색상 공간으로 변환
Lab에서 display-p3나 rec2020과 같은 미리 정의된 공간으로 변환도 여러 단계를 거쳐야 하며, 실제로 마지막 단계만 비선형이고 나머지는 선형 계산이므로 통합할 수 있습니다.
- Lab을 (D50 적응된) XYZ로 변환
- 필요하다면 Lab에서 사용하는 D50 기준백색점을 sRGB 및 대부분의 다른 RGB 공간에서 사용하는 D65 기준백색점으로 선형 Bradford 변환. prophoto-rgb는 이 단계가 필요 없음.
- (D65 적응된) CIE XYZ를 선형 RGB로 변환
- 선형광 RGB를 RGB로 변환(감마 인코딩)
Oklab에서 변환도 유사하며, 색상 적응 단계는 prophoto-rgb에만 필요합니다.
- Oklab을 (D65 적응된) XYZ로 변환
- 필요하다면 Oklab에서 사용하는 D65 기준백색점을 D50 기준백색점(prophoto-rgb에서 사용)으로 선형 Bradford 변환.
- (D65 적응된) CIE XYZ를 선형 RGB로 변환
- 선형광 RGB를 RGB로 변환(감마 인코딩)
이 변환에 대한 샘플 JavaScript 코드는 § 19 색상 변환 샘플 코드에 있습니다.
구현체에서는 소스와 대상 색상 영역(gamut) 내의 색상에 대해 결과가 동일하다면 (예: ICC 프로파일의 상대 컬러리메트릭 렌더링 의도 사용 등) 다른 방식으로 이 단계를 구현해도 됩니다.
10.12. 미리 정의된 RGB 색상 공간 간 변환
한 미리 정의된 RGB 색상 공간에서 다른 공간으로 변환하려면 여러 단계를 거쳐야 하며, 기준백색점이 다를 때만 필요한 단계가 하나 있습니다. src에서 dest로 변환하려면:
- 감마 인코딩된 srcRGB를 선형광 srcRGB로 변환(감마 인코딩 해제)
- 선형 srcRGB를 CIE XYZ로 변환
- src와 dest의 기준백색점이 다르면, XYZ 값을 srcWhite에서 destWhite로 선형 Bradford 변환.
- CIE XYZ를 선형 destRGB로 변환
- 선형광 destRGB를 destRGB로 변환(감마 인코딩)
미리 정의된 RGB 색상 공간 간 변환에 대한 샘플 JavaScript 코드는 § 19 색상 변환 샘플 코드에 있습니다.
10.13. 간단한 알파 합성
그리기 시, 구현체는 Compositing and Blending Level 1 [Compositing]의 Section 5.1 Simple alpha compositing의 규칙을 따라 알파를 처리해야 합니다.
11. 색상 변환
테스트
이 절은 이후에 사용될 알고리즘을 제공하며, 테스트가 필요하지 않습니다.
색상은 한 색상 공간에서 다른 색상 공간으로 변환할 수 있으며, 색역 매핑(gamut mapping)이 없고 각 색상 공간이 색역을 벗어난 색도 표현 가능하다면 (RGB 색상 공간의 경우 전달 함수가 확장 범위에 대해 정의되어 있어야 함), (숫자 계산 및 반올림 오차를 제외하면) 두 색상은 동일하게 보이고 같은 색상 자극을 나타냅니다.
- src의 모든 powerless component를 missing component로 변경합니다.
- src가 원통 극좌표 색상(cylindrical polar color) 표현이라면, col1을 해당 직교 직사각형 색상(rectangular orthogonal color) 표현으로 변환하고, 이를 새로운 col1로 합니다.
- col1을 변환 준비합니다.
- 모든 missing component를 0으로 대체합니다.
- src가 linear-light 표현이 아니라면, 감마 인코딩을 되돌려 선형광(linear light)으로 변환하고 이를 새로운 col1로 합니다.
- col1을 지정된 화이트포인트 src-white로 CIE XYZ로 변환하고, xyz로 합니다.
- dest-white가 src-white와 다르면, xyz를 dest-white로 선형 Bradford 색도 적응 변환(chromatic adaptation transform)을 사용해 적응 변환하고, 이를 새로운 xyz로 합니다.
- dest가 원통 극좌표 색상 표현이라면, dest-rect를 해당 직교 직사각형 색상 표현으로 둡니다. 아니면, dest-rect를 dest로 둡니다.
- xyz를 dest로 변환하고, 전달 함수(감마 인코딩 등)를 적용하여 col2를 만듭니다.
- dest가 디스플레이 등 물리적 출력 색상 공간이라면, col2는 CSS 색역 매핑(css gamut mapped)이 적용되어야 하며, 출력 가능해야 합니다.
- dest-rect가 dest와 다르다면, 즉 dest가 원통 극좌표 색상 표현일 경우, dest-rect에서 dest로 변환하고 이를 col2로 둡니다. 이 과정에서 missing component가 생길 수 있습니다.
12. <color> 값 비교
두 <color> 값이 아래 알고리즘으로 비교해 같다면, 이 둘을 동등한 색상(equivalent colors)이라고 합니다. 이 비교는 예를 들어, style() 컨테이너 쿼리 [CSS-CONDITIONAL-5] 및 CSS 전환 [CSS-TRANSITIONS-1]에서 색상 값이 변경되었는지 판단할 때 사용됩니다.
두 <color> 값 C1, C2에 대해, 아래 알고리즘이 true를 반환할 때에만 이들은 동등한 색상입니다:
- C1 및 C2 각각에서 모든 powerless component를 missing component로 변환합니다.
-
C1과 C2가 같은 <color-space>라면:
- 각 컴포넌트(알파 값 포함)를 하나씩 비교합니다. missing component는 다른 missing component만 같다고 간주합니다. 두 수치형 컴포넌트는 구현 정의의 매우 작은 값(ε) 이하로만 다르면 같은 것으로 간주합니다.
- 모든 컴포넌트가 같을 때만 true를 반환합니다.
- 그렇지 않으면, C1과 C2는 서로 다른 <color-space>에 있습니다. 두 색상 중 하나에라도 missing component가 있다면, false를 반환합니다.
- 그렇지 않으면, 어느 색도 누락된 구성요소를 갖지 않는다. C1과 C2를 모두 oklab으로 변환한 다음, 변환된 색의 모든 구성요소(알파 포함)가 표준화된 Oklab ε 0.00001을 사용하여 같다고 비교되는 경우에만 true를 반환한다.
참고: 서로 다른 <color-space>로 표현된 두 색상이 색도적으로 같다면 (예: red와 color(srgb 1 0 0)), 이 알고리즘의 4단계 덕분에 동등한 색상으로 간주됩니다. 두 색상 모두 동일한 oklab 값으로 변환됩니다.
이 비교에서, rgb(), rgba(), hsl(), hsla(), hwb(), 16진수 색상(hex colors), 이름 있는 색상(named colors), 시스템 색상(system colors)은 모두 srgb <color-space>에 있다고 간주합니다.
13. 색상 보간
색상 보간은 그라디언트, 합성, 필터, 전환, 애니메이션, 그리고 색상 혼합 및 색상 수정 함수에서 발생합니다.
두 <color> 값 사이의 보간은 다음 단계들을 수행하여 이루어집니다:
- 두 색상에서 유사한 구성 요소와 유사한 집합을 확인하고, 이를 이월(carried forward)합니다.
- 두 색상을 변환할 수 있도록 준비합니다. 이 과정은 모든 무력한(powerless) 구성 요소를 누락된(missing) 값으로 바꿉니다.
- 두 색상을 모두 지정된 색상 공간으로 변환합니다. 이 색상 공간은 아래에서 보간 색상 공간이라고 부릅니다.
- (필요한 경우) 변환된 색상에 이월된 값을 다시 삽입합니다.
- (필요한 경우) 선택된 <hue-interpolation-method>에 따라 색조를 보정합니다.
- 색상 구성 요소를 프리멀티플라이(pre-multiplied) 형태로 변경합니다.
- 색상의 계산된 값의 각 구성 요소를 각각 선형 보간합니다.
- 프리멀티플라이를 해제합니다.
currentcolor로 또는 그 반대로 보간하는 것이 가능합니다. 이때 사용되는 수치 값은 사용 값입니다.
13.1. 보간용 색상 공간
CSS의 다양한 기능은 색상 보간에 의존합니다.
색상을 혼합하거나 조합하는 방식은 사용되는 보간 색상 공간에 따라 결과가 달라집니다. 따라서 각 보간 사례마다 적합한 색상 공간이 다를 수 있습니다.
-
어떤 경우에는 두 가지 색광을 실제로 혼합한 결과가 필요한 경우가 있습니다. 이럴 때는 CIE XYZ, display-p3-linear 또는 srgb-linear 색 공간이 적합합니다. 이 색 공간들은 빛의 강도에 따라 선형입니다.
-
색상이 지각적으로 균등하게 배분되어야 하는 경우(예: 그라데이션), Oklab 색 공간(그리고 이전의 Lab)은 지각적 균등성을 고려하여 설계되었습니다.
-
색상 혼합 과정에서 회색으로 흐려지는 현상을 피하고 싶고, 즉 전환 전체에서 채도를 최대화하고 싶다면, OkLCh(그리고 이전의 LCH)가 그 목적에 잘 맞습니다.
-
마지막으로, 기존 웹 콘텐츠와의 호환성이 가장 중요한 고려사항일 수 있습니다. sRGB 색 공간은 선형광도 아니고 지각적 균등도 아니지만, 이런 경우에는 선택지입니다. 혼합 결과가 너무 어둡거나 회색빛이 된다 하더라도 말입니다.
이러한 기능을 통틀어 호스트 문법(host syntax)이라 부릅니다.
호스트 문법이 보간 색상 공간을 지정할 수 있도록 이 명세는 color-interpolation-method 생산식을 제공합니다. 이 명세 자체에서는 사용하지 않으며, 다른 명세에서 사용할 수 있도록 노출합니다; 예: CSS Images 4 § 3.1 Linear Gradients: the linear-gradient() 표기법 참조.
호스트 문법은 각 경우에 기본 보간 색상 공간이 무엇인지를 정의해야 하며, 저자가 이 기본값을 재정의할 수 있는 문법도 제공하는 것이 바람직합니다. 해당 문법이 속성 값의 일부라면 아래 정의된 color-interpolation-method 생산식을 사용해야 하며, CSS 전반에 걸쳐 일관성을 보장합니다. 색상 보간 방법에 대한 추가 커스터마이징이 있다면 CSS 전체에 자동으로 반영될 수 있습니다.
<color-space> = <rectangular-color-space> | <polar-color-space> <rectangular-color-space> = srgb | srgb-linear | display-p3 | display-p3-linear | a98-rgb | prophoto-rgb | rec2020 | lab | oklab | <xyz-space> <polar-color-space> = hsl | hwb | lch | oklch <hue-interpolation-method> =[ shorter | longer | increasing | decreasing] hue <color-interpolation-method> = in[ <rectangular-color-space> | <polar-color-space> <hue-interpolation-method>?]
<rectangular-color-space>와 <polar-color-space> 정의에 나오는 키워드는 각 색상 공간을 의미하며, CSS에서는 같은 이름의 함수 표기법으로, 또는 (함수가 없으면) <ident>로 color() 함수에서 표현됩니다.
테스트
- gradients-with-transparent.html (실시간 테스트) (소스)
- gradient-eval-001.html (실시간 테스트) (소스)
- gradient-eval-002.html (실시간 테스트) (소스)
- gradient-eval-003.html (실시간 테스트) (소스)
- gradient-eval-004.html (실시간 테스트) (소스)
- gradient-eval-005.html (실시간 테스트) (소스)
- gradient-eval-006.html (실시간 테스트) (소스)
- gradient-eval-007.html (실시간 테스트) (소스)
- gradient-eval-008.html (실시간 테스트) (소스)
- gradient-eval-009.html (실시간 테스트) (소스)
- gradient-none-interpolation.html (실시간 테스트) (소스)
- oklab-gradient.html (실시간 테스트) (소스)
- srgb-gradient.html (실시간 테스트) (소스)
- srgb-linear-gradient.html (실시간 테스트) (소스)
- xyz-gradient.html (실시간 테스트) (소스)
- gradient-interpolation-method-valid.html (실시간 테스트) (소스)
- gradient-interpolation-method-invalid.html (실시간 테스트) (소스)
- gradient-interpolation-method-computed.html (실시간 테스트) (소스)
호스트 문법이 보간이 수행되어야 할 색상 공간을 정의하지 않는 경우, 기본값은 Oklab입니다.
<polar-color-space>의 경우, <hue-interpolation-method>가 지정되지 않으면, 기본값은 shorter입니다.
하지만, 사용자 에이전트는 반드시 레거시 sRGB 색상 형식 (16진수 색상, 이름 있는 색상, rgb(), hsl() 또는 hwb() 및 이에 대응하는 알파 포함 형식) 사이의 보간을 감마 인코딩된 sRGB 공간에서 처리해야 합니다. 이는 Web 호환성을 제공합니다. 레거시 sRGB 콘텐츠는 기본적으로 sRGB 공간에서 보간됩니다.
이는 또한 저자들이 더 나은 보간을 선택할 수 있다는 의미입니다, sRGB 색상끼리의 보간에도, 최소한 하나의 색상에 레거시가 아닌 color(srgb r g b) 형태를 사용하거나, 보간 색상 공간을 명시적으로 지정함으로써.
보간될 색상이 보간 색상 공간의 가시영역을 벗어난다면, 해당 공간으로 변환된 후, 값이 범위를 벗어날 수 있습니다.
이 값들은 잘라내지 않고, 있는 그대로 보간해야 합니다.
13.2. 누락된 컴포넌트와의 색상 보간
두 색상을 보간 색상 공간으로 변환하는 과정에서, 모든 누락된 컴포넌트는 값 0으로 대체됩니다.
따라서 두 색상을 보간하는 첫 단계는, 입력 색상에서 누락된 컴포넌트를 분류하고, 이를 보간 색상 공간의 컴포넌트와 비교하는 것입니다. 만약 유사 컴포넌트 중 누락된 컴포넌트가 발견되면, 이들은 전달됨(carried forward) 처리되어 변환된 색상에 프리멀티플라이드 및 선형 보간 전에 재삽입됩니다.
마찬가지로, 원래 색상에서 아래에서 정의되는 유사 집합(analogous set) 의 모든 구성 요소가 누락된 구성 요소라면, 이들은 모두 이월(carried forward)되어 대응하는 유사 집합에 다시 삽입됩니다. 이는 보간 색상 공간에서 이루어집니다.
알파는 자체적으로 유사한 구성 요소입니다 (알파는 알파와 유사함), 따라서 누락된 알파는 다른 모든 누락된 구성 요소와 정확히 동일한 방식으로 계속 전달됩니다.
유사 컴포넌트는 다음과 같습니다:
| 카테고리 | 컴포넌트 |
|---|---|
| 빨강 | r,x |
| 초록 | g,y |
| 파랑 | b,z |
| 명도 | L |
| 채도/색도 | C, S |
| 색상각 | H |
| 반대축 a | a |
| 반대축 b | b |
| 알파 | alpha |
Note: 이 분류의 목적상, XYZ 공간은 초포화 RGB 공간으로 간주됩니다. 또한 채도(Saturation)는 명도(Lightness)에 의존하지만, 여기서는 Chroma와 같은 범주에 속합니다. HWB의 Whiteness 및 Blackness 구성 요소는 다른 색상 공간에 대응물이 없습니다.
추가로, 임의의 두 색상 공간에 대해, 모든 유사 구성 요소를 제거한 뒤 남는 구성 요소들은 구성 요소의 유사 집합(analogous set)을 형성합니다.
Note: 모든 색상 구성 요소의 전체 집합은 개별 유사 구성 요소가 하나도 없을 때 남는 유사 집합이므로, 모든 색상 구성 요소가 누락됨인 색상은 보간 색상 공간에서도 모든 색상 구성 요소가 누락됨입니다.
lab ( 50 % none none)
을 LCH로 변환하여
보간할 때,
Lightness는 개별적으로 유사합니다.
나머지 구성 요소들
(Lab의 a와 b;
LCH의 C와 H)
는 유사 집합을 형성합니다.
a와 b가 모두 누락됨이므로,
C와 H도 모두 누락됨으로
이월되며,
따라서 lch ( 50 % none none)
이
lch ( 50 % 0 0 )
대신 생성됩니다.
마찬가지로,
를 보간을 위해 OKLab로 변환하면
이 됩니다.
왜냐하면 세 색상 구성 요소가
유사 집합을 이루기 때문입니다
(sRGB와 OKLab 사이에는 개별 유사 구성 요소가 없습니다).
lch ( 50 % 0.02 none) color ( display-p30.7 0.5 none)
변환 결과는 다음과 같습니다
oklch ( 56.897 % 0.0001 0 ) oklch ( 63.612 % 0.1522 78.748 )
그리고 전달된 누락된 구성요소가 다시 삽입되면, 실제로 보간되는 두 색상은 다음과 같습니다:
oklch ( 56.897 % 0.0001 none) oklch ( 63.612 % 0.1522 78.748 )
만약 전달된 누락된 구성요소를 가진 색상이 동일하지 않은 값을 가진 다른 색상과 보간된다면, 누락된 구성요소는 다른 색상의 그 구성요소 값으로 간주합니다.
따라서, 이월(carrying-forward) 단계는 모든 무력한 구성 요소(powerless component) 처리 이전에 수행되어야 합니다.
oklch ( 78.3 % 0.108 326.5 ) oklch ( 39.2 % 0.4 none)
그럼 실제로 보간되는 색상은 다음과 같습니다
oklch ( 78.3 % 0.108 326.5 ) oklch ( 39.2 % 0.4 326.5 )
그리고 아래와 같이 보간되지 않습니다
oklch ( 78.3 % 0.108 326.5 ) oklch ( 39.2 % 0.4 0 )
전달된 누락된 구성요소가 알파인 경우, 색상은 변환 결과 0으로 처리되는 값이 아니라, 전달된 값으로 사전곱셈(premultiplied)되어야 합니다.
oklch ( 0.783 0.108 326.5 /0.5 ) oklch ( 0.392 0.4 0 / none)
그럼 실제로 보간되는 색상은 다음과 같습니다
oklch ( 78.3 % 0.108 326.5 /0.5 ) oklch ( 39.2 % 0.4 0 /0.5 )
이 때 사전곱셈된 OkLCh 값은 [0.3915, 0.054, 326] 및 [0.196, 0.2, 0]이 됩니다.
만약 두 색상 모두 누락된 특정 구성요소라면, 보간 결과 색상도 해당 구성요소가 누락된 상태가 됩니다.
13.3. 알파와 함께 보간하기
보간할 색상이 완전히 불투명하지 않으면, 먼저 다음과 같이 프리멀티플라이드 처리합니다:
-
알파 값이 none이면, 프리멀티플라이드 값은 원래 값과 동일합니다. 그렇지 않으면,
-
컴포넌트 값 중 none이 있으면, 프리멀티플라이드 값도 none입니다.
-
직교 좌표 색상 시스템에서는 모든 컴포넌트 값을 알파값으로 곱합니다.
-
원통형 극좌표 색상 시스템에서는 색상각(Hue)은 곱하지 않지만, 나머지 두 축은 곱합니다.
프리멀티플라이드 색상 값에서 원래 색상 값을 얻으려면,
-
보간된 알파 값이 0 또는 none이면, 원래 값은 프리멀티플라이드 값과 동일합니다. 그렇지 않으면,
-
컴포넌트 값 중 none이 있으면, 원래 값도 none입니다.
-
그 외에는, 프리멀티플라이드된 각 컴포넌트를 보간된 알파 값으로 나눕니다.
프리멀티플라이드 알파가 왜 유용한가?
프리멀티플라이드 표현으로 색상 보간하면, 비프리멀티플라이드 표현보다 더 보기 좋은 전환이 만들어지는 경향이 있으며, 특히 완전히 불투명한 색상에서 완전히 투명한 색상으로 전환할 때 그렇습니다.
투명도 또는 색상이 고정된 채로 전환할 때는
(예:
(불투명 빨강)
와
(불투명 파랑),
또는
(불투명 빨강)
와
(투명 빨강))
프리멀티플라이드 방식과 비프리멀티플라이드 방식 모두 결과가 동일합니다.
차이는 색상과 투명도가 둘 다 다를 때만 발생합니다.
linear-gradient ( 90 deg , red, transparent, blue)
프리멀티플라이드 색상에서는, "transparent"로 전환할 때 항상 보기 좋습니다:
반면, 비프리멀티플라이드 공간에서 잘못 전환하면, 그라데이션 중앙이 눈에 띄게 회색빛이 되는데, "transparent"가 실제로는 rgba(0,0,0,0), 즉 투명 검정의 약어여서 빨강은 투명해질수록 검정으로 전환되고, 파랑도 마찬가지입니다:
이 색상의 선형 보간 중간값은 [23.4% 10.2% 38.8%]이며, 알파 값이 0.5일 때, 프리멀티플라이드 해제하면 rgb(46.8% 20.4% 77.6% / 0.5) 가 됩니다.
선형 보간의 중간값은 [29.4365% 25.776 3.554]이며, 알파 값이 0.5일 때, 프리멀티플라이드 해제하면 lab(58.873% 51.552 7.108) / 0.5) 가 됩니다.
선형 보간의 중간값(기본값인 shorter hue arc 기준)은 [29.4365% 40.563 31.82]이며, 알파 값이 0.5일 때, 프리멀티플라이드 해제하면 lch(58.873% 81.126 31.82) / 0.5) 가 됩니다.
알파 프리멀티플라이드 및 해제에 대한 샘플 JavaScript 코드는 § 19 색상 변환 샘플 코드에 있습니다.
13.4. 색상각 보간
색상각(hue angle)이 있는 색상 함수(LCH, HSL, HWB 등)는 보간 방법이 여러 가지입니다. 360°를 초과하는 호(arc)는 거의 바람직하지 않으므로, 보간 전에 색상각을 조정해 각 컴포넌트의 보간이 360° 미만, 보통 180° 미만에서 이루어지도록 합니다.
호스트 문법에서 색상각 보간 알고리즘을 다음 중 하나로 지정할 수 있습니다 (아래 각도는 도 단위로 설명하지만, 표현 방식에 관계없이 논리는 동일합니다). 색상각 보간 전략 지정은 이미 <color-interpolation-method> 문법에서 <hue-interpolation-method> 토큰으로 지원됩니다.
별도로 지정하지 않으면, 호스트 문법에서 특정 색상각 보간 알고리즘을 선택하지 않은 경우 기본값은 shorter입니다.
참고: 참고로, 보간 색상이 지정된 보간 색상 공간에 이미 있지 않다면, 변환 과정에서 무효 컴포넌트가 누락 컴포넌트로 바뀝니다.
13.4.1. shorter
색상각은 시작·종료 색상 사이의 짧은(shorter) 호를 따라 보간됩니다.
각도는 θ₂ - θ₁ ∈ [-180, 180]이 되도록 조정합니다. 의사자바스크립트:
if( θ₂ - θ₁ >180 ) { θ₁ +=360 ; } else if( θ₂ - θ₁ <-180 ) { θ₂ +=360 ; }
13.4.2. longer
색상각은 시작·종료 색상 사이의 긴(longer) 호를 따라 보간됩니다.
각도는 θ₂ - θ₁ ∈ {(-360, -180], [180, 360)}이 되도록 조정합니다. 의사자바스크립트:
if( 0 < θ₂ - θ₁ <180 ) { θ₁ +=360 ; } else if( -180 < θ₂ - θ₁ <=0 ) { θ₂ +=360 ; }
13.4.3. increasing
색상각은 첫 번째 색상에서 두 번째 색상으로 진행할 때 항상 증가(increasing) 방향으로 보간됩니다. 각도가 360이 되면 0으로 리셋 후 계속 증가합니다.
두 각도 차이에 따라 결과는 shorter 또는 longer와 같을 수 있습니다. 하지만 한쪽 색상각이 애니메이션될 때, 각도 차가 180도를 지나면 보간 호가 뒤집히지 않습니다.
만약 두 번째 색의 hue가 oklch(0.7 0.1 230)로 애니메이션되면, 중간값은 (30 + 230) * 0.5 = 130도가 되어, 같은 증가 방향으로 보간되어, oklch(0.6 0.1 130) (다른 녹색)입니다. 중간에 색상각 호가 뒤집히지 않습니다.
각도는 θ₂ - θ₁ ∈ [0, 360)이 되도록 조정합니다. 의사자바스크립트:
if( θ₂ < θ₁) { θ₂ +=360 ; }
13.4.4. decreasing
색상각은 첫 번째 색상에서 두 번째 색상으로 진행할 때 항상 감소(decreasing) 방향으로 보간됩니다. 각도가 0이 되면 360으로 리셋 후 계속 감소합니다.
두 각도 차이에 따라 결과는 shorter 또는 longer와 같을 수 있습니다. 하지만 한쪽 색상각이 애니메이션될 때, 각도 차가 180도를 지나면 보간 호가 뒤집히지 않습니다.
만약 두 번째 색의 hue가 oklch(0.7 0.1 230)로 애니메이션되면, 중간값은 (30 + 360 + 230) * 0.5 = 310도이며, 같은 감소 방향으로 보간되어, oklch(0.6 0.1 310) (다른 보라색)입니다. 중간에 색상각 호가 뒤집히지 않습니다.
각도는 θ₂ - θ₁ ∈ (-360, 0]이 되도록 조정합니다. 의사자바스크립트:
if( θ₁ < θ₂) { θ₁ +=360 ; }
14. 색역 매핑
14.1. 색역 매핑 소개
참고: 이 섹션은 문서의 다른 곳에서 제시된 구체적인 요구사항에 대한 중요한 배경을 제공합니다.
이 섹션은 규범적이지 않습니다
테스트
이 섹션은 규범적이지 않으므로 테스트가 필요하지 않습니다.
원본 색 공간의 색상을 더 작은 색 영역을 가진 다른 목적 색 공간으로 변환할 때, 일부 색상은 목적 색 공간의 가시영역을 벗어납니다.
중간 색 계산에서는 이러한 가시영역 밖 값이 유지됩니다. 하지만 목적지가 디스플레이 장치(화면 또는 프린터) 인 경우에는 영역 밖 값을 가시영역 내 색상으로 변환해야 합니다.
색 공간 매핑(gamut mapping)은 외관이 가장 덜 변화된 가시영역 내 색상을 찾는 과정입니다.
영역 밖 색상 중 일부는 실제 세계의 색상에 해당합니다 (물리적으로 재현 가능함) 반면, 다른 색상은 가상의 색상입니다 (스펙트럼 경계 밖에 위치하며, 단일 파장에서 100% 이상의 에너지가 필요하므로) 실제로 구현할 수 없습니다. 이러한 색상은 주로 "이 색상의 채도를 100배로 올리기" 같은 계산 과정에서 나옵니다.
이 네 모서리 중 세 곳은 스펙트럼 경계 밖에 위치하며, 따라서 가상의 색상에 해당합니다.
14.1.1. 클리핑
가장 단순하면서 가장 추천되지 않는 방법은 구성요소 값을 단순히 표시 가능한 범위로 클리핑하는 것입니다.
이 방법의 동기는 속도이기 때문에, 일반적으로 선형광 변환 없이 감마 인코딩된 값에서 바로 클리핑을 수행합니다.
이로 인해 (RGB 디스플레이의) 세 원색의 비율이 바뀌면서 색상 변화(눈에 띄는 색상각 변화)가 발생합니다.
color ( srgb-linear 0.5 1 3 )
색상을 생각해 보세요.
이것은 선형광 색 공간이므로,
세 구성요소의 강도를 비교해 보면
파란색 빛의 양이
초록색의 3배,
빨강색 빛 양은 초록색의 절반입니다.
빨강 대비 파랑의 비율은 6:1.
OkLCh에서는 이 색상은 색상각 265.1°를 가집니다.
이제 이 색상을 sRGB 가시영역으로 클리핑하면,
이 됩니다.
파란색 빛 양은 초록색과 같습니다.
OkLCh에서는 색상각 196.1°가 되어,
69°만큼 크게 달라집니다.
색상이 너무 멀리 가시영역을 벗어나지 않았을 때는, 클리핑 결과가 수용할 만한 경우도 있습니다. 특히 더 어둡거나(혹은 음수인) 구성요소 값일 때 그렇습니다.
color ( rec2020 0.54 0.9 0 )
색상은
oklch ( 80.72 % 0.3296 141.6 )
입니다.
p3 색공간으로 변환하면, 파랑값이 음수로 나와
가시영역 밖임을 알 수 있습니다:
선형광에서는
입니다.
감마 인코딩된 p3 색상을 p3 가시영역으로 클리핑하면
선형광에서는
이 되고, 비교를 위해
입니다.
이것은 좋은 결과입니다; 색상각과 명도(lightness)는 거의 변하지 않고 채도(chroma)만 약간 줄어듭니다(예상된 결과).
선형광 빨강, 초록, 파랑의 퍼센트로 보면, 빨강과 초록은 동일, 파랑은 -1.46% 증가한 값입니다.
color ( prophoto-rgb 0.2 1.0 0.1 )
색상은
oklch ( 85.07 % 0.4873 151.4 )
입니다.
p3 색공간으로 변환하면, 색상은 확실하게
가시영역 밖입니다:
선형광에서는
입니다.
감마 인코딩된 p3 색상을 p3 가시영역으로 클리핑하면
선형광에서는
(정확히 0 또는 1인 값은 감마 인코딩에 영향받지 않음)
비교를 위해
입니다.
썩 좋은 결과는 아니지만 시각적으로는 수용 가능. 여기서는 색상각이 좀 더 많이 바뀌었으며, 5.8° 변화입니다.
선형광 빨강, 초록, 파랑의 퍼센트로 보면, 빨강은 57% 증가, 초록은 6.7% 감소, 파랑은 23% 증가했습니다.
14.1.2. 가장 가까운 색상(MINDE)
더 나은 방법은, 지각적으로 균등한 색상 공간에서, 가장 가까운 영역 내 색상(최소 ΔE 또는 MINDE)을 찾는 것입니다. 이 방식의 성공은 색역 매핑 색상 공간의 균등성 정도와 deltaE 함수의 예측 정확도에 달려 있습니다.
그러나 색역 매핑을 할 때 hue의 변화는 특히 거슬립니다; chroma의 변화는 좀 더 용인 가능하며, 명도의 작은 변화도 chroma 감소가 더 클 경우엔 받아들여질 수 있습니다. MINDE는 각 차원의 변화를 동등하게 취급하므로, 결과가 최적이 아닙니다.
14.1.3. 채도 축소
MINDE를 구현하려면, 색상을 지각적으로 균일한 극좌표 색 공간에서 색상(hue)을 고정하고, 채도(chroma)를 점차 줄여 가시영역에 들 때까지 이동시킵니다.
이 과정은 알고리즘적으로 일정 명도와 색상을 가진 선(ray)이 영역 경계와 만나는 기하학적 교점을 찾아서 수행할 수도 있고, 반복적으로 채도를 줄이며 영역 내로 들어갈 때까지 검증할 수도 있습니다.
참고: 속도 향상을 위해 반복은 주로 이진 탐색(binary search)으로 처리됩니다.
color ( display-p3 1 1 0 ) )
을 sRGB 디스플레이로 매핑합니다.
색 영역 매핑에 사용된 색 공간은 OkLCh입니다.
는color ( display-p31 1 0 )
이고, 이는color ( srgb1 1 -0.3463 )
color ( oklch0.96476 0.24503 110.23 )
입니다. 채도 값을 점차 줄이면 결과 색상이 sRGB 가시영역에 들어올 때 (모든 값이 음수가 아니거나 1을 넘지 않을 때) 색 영역 매핑 결과가 얻어집니다.
이것은color ( oklch0.96476 0.21094 110.23 )
color ( srgb0.99116 0.99733 0.00001 )
14.1.4. 과도한 채도 축소
또한, 이 간단한 MINDE 방법은 특정 색상, 특히 노랑과 시안처럼 매우 밝은 색상에 최적이 아닌 결과를 낼 수 있습니다. 만약 가시영역 경계의 상단이 평평하거나 약간 오목하다면, 일정 명도의 선이 가시영역 경계 바로 위를 스치게 되어 그 경우 채도가 지나치게 낮아질 수 있습니다.
사용하는 색 공간에 따라, 색 영역 매핑 결과의 품질이 달라집니다.
color ( display-p3 1 1 0 )의
채도가 CIE LCH 색 공간에서 점차 줄어듭니다.
color ( display-p3 1 1 0 )의
채도가 이번에는 OkLCh 색 공간에서 점차 줄어듭니다.
14.1.5. 채도 축소와 국소 클리핑
단순 chroma 축소 알고리즘을 개선하려면: 각 단계마다, 현재 매핑된 색상과 클리핑된 버전 사이의 색상 차이를 계산합니다. 만약 현재 색상이 색역 경계 밖이지만 클리핑 버전과의 색상 차이가 지각 가능 최소 차이(just noticeable difference, JND) 임계값 이하면, 클리핑 버전 색상을 매핑 결과로 반환합니다. 실질적으로, 각 단계마다 MINDE 매핑을 수행하되 hue와 명도 변화가 아주 작고 눈에 띄지 않도록 제한합니다.
color ( display-p3 1 1 0 )은
CIE LCH 색상 공간에서 chroma를 점진적으로 줄이고,
국소 클리핑을 적용합니다.
color ( display-p3 1 1 0 )은
OKLCh 색상 공간에서 chroma를 점진적으로 줄이고,
국소 클리핑을 적용합니다.
14.1.6. 지각적 균등성의 일탈: 색상각 곡률
CIE LCH 색 공간에서 영역 매핑을 수행하면, deltaE2000 거리 척도를 쓰더라도, 색상각이 270°에서 330° 사이에 있는 색상에서 색상 변화(hue shift)가 크게 발생하여 결과가 최적이 아님이 알려져 있습니다.
OkLCh 색 공간과 deltaEOK 거리 척도를 쓰면 모든 색상각에서 이런 문제가 발생하지 않습니다.
14.2. CSS RGB 대상 색역 매핑
테스트
색상의 실제 값은 스크립트에서 노출되지 않으므로 자동으로 테스트하 기 어렵습니다.
세 가지 CSS 가뭇 매핑 알고리즘은 개별적인 표준 다이내믹 레인지(SDR) CSS 색상 중 RGB 디스플레이 가뭇 을 벗어나는 색상에 적용되며, 이들은 css 가뭇 매핑이 필요합니다.
구현체는 품질 및 실행 효율성 트레이드오프에 따라 세 가지 알고리즘 중 아무거나 선택할 수 있으며, CSS가 가뭇 매핑을 요구하는 곳에서는 선택한 알고리즘을 반드시 사용해야 합니다.
이 알고리즘들은 모두 상대 색도 의도를 구현합니다. 목적지 가뭇 내의 색상은 변하지 않습니다.
참고: 다른 상황, 특히 최대 흑색 레벨이 0보다 상당히 높은 프린터 가뭇 매핑의 경우, 흑점과 백점을 정렬하는 별도의 알고리즘이 필요하 며, 이 과정에서 매우 밝거나 어두운 색상의 명도가 채도가 감소함에 따라 변합니다.
참고: 이 알고리즘들은 개별적 인 색상에만 적용됩니다; 컬러 이미지 의 경우 인접 픽셀간 관계와 디테일, 텍스처 보존이 중요하므로, 지각적 렌더링 의도가 더 적합하며 이때는 목적지 가뭇 내의 색상까지 바뀔 수 있습니다.
세 CSS 가뭇 매핑 알고리즘은 모두 OkLCh 색 공간에서 명도 와 색상은 유지하고 채도를 줄이는 것을 목표로 합니다.
명도 축의 범위를 벗어난 색상의 경우, 명도가 1.0 이상이면 목적지 색 공간에서 흰색을, 명도가 0.0 이하이면 검정을 반환합니다.
14.2.1. 로컬 MINDE를 이용한 이진 검색 가뭇 매핑
이 이진 검색 알고리즘에서는 deltaEOK 색상 차이 공식을 사용합니다. 그리고 local-MINDE 개선도 적용됩니다. 탐색의 각 단계에서, 현재 매핑된 색상 과 그 색상을 클리핑한 버전 사이의 deltaEOK를 계산합니다.
현재 색상이 가뭇 경계 밖 이지만, 클리핑된 버전과의 deltaEOK 가 인지 가능한 최소 변화량 (JND) 임계값보다 낮으면, 클리핑된 색상을 매핑 결과로 반환합 니다. 이는 눈에 띄는 색상 변화 없이 좋은 결과를 내며, 오목한 가뭇 경계 부근의 과도한 채도 감소를 피할 수 있지만 계산량이 많을 수 있습니다.
OkLCh 색 공간에서 JND 1은 OkLCh 차이 0.02입니다.
참고: CIE Lab 색 공간에서 명도 범위가 0~100이고 deltaE2000을 쓰면 JND 1은 2입니다. Oklab 및 OkLCh의 명도 범위는 0~1이므로 deltaEOK를 쓸 때 JND는 100배 작습니다.
참고: 실험과 구현 비교 목적으로, 로컬 MINDE 이진 검색 알고리즘 구현체가 Coloraide (파이썬) [Coloraide-MINDE] 와, color.js (자바스크립트) [colorjs-MINDE]에 서 제공됩니다.
14.2.2. 로컬 MINDE 이진 검색 가뭇 매핑 샘플 의사코드
- 만약 destination이 가뭇 제한이 없다면 (XYZ-D65, XYZ-D50, Lab, LCH, Oklab, OkLCh), origin 을 destination으로 변환해 매핑 결과로 반환합니다.
- origin_OkLCh를 origin color space에서 OkLCh 로 변환
- origin_OkLCh의 명도 가 100% 이상이면 `oklab(1 0 0 / origin.alpha)`를 destination 으로 변환, 매핑 결과로 반환
- origin_OkLCh의 명도 가 0% 이하이면 `oklab(0 0 0 / origin.alpha)`를 destination 으로 변환, 매핑 결과로 반환
- inGamut(color) 함수는 색상이 목적지 가뭇 내이면 true를 반환. HSL, HWB는 sRGB 가뭇만 체크.
- inGamut(origin_OkLCh) 가 true라면 origin_OkLCh를 destination으로 변환해서 매핑 결과로 반환
- 그 외는 delta(one, two) 함수, 두 색상 deltaEOK 반환
- JND는 0.02
- epsilon은 0.0001
- clip(color) 함수는 color를 destination으 로 변환 후 각 성분을 범위 내로 클램핑해 반환
- current는 origin_OkLCh
- clipped는 clip(current)에 할당
- E는 delta(clipped, current)
-
만약 E <
JND라면
- clipped 를 가뭇 매핑 결과로 반환
- min는 0
- max는 origin_OkLCh의 OkLCh 채도
- min_inGamut 에 true (min이 가뭇 내에 있을 때)
-
(max-min
> epsilon) 동안 반복
- chroma를 (min+max)/2로 설정
- current의 채도를 chroma로 설정
- min_inGamut 참이고 inGamut(current)도 참이면 min = chroma, 계속
-
아니라면:
- clipped = clip(current)
- E = delta(clipped, current)
-
만약 E
< JND
- (JND - E < epsilon)이면 clipped 반환
-
아니면
- min_inGamut을 false로
- min = chroma
- 그 외에는 max=chroma, 반복
- clipped를 가뭇 매핑된 색상으로 반환
14.2.3. EdgeSeeker 색역 매핑
EdgeSeeker 알고리즘은 기하학 및 조회 테이블 기반의 접근 방식으로, 원래 Alexey Ardov가 color.js 라이브러리를 위해 개발하였다 [colorjs-EdgeSeeker].
주어진 임의의 색상환(hue)에 대해, 색역 경계 단면은 곡선형 상단 부분과 선형 하단 부분으로 표현되며, 해당 색상환의 최고 채도 지점에서 서로 연결됩니다.
이 알고리즘을 초기화하려면, 주어진 대상 RGB 공간에 대해 조회 테이블(LUT)을 구성하고 각 색상환 단면에서 가장 높은 채도의 Oklch 색상을 저장합니다. 가장 가까운 LUT 값들 간의 선형 보간을 사용하여 색역 매핑할 각 색상의 정확한 색상환에 대한 최고 채도 색상을 추정합니다.
그다음 일정한 명도 광선(constant-lightness ray)과 색역 경계의 교점을 계산합니다. 이는 경계의 하단(선형) 부분에서는 빠르고, 상단(곡선) 부분에서도 여전히 상당히 빠릅니다.
이 방법은 LUT용 메모리를 사용하는 대가로 좋은 결과를 제공합니다.
14.2.4. EdgeSeeker 색역 매핑을 위한 샘플 의사코드
14.2.5. Ray Trace 색역 매핑
Ray Trace 알고리즘은 RGB 색역 매핑을 위한 기하학적 접근 방식으로, 고정된 명도에서 빠른 채도 감소를 수행합니다. 이 알고리즘은 원래 Isaac Muse가 Coloraide Python Library [Coloraide-Ray-Trace]를 위해 개발했습니다.
매핑할 색상은 먼저 Oklch로 변환되고, 이어서 해당 색상의 무채색 버전이 생성되며, 이는 중립 축의 기준점(anchor)이 됩니다. 이 두 색상은 이후 대상 RGB 공간의 선형광 버전으로 변환됩니다.
이제 색역 경계가 축 정렬 큐브이므로, 교차점을 찾는 것이 더 빠릅니다.
RGB 큐브 내부의 기준점에서 현재 색상까지 광선을 쏩니다. 이 경로를 따라 RGB 색역 표면과의 교차점을 찾고, 이는 색역 매핑된 색상의 첫 번째 근사값이 됩니다.
RGB 공간은 지각적으로 균일하지 않으므로, 고정 색조, 고정 명도 광선은 실제로 RGB 공간에서는 곡선 경로가 됩니다.
첫 번째 근사값은 다시 Oklch로 변환되어, 점을 채도 감소 경로 위에 다시 투영함으로써 지각적 색 공간에서 색상을 보정하고, 색조와 명도를 수정합니다. 보정된 색상은 새로운 현재 색상이 되며, 감소된 채도 선상에서 훨씬 더 가까운 색상이 되어야 합니다.
이 과정은 반복되며(최대 세 번 더), 매번 경로상에서 더 나은, 더 가까운 색상을 찾습니다. 마지막으로 단순 클리핑을 사용하여 부동소수점 계산 오류를 보정합니다.
그 결과는 낮은 JND를 사용한 지역 MINDE 기반 이진 탐색과 비교할 수 있으면서도, 훨씬 더 빠르고 예측 가능하고 일관된 시간 내에 결과를 제공합니다.
이미지 저작권 Isaac Muse.
Note: 실험 및 구현 비교를 위해, Ray Trace 구현은 Coloriade 라이브러리(Python) [Coloraide-Ray-Trace] 및 color.js 라이브러리(JavaScript) [colorjs-RayTrace]에서 사용할 수 있습니다.
14.2.6. Ray Trace 색역 매핑을 위한 샘플 의사코드
- destination에 색역 제한이 없다면 (XYZ-D65, XYZ-D50, Lab, LCH, Oklab, OkLCh), origin을 destination으로 변환하여 색역 매핑된 색상으로 반환합니다.
- origin_OkLCh를 origin을 origin color space에서 OkLCh 색상 공간으로 변환한 값으로 둡니다.
- origin_OkLCh의 Lightness가 100% 이상이면, `oklab(1 0 0 / origin.alpha)`를 destination으로 변환하여 색역 매핑된 색상으로 반환합니다.
- origin_OkLCh의 Lightness가 0% 이하이면, `oklab(0 0 0 / origin.alpha)`를 destination으로 변환하여 색역 매핑된 색상으로 반환합니다.
- l_origin을 origin_OkLCh의 OkLCh lightness 구성 요소로 둡니다.
- h_origin을 origin_OkLCh의 OkLCh hue 구성 요소로 둡니다.
- anchor를 l_origin을 lightness로, 0을 chroma로, h_origin을 hue로 하여 만든 무채색 OkLCh 색상으로 두고, 이를 destination의 linear-light 형태로 변환합니다.
- origin_rgb를 origin_OkLCh를 destination의 linear-light 형태로 변환한 값으로 둡니다.
-
origin_rgb가 색역 안에 있지 않다면
- low를 0.0 + 1E-6으로 둡니다 1
- high를 1.0 - 1E-6으로 둡니다 2
- last를 origin_rgb로 둡니다
-
for (i=0; i<4; i++)
-
if (i > 0)
- current_OkLCh를 origin_rgb를 OkLCh로 변환한 값으로 둡니다
- current_OkLCh의 lightness를 l_origin으로 둡니다
- current_OkLCh의 hue를 h_origin으로 둡니다 3
- origin_rgb를 current_OkLCh를 destination의 linear-light 형태로 변환한 값으로 둡니다
- 광선을 쏩니다: 시작점 start = anchor, 끝점 end = origin_rgb 로 하여, 이 광선과 색역 경계의 교차점을 intersection으로 둡니다.
- 교차점을 찾지 못하면, origin_rgb를 last로 두고 루프를 종료합니다 5
- if (i >0) AND (origin_rgb의 각 구성 요소가 low와 high 사이에 있다면) anchor를 origin_rgb로 둡니다 4
- origin_rgb를 intersection으로 둡니다
- last를 intersection으로 둡니다
-
if (i > 0)
- clip(color)를 color를 destination으로 변환하고, 각 구성 요소를 해당 기준 범위의 경계로 제한한 뒤 그 결과를 반환하는 함수로 둡니다
- clipped를 clip(current)으로 둡니다
- clipped를 색역 매핑된 색상으로 반환합니다
- bmin과 bmax를 색역의 하한 및 상한을 담은 3요소 배열로 둡니다 6
- tfar를 무한대로 둡니다(또는 매우 큰 수)
- tnear를 음의 무한대로 둡니다(또는 매우 큰 음수)
- direction을 3요소 배열로 둡니다
-
for (i = 0; i < 3; i++):
- a를 start [i]로 둡니다
- b를 end [i]로 둡니다
- d를 b - a로 둡니다
- direction [i]를 d로 둡니다
-
if abs(d) < 1E-12
- inv_d를 1 / d로 둡니다
- t1를 (bmin [i] - a ) * inv_d로 둡니다
- t2를 (bmax [i] - a ) * inv_d로 둡니다
- tnear를 max(min(t1, t2), tnear )로 둡니다
- tfar를 min(max(t1, t2), tfar )로 둡니다
-
else if (a < bmin[i] or a >
bmax[i])
- INTERSECTION NOT FOUND를 반환합니다
-
if (tnear > tfar or tfar < 0)
- INTERSECTION NOT FOUND를 반환합니다
-
if tnear < 0
- tnear를 tfar로 둡니다 7
-
if tnear is infinite (or matches the initial very large value)
- INTERSECTION NOT FOUND를 반환합니다
-
for (i =0; i < 3; i++):
- result [i]를 start [i] + direction [i] * tnear로 둡니다
- result를 반환합니다
14.2.6.1. Ray Trace 알고리즘 주석
- 최소값이 0이라고 가정하며, 모든 채널의 최소값이 동일하다고 가정합니다. 값은 단위 유형에 비해 충분히 작아야 합니다. 64비트의 경우 1e-14 정도까지도 가능하지만, 실무에서는 1e-6이면 충분합니다.
- 1.0은 색역 안에 있는 최대 채널 값을 나타내며, 모든 채널의 최대값이 동일하다고 가정합니다.
- 이는 current 색상이 채도 감소 곡선에서 벗어났을 경우 다시 그 곡선 위로 되돌립니다.
- 이는 origin_rgb가 색역 표면보다 아래에 있음을 의미하므로, 색역 표면에 더 가까운 기준점으로 사용합니다.
- 이는 특정 지각적 매핑 공간이 눈에 보이는 스펙트럼 밖의 지나치게 넓은 색상 때문에 완전히 붕괴하는 치명적 실패 상황을 위해 제공됩니다. CSS에서 비허상(non-imaginary) 색상이 이를 유발해서는 안 된다고 기대합니다.
- 일반적인 RGB 공간에서는 각 구성 요소의 색역 경계가 0과 1이므로 이는 3요소 배열이 아닌 하나의 상수로 단순화됩니다.
- start -> end 방향에서 첫 번째 교차점을 우선시합니다.
15. <color> 값 해석하기
특정 속성에 대해 별도의 명시가 없는 한, 지정된 색상은 계산된(computed) 색상으로 해석된 후, 아래에 설명된 대로 사용된(used) 색상으로 추가 해석됩니다.
해석된 값(resolved value)은 <color>의 사용된 값입니다.
테스트
15.1. sRGB 값 해석하기
이는 다음에 적용됩니다:
다음에는 적용되지 않습니다:
-
color() 값 중 srgb 또는 srgb-linear 색상 공간을 사용하는 값.
sRGB 색상이 작성자에 의해 이름 있는 색상으로 명시되었거나, 시스템 색상으로 명시되었다면, 선언된 값은 해당 이름 있는 색상 또는 시스템 색상을 ASCII 소문자로 변환한 것입니다. 계산된 값과 사용된 값은 이에 대응하는 sRGB 색상이며, 지정된 alpha 성분과 함께 ([0, 1]로 클램핑한 후) 지정되지 않았다면 불투명으로 기본 설정됩니다).
그렇지 않으면, 선언된 값, 계산된 값 및 사용된 값은 이에 대응하는 sRGB 색상이며, 지정된 alpha 성분과 함께 ([0, 1]로 클램핑한 후) 지정되지 않았다면 불투명으로 기본 설정됩니다).
역사적 이유로, calc()가 sRGB 색상에서 단일 값으로 해석될 때, 선언된 값은 "calc(" ")" 래퍼 없이 직렬화됩니다.
또한 역사적 이유로, calc()가 단일 값으로 단순화될 때, 색상 값은 [0.0, 255.0]로 클램핑됩니다.
이 클램핑은 또한 Infinity, -Infinity, 그리고 NaN 같은 값도 처리하며, 각각 255, 0, 0으로 클램핑됩니다.
테스트
15.2. Lab 및 LCH 값 해석하기
지정 값, 계산 값, 사용 값은 해당하는 CIE Lab 또는 LCH 색상이며 (L, C, H 클램핑 후) 지정된 알파 컴포넌트와 함께 (<number>로, <percentage>가 아님; 알파 미지정 시 기본값은 불투명입니다).
a, b, C 값은 이론적으로 제한이 없지만, 사실상 무한대에 근접하는 값에 대한 구현체별 한계가 있을 수 있습니다.
15.3. Oklab 및 OkLCh 값 해석
이 항목은 oklab() 및 oklch() 값에 적용됩니다.
선언값, 계산값, 사용값은 해당 Oklab 또는 OkLCh 색상이며 (L, C, H는 클램핑한 뒤) 명시된 알파 컴포넌트가 결합된 형태입니다 (알파는 <number> 타입(퍼센트가 아님 <percentage> 아님), 미지정시 기본 불투명).
a, b, C 값은 이론상 무한대로 커질 수 있지만, 무한대에 가까워질 때의 구현체별 한계 가 있을 수 있습니다.
15.4. color() 함수 값 해석하기
지정 값, 계산 값, 사용 값은 지정된 색상 공간의 색상이며, 지정된 알파 컴포넌트와 함께 (<number>로, <percentage>가 아님; 알파 미지정 시 기본값은 불투명입니다).
예를 들어 아래의 계산 값은
color ( display-p30.823 0.6554 0.2537 /1 )
다음과 같습니다:
color ( display-p30.823 0.6554 0.2537 )
xyz 색상 공간으로 지정된 색상은 xyz-d65 색상 공간의 별칭이므로, 계산 값과 사용 값은 xyz-d65 색상 공간에 있습니다.
r, g, b, x, y, z 값은 이론적으 로는 제한이 없지만, 구현별로 무한대에 가까운 값에 대한 구현체별 한계 가 있을 수 있습니다.
15.5. 기타 색상 해석하기
이 내용은 시스템 색상(<deprecated-color> 포함), transparent, 그리고 currentcolor에 적용됩니다.
각 <system-color> 키워드와 <deprecated-color> 키워드의 선언된 값은 그 자체입니다. 계산된 값은 해당 색상 공간에 있는 대응 색상입니다. 그러나 이러한 색상은 강제 색상 모드에 의해 변경되어서는 안 됩니다.
< button style = "color: ButtonText; background: ButtonFace" ></ button >
color 속성의 지정 값은 "ButtonText" 계산 값은 예를 들어 rgb(0, 0, 0)일 수 있습니다.
transparent의 지정 값은 "transparent"이고, 계산 값과 사용 값은 투명 검정(transparent black)입니다.
currentcolor 키워드는 그 자체로 계산됩니다.
color 속성에서는, currentcolor의 사용 값은 상속된 값으로 해석됩니다. 다른 속성에서는, 사용 값이 같은 요소의 color 속성의 사용 값입니다.
참고: 즉 currentcolor 값이 상속될 경우, 키워드로 상속되며, color 속성 값 자체로 상속되는 것이 아니므로, 자식 요소는 자신의 color 속성으로 값을 해석합니다.
< div > < p > Assume this example text is long enough to wrap on multiple lines.</ p > </ div >
그리고 아래 css:
div{ color : forestgreen; text-shadow : currentColor; } p{ color : mediumseagreen; } p::firstline{ color : yellowgreen; }
첫 번째 줄 fragment의 text-shadow 속성에 대한 사용 값은 yellowgreen입니다.
테스트
16. <color> 값 직렬화하기
이 절은 CSS Object Model의 다음 부분을 갱신하고 대체합니다. section CSS 값 직렬화, 이는 <color> 값의 직렬화와 관련됩니다.
이 절에서, 명세서에 사용되는 문자열과 그에 대응하는 문자는 다음과 같습니다.
| String | Character(s) |
|---|---|
| " " | U+0020 SPACE |
| "#" | U+0023 NUMBER SIGN |
| "," | U+002C COMMA |
| "-" | U+002D HYPHEN-MINUS |
| "." | U+002E FULL STOP |
| "/" | U+002F SOLIDUS |
| "none" | U+006E LATIN SMALL LETTER N U+006F LATIN SMALL LETTER O U+006E LATIN SMALL LETTER N U+0065 LATIN SMALL LETTER E |
문자열 "."은 로케일과 관계없이 소수점 구분자로 사용되어야 하며, 천 단위 구분자는 없어야 합니다.
누락된 색상 구성 요소를 지원하는 구문 형식의 경우, 값 none(동등하게 NONE, nOnE 등)은 모두 소문자로 직렬화되어야 하며, 문자열 "none"으로 표현되어야 합니다.
16.1. 알파 값 직렬화하기
이 내용은 선택적 알파 값을 가질 수 있는 모든 <color> 값에 적용됩니다. opacity 속성에는 적용되지 않습니다.
알파가 [0, 1] 범위로 클램핑된 뒤 1이면, 직렬화에서 생략됩니다; 1(완전 불투명)이 기본값입니다.
알파가 1이 아닌 다른 값이면, 아래 설명된 대로 직렬화에 명시적으로 포함됩니다.
값이 0~255의 정수(8비트 부호 없는 정수)로 내부 표현되는 경우, 다음 단계를 따릅니다:
- alpha를 주어진 정수로 둡니다.
- 0~100 사이의 정수 중, 2.55를 곱하고 가장 가까운 정수로 반올림(Math.round, 두 값이 똑같이 가까우면 큰 쪽으로 반올림)했을 때 alpha가 되는 값이 있으면, 해당 정수를 100으로 나눈 값을 rounded로 둡니다.
- 없으면, alpha를 0.255로 나눈 뒤 가장 가까운 정수로 반올림(Math.round, 두 값이 똑같이 가까우면 큰 쪽으로 반올림), 1000으로 나눈 값을 rounded로 둡니다.
- rounded를 <number>로 직렬화해 반환합니다.
그 외에는, 주어진 값을 (<number>로, <percentage>가 아님) 직렬화해 반환합니다.
예를 들어, 알파가 8비트 부호 없는 정수 237로 저장된 경우, 정수 93이 조건에 부합하므로 Math.round(93 * 2.55)가 237이 되어, 알파는 "0.93"으로 직렬화됩니다.
반면, 알파가 8비트 부호 없는 정수 236인 경우, 해당하는 정수가 없으므로 (92는 235, 94는 240이 됨), 236 ÷ 0.255 = 925.490196078이므로, 알파는 "0.92549"로 직렬화됩니다 (최대 6자리, 끝의 0은 생략).
<number> 값은 10진수로 표현되며, "." 문자가 소수점 구분자로 사용됩니다. 앞의 0은 생략하면 안 됩니다. 뒤의 0은 생략해야 합니다.
예를 들어, 알파 값이 70%라면 직렬화 문자열은 "0.7"이 됩니다. 소수점 앞에 0이 있고, "."이 소수점 구분자이며 (로캘이 ',' 등 다른 문자를 쓰더라도), "7" 뒤에 오는 0은 모두 생략됩니다.
알파 값의 정밀도(직렬화 시 소수점 이하 자리수)는 이 명세에서 정의하지 않지만, 정수 백분율 값이 왕복 가능한 수준이어야 합니다. 따라서 직렬화 값은 최소 소수점 이하 두 자리 이상이어야 하며 (끝의 0이 제거된 경우 제외). 값은 +∞ 방향으로 반올림되어야 하며, 자르기(truncate)하면 안 됩니다.
예를 들어, 알파 값이 12.3456789%라면, "0.12", "0.123", "0.1234", "0.12346" (5는 +∞로 반올림, 뒤에 6이 있으므로) 또는 더 긴 직렬화 문자열로 표현될 수 있습니다.
<alpha-value>가 유효 범위 밖에서 지정된 경우, 구문 분석 시 클램핑되므로 지정 값은 클램핑됩니다. 다만, CSS Values 4 § 10.12 범위 검사에 따라, calc()로 지정된 <alpha-value>는 직렬화 시 지정 형태에서는 클램핑되지 않지만, 계산 값은 클램핑됩니다.
16.2. sRGB 값 직렬화하기
다음 sRGB 값들의 직렬화 형식:
은 선언된 값에서 파생됩니다.
작성자가 CSS 이름 있는 색상, 시스템 색상, deprecated-color, 또는 transparent로 설정한 속성 값을 직렬화할 때, 따라서 선언된 값에 대해서는 ASCII 소문자 키워드 값이 유지됩니다. 계산된 값과 사용된 값에는 대응하는 sRGB 값이 사용됩니다.
따라서 transparent의 직렬화된 선언된 값은 문자열 "transparent"이며, transparent의 직렬화된 계산된 값은 문자열 "rgba(0, 0, 0, 0)"입니다.
그 밖의 모든 sRGB 값에 대해서는, 선언된 값, 계산된 값 및 사용된 값이 대응하는 sRGB 값입니다.
직렬화 중에, 선택된 직렬화 형식 (쉼표 구분자를 사용하는 레거시 색상 문법 또는 sRGB 값의 HTML 호환 직렬화)이 none 키워드를 표현할 수 없는 경우, 모든 누락된 값은 0으로 변환됩니다. 적어도 하나의 구성 요소가 누락되고, 값이 none을 지원하는 형식으로 직렬화될 수 있는 경우, 해당 형식이 § 16.2.2 sRGB 값의 CSS 직렬화에 설명된 대로 선택되어, 누락된 색상 구성 요소가 none으로 유지됩니다.
16.2.1. HTML 호환 sRGB 값 직렬화
다음 조건이 모두 참이라면:
- 색상 공간이 sRGB이다
- 알파가 1이다
- RGB 구성 요소 값이 내부적으로 0에서 255까지의 정수로 표현된다 (즉, 8비트 부호 없는 정수)
- HTML 호환 직렬화가 요청됨
그렇다면 대응하는 sRGB 값은 다음과 같이 6자리 16진수 색상 표기법으로 직렬화됩니다:
7자로 이루어진 문자열이며, 문자 "#"로 시작하고, 이어서 빨강 구성 요소, 초록 구성 요소, 파랑 구성 요소를 이 순서대로 각각 두 자리 16진수로 나타냅니다. 이때 ASCII 소문자 16진수를 사용합니다. 공백은 허용되지 않습니다.
context. fillStyle= "rgb(255, 0, 255)" console. log( context. fillStyle); // "#ff00ff"
색상 공간은 sRGB이고, 표현은 구성 요소당 8비트이며, 데이터 형식은 none 값을 생성하지도 않고 확장 범위 값도 지원하지 않으며, 알파는 1입니다.
HTML 호환 직렬화는 문자열 "#ff00ff"입니다 ("#FF00FF"가 아님).
그 외의 경우, sRGB에 대해서는 sRGB 값의 CSS 직렬화가 사용되며, 다른 색상 공간에 대해서는 해당 직렬화를 <color> 값에 적용합니다.
context. fillStyle= "lab(29% 39 20)" console. log( context. fillStyle); // "lab(29 39 20)"
CSS 직렬화는 문자열 "lab(29 39 20)"입니다.
context. fillStyle= "#ff00ffed" console. log( context. fillStyle); // "rgba(255, 0, 255, 0.93)"
알파가 1이 아니므로, CSS 직렬화는 문자열 "rgba(255, 0, 255, 0.93)"입니다.
16.2.2. CSS sRGB 값 직렬화
값에 누락된 색상 구성 요소가 없는 경우, 해당 sRGB 값은 (클램프된) 알파가 정확히 1인지 여부에 따라 rgb() 또는 rgba() 형식을 사용하며, 함수 이름은 모두 ASCII 소문자로 표기됩니다.
호환성을 위해, sRGB 구성 요소 값은 <number> 형식으로 직렬화되며, <percentage> 형식은 사용하지 않습니다. 또한 호환성을 위해, 구성 요소 값은 저장된 비트 깊이와 관계없이 범위 [0-255]의 10진수로 직렬화됩니다.
앞서 언급했듯이, 단위 alpha 값은 명시적으로 직렬화되지 않습니다. 또한 호환성을 위해 alpha가 정확히 1이면 rgb() 형식을 사용하고, 암시적 alpha를 둡니다. 그렇지 않으면 rgba() 형식을 사용하고, 명시적 alpha 값을 둡니다.
호환성을 위해, 쉼표 구분자를 사용하는 레거시 형식을 사용합니다; 각 쉼표 뒤에는 정확히 하나의 ASCII 공백이 옵니다. 여기에는 rgba()의 파란색 구성 요소와 alpha 값 사이를 구분하는 데 사용되는 쉼표(슬래시가 아님)도 포함됩니다.
그러나 쉼표 구분자를 사용하는 레거시 색상 문법은 none을 표현할 수 없습니다. 값에 적어도 하나의 누락된 색상 구성 요소가 있는 경우, 직렬화 형식은 해당 구성 요소를 none 키워드로 유지하도록 선택되며, 이는 선언된 값의 색상 함수에 기반합니다:
-
rgb()와 rgba() 값의 경우 (이 목록에서 유일하게 none을 허용하는 구문을 가진 sRGB 형식; 16진수 색상, 이름 있는 색상, 시스템 색상, 사용 중단된 색상, 및 transparent은 파라미터 구문이 없어 누락된 색상 구성 요소가 존재하지 않음), 값은 현대 공백 구분형 rgb() 대신 color() 함수로 srgb 색 공간에서 직렬화됩니다. "color(srgb" 다음에 한 칸을 띄우고, 알파를 제외한 세 구성 요소를 <number>로 [0, 1] 범위 또는 none(누락인 경우)로 직렬화하며, 알파가 1이 아니거나 누락된 경우에만 " / "와 알파 구성 요소를 추가하고 (알파 규칙에 따라 직렬화하거나 none(누락된 경우)으로 직렬화) ")"로 닫습니다.
-
hsl()와 hsla() 값의 경우, 현대 공백 구분형 hsl() 구문을 사용하며, 알파가 존재하면 슬래시를 붙입니다. 함수 이름은 작성 시 hsla()를 사용했더라도 "hsl" (ASCII 소문자)입니다. 색상(Hue)은 도 단위의 정규화된 <number>로 직렬화하고, 채도와 명도는 <percentage>로 직렬화하며, 알파는 1이 아니거나 누락된 경우에만 알파 규칙에 따라 직렬화하고, 누락된 구성 요소(missing component)는 none 키워드로 직렬화됩니다.
-
hwb() 값의 경우, 현대 공백 구분형 hwb() 구문을 사용하며, 알파가 존재하면 슬래시를 붙입니다. 함수 이름은 "hwb" (ASCII 소문자)입니다. 색상(Hue)은 도 단위의 정규화된 <number>로 직렬화하고, 흰색(Whiteness)과 검은색(Blackness)은 <percentage>로 직렬화하며, 알파는 1이 아니거나 누락된 경우에만 알파 규칙에 따라 직렬화하고, 누락된 구성 요소(missing component)는 none 키워드로 직렬화됩니다.
Note: 이는 hsl() 또는 hwb() 값에 none이 포함된 경우, 해당 값이 자체 색상 함수로 직렬화되며, 레거시 형식에서 none을 표현할 수 없는 rgba()로 변환되지 않음을 의미합니다. 반면, rgb() 값에 none이 포함된 경우, color(srgb …)를 통해 직렬화됩니다. 현대 공백 구분형 rgb() 자체도 none을 표현할 수 있지만, sRGB CSS 직렬화는 다른 모든 색 공간을 비레거시 형식으로 직렬화하는 방식과 일관성을 유지하기 위해 color(srgb …)를 사용합니다. 이는 CSS Color 5 § 11.2 Serializing Origin Colors에 정의된 상대 색상 구문 동작과 유사합니다.
hwb ( 740 deg 20 % 30 % /50 % )
먼저 다음으로 정규화됩니다.
hwb ( 20 20 % 30 % /50 % )
그 다음 sRGB로 변환되어 다음과 같이 직렬화됩니다.
rgba ( 178.5 , 93.5 , 51 , 0.5 )
반환 결과의 정밀도는 아래에 설명되어 있습니다.
hwb ( 20 none30 % / none)
누락된 색상 구성 요소를 포함하며 (화이트니스와 알파가 모두 none), 따라서 rgba()를 통해 직렬화되지 않습니다. 대신 현대 hwb() 구문을 사용하여 직렬화됩니다.
hwb ( 20 none30 % / none)
각 none 값을 그대로 유지합니다.
Note: CSS Color 3와 달리, rgb() 함수의 매개변수는 <number> 타입이며, <integer>가 아닙니다. 따라서 8비트 이상의 정밀도는 소수점 부분으로 표시됩니다.
sRGB 구성 요소 값이 유지되는 정밀도, 즉 직렬화된 값에서 유효 숫자의 수는 이 명세에서 정의되지 않지만, 최소한 8비트 값을 원래대로 복원할 수 있을 만큼 충분해야 합니다. 값은 +∞ 방향으로 반올림해야 하며, 단순 절삭(truncate)은 허용되지 않습니다.
Note: getComputedStyle에서 반환된 색상 값이 <integer> 구성 요소 값을 기대하는 스크립트 작성자는, <number>도 처리할 수 있도록 업데이트하는 것이 좋습니다.
예를 들어,
rgb ( 146.064 107.457 131.223 )
은 현재 유효하며, 다음과 동일합니다.
rgb ( 57.28 % 42.14 % 51.46 % )
두 경우 모두의 적합한 직렬화 형식은 "rgb(146.06, 107.46, 131.2)" 문자열입니다.
모든 구성 요소 값의 뒤따르는 소수점 0은 생략해야 하며, 소수점 이하가 모두 0이면 소수점 자체도 생략해야 합니다. 이는 정수 구성 요소 값으로 지정된 sRGB 색상이 이전과 호환되는 정수 값으로 직렬화됨을 의미합니다.
16.3. Lab 및 LCH 값 직렬화
lch() 및 lab() 값의 직렬화 형태는 계산 값에서 유도되며, lab() 또는 lch() 형태를 사용합니다. 함수명은 모두 ASCII 소문자입니다.
컴포넌트 값은 10진수로 직렬화되며; L, a, b, C 컴포넌트 값은 <number>로 직렬화되며, Lab 백분율 기준 범위 또는 LCH 백분율 기준 범위를 사용하여 백분율을 숫자로 변환합니다; 0% L은 0, 100% L은 100으로 매핑됩니다. 컴포넌트 값 사이 구분자는 ASCII 공백 문자 " "입니다.
컴포넌트 값의 소수점 이하 0은 모두 생략되어야 하며; 소수점 이하가 모두 0이면 소수점도 생략해야 합니다.
lab() 컴포넌트 값의 정밀도 (직렬화 값의 유효숫자 자리수)는 이 명세에서 정의하지 않지만, 광색역으로 인해 0~100의 L 값, ±127의 a/b 값이 왕복 가능한 수준이어야 하며, 최소 16비트 정밀도가 필요합니다; 결과적으로 소수점 이하 최소 3자리 이상이어야 하며, 끝의 0이 생략된 경우 제외. (내부 저장은 half float 또는 float 권장). 값은 +∞ 방향으로 반올림되어야 하며, 자르면 안 됩니다.
참고: ±125를 넘는 a/b 값도 초광색역에서는 가능합니다. 예를 들어 prophoto-rgb 원색 및 2차색은 이 범위를 넘지만 ±200 이내입니다.
앞서 언급한 대로, 알파값이 1이면 명시적으로 직렬화하지 않습니다. 1이 아닌 알파값은 명시적으로 직렬화해야 하며, " / " (ASCII 공백, 슬래시, 또다른 공백) 문자열로 b값과 알파값을 구분합니다.
아래의 직렬화 값은
lch ( 56.2 % 83.6 357.4 /93 % )
문자열 "lch(56.2 83.6 357.4 / 0.93)"이며, "lch(56.2% 83.6 357.4 / 0.93)"이 아닙니다.
16.4. Oklab 및 OKLCh 값 직렬화
oklch() 및 oklab() 값의 직렬화 형태는 계산 값에서 유도되며, oklab() 또는 oklch() 형태를 사용합니다. 함수명은 모두 ASCII 소문자입니다.
컴포넌트 값은 10진수로 직렬화되며; L, a, b, C 컴포넌트 값은 <number>로 직렬화되며, Oklab 백분율 기준 범위 또는 OKLCh 백분율 기준 범위를 사용하여 백분율을 숫자로 변환합니다; 0% L은 0, 100% L은 1.0으로 매핑됩니다. 컴포넌트 값 사이 구분자는 ASCII 공백 문자 " "입니다.
아래의 직렬화 값은
oklab ( 54.0 % -0.10 -0.02 )
문자열 "oklab(0.54 -0.1 -0.02)"이며, "oklab(54 -0.1 -0.02)" 또는 "oklab(54% -0.1 -0.02)"가 아닙니다.
컴포넌트 값의 소수점 이하 0은 모두 생략되어야 하며; 소수점 이하가 모두 0이면 소수점도 생략해야 합니다.
아래의 직렬화 값은
oklch ( 56.43 % 0.0900 123.40 )
문자열 "oklch(0.5643 0.09 123.4)"이며, "oklch(0.5643 0.0900 123.40)"이 아닙니다.
oklab() 컴포넌트 값의 정밀도 (직렬화 값의 유효숫자 자리수)는 이 명세에서 정의하지 않지만, 광색역으로 인해 0~1(0%~100%)의 L 값, ±0.5의 a/b/C 값이 왕복 가능한 수준이어야 하며, 최소 16비트 정밀도가 필요합니다; 결과적으로 소수점 이하 최소 5자리 이상이어야 하며, 끝의 0이 생략된 경우 제외. (내부 저장은 half float 또는 float 권장). 값은 +∞ 방향으로 반올림되어야 하며, 자르면 안 됩니다.
참고: ±0.5를 넘는 a/b/C 값도 초광색역에서는 가능합니다. 예를 들어 prophoto-rgb의 초록·파랑 원색은 C가 각각 0.526, 1.413입니다.
앞서 언급한 대로, 알파값이 1이면 명시적으로 직렬화하지 않습니다. 1이 아닌 알파값은 명시적으로 직렬화해야 하며, " / " (ASCII 공백, 슬래시, 또다른 공백) 문자열로 마지막 컴포넌트(b, 또는 C) 값과 알파값을 구분합니다.
16.5. color() 함수 값 직렬화
color() 값의 직렬화 형태는 계산 값에서 유도되며, color() 형태를 사용합니다. 함수명과 색상 공간 이름은 ASCII 소문자입니다.
컴포넌트 값은 10진수로 <number>로 직렬화됩니다. 컴포넌트 값 사이, 그리고 색상 공간 이름과 첫 컴포넌트 사이에는 ASCII 공백 문자 " "를 사용합니다.
아래의 직렬화 값은
color ( dIsPlAy-P30.964 0.763 0.787 )
문자열 "color(display-p3 0.96 0.76 0.79)"입니다. 소수점 이하 두 자리로 유지한 경우, 0.787이 0.79로 반올림되었으며 0.78로 잘리지 않았다는 점에 유의하세요.
컴포넌트 값의 소수점 이하 0은 모두 생략되어야 하며; 소수점 이하가 모두 0이면 소수점도 생략해야 합니다.
아래의 직렬화 값은
color ( rec20200.400 0.660 0.340 )
문자열 "color(rec2020 0.4 0.66 0.34)"이며, "color(rec2020 0.400 0.660 0.340)"이 아닙니다.
색상 공간이 sRGB라도 직렬화 결과에 색상 공간 이름을 명시적으로 포함해야 합니다.
미리 정의된 색상 공간별 최소 왕복 정밀도는 아래와 같습니다:
| 색 공간 | 최소 비트수 |
|---|---|
| srgb | 10 |
| srgb-linear | 12 |
| display-p3 | 10 |
| display-p3-linear | 12 |
| a98-rgb | 10 |
| prophoto-rgb | 12 |
| rec2020 | 12 |
| xyz, xyz-d50, xyz-d65 | 16 |
(16비트, half-float, 또는 float 컴포넌트당 으로 내부 저장하는 것을 권장함). 값은 +∞ 방향 반올림되어야 하며, 절삭(truncate)해서는 안 됩니다.
참고: 기존 방식 (rgb(), hsl() 등)과 비교해, color(srgb)는 좀 더 높은 최소 정밀도를 요구합니다. 더 높은 정밀도를 원하는 스타일시트 작성자는 color(srgb) 형식을 사용하는 것이 좋습니다.
앞서 언급한 대로, 알파 값이 1이면 명시적으로 직렬화되지 않습니다. 1이 아닌 알파 값은 반드시 명시적으로 직렬화해야 하며, 문자열 " / " (ASCII 스페이스, 슬래시, 또 하나의 스페이스) 를 사용해 마지막 색상 컴포넌트 값과 알파 값을 구분해야 합니다.
다음 값의 직렬화 결과는
color ( prophoto-rgb0.2804 0.40283 0.42259 /85 % )
소수점 3자리까지 보존 시 문자열 "color(prophoto-rgb 0.28 0.403 0.423 / 0.85)"가 됩니다.
16.6. 기타 색상 직렬화
이 내용은 currentcolor에 적용됩니다.
이 값의 직렬화 형태는 계산 값에서 유도되며, 색상 이름은 ASCII 소문자입니다.
currentColor의 직렬화 값은 "currentcolor" 문자열입니다.
17. opacity-value 직렬화
이 내용은 opacity 속성에 적용됩니다.
opacity 값의 지정값이 리터럴 <percentage-token> 과 일치하는 경우(즉, calc()를 사용하지 않은 경우) 해당 값은 동등한 <number> 값(0%는 0, 100%는 1)으로 직렬화해야 합니다. 그렇지 않으면 opacity 값의 지정값은 문법의 표준 직렬화 방식을 따라야 합니다.
이 <number> 값은 10진수로 표현되며, 소수점 기호로 "."을 사용합니다. 앞의 0은 생략하지 않아야 하며, 뒷부분 0은 생략해야 합니다.
opacity 값이 [0,1] 범위를 벗어나도, 직렬화된 지정값에서는 클램핑 없이 보존됩니다.
opacity 값의 정밀도와, 즉 직렬화 시 소수점 이하 자리수는 이 명세에서 정의하지 않지만, 정수형 백분율 값을 왕복할 수 있을 정밀도는 확보해야 합니다. 따라서 직렬화 값은 최소 두 자리 소수까지 포함해야 하며 (단, 마지막 0이 모두 제거된 경우는 제외). 값은 반드시 +∞ 방향으로 반올림해야 하며, 절삭해서는 안 됩니다.
18. 기본 스타일 규칙(Default Style Rules)
아래 스타일시트는 참고용이며, 규범적이지 않습니다. 이 스타일시트는 구현체가 HTML 문서의 기본 스타일로 사용할 수 있습니다.
/* 하드 데스크탑 사용자 에이전트의 하이퍼링크 색상 */ :link{ color : LinkText; } :visited{ color : VisitedText; } :active{ color : ActiveText; }
19. 색 변환 샘플 코드
이 섹션은 규범적이지 않습니다.
테스트
이 섹션은 규범적이지 않으며, 테스트가 필요하지 않습니다.
명확성을 위해 행렬 곱셈에는 라이브러리를 사용합니다. (곱셈과 덧셈을 모두 인라인하는 것보다 더 읽기 쉽습니다). 행렬은 컬럼 우선 순서입니다.
// 색상 변환 샘플 코드 // 변환은 ICC 프로파일과 컬러 매니지먼트 시스템으로도 수행할 수 있습니다 // 명확성을 위해 행렬 곱셈에 라이브러리(multiply-matrices.js)를 사용합니다 // 표준 백색점, 4자리 CIE x,y 색도값으로 정의됨 const D50= [ 0.3457 / 0.3585 , 1.00000 , ( 1.0 - 0.3457 - 0.3585 ) / 0.3585 ]; const D65= [ 0.3127 / 0.3290 , 1.00000 , ( 1.0 - 0.3127 - 0.3290 ) / 0.3290 ]; // sRGB 관련 함수들 function lin_sRGB( RGB) { // sRGB 값 배열을 변환합니다 // 가뭇 내 값이 [0 - 1] 범위에 있을 때 // 선형광(언컴팬딩) 형태로 변환합니다. // https://en.wikipedia.org/wiki/SRGB // 확장 전달 함수: // 음수 값의 경우, 선형 부분은 축 반사로 확장되고, // 그 다음 반사된 거듭제곱 함수가 사용됩니다. return RGB. map( function ( val) { let sign= val< 0 ? - 1 : 1 ; let abs= Math. abs( val); if ( abs<= 0.04045 ) { return val/ 12.92 ; } return sign* ( Math. pow(( abs+ 0.055 ) / 1.055 , 2.4 )); }); } function gam_sRGB( RGB) { // 선형광 sRGB(0.0-1.0 범위) 배열을 감마 보정형으로 변환합니다 // https://en.wikipedia.org/wiki/SRGB // 확장 전달 함수: // 음수 값은 축 반사로 선형 부분이 확장되고, // 그 아래에서 반사된 pow가 사용됩니다 return RGB. map( function ( val) { let sign= val< 0 ? - 1 : 1 ; let abs= Math. abs( val); if ( abs> 0.0031308 ) { return sign* ( 1.055 * Math. pow( abs, 1 / 2.4 ) - 0.055 ); } return 12.92 * val; }); } function lin_sRGB_to_XYZ( rgb) { // 선형광 sRGB 값을 CIE XYZ로 변환합니다 // sRGB 고유의 백색 D65를 사용(색도 적응 없음) var M= [ [ 506752 / 1228815 , 87881 / 245763 , 12673 / 70218 ], [ 87098 / 409605 , 175762 / 245763 , 12673 / 175545 ], [ 7918 / 409605 , 87881 / 737289 , 1001167 / 1053270 ], ]; return multiplyMatrices( M, rgb); } function XYZ_to_lin_sRGB( XYZ) { // XYZ를 선형광 sRGB로 변환합니다 var M= [ [ 12831 / 3959 , - 329 / 214 , - 1974 / 3959 ], [ - 851781 / 878810 , 1648619 / 878810 , 36519 / 878810 ], [ 705 / 12673 , - 2585 / 12673 , 705 / 667 ], ]; return multiplyMatrices( M, XYZ); } // display-p3 관련 함수들 function lin_P3( RGB) { // display-p3 RGB 배열(0.0 - 1.0 범위)을 선형광 형태로 변환합니다 return lin_sRGB( RGB); // sRGB와 동일 } function gam_P3( RGB) { // 선형광 P3(0.0-1.0 범위)를 감마 보정형으로 변환합니다 return gam_sRGB( RGB); // sRGB와 동일 } function lin_P3_to_XYZ( rgb) { // 선형광 display-p3 값을 CIE XYZ로 변환합니다 // D65 사용(색도 적응 없음) // http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html var M= [ [ 608311 / 1250200 , 189793 / 714400 , 198249 / 1000160 ], [ 35783 / 156275 , 247089 / 357200 , 198249 / 2500400 ], [ 0 / 1 , 32229 / 714400 , 5220557 / 5000800 ], ]; return multiplyMatrices( M, rgb); } function XYZ_to_lin_P3( XYZ) { // XYZ를 선형광 P3로 변환합니다 var M= [ [ 446124 / 178915 , - 333277 / 357830 , - 72051 / 178915 ], [ - 14852 / 17905 , 63121 / 35810 , 423 / 17905 ], [ 11844 / 330415 , - 50337 / 660830 , 316169 / 330415 ], ]; return multiplyMatrices( M, XYZ); } // prophoto-rgb 함수들 function lin_ProPhoto( RGB) { // prophoto-rgb 값 배열을 변환합니다 // 가뭇 내 색상은 [0.0 - 1.0] 범위 // 선형광(언컴팬딩) 형태로 변환 // 전달 곡선은 감마 1.8이며 작은 선형 구간이 있음 // 확장 전달 함수 const Et2= 16 / 512 ; return RGB. map( function ( val) { let sign= val< 0 ? - 1 : 1 ; let abs= Math. abs( val); if ( abs<= Et2) { return val/ 16 ; } return sign* Math. pow( abs, 1.8 ); }); } function gam_ProPhoto( RGB) { // 선형광 prophoto-rgb(0.0-1.0 범위)를 감마 보정형으로 변환합니다 // 전달 곡선은 감마 1.8이며 작은 선형 구간이 있음 // TODO: 음수 값에 대해선 축 반사로 선형 구간을 확장하고, 그 아래에 pow 추가 const Et= 1 / 512 ; return RGB. map( function ( val) { let sign= val< 0 ? - 1 : 1 ; let abs= Math. abs( val); if ( abs>= Et) { return sign* Math. pow( abs, 1 / 1.8 ); } return 16 * val; }); } function lin_ProPhoto_to_XYZ( rgb) { // 선형광 prophoto-rgb 값을 CIE D50 XYZ로 변환합니다 // 행렬은 유리수 형태로 표현하기 어렵지만 64비트 정확도로 계산됩니다 // 자세한 내용: https://github.com/w3c/csswg-drafts/issues/7675 var M= [ [ 0.79776664490064230 , 0.13518129740053308 , 0.03134773412839220 ], [ 0.28807482881940130 , 0.71183523424187300 , 0.00008993693872564 ], [ 0.00000000000000000 , 0.00000000000000000 , 0.82510460251046020 ] ]; return multiplyMatrices( M, rgb); } function XYZ_to_lin_ProPhoto( XYZ) { // D50 XYZ를 선형광 prophoto-rgb로 변환합니다 var M= [ [ 1.34578688164715830 , - 0.25557208737979464 , - 0.05110186497554526 ], [ - 0.54463070512490190 , 1.50824774284514680 , 0.02052744743642139 ], [ 0.00000000000000000 , 0.00000000000000000 , 1.21196754563894520 ] ]; return multiplyMatrices( M, XYZ); } // a98-rgb 함수들 function lin_a98rgb( RGB) { // a98-rgb 값 배열(0.0 - 1.0 범위)을 선형광 형태로 변환합니다 // 음수 값도 허용됩니다 return RGB. map( function ( val) { let sign= val< 0 ? - 1 : 1 ; let abs= Math. abs( val); return sign* Math. pow( abs, 563 / 256 ); }); } function gam_a98rgb( RGB) { // 선형광 a98-rgb(0.0-1.0 범위)를 감마 보정형으로 변환합니다 // 음수 값도 허용됩니다 return RGB. map( function ( val) { let sign= val< 0 ? - 1 : 1 ; let abs= Math. abs( val); return sign* Math. pow( abs, 256 / 563 ); }); } function lin_a98rgb_to_XYZ( rgb) { // 선형광 a98-rgb 값을 CIE XYZ로 변환합니다 // 자세한 내용: http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html // 아래 값은 수치 정밀도가 섹션 4.3.5.3보다 높음 // 값들은 R G B W의 색도 좌표로부터 1차 원리로 계산되었습니다 // matrixmaker.html 참조 var M= [ [ 573536 / 994567 , 263643 / 1420810 , 187206 / 994567 ], [ 591459 / 1989134 , 6239551 / 9945670 , 374412 / 4972835 ], [ 53769 / 1989134 , 351524 / 4972835 , 4929758 / 4972835 ], ]; return multiplyMatrices( M, rgb); } function XYZ_to_lin_a98rgb( XYZ) { // XYZ를 선형광 a98-rgb로 변환합니다 var M= [ [ 1829569 / 896150 , - 506331 / 896150 , - 308931 / 896150 ], [ - 851781 / 878810 , 1648619 / 878810 , 36519 / 878810 ], [ 16779 / 1248040 , - 147721 / 1248040 , 1266979 / 1248040 ], ]; return multiplyMatrices( M, XYZ); } // Rec. 2020 관련 함수들 function lin_2020( RGB) { // rec2020 RGB 배열(0.0 - 1.0 범위)을 선형광 형태로 변환합니다 // Rec. ITU-R BT.1886 부록 1의 전기광학 전달 함수 참조 // b(black lift)=0, a(user gain)=1 // 확장 범위에 대해 정의되며, 클램프하지 않음 return RGB. map( function ( val) { let sign= val< 0 ? - 1 : 1 ; let abs= Math. abs( val); >return sign* Math. pow( abs, 2.4 ); }); } function gam_2020( RGB) { // 선형광 rec2020(0.0-1.0 범위)을 감마 보정형으로 변환합니다 // Rec. ITU-R BT.1886 부록 1 참조 (b=0, a=1) // 확장 범위에 대해 정의되며, 클램프하지 않음 return RGB. map( function ( val) { let sign= val< 0 ? - 1 : 1 ; let abs= Math. abs( val); >return sign* Math. pow( abs, 1 / 2.4 ); }); } function lin_2020_to_XYZ( rgb) { // 선형광 rec2020 값을 CIE XYZ로 변환합니다 // D65 사용(색도 적응 없음) var M= [ [ 63426534 / 99577255 , 20160776 / 139408157 , 47086771 / 278816314 ], [ 26158966 / 99577255 , 472592308 / 697040785 , 8267143 / 139408157 ], [ 0 / 1 , 19567812 / 697040785 , 295819943 / 278816314 ], ]; // 실제로 0은 4.994106574466076e-17로 계산됩니다 return multiplyMatrices( M, rgb); } function XYZ_to_lin_2020( XYZ) { // XYZ를 선형광 rec2020으로 변환합니다 var M= [ [ 30757411 / 17917100 , - 6372589 / 17917100 , - 4539589 / 17917100 ], [ - 19765991 / 29648200 , 47925759 / 29648200 , 467509 / 29648200 ], [ 792561 / 44930125 , - 1921689 / 44930125 , 42328811 / 44930125 ], ]; return multiplyMatrices( M, XYZ); } // 색도 적응 function D65_to_D50( XYZ) { // D65에서 D50으로의 Bradford 색도 적응 // 아래 행렬은 세 단계 연산의 결과입니다: // - XYZ를 망막 콘 도메인으로 변환 // - 한 기준 백색에서 다른 기준 백색으로 구성 요소를 스케일 // - 다시 XYZ로 변환 // 자세한 내용: https://github.com/LeaVerou/color.js/pull/354/files var M= [ [ 1.0479297925449969 , 0.022946870601609652 , - 0.05019226628920524 ], [ 0.02962780877005599 , 0.9904344267538799 , - 0.017073799063418826 ], [ - 0.009243040646204504 , 0.015055191490298152 , 0.7518742814281371 ] ]; return multiplyMatrices( M, XYZ); } function D50_to_D65( XYZ) { // D50에서 D65로의 Bradford 색도 적응 // 자세한 내용: https://github.com/LeaVerou/color.js/pull/360/files var M= [ [ 0.955473421488075 , - 0.02309845494876471 , 0.06325924320057072 ], [ - 0.0283697093338637 , 1.0099953980813041 , 0.021041441191917323 ], [ 0.012314014864481998 , - 0.020507649298898964 , 1.330365926242124 ] ]; return multiplyMatrices( M, XYZ); } // CIE Lab 및 LCH function XYZ_to_Lab( XYZ) { // XYZ가 D50 기준일 때 CIE Lab으로 변환합니다 // CIE 표준에서 유리수 분수로 정의됨 var ε= 216 / 24389 ; // 6^3/29^3 var κ= 24389 / 27 ; // 29^3/3^3 // 참조 백색에 대해 스케일된 XYZ로 xyz 계산 var xyz= XYZ. map(( value, i) => value/ D50[ i]); // 이제 f 계산 var f= xyz. map( value=> value> ε? Math. cbrt( value) : ( κ* value+ 16 ) / 116 ); return [ ( 116 * f[ 1 ]) - 16 , // L 500 * ( f[ 0 ] - f[ 1 ]), // a 200 * ( f[ 1 ] - f[ 2 ]) // b ]; // L 범위 [0,100]. CSS에서 사용하려면 100을 곱하고 % 추가 } function Lab_to_XYZ( Lab) { // Lab을 D50 기준 XYZ로 변환 // http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html var κ= 24389 / 27 ; // 29^3/3^3 var ε= 216 / 24389 ; // 6^3/29^3 var f= []; // 휘도 관련 항부터 f 계산 시작 f[ 1 ] = ( Lab[ 0 ] + 16 ) / 116 ; f[ 0 ] = Lab[ 1 ] / 500 + f[ 1 ]; f[ 2 ] = f[ 1 ] - Lab[ 2 ] / 200 ; // xyz 계산 var xyz= [ Math. pow( f[ 0 ], 3 ) > ε? Math. pow( f[ 0 ], 3 ) : ( 116 * f[ 0 ] - 16 ) / κ, Lab[ 0 ] > κ* ε? Math. pow(( Lab[ 0 ] + 16 ) / 116 , 3 ) : Lab[ 0 ] / κ, Math. pow( f[ 2 ], 3 ) > ε? Math. pow( f[ 2 ], 3 ) : ( 116 * f[ 2 ] - 16 ) / κ]; // 참조 백색으로 xyz를 스케일하여 XYZ 계산 return xyz. map(( value, i) => value* D50[ i]); } function Lab_to_LCH( Lab) { var epsilon= 0.0015 ; var chroma= Math. sqrt( Math. pow( Lab[ 1 ], 2 ) + Math. pow( Lab[ 2 ], 2 )); // 채도 var hue= Math. atan2( Lab[ 2 ], Lab[ 1 ]) * 180 / Math. PI; if ( hue< 0 ) { hue= hue+ 360 ; } if ( chroma<= epsilon) { hue= NaN ; } return [ Lab[ 0 ], // L은 여전히 L chroma, // 채도 hue// 색상, 도 단위 [0 ~ 360) ]; } function LCH_to_Lab( LCH) { // 극좌표 형태에서 변환 return [ LCH[ 0 ], // L은 여전히 L LCH[ 1 ] * Math. cos( LCH[ 2 ] * Math. PI/ 180 ), // a LCH[ 1 ] * Math. sin( LCH[ 2 ] * Math. PI/ 180 ) // b ]; } // OKLab 및 OKLCH // https://bottosson.github.io/posts/oklab/ // 일관된 기준 백색을 위한 XYZ <-> LMS 행렬 재계산 // 자세한 내용: https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484 // 64비트 정밀도로 재계산됨 // 참조: https://github.com/color-js/color.js/pull/357 function XYZ_to_OKLab( XYZ) { // D65 기준 XYZ를 OKLab으로 변환 var XYZtoLMS= [ [ 0.8190224379967030 , 0.3619062600528904 , - 0.1288737815209879 ], [ 0.0329836539323885 , 0.9292868615863434 , 0.0361446663506424 ], [ 0.0481771893596242 , 0.2642395317527308 , 0.6335478284694309 ] ]; var LMStoOKLab= [ [ 0.2104542683093140 , 0.7936177747023054 , - 0.0040720430116193 ], [ 1.9779985324311684 , - 2.4285922420485799 , 0.4505937096174110 ], [ 0.0259040424655478 , 0.7827717124575296 , - 0.8086757549230774 ] ]; var LMS= multiplyMatrices( XYZtoLMS, XYZ); // JavaScript의 Math.cbrt는 부호를 보존한 세제곱근을 반환합니다 // 다른 언어로 포팅할 때 주의하세요 // 일반적인 거듭제곱 함수를 사용하려는 유혹에 특히 주의 return multiplyMatrices( LMStoOKLab, LMS. map( c=> Math. cbrt( c))); // L 범위 [0,1]. CSS에서 사용하려면 100을 곱하고 % 추가 } function OKLab_to_XYZ( OKLab) { // OKLab을 D65 기준 XYZ로 변환 var LMStoXYZ= [ [ 1.2268798758459243 , - 0.5578149944602171 , 0.2813910456659647 ], [ - 0.0405757452148008 , 1.1122868032803170 , - 0.0717110580655164 ], [ - 0.0763729366746601 , - 0.4214933324022432 , 1.5869240198367816 ] ]; var OKLabtoLMS= [ [ 1.0000000000000000 , 0.3963377773761749 , 0.2158037573099136 ], [ 1.0000000000000000 , - 0.1055613458156586 , - 0.0638541728258133 ], [ 1.0000000000000000 , - 0.0894841775298119 , - 1.2914855480194092 ] ]; var LMSnl= multiplyMatrices( OKLabtoLMS, OKLab); return multiplyMatrices( LMStoXYZ, LMSnl. map( c=> c** 3 )); } function OKLab_to_OKLCH( OKLab) { var epsilon= 0.000004 ; var hue= Math. atan2( OKLab[ 2 ], OKLab[ 1 ]) * 180 / Math. PI; var chroma= Math. sqrt( OKLab[ 1 ] ** 2 + OKLab[ 2 ] ** 2 ); if ( hue< 0 ) { hue= hue+ 360 ; } if ( chroma<= epsilon) { hue= NaN ; } return [ OKLab[ 0 ], // L은 여전히 L chroma, hue]; } function OKLCH_to_OKLab( OKLCH) { return [ OKLCH[ 0 ], // L은 여전히 L OKLCH[ 1 ] * Math. cos( OKLCH[ 2 ] * Math. PI/ 180 ), // a OKLCH[ 1 ] * Math. sin( OKLCH[ 2 ] * Math. PI/ 180 ) // b ]; } // 전치(전-멀티플라이드) 알파 변환 function rectangular_premultiply( color, alpha) { // 직교 직사각형 색 공간의 색상과 알파 값을 받아 // 전-멀티플라이드 형태를 반환합니다 return color. map(( c) => c* alpha) } function rectangular_un_premultiply( color, alpha) { // 전-멀티플라이드 색상과 알파 값을 받아 실제 색상을 반환합니다 if ( alpha=== 0 ) { return color; // 0으로 나누는 것을 방지 } return color. map(( c) => c/ alpha) } function polar_premultiply( color, alpha, hueIndex) { // 원통형(극좌표) 색 공간의 색상과 알파 값을 받아 // 전-멀티플라이드 형태를 반환합니다. // hueIndex는 색상 각도에 해당하는 배열 인덱스를 의미합니다 // 예: OKLCH에서는 2, HSL에서는 0 return color. map(( c, i) => c* ( hueIndex=== i? 1 : alpha)) } function polar_un_premultiply( color, alpha, hueIndex) { // 원통형 색 공간의 색상과 알파 값을 받아 실제 색상을 반환합니다 // hueIndex는 색상 각도에 해당하는 배열 인덱스를 의미합니다 // 예: OKLCH에서는 2, HSL에서는 0 if ( alpha=== 0 ) { return color; // 0으로 나누는 것을 방지 } return color. map(( c, i) => c/ ( hueIndex=== i? 1 : alpha)) } // 편의 함수 예시 function hsl_premultiply( color, alpha) { return polar_premultiply( color, alpha, 0 ); }
20. ΔE2000 및 ΔEOK 색상 차이 샘플 코드
이 섹션은 규범적이지 않습니다.
테스트
이 섹션은 규범적이지 않으며, 테스트가 필요하지 않습니다.
20.1. ΔE2000
가장 단순한 색상 차이 지표인 ΔE76은 Lab 색공간에서의 유클리드 거리입니다. 이는 좋은 1차 근사값이지만, 인쇄 및 섬유 염색과 같은 색상 중요 산업에서는 더 향상된 공식이 개발되었습니다. 현재 가장 널리 사용되는 공식은 ΔE2000입니다. 이 공식은 ΔE76에 비해 여러 비대칭성과 비선형성을 보정합니다. 공식이 복잡하고, 중간 계산의 부호에 크게 의존하기 때문에 많은 구현체가 잘못된 결과를 내기도 합니다 [Sharma].
아래 샘플 코드는 검증 되었으며, [Sharma]에서 공개한 Lab 값 쌍과 ΔE2000 기대값 테스트 세트에 대해 유효 숫자 5자리까지 맞으며, 정확합니다.
// deltaE2000은 통계적으로 deltaE76 및 deltaE94보다 // 유의미하게 개선된 것으로, // CIE 및 Idealliance에서 권장합니다. // 특히 10 deltaE76 미만의 색상 차이에 대해 그렇지만, // 매우 복잡하며 // 많은 구현체에 작은 오류가 존재합니다! /** * @param {number[]} reference - CIE Lab 값의 배열: L은 0..100, a와 b는 약 -150..150 * @param {number[]} sample - CIE Lab 값의 배열: L은 0..100, a와 b는 약 -150..150 * @return {number} 색상 샘플과 기준(reference) 색상간의 차이 정도 */ function deltaE2000( reference, sample) { // 기준(reference) 색상과 샘플 색상이 주어지면, // 둘 다 CIE Lab 공간에서, // deltaE 2000 값을 계산합니다. // 이 구현은 파라메트릭 // 가중치 kL, kC, kH값이 // (관측 조건의 영향에 대한) // 모두 1로 설정됨을 전제합니다. 이는 일반적입니다. let [ L1, a1, b1] = reference; let [ L2, a2, b2] = sample; let C1= Math. sqrt( a1** 2 + b1** 2 ); let C2= Math. sqrt( a2** 2 + b2** 2 ); let Cbar= ( C1+ C2) / 2 ; // 평균 채도(Chroma) // 평균 채도를 이용한 a축 비대칭 계수 계산 // 근중성(near-neutral) 색상에서 JND 타원을 다시 원(circle)으로 돌려줌 let C7= Math. pow( Cbar, 7 ); const Gfactor= Math. pow( 25 , 7 ); let G= 0.5 * ( 1 - Math. sqrt( C7/ ( C7+ Gfactor))); // a축을 비대칭 계수로 스케일 // 이 부분이 Lab2000 색 공간이 없는 이유이기도 함 let adash1= ( 1 + G) * a1; let adash2= ( 1 + G) * a2; // 보정된 a, 원래 b축으로부터 새 채도(Chroma) 계산 let Cdash1= Math. sqrt( adash1** 2 + b1** 2 ); let Cdash2= Math. sqrt( adash2** 2 + b2** 2 ); // 새 색상각(hue) 계산, 완전 중성이면 0 // 라디안이 아니라 도(degree) 단위 사용 const π= Math. PI; const r2d= 180 / π; const d2r= π/ 180 ; let h1= ( adash1=== 0 && b1=== 0 ) ? 0 : Math. atan2( b1, adash1); let h2= ( adash2=== 0 && b2=== 0 ) ? 0 : Math. atan2( b2, adash2); if ( h1< 0 ) { h1+= 2 * π; } if ( h2< 0 ) { h2+= 2 * π; } h1*= r2d; h2*= r2d; // 밝기(Lightness) 및 채도 차이, 부호(sign)가 중요 let ΔL= L2- L1; let ΔC= Cdash2- Cdash1; // 색상각(hue) 차이, 부호에 유의 let hdiff= h2- h1; let hsum= h1+ h2; let habs= Math. abs( hdiff); let Δh; if ( Cdash1* Cdash2=== 0 ) { Δh= 0 ; } else if ( habs<= 180 ) { Δh= hdiff; } else if ( hdiff> 180 ) { Δh= hdiff- 360 ; } else if ( hdiff< - 180 ) { Δh= hdiff+ 360 ; } else { console. log( "상상할 수 없는 일이 발생했습니다" ); } // 가중치가 적용된 색상각 차이, 채도가 클수록 영향도 큼 let ΔH= 2 * Math. sqrt( Cdash2* Cdash1) * Math. sin( Δh* d2r/ 2 ); // 평균 밝기와 채도 계산 let Ldash= ( L1+ L2) / 2 ; let Cdash= ( Cdash1+ Cdash2) / 2 ; let Cdash7= Math. pow( Cdash, 7 ); // CIELAB의 청색 영역 비선형성 보정 // 네 가지 가능성의 색상 가중치, // 각도에 따라 부호 결정 let hdash; if ( Cdash1* Cdash2=== 0 ) { hdash= hsum; } else if ( habs<= 180 ) { hdash= hsum/ 2 ; } else if ( hsum< 360 ) { hdash= ( hsum+ 360 ) / 2 ; } else { hdash= ( hsum- 360 ) / 2 ; } // CIELAB의 불균일성 위치 보정 // JND(Just Noticeable Difference) 타원을 더 구(球)에 가깝게 만듦 // SL: 밝기(Lightness) 선명화 계수 // 배경의 L=50을 기준으로 가정 let lsq= ( Ldash- 50 ) ** 2 ; let SL= 1 + (( 0.015 * lsq) / Math. sqrt( 20 + lsq)); // SC: CMC, deltaE 94와 유사한 채도(Chroma) 요인 let SC= 1 + 0.045 * Cdash; // T: 청색 계열 비선형 교차 항 let T= 1 ; T-= ( 0.17 * Math. cos(( hdash- 30 ) * d2r)); T+= ( 0.24 * Math. cos( 2 * hdash* d2r)); T+= ( 0.32 * Math. cos((( 3 * hdash) + 6 ) * d2r)); T-= ( 0.20 * Math. cos((( 4 * hdash) - 63 ) * d2r)); // SH: 채도와 조정 색상각에 따른 색상 요인, deltaE94와 유사 let SH= 1 + 0.015 * Cdash* T; // RT: JND 타원의 회전을 보상하는 색상 회전 항 // 및 Munsell 상수 색상선 // 중~고 채도의 청색 영역에서 // (색상 225~315) let Δθ= 30 * Math. exp( - 1 * ((( hdash- 275 ) / 25 ) ** 2 )); let RC= 2 * Math. sqrt( Cdash7/ ( Cdash7+ Gfactor)); let RT= - 1 * Math. sin( 2 * Δθ* d2r) * RC; // 마지막으로, deltaE를 항(term)별 제곱합의 제곱근으로 계산 let dE= ( ΔL/ SL) ** 2 ; dE+= ( ΔC/ SC) ** 2 ; dE+= ( ΔH/ SH) ** 2 ; dE+= RT* ( ΔC/ SC) * ( ΔH/ SH); return Math. sqrt( dE); // 만세!!! };
20.2. ΔEOK
Oklab은 CIE Lab에서 발생하는 색상 선형성, 색상 균일성, 채도 비선형성의 문제를 겪지 않기 때문에, 색상 차이 지표가 이러한 문제를 보정할 필요가 없으며 단순히 Oklab 색공간에서의 유클리드 거리로 정의됩니다.
// deltaE OK 계산 // 단순 제곱합의 제곱근 /** * @param {number[]} reference - OKLab 값 배열: L은 0..1, a와 b는 -1..1 * @param {number[]} sample - OKLab 값 배열: L은 0..1, a와 b는 -1..1 * @return {number} 기준색상과 샘플 색상 간의 차이 정도 */ function deltaEOK( reference, sample) { let [ L1, a1, b1] = reference; let [ L2, a2, b2] = sample; let ΔL= L1- L2; let Δa= a1- a2; let Δb= b1- b2; return Math. sqrt( ΔL** 2 + Δa** 2 + Δb** 2 ); }
부록 A: 폐지된 CSS 시스템 색상
이전 CSS 버전에서는 여러 추가 시스템 색상을 정의했습니다. 하지만 이러한 색상 키워드는 폐지되었으며, 그 이유는 원래 목적(웹사이트 요소를 네이티브 OS와 유사하게 보이게 하는 것)을 충분히 달성하지 못하고, 웹페이지가 네이티브 OS 대화상자를 “스푸핑”하기 쉽게 만들어 보안 위험을 초래하며, 지문 채취 범위를 넓혀 사용자 프라이버시를 저해하기 때문입니다.
사용자 에이전트는 이러한 키워드를 지원해야 하며, 지문 채취를 줄이기 위해 아래에 나열된 (폐지되지 않은) 시스템 색상에 매핑해야 합니다. 저자는 이러한 키워드를 사용하면 안 됩니다.
폐지된 시스템 색상은 <deprecated-color> 서브타입으로 나타내며, 아래와 같이 정의됩니다:
- ActiveBorder
- 활성 창 테두리. ButtonBorder와 동일.
- ActiveCaption
- 활성 창 캡션. Canvas와 동일.
- AppWorkspace
- 다중 문서 인터페이스 배경색. Canvas와 동일.
- Background
- 데스크탑 배경. Canvas와 동일.
- ButtonHighlight
- 3D 요소 중 빛을 받는 쪽의 테두리 색상(테두리 한 겹으로 3D처럼 보이는 경우). ButtonFace와 동일.
- ButtonShadow
- 3D 요소 중 빛을 받지 않는 쪽의 테두리 색상(테두리 한 겹으로 3D처럼 보이는 경우). ButtonFace와 동일.
- CaptionText
- 캡션, 크기 조절 박스, 스크롤바 화살표 박스의 텍스트. CanvasText와 동일.
- InactiveBorder
- 비활성 창 테두리. ButtonBorder와 동일.
- InactiveCaption
- 비활성 창 캡션. Canvas와 동일.
- InactiveCaptionText
- 비활성 캡션의 텍스트 색상. GrayText와 동일.
- InfoBackground
- 툴팁 컨트롤 배경색. Canvas와 동일.
- InfoText
- 툴팁 컨트롤 텍스트 색상. CanvasText와 동일.
- Menu
- 메뉴 배경색. Canvas와 동일.
- MenuText
- 메뉴 내 텍스트. CanvasText와 동일.
- Scrollbar
- 스크롤바 회색 영역. Canvas와 동일.
- ThreeDDarkShadow
- 3D 요소의 두 겹 테두리 중 바깥쪽(빛 반대)의 더 어두운 테두리 색상. ButtonBorder와 동일.
- ThreeDFace
- 3D 요소의 면 배경색(두 겹 테두리로 3D처럼 보이는 경우). ButtonFace와 동일.
- ThreeDHighlight
- 3D 요소의 두 겹 테두리 중 바깥쪽(빛을 받는 쪽)의 더 밝은 테두리 색상. ButtonBorder와 동일.
- ThreeDLightShadow
- 3D 요소의 두 겹 테두리 중 안쪽(빛을 받는 쪽)의 더 어두운 테두리 색상. ButtonBorder와 동일.
- ThreeDShadow
- 3D 요소의 두 겹 테두리 중 안쪽(빛 반대)의 더 밝은 테두리 색상. ButtonBorder와 동일.
- Window
- 창 배경색. Canvas와 동일.
- WindowFrame
- 창 프레임. ButtonBorder와 동일.
- WindowText
- 창 내 텍스트. CanvasText와 동일.
테스트
- deprecated-sameas-001.html (실시간 테스트) (소스)
- deprecated-sameas-002.html (실시간 테스트) (소스)
- deprecated-sameas-003.html (실시간 테스트) (소스)
- deprecated-sameas-004.html (실시간 테스트) (소스)
- deprecated-sameas-005.html (실시간 테스트) (소스)
- deprecated-sameas-006.html (실시간 테스트) (소스)
- deprecated-sameas-007.html (실시간 테스트) (소스)
- deprecated-sameas-008.html (실시간 테스트) (소스)
- deprecated-sameas-009.html (실시간 테스트) (소스)
- deprecated-sameas-010.html (실시간 테스트) (소스)
- deprecated-sameas-011.html (실시간 테스트) (소스)
- deprecated-sameas-012.html (실시간 테스트) (소스)
- deprecated-sameas-013.html (실시간 테스트) (소스)
- deprecated-sameas-014.html (실시간 테스트) (소스)
- deprecated-sameas-015.html (실시간 테스트) (소스)
- deprecated-sameas-016.html (실시간 테스트) (소스)
- deprecated-sameas-017.html (실시간 테스트) (소스)
- deprecated-sameas-018.html (실시간 테스트) (소스)
- deprecated-sameas-019.html (실시간 테스트) (소스)
- deprecated-sameas-020.html (실시간 테스트) (소스)
- deprecated-sameas-021.html (실시간 테스트) (소스)
- deprecated-sameas-022.html (실시간 테스트) (소스)
- deprecated-sameas-023.html (실시간 테스트) (소스)
부록 B: 폐지된 특이 Hex 색상
CSS가 quirks mode에서 파싱될 때, <quirky-color>은 특정 속성에서만 유효한 <color> 유형입니다:
이것은 이러한 속성을 포함하거나 참조하는 속성에서는 유효하지 않습니다. 예를 들면 background 축약 속성이나, 함수 표기법 예: color-mix() 내부에서는 유효하지 않습니다.
또한, <quirky-color>은
<color>
로서 @supports 규칙에서
영향을 받는 속성을 파싱할 때는 유효해야 하지만,
CSS.supports()
메서드에서 사용될 때는
이러한 속성에 대해 유효하지 않습니다.
<quirky-color>은 다음 규칙에 따라 <number-token>, <dimension-token>, 또는 <ident-token>으로 표현될 수 있습니다:
-
만약 <ident-token>이라면, 토큰의 표현은 정확히 3개 또는 6개의 문자로 이루어져야 하며, 모두 16진수 숫자여야 합니다. 이는 같은 값을 가진 <hex-color>를 나타냅니다.
-
만약 <number-token>이라면, 정수 플래그가 설정되어 있어야 합니다.
정수 값을 직렬화합니다. 직렬화 결과가 6자 미만이면, 길이가 6자가 될 때까지 앞에 "0" 문자를 붙입니다. 이는 같은 값을 가진 <hex-color>를 나타냅니다.
-
만약 <dimension-token>이라면, 정수 플래그가 설정되어 있어야 합니다.
정수 값을 직렬화하고, 토큰의 단위 표현을 덧붙입니다. 결과가 6자 미만이면, 길이가 6자가 될 때까지 앞에 "0" 문자를 붙입니다. 이는 같은 값을 가진 <hex-color>를 나타냅니다.
(다시 말해, Quirks Mode에서는 선행 "#" 없이도 16진수 색상을 쓸 수 있지만, 이상한 파싱 규칙이 적용됩니다.)
Tests
quirky hex colors
감사의 글
CSS Color 3에 기여한 분들 외에도, 편집자들은 Emilio Cobos Álvarez, Alexey Ardov, Chris Bai, Amelia Bellamy-Royds, Lars Borg, Mike Bremford, Andreu Botella, Dan Burzo, Max Derhak, fantasai, Simon Fraser, Devon Govett, Phil Green, Dean Jackson, Andreas Kraushaar, Pierre-Anthony Lemieux, Tiaan Louw, Cameron McCormack, Romain Menke, Chris Murphy, Isaac Muse, Jonathan Neal, Chris Needham, Björn Ottosson, Christoph Päper, Brad Pettit, Xidorn Quan, Craig Revie, Melanie Richards, Florian Rivoal, Jacob Rus, Joseph Salowey, Simon Sapin, Igor Snitkin, Lea Verou, Mark Watson, James Stuckey Weber, Sam Weinig, 그리고 Natalie Weizenbaum께 감사드립니다.
변경 내역
2025년 4월 24일 후보 권고안 초안 이후의 변경 사항
- Oklab에서 색 비교를 위해 ε를 0.00001로 표준화함 (Issue 13157)
- 두 <color> 값이 동등한 색상인지에 대한 새 절을 추가했습니다. 여기에는 동일 색상 공간 내 구성 요소 비교, 누락된 구성 요소의 처리, 그리고 oklab을 통한 색상 공간 간 비교가 포함됩니다. (Issue 13157)
- 주요 Color interpolation 절에서, 색조 보간 방법이 지정되지 않으면 shorter가 기본값임을 명확히 했습니다. (이는 이미 Hue Interpolation 절에 명시되어 있었습니다). (Issue 13788)
- 유사 구성 요소의 개념을 구성 요소의 유사 집합으로 확장하여, none → 0 변환을 최소화했습니다. (Issue 10210)
- 색상 변환을 두 단계로 분리했습니다. (Issue 10211)
- 시스템 색상이 사용된 색상 체계에 어떻게 반응하는지 명확히 했습니다. (Issue 13719)
- 요약문을 업데이트하여 색상 보간과 색역 매핑을 언급했습니다.
- CSS 색역 매핑의 목적에 관한 문구를 명확히 했습니다.
- ray trace 알고리즘이 end를 덮어쓰지 않도록 수정했습니다. (Issue 10579)
- ray trace 색역 매핑 알고리즘에 대한 의사코드를 추가했습니다. (Issue 10579)
- EdgeSeeker 및 Ray Trace 색역 매핑 알고리즘을 추가했습니다. 3가지 GMA 중 선택을 허용했습니다. (Issue 10579)
- CIE Lab에서 가상의 색상을 보여주는 도식을 추가했습니다.
- 색역 밖이지만 물리적으로 실현 가능한 색상과 가상 색상을 구분했습니다.
- 클리핑에 대한 설명을 보다 균형 있게 조정하여, 허용 가능한 결과를 주는 몇 가지 사례를 보여주었습니다. (Issue 10579)
- ΔE2000 샘플 구현의 불일치를 수정했습니다. (Issue 13322)
- AccentColor가 accent-color의 값을 따르도록 업데이트했습니다. 단, Forced Colors Mode에서는 제외됩니다. (Issue 5900)
- rec2020 색상 공간이 display-referred, 2.4 감마를 사용하도록 정의했습니다. (Issue 12574)
- 사전 정의된 색상 공간에 display-p3-linear을 추가했습니다. (Issue 11250)
- calc()를 사용한 opacity 값의 직렬화를 명확히 했습니다. (Issue 10426)
- 레거시 sRGB 색상 간 보간이 호환성을 위해 (다시) sRGB 공간에서 이루어지도록 했습니다. (Issue 7949)
- a와 b의 실제 CIE Lab 범위를 명확히 했습니다. (Issue 12208)
- Opacity 값이 hit testing에 영향을 주지 않음을 명확히 했습니다. (Issue 11339)
2024년 2월 13일 후보 권고안 초안 이후 변경 사항
- color 속성 내부에서는 원시 상속 값이 아니라 해석된 상속 값이 사용된다는 점을 명확히 함
- sRGB로 해석되거나 레거시 색상 구문을 지원하는 등 색상 범주를 나열함
- 색상각(hue) 정규화 예시 추가
- 유사 컴포넌트 표에서 알파(alpha)가 누락되어 있었으나, 본문에서 유사함이 설명된 부분을 수정함
- 불투명도(opacity) 값의 직렬화 관련 내용을 한 섹션에 모아 명확히 함
- color-interpolation-method 및 host 구문 관련 문구를 명확히 함
- 누락된 색상각(hue)에 대해 반환할 입실론(epsilon)을 정의함
- 중심 축에 충분히 가까운 무채색(achromatic) 및 누락된 색상각에 대해 보다 정확한 정의를 사용함
- “color channel” 대신 일관되게 “color component” 용어 사용(둘 다 혼용되었음)
- 상관 색온도(Correlated Color Temperature)가 정의, 설명 없이 등장하여, 안내성 참조를 추가함
- premultiplied 용어를 내보내어 일관되게 링크함
- 더 이상 deprecated/비-deprecated 시스템 색상 간의 동등성이 위험(risk)하지 않음
- “CSS <color> 파싱” 알고리즘의 의도된 사용 명확화
- HTML 호환 직렬화 예시 수정본 추가
- HTML 호환 직렬화에서 누락 값 체크를 제거, 이미 0으로 변환됨
- 누락된 값이 0이 되는 내용의 노트를 이동하여 HTML-호환, CSS 직렬화 모두에 적용되도록 함
- sRGB에 대한 HTML-호환 16진 직렬화 추가
- xyz-d65, xyz-d50 예시 하나씩 더 추가
- XYZ에서 어떤 컴포넌트(Y)가 밝기(brightness)를 나타내는지 명확히 함
- CSS 색역 매핑은 used 값이 아니라 실제(actual) 값에 적용된다는 점 명확히 함
- hslToRgb 샘플 코드에서 색상각 정규화 제거(입력 시 이미 정규화됨)
- 색역 매핑 알고리즘 4단계의 의사 코드 수정
- 보간(interpolation)이 두 색상을 결합하는 가장 일반적인 경우지만 유일하지 않음을 명확히 함
- deltaE 표에서 텍스트의 충분한 명암비 보장
- <absolute-color-function> 용어의 남은 사용을 제거, 일관성을 위해 <absolute-color> function으로 통일
- 감사의 글(acknowledgements) 섹션 갱신
- 색역(mesh) 다이어그램 추가
- CSSOM 직렬화는 지정(specified) 값이 아니라 선언(declared) 값 기준임을 명시
- 휘도(luminance)의 내보내기 정의 추가
- <opacity-value> 생성 규칙 추가
- hslToRgb 결과가 [0,1] 범위가 언제인지 명확히 함
- 직선화(linearized)된 경우 RGB 공간은 가법적임을 명확히 함
2022년 11월 1일 후보 권고안 초안 이후 변경 사항
- cssom-1에서 옮긴 uint8_t alpha 직렬화 단계 추가
- HSL 음수 채도(parse-time clamp)를 0으로 처리, CSS Color 3의 최신 interop 동작 복원
- 보간 시 항상 색 공간 변환을 수행, powerless 컴포넌트는 누락 처리
- alpha 1 직렬화 생략 시점 명확화
- hue 각도를 [0,360]로 제한하는 중복 구속 조건 제거(이미 처리됨)
- ActiveCaption 설명 수정(배경색임)
- 불투명도(opacity)와 알파(alpha) 구분, opacity는 opacity-value 사용(클램핑 방식 다름)
- premultiplication 이전에 carry-forward 처리 명확화
- 색역 매핑 알고리즘 업데이트
- hue 보간 관련 이슈 수정
- HWB에서 white 또는 black이 100%일 때 무채색이라는 기준은 합이 100%임을 명확히
- rgb → hsl 변환 시 음수 채도 반환 방지, hue를 반대쪽으로 조정
- ProPhoto에 64비트 정확도 행렬 사용(유리수 표현 불가)
- Oklab 행렬을 64비트 정확도로 재계산(이전 32비트와 결과 동일)
- GMA 결과를 목적지 색 공간에서 항상 반환(목적지가 무한대이면 매핑 없음)
- Oklab에서 JND 1의 값이 0.02인 이유 설명 추가
- sRGB 값 해석은 color() 함수에는 적용되지 않음을 명확화
- alpha 값 정의 위치를 opacity 속성 위로 이동, opacity 지정값은 클램핑하지 않음 명확화
- 시스템 색상은 프라이버시 보호를 위해 스푸핑 명시적으로 허용
- D50→D65 역색도 적응 행렬 수정
- 선형 Bradford와 원래 Bradford 색도 적응 알고리즘 명확 구분
- 색역 매핑 알고리즘에서 clipped를 바로 gamut mapped 결과로 반환, 불필요한 단계 제거
- 색도 적응 행렬을 더 높은 정밀도로 업데이트
- 색상 파싱 알고리즘(parse a css color) 추가, 타 명세에 색상 처리 재정의 필요 없음
- 색역 매핑에서 geometric 용어 사용(analytical 대신)
- HSL 문법과 문장 일치(퍼센트, 숫자 모두 허용)
- LCH 알파 보간 예제 수정(hue 각도 un-premultiply 오류 수정)
- sRGB, display-p3 전달 함수 수정(특정 컴포넌트 값에서만 영향, 실제 8/10비트에서는 불가능)
- 시스템 색상 지정값은 자신임을 명확화
- PNG cICP 청크 명시, 이미지 태깅 용도
- hue 증가/감소 시 0/360 처리 방식 기술
- 무력(HWB hue) 단점이 HSL hue와 동일함 명확화
- 휘도(luminance)와 명도(lightness) 비교 및 도표 추가
- hue 보간 키워드 설명 및 예제 추가
- 무채색 HWB 색상에 대한 규범적 문장 사용
- hue 보간 각도 범위 [0,360)로 수정([0,360] 아님)
- L=0%/100%일 때 검은색/흰색 표시되는 것은 색역 매핑 때문임을 명확화, powerlessness 설명 제거
- ‘representing black’ ‘representing white’ 혼란스러운 문장 제거
- opponent a, b가 유사함 명확화
- RGB 컴포넌트 지정값 범위로 일관성 있게 명시
- Lab, LCH, Oklab, OKLCh 직렬화 시 퍼센트 참조 범위 명시
- Oklab 보간 필수, 이전 ‘may’ 삭제, 명시적 opt-out 설명
- Lab, LCH, Oklab, OKLCh 튜토리얼은 비규범적임을 명확히 표시, 일부 정의는 본문으로 이동
- 보간 시 유사 컴포넌트 체크가 색 공간 변환 이전임을 명확히
- HWB 구문 변경 및 참조 범위, CSS Color 5에서 역포팅
- carry-forward 연산을 powerless 처리 이전에 하도록 명확화
- 레거시 rgb() 구문에서 color 컴포넌트는 모두 숫자 또는 모두 퍼센트여야 함을 명확화
- 레거시 구문에서는 color 컴포넌트가 모두 퍼센트 또는 모두 숫자여야 함 명확화
- 명시 범위 초과 alpha 예제 추가(calc() 사용 여부 구분)
- 직렬화 시 끝자리 0 자르기 예제 관련 텍스트에 배치
- 예시 명확화, text-shadow 값 사용
- currentColor 해석 명확화
- 감사의 글 업데이트
- 무채색이 a,b 또는 chroma가 누락된 것이라는 주장 제거
- HSL, HWB를 무한대 색역으로 변경, 라운드트립 향상 목적
- HSL 퍼센트 참조 범위 정의
- 최신 색상 구문 hsl(), hsla()는 혼합 숫자·퍼센트 허용
- 최신 색상 구문 rgb(), rgba()는 혼합 숫자·퍼센트 허용
- ‘modern color syntax’ 용어 정의(레거시 색상 구문은 이미 정의됨)
- ‘analogous components’ 용어 일관 사용
- 모든 미리 정의된 색 공간에서 보간 허용으로 변경
- color() 함수에는 RGB/XYZ 세 파라미터 요구 명확화
- 이름 색상, 시스템 색상, transparent 직렬화 명확화
- Lab, LCH, Oklab, OKLCh의 지정값 정의
- 기타 sRGB 색상의 지정값 정의
- 이름·시스템 색상의 지정값 정의
- 파싱값 시점에서 alpha, Lightness, Chroma, Hue 클램핑
- CIE Lightness, specular white 언급 삭제
- as-specified Hue 유지 요구 삭제; [0, 360]로 클램핑
- Lightness 및 숫자 직렬화 예시 일관화
- 사소한 오타 및 편집적 명확화
2022년 7월 5일 후보 권고안 초안 이후 변경 사항
- hue 보간 “specified” 값 제거
- hue 보간 각도 정의 더 정확하게, 360deg 차이 유지
- premultiplication에서 carry-forward alpha 예시 추가
- L=100%일 때 a,b, C,h powerless임을 명확화(흰색 표현)
- L=400 언급 제거, hdr-CIELAB에 해당, CIE Lab에는 적용 안 됨
- Oklab, OKLCh 대문자 일관화
- 용어 섹션에 valid color, invalid color, out of gamut, in gamut 정의 이동
- “longer” hue 보간 정의 수정
- 호스트 구문(host syntax) 개념 추가 설명
- 색상 견본(color swatch) 접근성 개선
- 레거시 형태는 “none” 지원하지 않음 명확화
- hue 생성식에서 “none” 제거, 레거시 구문에서 허용 안 함
- CMYK, CMYKOGV 일부 언급 제거, CSS Color5로 이동
- 보간 색상에서 누락값 처리 방법 명확화
- xyz-params 문법 업데이트, 숫자와 퍼센트 모두 허용으로 본문과 일치
- 모든 예제·도표에 ID, self-link 명시
- 색역 매핑 소개 읽기 중요성 명확화, 구현자 대상
- 커스텀 색 공간 관련 남은 언급 제거(feature는 CSS Color 5 이동)
- <color> 및 <alpha-value> 문법 리팩토링
- 더 나은 독해 흐름을 위한 편집적 리팩토링
- 색역 매핑 알고리즘 의사코드 업데이트, 불필요한 deltaE 호출 제거
2022년 6월 28일 작업 초안 이후 변경 사항
- 후보 권고안 상태로 업데이트
2022년 4월 28일 작업 초안 이후 변경 사항
- opacity 속성을 모듈 최상단(color 속성 옆)에 이동, 세부 설명 전 배치
- color 속성 설명 개선, 특히 다른 속성에 미치는 영향
- 동일 모듈 색상에서 hue 보간 더 긴 쪽 공식 수정
- 새 시스템 색상 AccentColor, AccentColorText 추가
- 색 공간 변환 단계 전체 설명을 새 섹션에 추가
- premultiplication 및 un-premultiplication에 대해 none alpha 처리 설명
2021년 12월 15일 작업 초안 이후 변경 사항
- 시스템 색상 완전 해석, 강제 색상 모드에서는 변경 금지
- color() 함수에 파라미터 수 오류 허용 삭제
- CIE Lightness 및 OK Lightness 직렬화를 퍼센트 대신 숫자로 변경
- 폐지된 시스템 색상 동등성 위험요소로 표시
- CIE 및 OK L,a,b,C 퍼센트 값 참조 범위 추가
- 직사각형/극좌표 색 공간 모두에 premultiplication/undo 샘플 코드 추가 공지
- 색역 매핑 본문 및 의사코드에 범위 초과 클램핑 추가
- ProPhoto RGB / ROMM에 대한 규범적 참고 추가
- sRGB 및 Display P3의 참조 주변(black point) 값 수정
- Display P3에 대한 규범적 참고 추가
- 흰색보다 더 흰색, 검은색보다 더 검은색의 색역 축소에서 무한 루프 방지
- none 값 직렬화 명확화
- Oklab 보간 opt-in 명확화, 레거시 색상에는 적용되지 않음
- none 값으로 premultiplication 동작 정의
- rgb에서 누락값은 0으로 직렬화 명확화
- calc()에서 none 값 사용 명확화
- System Colors 표기 일관성 오류, 오타 수정
- SelectedItem, SelectedItemText 예시 추가
- 레거시 색상 존재/부존재 명시
- CIE XYZ에 대한 규범적 참고 추가
- HWB, HSL에 대한 규범적 참고 추가
- hwb()는 레거시 문법이 아니므로, 이전 콤마 구분 구문 지원하지 않음 명확화
- 레거시 색상만 색역 매핑 수행, 나머지는 무한대
- 분광광도계(spectrophotometer), 분광복사계(spectroradiometer) 용어 구분
- 사소한 오타 및 문법 개선
2021년 6월 1일 작업 초안 이후 변경 사항
- 색역 매핑 섹션 추가, CSS 색역 매핑 알고리즘 정의(OKLCh에서 chroma 축소 및 지역 MINDE)
- color(xyz ...)의 계산값은 color(xyz-d65 ...)
- 보간 색 공간에 srgb-linear 추가
- Colors 3 이후 변경 사항 섹션 업데이트
- Oklab, OKLCh 값 해석 섹션 추가
- srgb-linear 색 공간 추가
- @color-profile 및 device-cmyk를 level 5로 이동(CSSWG 결의)
- 보간 색 공간(interpolation color space) 정의
- 행렬은 row-major임을 명확화, 행렬 곱 라이브러리 연결
- 옛 보안·프라이버시 섹션 분리
- quirks-mode 특이 hex 색상 정의
- device-cmyk에서 fallback 색상 제거
- 기본값 선언 없는 호스트 구문은 Oklab을 기본 사용
- deltaE OK 샘플 코드 추가
- OKlab, OKLCh 변환 샘플 코드 추가
- oklab(), oklch() 함수 추가 Oklab, OKLCh 설명 추가
- CIE LCH 결함 설명 추가
- none 키워드를 통해 색상 컴포넌트 모두 “누락” 가능, powerless 컴포넌트 자동 누락, NaN 참조는 “누락” 개념으로 수정
- x,y 백색점 값 명시, 전체에 일관 적용
- 호스트 구문(host syntax) 용어 정의
- override-color 색상 해석 시 컨텍스트 정의
- 새 시스템 색상 쌍 추가
- HSL, HWB 샘플 코드 수정
- 오류 없는 HSL 값 테이블로 교체
- Lea Verou 공동 편집자로 WG 결의에 따라 추가
- hue 각도 무한대 허용 명확화
- MarkText 예시 수정
- 도표, 예시 추가 및 수정
- 편집적 명확화
- 사소한 오타, 마크업 수정
2020년 11월 12일 작업 초안 이후 변경 사항
- Lab 값이 LCH로 변환될 때 거의 무채색에서 색상 불확정(hue indeterminate) 문제 명시
- RGB-Lab 상호변환 단계 중 선형 조합 단계 명확화
- CSS Color 5에서 사용할 @color-profile의 components 설명자 추가
- 모든 미리 정의된 RGB 색 공간을 확장 범위로 정의
- 색상 보간 전에 색역 매핑(gamut mapping)이나 색역 클리핑(gamut clipping) 단계가 없음을 명확히 함
- 레거시 sRGB 구문 보간 명확화
- color()에서 lab 옵션 제거
- 미리 정의된 색 공간 간 상호변환 단계 나열
- ‘color space’ 용어 일관 사용(두 단어)
- 색상 혼합 시 색 공간 선택에 대한 가이드 추가
- 예제 정밀도 향상을 위해 재계산
- 색상 보간(hue interpolation) 예제 추가
- color() 구문 단순화, fallback 옵션 제거
- @color-profile에서 연결할 수 있는 ICC 프로파일 유형 명확화
- 드문 ICC Named Colors 지원 제거
- 표준 백색점 색도(chromaticity) 정밀도 향상
- 한 미리 정의된 색 공간에서 상표(trademark) 설명 제거
- 보간 설명을 보간 공간(interpolation space)과 좀 더 일반적으로 서술
- 접근성 고려사항(Accessibility Considerations) 섹션 수정
- color()에서 color space 인자는 반드시 필요(sRGB도 포함)
- currentColor가 sRGB에 한정되지 않음을 명확화
- sRGB→XYZ→sRGB 행렬 소정 수정, round-trip 개선
- Rec2020 전달 함수 명확화, ITU Rec BT.2020-2 올바른 참고 추가
- 예제 fallback 구문 올바른 문법으로 수정
- 레거시 색상이 아닌 경우 감마 인코드 공간 보간 강제하지 않음
- premultiplied alpha 보간 정의
- currentColor로의 색상 보간 시작, 관련 논의
- NaN이 포함된 hue 보간 정의
- 색상 보간 일반화
- Lab에서 보간 정의, LCG로 오버라이드 가능
- hue 보간 관련 수정
- hue 각도 보간 정의
- 보간 섹션 추가
- 일부 예제 구문 수정
- color()에서 퍼센트 허용 컴포넌트 명확화
- lch()는 lab()로 직렬화하지 않고 자기 자신으로 직렬화하도록 변경
- color()에서 레거시 sRGB가 아닌 경우 컴포넌트당 최소 10비트 정밀도
- color()에서 color space는 선택 사항이 아님
- lab()과 color(lab) 간 최소 정밀도 일치
- color() 함수 fallback 절차 명확화 - 첫 번째 유효한 색상(색역 내)이 우선, 아니면 첫 번째 유효 색상을 색역 매핑, 아니면 투명 검은색
- opacity 속성과 불투명도가 있는 색상의 차이 명확화, 특히 중첩된 텍스트 글리프 렌더링에서
- ΔE2000 샘플 코드(검증된 것) 추가
- 기존에 정의되지 않았던 chromaticity 용어 정의, 예시 및 chromaticity 다이어그램 정의
- 색상 가산성(color additivity) 설명 추가, 예시 포함
- WPT 테스트에 소스 링크 추가
- color, valid color 용어 내보내기, 다른 명세에서 참조 가능
- 직렬화 시 컴포넌트당 최소 비트수 정의
- “applies to” 정의 업데이트(CSS-wide 변경)
- 미리 정의된 색 공간에 이미지 상태(display referred/scene referred) 추가
- 색도 좌표와 함께 백색점 상관 색온도(예: D65) 명시, 명확성 향상
- 반올림은 +∞ 방향임을 명확화
- 오타, 마크업 수정, 링크 수정
2019년 11월 5일 작업 초안 이후 변경 사항
- 다른 명세에서 사용할 용어 일부 내보내기
- WCAG 2.0에서 2.1로 요구사항 업데이트
- 직렬화에 사용되는 유니코드 문자 완전 명시
- 특수 이름 색상 직렬화 정의
- device-cmyk() 직렬화 정의
- color() 직렬화 정의
- 웹 호환 최대화 방식으로 RGB 직렬화 완전 정의
- Lab, LCH 직렬화 정의
- 알파 값 직렬화 완전 정의
- RFC2119 실수 방지 위한 일관성 점검
- 모든 예제에 ID 추가, 참조 가능하게 함
- 해석 색상(resolved color)과 직렬화 색상(serialized color) 섹션 분리
- (보안) ICC 프로파일은 실행 코드 없음 명시
- 범위 초과란 무엇인지 profiled colors에 대해 정의
- 범위 초과 클램핑 명확화
- 명시값 예제 추가
- 계산값(computed values) 명확화
- 지문채취 방지, 폐지된 시스템 색상에 필수 매핑 추가
- X11 색상 표준화 이유와 역사에 대한 설명 추가
- hwb 샘플 코드 수정
- MacBeth 패치용 DeltaE2000 값 표 추가
- ICC profile Internet Media type에 대한 설명 추가
- PNG sRGB 청크 참조 추가
- CMYK → Lab 변환 명확화
- RGB → Lab 변환 명확화
- HSL vs. LCH 비교 추가
- Rec BT.2020 색 공간 설명 보강
- prophoto-rgb 설명 업데이트
- Value Definitions 섹션에서 중복된 “keywords” 삭제
- 유효하지 않은 색상 예제 추가
- 여러 fallback 예제 추가
- 사소한 오타, 마크업 수정
- 선언되지 않은 커스텀 색 공간 처리 명확화
- 예제와 설명 노트 일부 명확화
- 유효/무효 ICC 프로파일 처리 규정
- 명시적으로 태그된 색 공간의 이미지 처리 규정
- 4k, SDR 비디오용 색 공간 정의
- 사용자 대비 설정 우선 적용 명시
- 강제 색상 모드 외에서 시스템 색상 의미 명확화
- 기본 스타일 규칙 업데이트
- color()에 CIE XYZ 색 공간 추가
- hue 각도 명확화, NaN 명시적으로 허용
- 시스템 색상 페어링 설명 보강, AA 접근성 대비 요구
- 중첩된 글리프와 opacity 속성 상호작용 경고 추가
- color 정의 문법 수정
- Highlight/HighlightText 설명 보강
- prophoto-rgb 전달 함수 수정
- prophoto-rgb 기본색 더 높은 정밀도 사용
- “표시 불가” 정의 시작
- canvas surface 관련 문단 삭제
- buttonborder, mark, marktext 시스템 색상 추가
- sRGB→HWB 역변환 추가
- 극좌표 색 공간은 원통형임을 명확화(구형 아님)
- 접근성 고려사항(Accessibility Considerations) 섹션 추가
- 색역 매핑을 컴포넌트별 클리핑이 아니라 chroma 축소로 서술 시작
- rec2020 백색 색도 수정
- @color-profile에서 device-cmyk 사용 가능; CMYK→color 알고리즘에서 단순 변환은 최후 수단으로만 사용
- 인쇄 지향 CMYK 및 KCMYOGV 예제 추가
- 사용자 정의 색 공간은 dashed-ident로, 미리 정의된 색 공간 확장성 확보
- color() 함수에 lab 옵션 추가
- CIE Lab에 대한 규범적 참고 추가
- prophoto-rgb가 D50 백색점 사용하므로 색도 적응 불필요 명확화
- LCH에서 각도 증가 방향 명확화
- 색상명은 ASCII 대소문자 구분 없음 명확화
- color 속성 초기값을 CanvasText로 변경
- 혼란스러운 gray() 함수 CSS WG 결의로 삭제
- 분산된 정의를 Color terminology 섹션에 통합
- 도움이 되는 그림 및 예제 추가
- 사소한 편집적 명확화, 맞춤법, 오타, 마크업 수정
2016년 7월 5일 작업 초안 이후 변경 사항
- Lab 및 LCH의 Lightness를 퍼센트로 변경, CSS 호환성 확보
- 색상 값 클램핑 명확화
- 퍼센트 opacity 허용
- sRGB, linear-light sRGB 용어 정의, 타 명세에서 사용 가능
- CSS 시스템 색상 목록 추가, Text를 CanvasText로 이름 변경
- 시스템 색상 키워드는 자신으로 계산됨
- 시스템 색상에 대해 computed/used 값 항목 추가
- 비폐지 시스템 색상 소개를 forced-colors 모드 중심으로 재작성
- 미리 정의된 색 공간 일관된 하이픈 사용
- 불투명하지 않은 요소가 레이어에 그려짐(포지션 없어도) 내용 복원
- color 속성 초기값을 검은색으로 변경
- LCH의 hue는 360deg로 모듈로 처리(이후 변경됨)
- LCH, Lab에서 L 허용 범위와 L=100 의미 명확화
- 비디오에서 사용하는 색 공간 참조 업데이트
- prophoto-rgb 미리 정의 색 공간 추가
- display-p3의 검은색/흰색 휘도값 수정
- display-p3 전달 함수 명확화
- a98-rgb 색 공간 추가, 기본색 색도 표 수정
- currentColor의 computed 값이 해석된 색상이 아님을 명확화
- 예제 구문을 최신 명세에 맞게 업데이트
- color-mod() 함수 제거
- propdef 테이블에서 “media” 삭제
- “transparent black”, “opaque black” 용어 내보내기, 일관 사용
- 계산된 값(percent 등) 명확화
- 색상 컴포넌트의 필수 정밀도 및 반올림 동작 명확화
- color 속성이 컬러 폰트 글리프에 영향 없음(명시적 참조 시 제외, 예: currentColor)
- 색상 값 해석 방법 명확화
- HSL, HWB, 이름 색상은 sRGB로 해석됨 명확화
- device-cmyk에서 sRGB로 변환 단순화
- 이전 콤마 사용 색상 구문을 “레거시”로 명명, 예제를 콤마 없는 형태로 변경
- 표시 색상을 디바이스 색역에 제한하는 불필요한 요구사항 제거
- P3를 display-p3로 이름 변경; DCI P3와 혼동하지 않도록 명확화
- “color()” 함수 파라미터 설명 보완
- 미리 정의된 색 공간을 “@color-profile” 식별자에서 허용하지 않음
- “color”, “color-adjust”, “opacity” 속성 정의에 정식 순서 추가
- 알파 합성(alpha compositing) 정의를 SVG11에서 CSS Compositing으로 변경
- 샘플 변환 코드가 비규범적임 명확화
- 보안·프라이버시 고려사항(Security and Privacy Considerations) 추가
- 여러 참고 문헌 최신 버전으로 업데이트
- 인라인 이슈를 GitHub 이슈 링크로 전환
- 사소한 편집 명확화, 서식 및 마크업 개선
Colors 3와의 변경 사항
CSS Color 3와 비교했을 때 가장 큰 변화는 CSS 색상이 더 이상 sRGB의 좁은 색역에만 국한되지 않는다는 점입니다.
이를 지원하기 위해 여러 새로운 기능이 추가되었습니다:
다른 기술적 변경 사항:
- <color>의 직렬화는 이제 CSS Object Model이 아니라 여기에서 지정됩니다.
- HWB 표기법에서 sRGB 색상을 지정하기 위한 hwb() 함수가 추가되었습니다.
- 이름 있는 색상 rebeccapurple가 추가되었습니다.
또한 몇 가지 구문상의 변경이 있었습니다:
- rgb() 및 rgba() 함수는 이제 <number>을 허용하며, <integer> 대신 사용됩니다.
- hsl() 및 hsla() 함수는 이제 색조(hue)에 대해 <angle>과 <number>을 모두 허용합니다.
- rgb() 및 rgba(), 그리고 hsl() 및 hsla()는 이제 서로의 별칭(alias)으로 동작합니다 (모두 선택적 알파(alpha)를 가집니다).
- rgb(), rgba(), hsl(), 및 hsla()는 모두 공백으로 구분된 인수와 선택적 슬래시(/)로 구분된 불투명도(opacity)를 사용하는 새로운 구문(syntax)을 갖게 되었습니다. 모든 색상 함수는 이제 이 구문 형식을 사용하며, CSS 기능적 표기법 설계 원칙과 일치합니다.
- 모든 <alpha-value> 사용은 이제 <percentage>와 <number> 모두를 허용합니다.
- 투명도를 지정하기 위해 4자리 및 8자리 16진수(hex) 색상이 추가되었습니다.
- none 값이 추가되어, 무력한 구성 요소를 나타낼 수 있습니다.
21. 보안 고려 사항
시스템 색상은 실제로 사용자의 시스템 색상과 일치한다면 보안 위험이 있습니다. 악성 사이트가 시스템에서 제공하는 것처럼 보이는 사용자 인터페이스를 만들기 쉬워지기 때문입니다. 하지만 이제 여러 시스템 색상이 "일반적"으로 정의되었으므로, 이러한 위험은 완화된 것으로 여겨집니다.
22. 프라이버시 고려 사항
이 명세는 "시스템" 색상을 정의하며, 이론적으로 사용자의 OS 설정 정보를 노출할 수 있고, 이는 지문채취(fingerprinting) 위험이 있습니다.
23. 접근성 고려 사항
이 명세는 저자들이 색상만으로 구분하는 것을 피할 것을 권장합니다.
이 명세는 브라우저가 특정 시스템 색상 전경/배경 조합에 대해 충분한 대비를 보장할 것을 권장합니다. AA 또는 AAA 대비 비율을 구체적으로 요구하는 것은 고려되었으나, 브라우저가 종종 OS에서 선택한 색상이나 사용자가 직접 선택한 색상을 그대로 전달하기 때문에, (편두통이나 간질 등으로 낮은 대비를 원하는 사용자를 포함하여) CSSWG에서는 특정 대비 수준을 요구할 수 없었습니다.