1. 소개
이 명세서는 ::marker 의사 요소, 마커를 생성하는 list-item display type, 그리고 마커의 위치와 스타일을 제어하는 여러 속성을 정의합니다.
또한 카운터도 정의하며, 이는 마커의 기본 내용을 생성하는 데 자주 사용되는 특수 숫자 객체입니다.
< style > li :: marker { content : "(" counter( list-item , lower-roman ) ")" ; } li { display : list-item ; } </ style > < ol > < li > This is the first item.< li > This is the second item.< li > This is the third item.</ ol >
다음과 같이 출력됩니다:
(i) This is the first item. (ii) This is the second item. (iii) This is the third item.
참고: 이 예시는 HTML에서 보통보다 훨씬 더 장황하지만, 대부분의 필요한 스타일은 UA 기본 스타일시트에서 처리해줍니다.
하위 선택자와 자식 선택자를 사용하면, 중첩된 리스트의 깊이에 따라 서로 다른 마커 타입을 지정할 수 있습니다.
1.1. 값 정의
이 명세서는 CSS 속성 정의 관례를 [CSS2]에서 따르며, 값 정의 문법을 [CSS-VALUES-3]에서 사용합니다. 이 명세서에서 정의되지 않은 값 타입은 CSS 값 및 단위 [CSS-VALUES-3]에서 정의됩니다. 다른 CSS 모듈과의 결합을 통해 이러한 값 타입의 정의가 확장될 수 있습니다.
각 속성의 정의에 명시된 속성별 값 외에도, 이 명세서에서 정의된 모든 속성은 CSS-공통 키워드도 속성 값으로 허용합니다. 가독성을 위해 여기에서는 명시적으로 반복하지 않았습니다.
2. 리스트 아이템 선언
리스트 아이템은 display 속성이 list-item으로 설정된 모든 요소입니다. 리스트 아이템은 ::marker 의사 요소를 생성합니다; 다른 요소에서는 생성되지 않습니다. 또한 리스트 아이템은 암시적으로 list-item 카운터를 자동으로 증가시킵니다 (자세한 내용은 § 4.6 암시적 list-item 카운터 참조).
3. 마커
리스트 아이템 display type의 주요 특징은 마커로, 리스트에 있는 각 리스트 아이템의 시작을 나타내는 기호나 서수입니다. CSS 레이아웃 모델에서 리스트 아이템 마커는 각 리스트 아이템에 연결된 마커 박스로 표현됩니다. 이 마커의 내용은 리스트 아이템의 list-style-type 및 list-style-image 속성, 그리고 ::marker 의사 요소에 속성을 지정하여 제어할 수 있습니다.
3.1. ::marker 의사 요소
마커 박스는 ::marker 의사 요소에 의해 리스트 아이템의 첫 번째 자식으로 생성되며, 리스트 아이템의 ::before 의사 요소 (해당 요소에 존재하는 경우)보다 앞에 위치합니다. 내용은 § 3.2 마커 내용 생성에 정의된 대로 채워집니다.
< style > p { margin-left : 12 em ; } p . note { display : list-item ; counter-increment : note-counter ; } p . note :: marker { content : "Note " counter( note - counter ) ":" ; } </ style > < p > This is the first paragraph in this document.< p class = "note" > This is a very short document.< p > This is the end.
다음과 같이 렌더링됩니다:
This is the first paragraph in this document. Note 1: This is a very short document. This is the end.
< style > p { margin-left : 8 em } /* 카운터 공간 확보 */ li { list-style-type : lower-roman ; } li :: marker { color : blue ; font-weight : bold ; } </ style > < p > This is a long preceding paragraph ...< ol > < li > This is the first item.< li > This is the second item.< li > This is the third item.</ ol > < p > This is a long following paragraph ...
위의 문서는 다음과 같이 렌더링됩니다:
This is a long preceding paragraph ... i. This is the first item. ii. This is the second item. iii. This is the third item. This is a long following paragraph ...
이전에는 마커를 스타일링하는 유일한 방법은 상속을 통해서였으며, 원하는 마커 스타일을 리스트 아이템에 지정한 후, 리스트 아이템의 실제 내용에 감싸는 래퍼 요소에서 이를 다시 되돌려야 했습니다.
마커 박스는 리스트 아이템에서만 존재합니다: 다른 요소에서는, ::marker 의사 요소의 content 속성은 반드시 none으로 계산되어야 하며, 생성이 억제됩니다.
3.1.1. ::marker에 적용되는 속성
모든 속성은 ::marker 의사 요소에 설정할 수 있으며, 계산된 값을 가집니다; 하지만, 실제로 마커 박스에 적용되는 CSS 속성은 다음과 같습니다:
- text-combine-upright, unicode-bidi, direction 속성 ([CSS-WRITING-MODES-3] 참조)
- content 속성 (§ 3.2 마커 내용 생성 참조)
- 모든 애니메이션 및 트랜지션 속성 ([CSS-ANIMATIONS-1], [CSS-TRANSITIONS-1] 참조)
향후 명세서에서 이 속성 목록이 확장될 것으로 예상됩니다; 그러나 현재는 마커 박스 레이아웃이 완전히 정의되어 있지 않으므로, 이들 속성만 허용됩니다.
기타 속성은 마커 박스에 작성자 출처에서 설정할 때 효과를 주지 않아야 합니다. UA는 이러한 속성을 적용되지 않는 것으로 처리하거나, UA 출처 !important 규칙으로 값을 강제할 수 있습니다. 그러나 텍스트에 적용되는 상속 가능한 속성은 ::marker 의사 요소에 설정할 수 있습니다: 이들은 해당 텍스트 내용에 상속되어 적용됩니다.
- white-space, text-transform, letter-spacing ([CSS-TEXT-3] 참조)
- 모든 폰트 속성 ([CSS-FONTS-3] 및 후속 문서 참조)
- color 속성 ([CSS-COLOR-3] 참조)
UA는 다음 규칙을 기본 스타일시트에 추가해야 합니다:
::marker, ::before::marker, ::after::marker { unicode-bidi: isolate; font-variant-numeric: tabular-nums; white-space: pre; text-transform: none; }
참고: ::marker 의사 요소는 마커 박스를 나타낼 수 있지만,
::before 또는 ::after
의사 요소의 마커 박스도 나타낼 수 있습니다.
복합 선택자
::marker
(*::marker으로 확장됨, [SELECTORS-4] 참조)
은 이러한 마커를 선택하지 않습니다—
white-space: pre는 원하는 동작과 완전히 일치하지 않습니다; text-space-collapse: preserve-spaces + text-space-trim: discard-after가 더 근접할 수 있습니다. 자세한 논의는 이슈 4448 및 이슈 4891에서 확인하세요.
3.2. 마커 내용 생성
마커 박스의 내용은 아래 조건들 중 처음으로 참이 되는 것에 의해 결정됩니다:
- content가 ::marker에 직접 지정되어 있고, normal이 아닌 경우
- 마커 박스의 내용은 content 속성에 의해 정의되며, ::before와 동일하게 동작합니다.
- list-style-image가 원본 요소에 지정되어 마커 이미지를 정의하는 경우
- '마커 박스에는 지정된 마커 이미지를 나타내는 익명 인라인 대체 요소가 포함되고, 그 뒤에는 하나의 공백(U+0020 SPACE)으로 구성된 텍스트 런이 따라옵니다.
- list-style-type이 원본 요소에 지정되어 마커 문자열을 정의하는 경우
- 마커 박스에는 지정된 마커 문자열로 구성된 텍스트 런이 포함됩니다.
- 그 외의 경우
- 마커 박스는 내용을 가지지 않으며, ::marker는 박스를 생성하지 않습니다.
추가적으로, UA는 보존된 강제 줄바꿈을 공백으로 변환하거나 버릴 수 있습니다.
3.3. 이미지 마커: list-style-image 속성
Name: | list-style-image |
---|---|
Value: | <image> | none |
Initial: | none |
적용 대상: | list items |
상속 여부: | yes |
퍼센트값: | 해당 없음 |
계산된 값: | 키워드 none 또는 계산된 <image> |
정식 순서: | 문법 기준 |
애니메이션 타입: | 불연속(discrete) |
마커 이미지를 지정하며, list item의 marker를 content가 normal인 경우에 채웁니다. 값은 다음과 같습니다:
- <image>
- <image> 가 유효한 이미지를 나타내는 경우, 해당 요소의 마커 이미지로 <image>를 지정합니다. 그렇지 않으면 요소는 마커 이미지를 가지지 않습니다.
- none
- 해당 요소는 마커 이미지를 가지지 않습니다.
li{ list-style-image : url ( "http://www.example.com/ellipse.png" ) }
3.4. 텍스트 기반 마커: list-style-type 속성
Name: | list-style-type |
---|---|
Value: | <counter-style> | <string> | none |
Initial: | disc |
적용 대상: | list items |
상속 여부: | yes |
퍼센트값: | 해당 없음 |
계산된 값: | 지정된 값 |
정식 순서: | 문법 기준 |
애니메이션 타입: | 불연속(discrete) |
마커 문자열을 지정하며, list item의 marker를 content 값이 normal이고 마커 이미지가 없는 경우에 채웁니다. 값은 다음과 같습니다:
- <counter-style>
-
해당 요소의 마커 문자열을
지정된 list-item 카운터 값을
지정된 <counter-style>로
표현한 값으로 지정합니다.
구체적으로, 마커 문자열은 카운터 생성 규칙에 따라 list-item 카운터 값을 지정된 <counter-style>로 변환하여, prefix로 시작하고 suffix로 끝납니다. 지정된 <counter-style> 이 존재하지 않으면 decimal이 사용됩니다.
- <string>
- 해당 요소의 마커 문자열은 지정된 <string>입니다.
- none
- 해당 요소는 마커 문자열을 가지지 않습니다.
ul{ list-style-type : "★" ; } /* 마커를 "별" 문자로 설정 */ p.note{ display : list-item; list-style-type : "Note: " ; list-style-position : inside; } /* note 문단에 "Note: " 문자열 마커 부여 */ ol{ list-style-type : upper-roman; } /* 모든 순서 리스트를 upper-roman 카운터 스타일로 설정 (Counter Styles 명세 [[CSS-COUNTER-STYLES]]에 정의됨) */ ul{ list-style-type : symbols ( cyclic'○' '●' ); } /* 모든 비순서 리스트 아이템의 마커를 빈 원과 채워진 원으로 교대로 설정 */ ul{ list-style-type : none; } /* 유효한 list-style-image가 지정되지 않는 이상 마커를 완전히 숨김 */
3.5. 마커 위치 지정: list-style-position 속성
Name: | list-style-position |
---|---|
Value: | inside | outside |
Initial: | outside |
적용 대상: | list items |
상속 여부: | yes |
퍼센트값: | 해당 없음 |
계산된 값: | 키워드(자세한 사항은 설명 참고) |
정식 순서: | 문법 기준 |
애니메이션 타입: | 불연속(discrete) |
이 속성은 ::marker가 인라인으로 렌더링될지, 혹은 list item 바로 바깥에 위치할지를 지정합니다. 값은 다음과 같습니다:
- inside
- 특별한 효과 없음. (::marker는 list item 내용의 시작에 인라인 요소로 표시됨.)
- outside
-
list item이 블록 컨테이너인 경우:
마커 박스는 블록 컨테이너이며, 주 블록 박스 바깥에
위치합니다;
단, float 옆에 위치한 리스트 아이템 마커의 위치는 정의되지 않습니다.
CSS는 마커 박스의 정확한 위치나 페인팅 순서를 명시하지 않지만,
박스의 inline-start 쪽에 위치하도록 요구합니다.
writing mode는 marker-side에 의해 지정된 박스의 것을 사용합니다.
마커 박스는 주 블록 박스의 테두리에 고정되어,
주 박스의 콘텐츠와 함께 스크롤되지 않습니다.
UA는 요소의 overflow가 visible이 아닐 경우 마커를 숨길 수 있습니다.
(이 허용 사항은 향후 변경될 수 있습니다.)
마커 박스의 크기나 내용이 주 블록 박스의 높이, 혹은 첫 번째 라인 박스의 높이에 영향을 줄 수 있으며,
경우에 따라 새 라인 박스를 생성할 수도 있습니다;
이 상호작용은 정의되어 있지 않습니다.
이 부분은 CSS2에서 왔으며, 실제 정의가 필요합니다.
list item이 인라인 박스인 경우: 이 값은 inside와 동일하게 동작합니다.
또는 outside가 마커를 주 인라인 박스의 이전 형제 요소로 배치하도록 레이아웃할 수도 있습니다.
<style> ul.compact { list-style: inside; } ul { list-style: outside; } </style> <ul class=compact> <li>first "inside" list item comes first</li> <li>second "inside" list item comes first</li> </ul> <hr> <ul> <li>first "outside" list item comes first</li> <li>second "outside" list item comes first</li> </ul>
위 예시는 다음과 같이 포맷될 수 있습니다:
* first "inside" list item comes first * second "inside" list item comes second ======================== * first "outside" list item comes first * second "outside" list item comes second
3.6. 마커 스타일 지정: list-style 단축 속성
Name: | list-style |
---|---|
Value: | <'list-style-position'> || <'list-style-image'> || <'list-style-type'> |
Initial: | 개별 속성 참조 |
적용 대상: | list items |
상속 여부: | 개별 속성 참조 |
퍼센트값: | 개별 속성 참조 |
계산된 값: | 개별 속성 참조 |
애니메이션 타입: | 개별 속성 참조 |
정식 순서: | 문법 기준 |
list-style 속성은 list-style-type, list-style-image, list-style-position 세 가지 속성을 스타일 시트에서 한 번에 설정하는 단축 표기입니다.
ul{ list-style : upper-roman inside} /* 모든 UL */ ul ul{ list-style : circle outside} /* UL의 자식인 UL */
단축 표기에서 none 값을 사용할 때는 none이 list-style-image와 list-style-type 모두에서 유효한 값이기 때문에 모호할 수 있습니다. 이 모호함을 해결하기 위해, 단축 표기에서 none 값은 나머지 두 속성 중 단축 표기에서 별도로 설정되지 않은 속성에 적용되어야 합니다.
list-style : none disc; /* 이미지를 "none"으로, 타입을 "disc"로 설정 */ list-style: noneurl ( bullet.png ); /* 이미지를 "url(bullet.png)"로, 타입을 "none"으로 설정 */ list-style: none; /* 이미지와 타입 모두 "none"으로 설정 */ list-style: none discurl ( bullet.png ); /* 문법 오류 */
참고: <counter-style> 값은 list-style-type에서 문법적 모호성을 만들 수 있습니다. 이런 값들은 결국 <custom-ident> 값이므로, [CSS-VALUES-3]의 파싱 규칙이 적용됩니다.
li
)에
직접 지정할 수 있지만,
주의해서 사용해야 합니다.
다음 규칙을 살펴보세요:
ol.alpha li{ list-style : lower-alpha; } ul li{ list-style : disc; }
위 방법은 의도대로 동작하지 않습니다.
ul
을
ol class=alpha에 중첩하면,
첫 번째 규칙의 특이성 때문에 ul
의
리스트 아이템에 lower-alpha 스타일이 적용됩니다.
ol.alpha > li{ list-style : lower-alpha; } ul > li{ list-style : disc; }
이런 방식이 의도대로 동작합니다.
ol.alpha{ list-style : lower-alpha; } ul{ list-style : disc; }
이 방식이 더 좋으며, 상속을 통해 list-style 값이 리스트 아이템으로 전달됩니다.
3.7. marker-side 속성
Name: | marker-side |
---|---|
Value: | match-self | match-parent |
Initial: | match-self |
적용 대상: | list items |
상속 여부: | yes |
퍼센트값: | 해당 없음 |
계산된 값: | 지정된 키워드 |
정식 순서: | 문법 기준 |
애니메이션 타입: | 불연속(discrete) |
marker-side 속성은 outside marker box가 리스트 아이템 자체(즉, 원본 요소)의 방향성을 기준으로 배치될지, 아니면 리스트 컨테이너(즉, 원본 요소의 부모)의 방향성을 기준으로 배치될지를 지정합니다. 첫 번째 경우에는 동일한 리스트 내의 아이템들끼리 각각 지정된 방향성에 따라 마커 위치가 달라질 수 있으며, 두 번째 경우에는 리스트 전체에 지정된 방향성에 따라 모두 같은 쪽에 정렬됩니다.
- match-self
- marker box는 ::marker의 원본 요소의 방향성을 사용해 배치됩니다.
- match-parent
- marker box는 ::marker의 원본 요소의 부모의 방향성을 사용해 배치됩니다.
아래 두 렌더링 예시는 동일한 HTML에서 marker-side의 값만 다릅니다:
< ul > < li > english one< li dir = rtl > OWT WERBEH< li > english three< li dir = rtl > RUOF WERBEH</ ul >
match-self | match-parent |
---|---|
* english one OWT WERBEH * * english three RUOF WERBEH * |
* english one * OWT WERBEH * english three * RUOF WERBEH |
마커 내부의 구두점 순서를 올바르게 하려면, 부모의 direction 값도 고려해야 합니다. <https://github.com/w3c/csswg-drafts/issues/4202>
키워드 이름 변경 및 list-style-position과 병합에 대한 오픈 이슈가 있습니다.
4. 카운터를 이용한 자동 번호 매기기
카운터는, CSS에서 리스트 아이템에 자동으로 번호를 매기는 등, 특수한 숫자 추적기로 사용됩니다. 모든 요소는 0개 이상의 카운터 집합을 가지며, 이는 문서 트리 내에서 속성 값의 상속과 유사한 방식으로 상속됩니다. 카운터는 이름과 생성자로 식별되며, 정수 값을 가집니다. 카운터는 카운터 속성 counter-increment, counter-set, counter-reset을 통해 생성·조작하며, counter()와 counters() 함수 표기로 사용됩니다.
CSS 문법에서 카운터는 <counter-name> 타입으로 참조되며, <custom-ident>로 이름을 나타냅니다. <counter-name> 이름은 none 키워드와 일치할 수 없으며, 그러한 식별자는 잘못된 <counter-name>이 됩니다.
특정 요소에서 카운터 값을 해석하는 과정은 여러 단계입니다:
-
기존 카운터를 이전 요소에서 상속합니다.
-
새 카운터를 인스턴스화합니다 (counter-reset).
-
카운터 값을 증가시킵니다 (counter-increment).
-
카운터 값을 명시적으로 설정합니다 (counter-set).
-
카운터 값을 사용합니다 (counter()/counters()).
UA는 카운터 값의 최대/최소값에 대해 구현별 제한이 있을 수 있습니다. 카운터를 reset, set, increment할 때 값이 그 범위를 벗어나면, 값은 반드시 해당 범위로 클램핑되어야 합니다.
4.1. 카운터 생성: counter-reset 속성
Name: | counter-reset |
---|---|
Value: | [ <counter-name> <integer>? ]+ | none |
Initial: | none |
적용 대상: | 모든 요소 |
상속 여부: | no |
퍼센트값: | 해당 없음 |
계산된 값: | 키워드 none 또는 각 항목이 식별자와 정수 쌍인 리스트 |
정식 순서: | 문법 기준 |
애니메이션 타입: | 계산된 값 타입에 따라 다름 |
User Agent는 모든 미디어(비시각적 포함)에서 이 속성을 지원해야 합니다.
counter-reset 속성은 요소에 새로운 카운터를 인스턴스화하고, 지정된 정수 값으로 설정합니다. 값은 다음과 같이 정의됩니다:
- none
- 이 요소는 새로운 카운터를 생성하지 않습니다.
- <counter-name> <integer>?
- 주어진 <counter-name>의 카운터를 주어진 <integer> 값으로 인스턴스화하며, 기본값은 0입니다.
h1{ counter-reset : section-1 } h1{ counter-reset : imagenum99 }
은 imagenum만 리셋됩니다. 두 카운터 모두를 리셋하려면, 함께 명시해야 합니다:
H1{ counter-reset : section-1 imagenum99 }
동일 원리가 counter-set 및 counter-increment에도 적용됩니다. 자세한 내용은 [css-cascade-4]를 참고하세요.
동일한 <counter-name>이 속성 값에 여러 번 등장하면, 마지막 것만 적용됩니다.
4.2. 카운터 값 조작: counter-increment 및 counter-set 속성
Name: | counter-increment |
---|---|
Value: | [ <counter-name> <integer>? ]+ | none |
Initial: | none |
적용 대상: | 모든 요소 |
상속 여부: | no |
퍼센트값: | 해당 없음 |
계산된 값: | 키워드 none 또는 각 항목이 식별자와 정수 쌍인 리스트 |
정식 순서: | 문법 기준 |
애니메이션 타입: | 계산된 값 타입에 따라 다름 |
User Agent는 모든 미디어(비시각적 포함)에서 이 속성을 지원해야 합니다.
Name: | counter-set |
---|---|
Value: | [ <counter-name> <integer>? ]+ | none |
Initial: | none |
적용 대상: | 모든 요소 |
상속 여부: | no |
퍼센트값: | 해당 없음 |
계산된 값: | 키워드 none 또는 각 항목이 식별자와 정수 쌍인 리스트 |
정식 순서: | 문법 기준 |
애니메이션 타입: | 계산된 값 타입에 따라 다름 |
User Agent는 모든 미디어(비시각적 포함)에서 이 속성을 지원해야 합니다.
counter-increment 및 counter-set 속성은 기존 카운터의 값을 조작합니다. 아직 해당 이름의 카운터가 요소에 없을 경우에만 새 카운터를 인스턴스화합니다. 값은 다음과 같이 정의됩니다:
- none
- 이 요소는 어떤 카운터 값도 변경하지 않습니다.
- <counter-name> <integer>?
-
해당 요소의 지정된 카운터 값을
counter-set의 경우에는 값으로 설정하고,
counter-increment의 경우에는 값을 증가시킵니다.
만약 <integer> 값이 생략되면,
counter-increment의 경우 기본값은 1,
counter-set의 경우 기본값은 0입니다.
현재 해당 이름의 카운터가 요소에 없다면, 요소는 먼저 0으로 새 카운터를 인스턴스화한 뒤 값을 설정하거나 증가시킵니다.
이 예시는 "Chapter 1", "1.1", "1.2" 등 챕터와 섹션을 번호 매기는 방법을 보여줍니다.
h1 : :before{ content : "Chapter " counter ( chapter) ". " ; counter-increment : chapter; /* 챕터에 1 추가 */ counter-reset: section; /* 섹션을 0으로 설정 */ } h2::before{ content : counter ( chapter) "." counter ( section) " " ; counter-increment : section; }
동일한 <counter-name>이 속성 값에 여러 번 등장하면, 모두 순서대로 처리됩니다. 따라서 증가값은 누적되고, 마지막 설정값만 적용됩니다.
4.3. 중첩 카운터와 스코프
카운터는 “자기 중첩(self-nesting)” 특성을 가집니다. 새 카운터를 인스턴스화할 때, 부모로부터 동일 이름의 카운터를 상속받았다면, 동일 이름의 새 카운터가 기존 카운터 내부에 중첩되어 생성됩니다. 이는 HTML의 리스트처럼, 리스트가 임의 깊이로 중첩되는 상황에서 중요합니다: 각 레벨마다 고유 이름의 카운터를 정의하는 것이 불가능하기 때문입니다. counter() 함수는 해당 요소에 대해 지정된 이름의 가장 안쪽 카운터만 가져오며, counters() 함수는 해당 요소를 포함하는 동일 이름의 모든 카운터를 사용합니다.
스코프는 카운터를 최초로 인스턴스화한 요소에서 시작되어, 해당 요소의 자식들과 뒤따르는 형제 및 그들의 자손을 포함합니다. 단, 이후 형제 요소에서 counter-reset으로 동일 이름의 카운터를 명시적으로 생성한 경우, 그 이후의 스코프에는 이전 형제의 카운터가 포함되지 않아, 명시적 카운터 인스턴스화가 이전 형제를 가릴 수 있습니다.
카운터와 값의 스코프에 대한 정확한 규칙은 § 4.4 카운터 생성 및 상속을 참고하세요.
ol{ counter-reset : item} li{ display : block} li::before{ content : counter ( item) ". " ; counter-increment : item}
이 예시에서는, ol이 카운터를 생성하고, ol의 모든 자식이 그 카운터를 참조합니다.
n번째 item 카운터를 itemn로 표시하면, 아래 HTML 조각은 명시된 카운터를 사용합니다.
<ol>
item0 생성, 0으로 설정
<li>
item0 1로 증가<li>
item0 2로 증가
<ol>
item1 생성, 0으로 설정, item0에 중첩됨
<li>
item1 1로 증가<li>
item1 2로 증가<li>
item1 3로 증가
<ol>
item2 생성, 0으로 설정, item1에 중첩됨
<li>
item2 1로 증가</ol>
<li>
item1 4로 증가
<ol>
item3 생성, 0으로 설정, item1에 중첩됨
<li>
item3 1로 증가</ol>
<li>
item1 5로 증가</ol>
<li>
item0 3로 증가<li>
item0 4로 증가</ol>
<ol>
item4 생성, 0으로 설정
<li>
item4 1로 증가<li>
item4 2로 증가</ol>
4.4. 카운터 생성 및 상속
문서의 각 요소 또는 의사 요소는 해당 요소의 카운터의 (비어있을 수도 있는) 집합을 스코프 내에 가집니다. 이 카운터들은 다른 요소로부터 상속받거나, 해당 요소에서 직접 인스턴스화될 수 있습니다. 이러한 카운터들은 CSS 카운터 집합으로 표현되며, 이는 각 값이 다음을 포함하는 튜플인 집합입니다: 문자열 (카운터의 이름을 나타냄), 요소 (카운터의 생성자를 나타냄), 그리고 정수 (카운터의 값을 나타냄). 해당 집합 내에서 특정 이름의 가장 최근 카운터가 그 이름의 가장 안쪽 카운터를 나타냅니다.
4.4.1. 카운터 상속
-
element가 자신의 문서 트리의 루트라면, 요소는 초기에는 비어 있는 CSS 카운터 집합을 가집니다. 반환합니다.
-
element counters를 element 자신의 CSS 카운터 집합으로, element의 부모 요소의 CSS 카운터 집합을 복사합니다.
-
sibling counters를 element의 바로 앞 형제의 CSS 카운터 집합으로 하며, 만약 형제가 없다면 비어 있는 CSS 카운터 집합으로 합니다.
각 counter에 대해 sibling counters에서, element counters에 동일 이름의 카운터가 없다면, counter의 복사본을 element counters에 추가합니다.
-
value source를 element 바로 앞에 CSS 카운터 집합을 가지는 요소(트리 순서상)로 합니다.
각 source counter에 대해 value source에서, element counters에 동일 이름, 생성자를 가진 카운터가 있다면, 그 카운터의 값을 source counter의 값으로 설정합니다.
<ul style='counter-reset: example 0;'> <li id='foo' style='counter-increment: example;'> foo <div id='bar' style='counter-increment: example;'>bar</div> </li> <li id='baz'> baz </li> </ul>
트리 순서는 문서 트리를 정렬된 리스트로 바꾸며, 요소가 자식보다 먼저, 자식이 다음 형제보다 먼저 옵니다. 다시 말해, HTML 같은 언어에서는, 파서가 문서를 읽으며 시작 태그를 만나는 순서입니다.
여기서,
ul
요소는 example이라는 새로운 카운터를 생성하고,
그 값을 0으로 설정합니다.
#foo 요소는
ul
의
첫 번째 자식이므로,
이 카운터를 상속받습니다.
부모가 바로 앞 트리 순서 요소이기도 하므로,
값 0도 함께 상속받고,
바로 값을 1로 증가시킵니다.
#bar 요소도 동일하게 동작합니다. #foo로부터 example 카운터와 1 값을 상속받고, 값을 2로 증가시킵니다.
하지만 #baz 요소는 조금 다릅니다. #foo라는 이전 형제 요소로부터 example 카운터를 상속받지만, 값은 #foo의 1이 아니라, 트리 순서상 앞에 있는 #bar의 2 값을 상속받습니다.
이 동작 덕분에 하나의 카운터를 문서 전체에서 연속적으로 사용할 수 있어, 문서의 중첩 구조에 신경 쓰지 않고도 값을 계속 증가시킬 수 있습니다.
참고: 카운터 상속은 일반 CSS 상속처럼, [DOM] 문맥의 “평탄화된 요소 트리”에서 동작합니다.
4.4.2. 카운터 인스턴스화
-
counters를 element의 CSS 카운터 집합으로 설정합니다.
-
innermost counter를 counters에서 name 이름을 가진 마지막 카운터로 합니다. innermost counter의 원본 요소가 element 또는 element의 이전 형제라면, 해당 카운터를 counters에서 제거합니다.
-
새로운 카운터를 counters에 name 이름, element를 원본 요소, value를 초기값으로 추가합니다.
4.5. 박스를 생성하지 않는 요소의 카운터
박스를 생성하지 않는 요소 (예: display 값이 none이거나, content가 none인 의사 요소) 는 카운터를 설정, 리셋 또는 증가시킬 수 없습니다. 이런 요소에 대해 카운터 속성이 유효하긴 하지만, 아무런 효과를 가져서는 안 됩니다.
h2{ counter-increment : count2; } h2.secret{ display : none; }
참고: visibility를 으로 설정하는 것처럼 요소를 “숨기는” 다른 방법들은 여전히 박스를 생성하므로, 여기서는 예외가 아닙니다.
대체 요소의 자손
(예: HTML
option
,
또는 SVG
rect
)
가 카운터를 설정, 리셋 또는 증가시킬 수 있는지는 정의되어 있지 않습니다.
참고: 대체 요소 자손에서의 동작은 구현 간 상호운용성 부족으로 인해 현재 정의되어 있지 않습니다.
4.6. 암시적 list-item 카운터
작성자가 스타일에서 명시적으로 정의한 카운터 외에도, 리스트 아이템은 list-item 카운터를 자동으로 1씩 증가시키며, 이는 리스트 아이템의 기본 마커 문자열을 생성할 때 사용됩니다 (자세한 내용은 list-style-type 참고).
구체적으로, counter-increment 속성이 list-item 카운터에 대해 다른 증가값을 명시적으로 지정하지 않는 한, 모든 리스트 아이템에서 반드시 1씩 증가해야 하며, 이는 카운터가 일반적으로 증가되는 시점에 동작합니다 (마치 리스트 아이템에 list-item 1이 counter-increment 값에 추가된 것처럼, 새로운 카운터 인스턴스화 등 부수 효과 포함). 이는 counter-increment의 지정 또는 계산 값에 영향을 주지 않습니다.
단, 자동 list-item 증가는 리스트 아이템의 counter-increment에 list-item 카운터가 명시적으로 지정된 경우에는 발생하지 않습니다. 예: li { counter-increment: list-item 2; }는 list-item을 2씩 증가시키며, list-item 1이 무조건 추가된 경우처럼 3씩 증가하지 않습니다.
이는 자동 list-item 증가를 명시적으로 끌 수 있게 하며, 예: counter-increment: list-item 0;와 같이 사용할 수 있습니다.
그 외 모든 면에서, list-item 카운터는 다른 카운터와 동일하게 동작하며, 작성자가 리스트 아이템 스타일 조정이나 기타 용도로 자유롭게 사용할 수 있습니다.
아래 예시에서는, 리스트가 2씩 증가하도록 수정됩니다:
ol.evens > li { counter-increment: list-item 2; }
3개 아이템 리스트는 다음과 같이 렌더링됩니다
2. First Item 4. Second Item 6. Third Item
UA 및 호스트 언어는 list-item 카운터 값이 기본적으로 호스트 언어 의미론에 의해 결정된 기저 숫자 값을 반영하도록 해야 하며, UA 스타일시트 및 표현 힌트 스타일 매핑에서 리스트 아이템 스타일을 설정할 때 이를 보장해야 합니다. 자세한 내용은 부록 A: HTML용 샘플 스타일시트 참고.
ol > li::marker { content: counters(list-item,'.') '.'; }
이 규칙을 사용하는 중첩 리스트는 다음과 같이 렌더링됩니다
1. First top-level item 5. Second top-level item, value=5 5.3. First second-level item, list start=3 5.4. Second second-level item, list start=3 5.4.4. First third-level item in reversed list 5.4.3. Second third-level item in reversed list 5.4.2. Third third-level item in reversed list 5.4.1. Fourth third-level item in reversed list 5.5. Third second-level item, list start=3 6. Third top-level item
예시 마크업:
<ol> <li>First top-level item <li value=5>Second top-level item, value=5 <ol start=3> <li>First second-level item, list start=3 <li>Second second-level item, list start=3 <ol reversed> <li>First third-level item in reversed list <li>Second third-level item in reversed list <li>Third third-level item in reversed list <li>Fourth third-level item in reversed list </ol> </ol> <li>Third second-level item, list start=3 <li>Third top-level item </ol>
4.7. 카운터 출력: counter() 및 counters() 함수
카운터 자체로는 아무런 시각적 효과가 없지만, counter() 및 counters() 함수를 통해 값을 사용할 수 있으며, 이 함수의 사용된 값은 카운터 값을 문자열이나 이미지로 나타냅니다. 정의는 다음과 같습니다:
<counter> = <counter()> | <counters()> counter() = counter( <counter-name>, <counter-style>? ) counters() = counters( <counter-name>, <string>, <counter-style>? )
여기서 <counter-style> 은 카운터 스타일을 지정하며, 명명된 카운터를 표현하는 방법을 정의합니다. 자세한 내용은 [css-counter-styles-3] 참조.
- counter()
- 요소의 CSS 카운터 집합에서 지정된 <counter-name> 이름의 가장 안쪽 카운터 값을 카운터 스타일로 표현한 것입니다.
- counters()
- 요소의 CSS 카운터 집합에서 지정된 <counter-name> 이름의 모든 카운터 값을 카운터 스타일로 표현하며, 바깥쪽에서 안쪽 순서로 정렬된 후 지정된 <string>으로 연결됩니다.
두 경우 모두, <counter-style> 인자가 생략되면 기본값은 decimal입니다.
만약 카운터 이름 <counter-name>이 해당 요소에 존재하지 않을 때 counter() 또는 counters()를 사용하면, 우선 시작값 0으로 인스턴스화됩니다.
H1::before { content: counter(chno, upper-latin) ". " } /* "A. A History of Discontent"와 같은 헤딩 생성 */ H2::before { content: counter(section, upper-roman) " - " } /* "II - The Discontent Part"와 같은 헤딩 생성 */ BLOCKQUOTE::after { content: " [" counter(bq, decimal) "]" } /* "... [3]"과 같이 블록 인용 끝에 번호 표시 */ DIV.note::before { content: counter(notecntr, disc) " " } /* 모든 div.note 앞에 단순히 불릿 생성 */ P::before { content: counter(p, none) } /* 아무것도 삽입하지 않음 */
< ul > < li > one</ li > < li > two< ul > < li > nested one</ li > < li > nested two</ li > </ ul > </ li > < li > three</ li > </ ul > < style > li :: marker { content : '(' counters ( list-item , '.' ) ') ' ; } </ style >
위의 문서는 다음과 같이 렌더링됩니다:
(1) one (2) two (2.1) nested one (2.2) nested two (3) three
< h1 > First H1</ h1 > ...< h2 > First H2 in H1</ h2 > ...< h2 > Second H2 in H1</ h2 > ...< h3 > First H3 in H2</ h3 > ...< h1 > Second H1</ h1 > ...< h2 > First H2 in H1</ h2 > ...< style > body { counter-reset : h1 h2 h3 ; } h1 { counter-increment : h1 ; counter-reset : h2 h3 ;} h2 { counter-increment : h2 ; counter-reset : h3 ; } h3 { counter-increment : h3 ; } h1 :: before { content : counter( h1 , upper-alpha ) ' ' ; } h2 :: before { content : counter( h1 , upper-alpha ) '.' counter( h2 , decimal ) ' ' ; } h3 :: before { content : counter( h1 , upper-alpha ) '.' counter( h2 , decimal ) '.' counter( h3 , lower-roman ) ' ' ; } </ style >
위의 문서는 다음과 같이 렌더링됩니다:
A First H1 ... A.1 First H2 in H1 ... A.2 Second H2 in H1 ... A.2.i First H3 in H2 ... B Second H1 ... B.1 First H2 in H1 ...
다른 사례로는 변형(transform)이 서로 조금씩 다르도록 중첩 또는 형제 요소에 적용하는 경우가 있습니다. 오늘날에는 이를 적절하게 하려면 프리프로세서를 써야 하지만, 카운터를 사용하면 "일반" CSS에서도 잘 동작할 수 있습니다.
(현재는 커스텀 속성과 중첩된 calc()를 쌓아가며 중첩 케이스에 대해 값을 쌓을 수 있지만, 다소 불편하며 형제에는 적용되지 않습니다.)
제안: counter-value(<counter-name>) 함수 추가, 이 함수는 명명된 카운터의 값을 문자열이 아닌 정수로 반환합니다.
자세한 내용은 이슈 1026 참고.
부록 A: HTML용 샘플 스타일시트
이 섹션은 정보 전달용이며, 규범적(normative)이지 않습니다. [HTML]의 Rendering 챕터가 HTML 리스트에 적용되는 규범적 기본 속성을 정의합니다. 이 샘플 스타일시트는 친숙한 마크업 관례로 CSS 기능을 보여주기 위해 제공됩니다.
ol[reversed]
리스트 번호 매기기를 CSS에서 지원하는 방법에 대한 논의가 진행 중입니다.
자세한 내용은 이슈 4181 참고.
/* 리스트 아이템 설정 */ li { display: list-item; /* 'counter-increment: list-item'을 내포 */ } /* ol과 ul에서 list-item 카운터 스코프 설정 */ ol, ul { counter-reset: list-item; } /* 리스트의 기본 list-style-type */ ol { list-style-type: decimal; } ul { list-style-type: toggle(disc, circle, square); } /* ol과 ul 요소의 type 속성 */ ul[type="disc"] { list-style-type: disc; } ul[type="circle"] { list-style-type: circle; } ul[type="square"] { list-style-type: square; } ol[type="1"] { list-style-type: decimal; } ol[type="a"] { list-style-type: lower-alpha; } ol[type="A"] { list-style-type: upper-alpha; } ol[type="i"] { list-style-type: lower-roman; } ol[type="I"] { list-style-type: upper-roman; } /* ol 요소의 start 속성 */ ol[start] { counter-reset: list-item calc(attr(start integer, 1) - 1); } /* li 요소의 value 속성 */ li[value] { counter-set: list-item attr(value integer, 1); } /* 박스 모델 규칙 */ ol, ul { display: block; margin-block: 1em; marker-side: match-parent; padding-inline-start: 40px; } ol ol, ol ul, ul ul, ul ol { margin-block: 0; } li { text-align: match-parent; }
감사의 글
이 명세는 다음의 의견을 통해 완성되었습니다: Aharon Lanin, Arron Eicholz, Brad Kemper, David Baron, Emilio Cobos Álvarez, Mats Palmgren, Oriol Brufau, Simon Sapin, Xidorn Quan
변경 사항
이 섹션은 이전 버전 이후의 변경 사항을 문서화합니다.
2020년 7월 9일 WD 이후 변경 사항
- ::marker 박스에 적용되는 속성과 ::marker 박스 내용에 적용되는 속성을 명확히 구분함. (이슈 4568)
- UA 기본 스타일 시트의 text-transform: none를 ::marker에 추가함. (이슈 4206)
- 카운터 상속이 먼저 부모에서 가져오고, 형제에서는 새로운 카운터일 때만 가져오도록 변경함. (이슈 5477)
2019년 8월 17일 WD 이후 변경 사항
- outside 리스트 마커가 block container임을 명시함. (그 outer display type은 아직 정의되지 않음.)
- ::marker에 적용되는 속성 목록을 [CSS-PSEUDO-4]에서 가져와 애니메이션, 트랜지션, white-space를 추가함.
- UA 기본 스타일 시트에 white-space: pre를 ::marker에 추가함. (이슈 4448) 단, 마커 박스의 정확한 공백 처리 동작은 아직 논의 중임.
2019년 4월 25일 WD 이후 변경 사항
- § 4 카운터를 이용한 자동 번호 매기기 섹션을 더 정확하고, 편집 명확성, CSS2와의 동기화를 위해 다시 작성함.
2014년 3월 20일 WD 이후 변경 사항
- 카운터 이름에 <custom-ident>를 일관되게 사용함.
- position: marker를 삭제함(마커 위치 지정은 이제 대부분 정의되지 않음; CSS2와 동일).
- 마커에 관한 장 전체를 다시 작성하여, 더 명확하게 하고 최신 기대에 맞추고 편집 개선을 함.
- list-item 카운터 정의를 별도 섹션으로 분리, 예시 추가, 명확화함.
- marker-side 값명을 박스/텍스트 정렬 규칙에 맞게 변경함.
- counter-set이 counter-increment 이후에 적용됨을 정의함. (이슈 3810)
- list-style 직렬화의 정식 순서를 <'list-style-type'>을 마지막에 오도록 설정함. (이슈 2624)
CSS 레벨 2에서 변경 사항
도입부 섹션에서 설명한 대로, 이 모듈은 CSS2.1과 비교해 상당한 변화가 있습니다.
- ::marker 의사 요소가 도입되어 리스트 마커를 직접 스타일링할 수 있게 되었습니다.
- list-style-type이 <string>뿐 아니라 <counter-style> 값을 [css-counter-styles-3]에서 확장하여 지원합니다.
- list-item 사전 정의된 카운터 식별자가 도입되었습니다.
- counter-set 속성이 추가되었습니다.
- 인라인 레벨 리스트 아이템을 허용했습니다. 자세한 내용은 [CSS-DISPLAY-3] 참고.