1. 소개
이 섹션은 규범적이지 않습니다.
대형 문서나 애플리케이션 (그리고 작은 것들도) 상당한 양의 CSS를 포함할 수 있습니다. CSS 파일 내의 많은 값들은 중복 데이터일 수 있습니다; 예를 들어, 사이트가 색상 테마를 정하고 세 가지 또는 네 가지 색상을 사이트 전체에서 재사용할 수 있습니다. 이러한 데이터를 변경하는 것은 어렵고 오류가 발생하기 쉽습니다, 왜냐하면 CSS 파일 전체(그리고 여러 파일에 걸쳐) 흩어져 있기 때문이며, 찾기 및 바꾸기로 해결하기 어려울 수 있습니다.
이 모듈은 사용자 정의 속성이라는 일련의 사용자 정의 속성군을 도입합니다. 저자는 임의의 값을 직접 지정한 이름의 속성에 할당할 수 있으며, var() 함수로 이러한 값을 문서 내 다른 속성에 사용할 수 있습니다. 이를 통해 대형 파일을 읽기 쉽고, 임의의 값이 이제는 설명적인 이름을 가지게 되며, 이러한 파일을 편집하는 과정도 훨씬 쉽고 오류가 적어집니다. 값을 한 번만 변경하면, 사용자 정의 속성에서, 해당 변수의 모든 사용처에 변경 사항이 자동으로 반영됩니다.
1.1. 값 정의
이 명세는 [CSS2]의 CSS 속성 정의 관례를 따르며, 값 정의 문법은 [CSS-VALUES-3]을 사용합니다. 이 명세에서 정의되지 않은 값 타입은 CSS 값 및 단위 [CSS-VALUES-3]에서 정의됩니다. 다른 CSS 모듈과의 조합으로 이러한 값 타입의 정의가 확장될 수 있습니다.
각 속성 정의에 명시된 속성별 값 외에도, 이 명세에서 정의된 모든 속성은 CSS 전역 키워드도 속성 값으로 허용합니다. 가독성을 위해 명시적으로 반복하지 않았습니다.
2. 사용자 정의 속성 정의: --* 속성군
이 명세는 사용자 정의 속성이라 불리는 제한 없는 속성 집합을 정의합니다. 이 속성들은 var() 함수의 대체 값을 정의하는 데 사용됩니다.
이름: | --* |
---|---|
값: | <declaration-value>? |
초기값: | 보장된 잘못된 값 |
적용 대상: | 모든 요소와 모든 의사 요소(제한된 속성 목록을 가진 경우도 포함) |
상속: | 예 |
백분율: | 해당 없음 |
계산된 값: | 변수가 대체된 지정한 값, 또는 보장된 잘못된 값 |
정식 순서: | 문법에 따름 |
애니메이션 유형: | 불연속 |
사용자 에이전트는 모든 미디어(비시각적 미디어 포함)에서 이 속성을 지원해야 합니다.
사용자 정의 속성은 이름이 두 개의 대시(U+002D 하이픈 마이너스)로 시작하는 모든 속성입니다, 예를 들어 --foo와 같습니다. <custom-property-name> 생성규칙은 이것에 해당합니다: 두 대시로 시작하는 유효한 <dashed-ident> (유효한 식별자)이며, 단 -- 자체는 제외, 이것은 CSS에서 미래 사용을 위해 예약되어 있습니다. 사용자 정의 속성은 저자와 사용자만 사용할 수 있으며, CSS가 이 명세에서 제시하는 것 이상의 의미를 부여하지 않습니다.
테스트
- variable-declaration-29.html (실시간 테스트) (소스)
- variable-declaration-31.html (실시간 테스트) (소스)
- variable-declaration-32.html (실시간 테스트) (소스)
- variable-declaration-33.html (실시간 테스트) (소스)
- variable-declaration-34.html (실시간 테스트) (소스)
- variable-declaration-35.html (실시간 테스트) (소스)
- variable-declaration-36.html (실시간 테스트) (소스)
- variable-declaration-40.html (실시간 테스트) (소스)
- variable-declaration-41.html (실시간 테스트) (소스)
- variable-declaration-42.html (실시간 테스트) (소스)
- variable-empty-name-reserved.html (실시간 테스트) (소스)
:root{ --main-color : #06c; --accent-color : #006; } /* CSS 파일의 나머지 부분 */ #foo h1{ color : var ( --main-color); }
이름 지정은 색상에 대한 기억 장치를 제공하며, 색상 코드에서 발생하기 쉬운 오타를 방지하고, 테마 색상이 변경될 경우 한 곳(사용자 정의 속성 값)에서만 수정하면 되므로 웹페이지의 모든 스타일시트에서 여러 번 수정할 필요가 없습니다.
다른 CSS 속성과 달리, 사용자 정의 속성 이름은 ASCII 대소문자 구분 없음이 아닙니다. 대신, 사용자 정의 속성 이름은 서로 동일한 경우에만 같습니다.
더 놀라운 예로, --foó와 --foó 또한 서로 다른 속성입니다. 첫 번째는 U+00F3(LATIN SMALL LETTER O WITH ACUTE)로 작성되어 있고, 두 번째는 ASCII "o" 다음에 U+0301(COMBINING ACUTE ACCENT)로 작성되어 있습니다. "서로 동일함" 관계는 두 문자열이 같은지 확인하기 위해 직접 코드포인트 비교를 사용합니다, 유니코드 정규화나 로케일별 비교의 복잡성과 문제를 피하기 위해서입니다.
운영체제, 키보드, 또는 입력 방법이 시각적으로 동일한 텍스트를 서로 다른 코드포인트 시퀀스로 인코딩하는 경우가 있습니다. 저자들은 혼란을 피하기 위해 변수 이름을 신중히 선택하거나, 이스케이프 및 기타 방법을 사용하여 비슷해 보이는 시퀀스가 실제로 동일함을 보장하는 것이 좋습니다. 예시는 [CHARMOD-NORM]의 2.3절을 참고하십시오.
--fijord : red; --fijord : green; --fijord : blue; .test{ background-color : var ( --fijord); }
첫 번째 사용자 정의 속성은 LATIN SMALL LETTER F + LATIN SMALL LETTER I + LATIN SMALL LETTER J의 시퀀스를 사용하고, 두 번째 속성은 LATIN SMALL LETTER F + LATIN SMALL LIGATURE IJ 시퀀스를 사용하며, 세 번째 속성은 LATIN SMALL LIGATURE FI + LATIN SMALL LETTER J 시퀀스를 사용합니다.
따라서 CSS에는 서로 다른 세 개의 사용자 정의 속성이 있으며, 그중 두 개는 사용되지 않습니다.
사용자 정의 속성은 all 속성에 의해 초기화되지 않습니다. 향후 모든 변수를 초기화하는 속성을 정의할 수 있습니다.
CSS 전역 키워드는 사용자 정의 속성에서도 사용할 수 있으며, 다른 속성에서와 동일한 의미를 가집니다.
테스트
- variable-declaration-43.html (실시간 테스트) (소스)
- variable-declaration-44.html (실시간 테스트) (소스)
- variable-declaration-45.html (실시간 테스트) (소스)
- variable-declaration-46.html (실시간 테스트) (소스)
- variable-declaration-47.html (실시간 테스트) (소스)
- variable-declaration-56.html (실시간 테스트) (소스)
- variable-declaration-57.html (실시간 테스트) (소스)
- variable-declaration-58.html (실시간 테스트) (소스)
- variable-declaration-60.html (실시간 테스트) (소스)
- variable-definition-keywords.html (실시간 테스트) (소스)
참고: 이는 일반적으로 캐스케이드 값 해석 시 해석되며, 사용자 정의 속성의 값으로 유지되지 않으므로, 해당 변수로 대체되지 않습니다.
참고: 이 모듈은 사용자 정의 속성을 var() 함수와 함께 “변수”로 사용하는 것에 중점을 두지만, 실제 사용자 정의 속성으로도 사용할 수 있으며, 스크립트에서 파싱 및 동작할 수 있습니다. CSS 확장 명세 [CSS-EXTENSIONS]가 이러한 사용 사례를 확장하고 더 쉽게 사용할 수 있도록 할 것으로 기대됩니다.
사용자 정의 속성은 일반 속성이므로,
모든 요소에 선언할 수 있고,
일반 상속 및 캐스케이드 규칙으로 처리되며,
@media
및 기타 조건부 규칙으로 조건부 선언이 가능하며,
HTML의 style
속성에서도 사용할 수 있고,
CSSOM으로 읽거나 설정할 수도 있습니다.
테스트
- css-vars-custom-property-inheritance.html (실시간 테스트) (소스)
- variable-created-document.html (실시간 테스트) (소스)
- variable-created-element.html (실시간 테스트) (소스)
- variable-cssText.html (실시간 테스트) (소스)
- variable-declaration-06.html (실시간 테스트) (소스)
- variable-definition-cascading.html (실시간 테스트) (소스)
- variable-external-declaration-01.html (실시간 테스트) (소스)
- variable-external-reference-01.html (실시간 테스트) (소스)
- variable-external-supports-01.html (실시간 테스트) (소스)
- variable-first-letter.html (실시간 테스트) (소스)
- variable-first-line.html (실시간 테스트) (소스)
- variable-pseudo-element.html (실시간 테스트) (소스)
- variable-reference-13.html (실시간 테스트) (소스)
- variable-reference-14.html (실시간 테스트) (소스)
- variable-reference-shorthands.html (실시간 테스트) (소스)
- variable-reference-visited.html (실시간 테스트) (소스)
특히, 전환이나 애니메이션도 가능하지만, UA가 내용 해석 방법을 알 수 없으므로, 지능적으로 보간할 수 없는 값 쌍에 사용하는 "50%에서 전환" 동작을 사용합니다. 단, 사용자 정의 속성이 @keyframes 규칙에서 사용될 경우, 애니메이션 오염됨(animation-tainted) 상태가 되며, 이는 애니메이션 속성에서 var() 함수로 참조될 때 처리 방식에 영향을 줍니다.
테스트
- variable-animation-from-to.html (실시간 테스트) (소스)
- variable-animation-over-transition.html (실시간 테스트) (소스)
- variable-animation-substitute-into-keyframe-shorthand.html (실시간 테스트) (소스)
- variable-animation-substitute-into-keyframe-transform.html (실시간 테스트) (소스)
- variable-animation-substitute-into-keyframe.html (실시간 테스트) (소스)
- variable-animation-substitute-within-keyframe-fallback.html (실시간 테스트) (소스)
- variable-animation-substitute-within-keyframe-multiple.html (실시간 테스트) (소스)
- variable-animation-substitute-within-keyframe.html (실시간 테스트) (소스)
- variable-animation-to-only.html (실시간 테스트) (소스)
Animation-tainted는 "전염성"이 있습니다: animation-tainted 속성을 참조하는 사용자 정의 속성도 animation-tainted가 됩니다.
:root{ --header-color : #06c; }
루트 요소에 사용자 정의 속성 --header-color를 선언하고, 값으로 "#06c"를 할당합니다. 이 속성은 문서의 나머지 요소에 상속됩니다. var() 함수로 값을 참조할 수 있습니다:
h1{ background-color : var ( --header-color); }
이 규칙은 background-color: #06c;를 작성하는 것과 동일합니다. 변수명을 사용하면 색상의 출처를 더 명확하게 알 수 있고, var(--header-color)가 문서 내 다른 요소에서 사용된다면 루트 요소의 --header-color 속성만 변경해 모든 사용처를 한 번에 업데이트할 수 있습니다.
:root{ --color : blue; } div{ --color : green; } #alert{ --color : red; } *{ color : var ( --color); } <p>나는 루트 요소에서 파란색을 상속받았어요!</p> <div>나는 녹색을 직접 설정받았어요!</div> <div id='alert' 나는 빨간색을 직접 설정받았어요! <p>나도 빨간색이에요, 상속 때문이에요!</p> </div>
:root, :root:lang ( en) { --external-link : "external link" ;} :root:lang ( el) { --external-link : "εξωτερικός σύνδεσμος" ;} a[ href^="http" ] ::after{ content : " (" var ( --external-link) ")" }
변수 선언은 별도의 파일에 보관할 수도 있어, 번역 유지 관리가 더 쉬워질 수 있습니다.
2.1. 사용자 정의 속성 값 문법
사용자 정의 속성에 허용되는 문법은 매우 관대합니다. <declaration-value> 생산식은 하나 이상의 토큰 시퀀스와 일치합니다. 단, 해당 시퀀스에 <bad-string-token>, <bad-url-token>, 일치하지 않는 <)-token>, <]-token>, 또는 <}-token>, 또는 최상위 <semicolon-token> 토큰이나 값이 "!"인 <delim-token> 토큰이 포함되어 있지 않아야 합니다.
테스트
또한, 사용자 정의 속성의 값에 var() 참조가 포함되어 있으면, var() 참조는 지정된 var() 문법에 따라 유효해야 합니다. 그렇지 않으면 사용자 정의 속성이 잘못된 것으로 간주되어 무시되어야 합니다.
참고: 이 정의는 일반적인 CSS 문법 규칙과 함께, 사용자 정의 속성 값에 맞지 않는 따옴표나 괄호가 포함되지 않음을 의미합니다. 따라서 다시 직렬화될 때 스타일 규칙과 같은 더 큰 문법 구조에 영향을 줄 수 없습니다.
참고: 사용자 정의 속성에는 끝에 !important가 포함될 수 있지만, 이것은 CSS 파서에 의해 속성 값에서 자동으로 제거되며, 해당 사용자 정의 속성을 CSS 계단식에서 "중요"하게 만듭니다. 즉, 최상위 "!" 문자의 금지는 !important의 사용을 막지 않으며, !important는 구문 검사 전에 제거됩니다.
--foo : if ( x >5 ) this.width =10 ;
이 값은 변수로서는 분명히 쓸모없지만, 일반 속성에서는 유효하지 않으므로, JavaScript에서 읽어 동작하게 할 수도 있습니다.
사용자 정의 속성의 값과, var() 함수가 사용자 정의 속성에 대입될 때의 값은 대소문자를 구분하며, 원래 작성자가 준 원래의 대소문자를 그대로 유지해야 합니다. (많은 CSS 값은 ASCII 대소문자 구분 없음이며, 사용자 에이전트는 이를 하나의 대소문자로 "정규화"할 수 있지만, 사용자 정의 속성에는 허용되지 않습니다.)
이로 인해 추가적인 영향이 있습니다.
예를 들어 CSS의 상대 URL은 값이 나타나는 스타일시트의 기준 URL을 기준으로 해석됩니다.
그러나 --my-image:
url(foo.jpg);와 같은 사용자 정의 속성이
스타일시트에 있다면,
즉시 절대 URL로 해석되지 않습니다;
만약 그 변수가 다른
스타일시트에서
background: var(--my-image);처럼 사용된다면,
그 시점에
로 해석됩니다.
2.2. 보장된 잘못된 값
사용자 정의 속성의 초기 값은 보장된 잘못된 값입니다. § 3 계단식 변수 사용: var() 표기법에 정의된 바와 같이, var()를 사용해 이 값을 가진 사용자 정의 속성을 대체하면, 이를 참조하는 속성은 계산값 시점에서 잘못됨이 됩니다.
이 값은 빈 문자열로 직렬화되지만, 실제로 --foo: ;처럼 사용자 정의 속성에 빈 값을 작성하는 것은 유효한 (빈) 값이며, 보장된 잘못된 값이 아닙니다. 만약 어떤 이유로든, 변수를 수동으로 보장된 잘못된 값으로 초기화하고 싶다면, initial 키워드를 사용하면 됩니다.
2.3. 의존성 순환 해결
사용자 정의 속성은 거의 평가되지 않은 채로 남아 있지만, 값에 var() 함수는 허용되고 평가됩니다. 이를 통해 사용자 정의 속성이 var()로 자기 자신을 참조하거나, 두 개 이상의 사용자 정의 속성이 서로를 참조하는 등 순환 의존성이 생길 수 있습니다.
각 요소마다, 각 사용자 정의 속성에 대한 노드가 포함된 방향성 의존성 그래프를 만듭니다. 만약 사용자 정의 속성 prop의 값에 var() 함수가 var 속성을 참조한다면 (var()의 폴백 인자 포함), prop에서 var로 엣지를 추가합니다. 자기 자신을 가리키는 엣지도 가능합니다.
의존성 그래프에 순환이 있으면, 해당 순환에 속한 모든 사용자 정의 속성은 계산값 시점에서 잘못됨이 됩니다.
테스트
참고: 순환에 참여하는 정의된 속성은 값에 잘못된 변수가 존재할 수 있으며 (계산값 시점에서 잘못됨), 아니면 자체 순환 처리 방식을 정의할 수 있습니다 (font-size가 em 값을 사용할 때처럼). 이들은 사용자 정의 속성처럼 보장된 잘못된 값으로 계산되지 않습니다.
:root{ --main-color : #c06; --accent-background : linear-gradient ( to top, var ( --main-color), white); }
--accent-background 속성은 (var(--main-color)을 사용하는 다른 모든 속성과 함께) --main-color 속성이 변경되면 자동으로 업데이트됩니다.
:root{ --one : calc ( var ( --two) +20 px ); --two : calc ( var ( --one) -20 px ); }
--one과 --two는 모두 이제 계산값 시점에서 잘못됨이 되며, 길이 대신 보장된 잘못된 값으로 계산됩니다.
중요한 점은 사용자 정의 속성은 값에 있는 var() 함수를 계산값 시점에 해석하며, 이 시점은 값이 상속되기 이전에 발생합니다. 일반적으로, 순환 의존성은 동일한 요소의 여러 사용자 정의 속성이 서로를 참조할 때만 발생합니다; 요소 트리의 상위에 정의된 사용자 정의 속성은 하위에 정의된 속성과 순환 참조를 일으킬 수 없습니다.
< one >< two >< three /></ two ></ one > < style > one { --foo : 10 px ; } two { --bar : calc( var ( --foo ) + 10 px ); } three { --foo : calc( var ( --bar ) + 10 px ); } </ style >
<one> 요소는 --foo 값을 정의합니다. <two> 요소는 이 값을 상속받고, 추가로 --bar에 foo 변수를 사용해 값을 할당합니다. 마지막으로, <three> 요소는 변수 치환 이후 --bar 값을 상속받습니다 (즉, calc(10px + 10px) 값을 보게 됩니다), 그리고 그 값으로 --foo를 다시 정의합니다. 상속받은 --bar 값에는 더 이상 <one>에 정의된 --foo에 대한 참조가 없으므로, var(--bar)로 --foo를 정의하는 것은 순환적이지 않으며, 실제로 나중에 (일반 속성에서 변수로 참조할 때) 30px로 해석됩니다.
3. 계단식 변수 사용: var() 표기법
사용자 정의 속성의 값은 var() 함수를 사용하여 다른 속성의 값에 대입할 수 있습니다. var()의 문법은 다음과 같습니다:
var () =var ( <custom-property-name>, <declaration-value>?)
테스트
- variable-reference-07.html (실시간 테스트) (소스)
- variable-reference-08.html (실시간 테스트) (소스)
- variable-reference-09.html (실시간 테스트) (소스)
- variable-reference-10.html (실시간 테스트) (소스)
- variable-reference-17.html (실시간 테스트) (소스)
- variable-reference-20.html (실시간 테스트) (소스)
- variable-reference-21.html (실시간 테스트) (소스)
- variable-reference-22.html (실시간 테스트) (소스)
- variable-reference-23.html (실시간 테스트) (소스)
- variable-reference-24.html (실시간 테스트) (소스)
- variable-reference-25.html (실시간 테스트) (소스)
- variable-reference-28.html (실시간 테스트) (소스)
- variable-reference-29.html (실시간 테스트) (소스)
- variable-reference-31.html (실시간 테스트) (소스)
- variable-reference-32.html (실시간 테스트) (소스)
- variable-reference-33.html (실시간 테스트) (소스)
- variable-reference-34.html (실시간 테스트) (소스)
- variable-reference-35.html (실시간 테스트) (소스)
- variable-reference.html (실시간 테스트) (소스)
@supports
- variable-supports-01.html (실시간 테스트) (소스)
- variable-supports-02.html (실시간 테스트) (소스)
- variable-supports-03.html (실시간 테스트) (소스)
- variable-supports-04.html (실시간 테스트) (소스)
- variable-supports-05.html (실시간 테스트) (소스)
- variable-supports-06.html (실시간 테스트) (소스)
- variable-supports-07.html (실시간 테스트) (소스)
- variable-supports-08.html (실시간 테스트) (소스)
- variable-supports-09.html (실시간 테스트) (소스)
- variable-supports-10.html (실시간 테스트) (소스)
- variable-supports-11.html (실시간 테스트) (소스)
- variable-supports-12.html (실시간 테스트) (소스)
- variable-supports-13.html (실시간 테스트) (소스)
- variable-supports-14.html (실시간 테스트) (소스)
- variable-supports-15.html (실시간 테스트) (소스)
- variable-supports-16.html (실시간 테스트) (소스)
- variable-supports-17.html (실시간 테스트) (소스)
- variable-supports-18.html (실시간 테스트) (소스)
- variable-supports-19.html (실시간 테스트) (소스)
- variable-supports-20.html (실시간 테스트) (소스)
- variable-supports-21.html (실시간 테스트) (소스)
- variable-supports-22.html (실시간 테스트) (소스)
- variable-supports-23.html (실시간 테스트) (소스)
- variable-supports-24.html (실시간 테스트) (소스)
- variable-supports-25.html (실시간 테스트) (소스)
- variable-supports-26.html (실시간 테스트) (소스)
- variable-supports-27.html (실시간 테스트) (소스)
- variable-supports-28.html (실시간 테스트) (소스)
- variable-supports-29.html (실시간 테스트) (소스)
- variable-supports-30.html (실시간 테스트) (소스)
- variable-supports-31.html (실시간 테스트) (소스)
- variable-supports-32.html (실시간 테스트) (소스)
- variable-supports-33.html (실시간 테스트) (소스)
- variable-supports-34.html (실시간 테스트) (소스)
- variable-supports-35.html (실시간 테스트) (소스)
- variable-supports-36.html (실시간 테스트) (소스)
- variable-supports-37.html (실시간 테스트) (소스)
- variable-supports-38.html (실시간 테스트) (소스)
- variable-supports-39.html (실시간 테스트) (소스)
- variable-supports-40.html (실시간 테스트) (소스)
- variable-supports-41.html (실시간 테스트) (소스)
- variable-supports-42.html (실시간 테스트) (소스)
- variable-supports-43.html (실시간 테스트) (소스)
- variable-supports-44.html (실시간 테스트) (소스)
- variable-supports-45.html (실시간 테스트) (소스)
- variable-supports-46.html (실시간 테스트) (소스)
- variable-supports-47.html (실시간 테스트) (소스)
- variable-supports-48.html (실시간 테스트) (소스)
- variable-supports-49.html (실시간 테스트) (소스)
- variable-supports-50.html (실시간 테스트) (소스)
- variable-supports-51.html (실시간 테스트) (소스)
- variable-supports-52.html (실시간 테스트) (소스)
- variable-supports-53.html (실시간 테스트) (소스)
- variable-supports-54.html (실시간 테스트) (소스)
- variable-supports-55.html (실시간 테스트) (소스)
- variable-supports-56.html (실시간 테스트) (소스)
- variable-supports-57.html (실시간 테스트) (소스)
- variable-supports-58.html (실시간 테스트) (소스)
- variable-supports-59.html (실시간 테스트) (소스)
- variable-supports-60.html (실시간 테스트) (소스)
- variable-supports-61.html (실시간 테스트) (소스)
- variable-supports-62.html (실시간 테스트) (소스)
- variable-supports-63.html (실시간 테스트) (소스)
- variable-supports-64.html (실시간 테스트) (소스)
- variable-supports-65.html (실시간 테스트) (소스)
- variable-supports-66.html (실시간 테스트) (소스)
- variable-supports-67.html (실시간 테스트) (소스)
일반적인 쉼표 생략 규칙의 예외로, 해당 규칙은 쉼표가 값을 구분하지 않을 때 생략을 요구하지만, 아무 것도 뒤따르지 않는 단독 쉼표는 var()에서 유효한 것으로 취급되어야 하며, 이는 빈 폴백 값을 나타냅니다.
테스트
참고: 즉, var(--a,)는 유효한 함수이며, --a 사용자 정의 속성이 잘못되었거나 없을 경우, var()가 아무것도 없는 것으로 대체됨을 지정합니다.
var() 함수는 요소의 모든 속성 값의 어떤 부분에도 사용할 수 있습니다. var() 함수는 속성명이나 셀렉터, 또는 속성 값 이외의 곳에서는 사용할 수 없습니다. (이렇게 사용하면 대개 잘못된 구문이 되거나, 변수와 아무 관련 없는 의미가 없는 값이 됩니다.)
테스트
.foo{ --side : margin-top; var ( --side) :20 px ; }
이것은 margin-top: 20px;을 설정하는 것과 동일하지 않습니다. 대신, 두 번째 선언은 잘못된 속성 이름 때문에 구문 오류로 그냥 버려집니다.
함수의 첫 번째 인자는 대체될 사용자 정의 속성의 이름입니다. 함수의 두 번째 인자는, 제공되는 경우, 폴백 값이며, 참조된 사용자 정의 속성의 값이 보장된 잘못된 값일 때 대체 값으로 사용됩니다.
테스트
- variable-declaration-08.html (실시간 테스트) (소스)
- variable-declaration-09.html (실시간 테스트) (소스)
- variable-declaration-10.html (실시간 테스트) (소스)
- variable-declaration-11.html (실시간 테스트) (소스)
- variable-declaration-12.html (실시간 테스트) (소스)
- variable-declaration-13.html (실시간 테스트) (소스)
- variable-declaration-22.html (실시간 테스트) (소스)
참고: 폴백의 문법은 사용자 정의 속성과 같이 쉼표를 허용합니다. 예를 들어, var(--foo, red, blue)는 폴백 값으로 red, blue를 정의합니다; 즉, 첫 번째 쉼표 이후부터 함수 끝까지가 모두 폴백 값으로 간주됩니다.
폴백이 없다면, 앱 작성자는 컴포넌트가 사용하는 모든 변수에 값을 제공해야 합니다. 폴백이 있다면 컴포넌트 작성자가 기본값을 지정할 수 있으므로, 앱 작성자는 오버라이드하고 싶은 변수만 값을 주면 됩니다.
/* 컴포넌트의 스타일: */ .component .header{ color : var ( --header-color, blue); } .component .text{ color : var ( --text-color, black); } /* 더 큰 애플리케이션의 스타일: */ .component{ --text-color : #080; /* header-color는 설정되지 않아서, blue(폴백 값)으로 남습니다 */ }
속성에 하나 이상의 var() 함수가 포함되어 있고, 그 함수들이 구문상 유효하다면, 전체 속성의 문법은 파싱 시점에 유효한 것으로 간주되어야 합니다. 실제 구문 검사는 var() 함수가 대체된 후 계산값 시점에만 이루어집니다.
테스트
속성 값에서 var()를 치환하려면:
- 사용자 정의 속성이 var() 함수의 첫 번째 인자로 지정되었고, 해당 var() 함수가 animation-tainted이며, 해당 속성이 애니메이션이 불가능한 속성에서 사용된다면, 이 알고리즘의 나머지에서 사용자 정의 속성은 초기 값을 갖는 것으로 처리한다.
- 사용자 정의 속성이 var() 함수의 첫 번째 인자로 지정되었고, 그 값이 초기 값이 아니라면, var() 함수를 해당 사용자 정의 속성의 값으로 치환한다.
- 그렇지 않고, var() 함수의 두 번째 인자가 폴백 값이라면, var() 함수를 폴백 값으로 치환한다. 폴백 값에 var() 참조가 있으면, 그것들도 치환한다.
-
그 외의 경우,
var() 함수가 포함된
속성은 계산값 시점에서 잘못됨이 된다.
참고: 속성이 계산값 시점에서 잘못됨이 되는 다른 경우도 있습니다.
테스트
- css-variable-change-style-001.html (실시간 테스트) (소스)
- css-variable-change-style-002.html (실시간 테스트) (소스)
- variable-declaration-01.html (실시간 테스트) (소스)
- variable-declaration-02.html (실시간 테스트) (소스)
- variable-declaration-03.html (실시간 테스트) (소스)
- variable-declaration-04.html (실시간 테스트) (소스)
- variable-declaration-05.html (실시간 테스트) (소스)
- variable-generated-content-dynamic-001.html (실시간 테스트) (소스)
- variable-presentation-attribute.html (실시간 테스트) (소스)
- variable-reference-01.html (실시간 테스트) (소스)
- variable-reference-02.html (실시간 테스트) (소스)
- variable-reference-03.html (실시간 테스트) (소스)
- variable-reference-04.html (실시간 테스트) (소스)
- variable-reference-05.html (실시간 테스트) (소스)
- variable-reference-12.html (실시간 테스트) (소스)
- variable-reference-16.html (실시간 테스트) (소스)
- variable-reference-40.html (실시간 테스트) (소스)
- variable-reference-refresh.html (실시간 테스트) (소스)
- variable-substitution-background-properties.html (실시간 테스트) (소스)
- variable-substitution-basic.html (실시간 테스트) (소스)
- variable-substitution-filters.html (실시간 테스트) (소스)
- variable-substitution-replaced-size.html (실시간 테스트) (소스)
- variable-substitution-shadow-properties.html (실시간 테스트) (소스)
- variable-substitution-variable-declaration.html (실시간 테스트) (소스)
CSSOM
.foo{ --gap : 20 ; margin-top : var ( --gap) px; }
이것은 margin-top: 20px; (길이)을 설정하는 것과 동일하지 않습니다. 대신, 이는 margin-top: 20 px; (숫자 뒤에 식별자)가 되어, margin-top 속성에는 단순히 잘못된 값입니다. 하지만 calc()를 사용하면 다음과 같이 같은 효과를 올바르게 낼 수 있습니다:
.foo{ --gap : 20 ; margin-top : calc ( var ( --gap) *1 px ); }
테스트
var() 함수는 치환이 계산값 시점에 이루어집니다. 모든 var() 함수가 치환된 후, 선언이 해당 선언된 문법과 일치하지 않으면, 그 선언은 계산값 시점에서 잘못된 것이 됩니다.
테스트
- variable-declaration-16.html (실시간 테스트) (소스)
- variable-declaration-17.html (실시간 테스트) (소스)
- variable-declaration-18.html (실시간 테스트) (소스)
- variable-declaration-19.html (실시간 테스트) (소스)
- variable-declaration-21.html (실시간 테스트) (소스)
- variable-transitions-transition-property-all-before-value.html (실시간 테스트) (소스)
- variable-transitions-value-before-transition-property-all.html (실시간 테스트) (소스)
모든 var() 함수가 치환된 후, 선언이 CSS 전체 키워드(그리고 공백만 있을 수도 있음)만 포함한다면, 해당 값은 해당 키워드가 처음부터 지정값이었던 것처럼 결정됩니다.
:root{ --looks-valid : 20 px ; } p{ background-color : var ( --looks-valid); }
20px는 background-color에 대해 잘못된 값이므로, 해당 속성의 값은 transparent(background-color의 초기 값)로 계산됩니다.
속성이 기본적으로 상속되는 것이라면, 예를 들어 color처럼, 초기값이 아니라 상속값으로 계산됩니다.
p{ color : var ( --does-not-exist, initial); }
위 코드에서 --does-not-exist 속성이 존재하지 않거나 계산값 시점에서 잘못됨이라면, var()는 initial 키워드로 치환되어, 해당 속성이 처음에 color: initial처럼 동작하게 만듭니다. 이는 폴백이 없을 때처럼 상속값이 아니라 문서의 초기 color 값을 갖게 만듭니다.
3.1. 잘못된 변수
사용자 정의 속성의 값이 보장된 잘못된 값이면, var() 함수는 치환에 사용할 수 없습니다. 시도하면 선언이 계산값 시점에서 잘못됨이 되고, 폴백이 유효한 경우를 제외하면 그렇습니다.
선언은 계산값 시점에서 잘못됨이 될 수 있습니다. 예를 들어 var()가 보장된 잘못된 값을 가진 사용자 정의 속성을 참조할 때, 혹은 유효한 사용자 정의 속성을 사용하지만, 그 속성 값이 모든 var() 함수 치환 후에도 잘못된 경우입니다. 이런 경우, 계산값은 속성의 종류에 따라 다음 중 하나가 됩니다:
- 속성이 등록되지 않은 사용자
정의 속성인 경우
- 등록된 사용자 정의 속성이 범용 문법을 가진 경우
-
계산값은 보장된 잘못된 값입니다.
- 그 외의 경우
-
속성이 상속되는 경우에는 상속값, 그렇지 않으면 초기값이 됩니다. 이는 속성 값이 unset 키워드로 지정된 것과 같습니다.
:root{ --not-a-color : 20 px ; } p{ background-color : red; } p{ background-color : var ( --not-a-color); }
<p> 요소는 투명 배경 (background-color의 초기값)을 가지게 되며, 빨간 배경이 되지 않습니다. 사용자 정의 속성이 해제되었거나, 잘못된 var() 함수를 포함한 경우에도 마찬가지입니다.
이것은 작성자가 스타일시트에 background-color: 20px를 직접 쓴 것과는 차이가 있습니다 - 그 경우에는 일반적인 구문 오류가 발생하여, 규칙이 버려지고 background-color: red 규칙이 적용됩니다.
참고: 계산값 시점에서 잘못됨 개념은 변수는 다른 구문 오류처럼 "빠르게 실패"할 수 없기 때문에 존재합니다. 사용자 에이전트가 속성 값이 잘못된 것을 알게 되는 시점에는 이미 다른 계단식 값들은 버려진 뒤입니다.
3.2. 축약 속성에서의 변수
var() 함수는 축약 속성을 구성요소 롱핸드로 파싱할 때, 그리고 축약 속성을 구성요소 롱핸드에서 직렬화할 때 몇 가지 복잡함을 만듭니다.
축약 속성에 var() 함수가 값에 포함되어 있으면, 해당 축약 속성과 연관된 롱핸드 속성은 특수한, 작성자가 관찰할 수 없는 대기-치환 값으로 채워져야 하며, 이는 축약 속성에 변수가 포함되어 있다는 것을 나타냅니다. 따라서 롱핸드 값은 변수가 치환될 때까지 결정할 수 없습니다.
이 값은 일반적으로 계단식되고, 계산값 시점에, var() 함수가 최종적으로 치환된 후, 축약 속성은 파싱되고 롱핸드에는 그 시점에서 적절한 값이 할당되어야 합니다.
테스트
참고: 축약 속성이 var() 없이 작성된 경우, 파싱 시점에 구성요소 롱핸드 속성으로 분리되어 파싱됩니다; 롱핸드들은 계단식에 참여하게 되고, 축약 속성은 사실상 폐기됩니다. 하지만 축약 속성에 var()가 포함된 경우에는 이렇게 할 수 없으며, var()가 무엇으로 치환될지 알 수 없기 때문입니다.
대기-치환 값은 API에서 관찰이 가능하다면 빈 문자열로 직렬화되어야 합니다.
테스트
축약 속성은 구성요소 롱핸드 속성의 값을 모아서, 동일한 값 집합으로 파싱될 수 있는 값을 합성하여 직렬화됩니다.
주어진 축약 속성의 모든 구성요소 롱핸드 속성이 동일한 원래 축약 값에서 온 대기-치환 값이면, 축약 속성은 그 원래(var()를 포함한) 값을 직렬화해야 합니다.
그렇지 않고, 주어진 축약 속성의 구성요소 롱핸드 속성 중 하나라도 대기-치환 값이거나, 아직 치환되지 않은 var() 함수를 포함한다면, 축약 속성은 빈 문자열로 직렬화해야 합니다.
3.3. 지나치게 긴 변수 안전하게 처리하기
순진하게 구현된 var() 함수는 "billion laughs attack"의 변형에 사용될 수 있습니다:
.foo {
--prop1 : lol;
--prop2 : var ( --prop1) var ( --prop1);
--prop3 : var ( --prop2) var ( --prop2);
--prop4 : var ( --prop3) var ( --prop3);
/* etc */
}
이 짧은 예시에서 --prop4의 계산값은 lol lol lol lol lol lol lol lol이 되어, 원래 lol이 8번 반복됩니다. 레벨을 하나 추가할 때마다 식별자 수가 두 배로 늘어나며, 단 30단계로 확장하기만 해도 --prop30에는 거의 10억 번의 식별자가 들어가게 됩니다.
이런 공격을 막기 위해, UA는 var() 함수가 확장될 때 허용되는 토큰 스트림의 길이에 UA가 정한 제한을 두어야 합니다. var()가 이 제한보다 긴 토큰 스트림으로 확장된다면, 확장되는 속성은 계산값 시점에서 잘못됨이 됩니다.
이 명세는 어떤 크기 제한을 둬야 하는지 정의하지 않습니다. 하지만 1킬로바이트 이상의 텍스트를 담는 사용자 정의 속성의 유효한 사용 사례도 있으므로, 제한은 비교적 높게 설정하는 것이 권장됩니다.
참고: UA가 자원 제약으로 인해 표준을 위반할 수 있다는 일반 원칙은 여기서도 여전히 유효합니다; UA는 별도로 지원하는 사용자 정의 속성의 길이나 식별자의 크기에 제한을 둘 수 있습니다. 이 절에서는 이 공격이 오랜 역사를 가지고 있고, 처음에는 개별 항목이 커 보이지 않더라도 충분히 위험할 수 있어서 특별히 언급한 것입니다.
4. API
모든 사용자 정의 속성 선언에는 대소문자 구분 플래그가 설정되어 있습니다.
참고: 사용자 정의 속성은 CSSStyleDeclaration 객체에서 카멜 케이스 형태로 나타나지 않습니다. 왜냐하면 이름에 대소문자가 모두 들어갈 수 있고, 이는 서로 다른 사용자 정의 속성을 나타내기 때문입니다. 자동 카멜 케이싱이 수행하는 텍스트 변환은 이와 호환되지 않습니다. 대신 getPropertyValue() 등으로 올바른 이름으로 접근할 수 있습니다.
4.1. 사용자 정의 속성 직렬화하기
사용자 정의 속성 이름은 작성자가 제공한 정확한 코드 포인트 시퀀스로, 대소문자를 변경하지 않고 직렬화해야 합니다.
참고: 사용자 정의 속성이 아닌 속성의 경우, 속성 이름은 ASCII 범위로 제한되고 ASCII 대소문자 구분 없음이므로, 구현체는 보통 이름을 소문자로 직렬화합니다.
사용자 정의 속성의 지정값은 작성자가 지정한 그대로 직렬화해야 합니다. 다른 속성에서 발생할 수 있는 주석 삭제, 공백 정규화, 숫자 토큰을 값에서 다시 직렬화 등 단순화 작업을 하면 안 됩니다.
사용자 정의 속성의 계산값 역시 작성자가 지정한 그대로 직렬화해야 하며, 단, var() 함수가 치환된 경우는 예외입니다.
테스트
--y : /* baz */ ; --x : /* foo */ var ( --y) /* bar */ ;
--x의 지정값 직렬화는
가 되어야 하며,
계산값 직렬화는
가 되어야 합니다.
(값 앞의 공백은 CSS 파서가 자동으로 잘라내므로 여기에는 보존되지 않습니다.)
예를 들어 사용자 정의 속성에 UUID를 저장할 때, --uuid: 12345678-12e3-8d9b-a456-426614174000처럼, 스크립트로 접근할 때 UUID가 작성된 그대로 반환되어야 합니다.
이 값은 기술적으로는 CSS에서 인접한 숫자와 차원들의 연속으로 파싱됩니다. 특히 "-12e3" 부분은 -12000에 해당하는 숫자로 파싱됩니다. 다른 컨텍스트에서 CSSOM이 요구하는 형태로 다시 직렬화하면, 작성자의 값 사용을 치명적으로 깨뜨릴 수 있습니다.
5. 변경 사항
5.1. 2021년 11월 11일 CR 초안 이후의 변경 사항
-
사용자 정의 속성이 모든 의사 요소에 적용된다는 점(제한된 속성 목록을 가진 의사 요소 포함)을 명확히 함
-
조합 문자, 합자 등과 관련된 문제를 보여주는 예시 추가
-
서로 비슷하게 보이지만 구분되는 코드 포인트 시퀀스를 사용하는 변수명에 대한 설명 강화
-
예시를 더 시각적으로 구분되는 언어(영어와 그리스어)로 명확히 함
-
보안과 프라이버시를 각각의 섹션으로 분리함
5.2. 2015년 12월 3일 CR 이후의 변경 사항
-
[css-syntax-3]가 선언 값에서 공백을 자동으로 잘라내므로, 사용자 정의 속성 문법에서 <declaration-value>를 선택적으로 만들었으며, 빈 변수도 허용됩니다. (이슈 774)
-
마찬가지로 var()에서 빈 폴백도 유효하도록 함.
-
'-' 속성은 CSS에서 향후 사용을 위해 예약됨.
-
"animation-tainted" 개념 추가, 비애니메이션 속성에서 변수를 통해 애니메이션 가능성을 숨기는 것을 방지함.
-
사용자 정의 속성의 초기값과 순환 혹은 치환 실패의 결과가 더 명확해지도록, 보장된 잘못된 값 개념을 정의했으며, 치환 실패가 폴백에 의해 최종적으로 처리될 때까지 전파될 수 있도록 허용함.
-
순환이 계산값 시점에서 잘못됨 동작을 트리거하도록 정의함.
-
변수가 CSS 전체 키워드로 해석될 수 있도록 허용함(폴백으로만 가능).
-
등록된 사용자 정의 속성이 계산값 시점에서 잘못됨일 때 비사용자 정의 속성처럼 동작함을 명확히 함.
-
var()가 포함된 롱핸드도 대기-치환 값이 있는 롱핸드처럼 축약 속성을 직렬화할 수 없게 만듦.
-
UA가 지수적 치환 공격을 방어하도록 요구함.
-
사용자 정의 속성의 값 직렬화 방법을 정의함(이전에는 속성명 직렬화만 명시됨).
5.3. 2014년 5월 6일 Last Call Working Draft 이후의 변경 사항
-
축약 속성이 변수 사용 시 롱핸드 직렬화 방법 정의
-
DOM의 "대소문자 구분" 정의 링크 추가
-
:lang()와 변수를 함께 사용하여 간단한 i18n을 구현하는 예시 추가
-
사용자 정의 속성에서 var() 사용 시 var() 문법에 따라 유효해야 함을 명확히 함.
6. 감사의 글
수년간 CSS Working Group에서 변수의 꿈을 지켜준 여러 분들께 많은 감사를 드립니다, 특히 Daniel Glazman과 David Hyatt에게. 메일링 리스트에서 이 변수 정의 발전에 기여해주신 여러 분들께도 감사드립니다, 특히 Brian Kardell, David Baron, François Remy, Roland Steiner, 그리고 Shane Stephens.
7. 프라이버시 고려사항
이 명세는 작성자가 직접 제어하는 페이지 내에서 스타일 정보를 전달하기 위한 순수 작성자 수준의 메커니즘을 정의합니다. 그러므로 새로운 프라이버시 고려사항은 없습니다.
8. 보안 고려사항
§ 3.3 지나치게 긴 변수 안전하게 처리하기에서는 var() 함수와 같은 "매크로 확장"과 유사한 메커니즘에 대해 오래된 서비스 거부(DoS) 공격을 지적하며, 이에 대한 방어 조치를 요구합니다.