CSS is a language for describing the rendering of structured documents (such as HTML and XML) on screen, on paper, in speech, etc. This draft contains the features of CSS level 3 relating to list styling. It includes and extends the functionality of CSS level 2 [[!CSS21]], which builds on CSS level 1 [[CSS1]]. The main extensions compared to level 2 are summarize here.
The list model in this module differs in some important ways from the list model in CSS2, specifically in its handling of markers. Implementation experience suggested the CSS2 model overloaded the ::before and ::after pseudo-elements with too much behavior, while at the same time introducing new properties when existing properties were sufficient.
Most block-level elements in CSS generate one principal block box. In this module, we discuss two CSS mechanisms that cause an element to have an associated marker: one method associates one principal block box (for the element's content) with a separate marker box (for decoration such as a bullet, image, or number), and the other inserts a marker box into the principal box. Unlike :before and :after content, the marker box cannot affect the position of the principal box, whatever the positioning scheme.
For instance, the following example illustrates how markers may be used to add parentheses around each numbered list item. This HTML application and style sheet:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<HTML>
<HEAD>
<TITLE>Creating a list with markers</TITLE>
<STYLE type="text/css">
LI::marker { content: "(" counter(list-item, lower-roman) ")"; }
LI { display: list-item; }
</STYLE>
</HEAD>
<BODY>
<OL>
<LI> This is the first item. </LI>
<LI> This is the second item. </LI>
<LI> This is the third item. </LI>
</OL>
</BODY>
</HTML>
should produce something like this:
(i) This is the first item. (ii) This is the second item. (iii) This is the third item.
With descendant selectors and child selectors, it's possible to specify different marker types depending on the depth of embedded lists.
A future release of this module will probably include ways to render tree lists.
To declare a list item, the 'display' property should be set to ''list-item''. This, in addition to generating a ''::marker'' pseudo-element and enabling the properties described below for that element, causes that element to increment the list item counter ''list-item''. (This does not affect the specified or computed values of the counter properties.)
The ''list-item'' counter is a real counter, and can be directly affected using the 'counter-increment' and ''counter-reset'' properties. It can also be used in the ''counter()'' and ''counters()'' functions.
The CSS3 box module may define other 'display' values which generate a list marker. These should also affect the ''list-item'' counter.
Note that this new model makes the ''marker'' display type redundant. That display type is therefore obsolete in the CSS3 Lists model.
| Name: | list-style-type |
|---|---|
| Value: | <string> | <counter-style> | none |
| Initial: | disc |
| Applies To: | all elements with ''display: list-item'' |
| Inherited: | yes |
| Media: | visual |
| Computed Value: | specified value |
This property specifies the default contents of the list item marker if 'list-style-image' has the value 'none' or if the image pointed to by the URI cannot be displayed. The value 'none' specifies no marker, and a string value uses the given string; otherwise, the value specifies a <counter-style> which is used to format the value of the ''list-item'' counter.
The ''::marker'' pseudoelement's default contents must be the value of the ''list-item'' counter, formatted according to the given counter style. Algorithms for formatting a value according to a counter style are given later in this spec.
The UA style sheet given later in this spec provides a large list of counter style definitions, and authors or users may define their own counter styles as well.
While authors may define their own counter styles using the ''@counter-style'' rule defined in this spec, there are many counter styles that CSS already defined in previous levels, and many more that can be usefully predefined. Appendix A contains a required UA stylesheet which defines a large number of counter styles using the ''@counter-style'' rule. A few styles require special handling beyond what can be expressed in a stylesheet, though. Those counter styles are described in this section.
The ''decimal'' counter style is the default fallback counter style for the ''@counter-style'' rule, and is also used in extraordinary situations like fallback loop. As such, it has to be well-defined at all times, so that a counter can always be formatted regardless of the validity of the defined counter styles.
UAs must not allow the definition of the ''decimal'' counter style given in Appendix A to be overridden.
CSS 2.1 defined three single-glyph counter styles (''circle'', ''disc'', and ''square''), but didn't define precisely how to render them, instead opting to describe generally how they should look and leaving it up to the UA to decide how to render the markers.
Appendix A gives normative definitions for these styles, but UAs may instead default to rendering these styles using a browser-generated image matching the description below. If the styles are overridden, the new style must be honored; this relaxation of the rendering requirements applies only to the default value of each counter style.
If the UA chooses to use an image for the default rendering of these counter styles, the image must be scalable and designed to attractively fill a box 1em wide and 1em tall.
Some real-life counter styles are unfortunately too complex to be accurately described using the ''@counter-style'' rule. The following styles must be supported as default counter styles as if they were defined by theoretical ''@counter-style'' rules placed at the end of the UA stylesheet defined in Appendix A, using the given name as the counter style name and the given algorithm to format counter values. They must be overrideable like any other predefined counter style.
This is a simple additive system defined for the range 1 to 999999. The digits are split into two groups of three. Within each group, appropriate digits are picked from the following list (at most one per column) and written in descending order by value (hundreds first). If there is more than one group, the first group is followed by U+05F3 HEBREW PUNCTUATION GERESH.
| Hundreds | Tens | Units | ||||||
|---|---|---|---|---|---|---|---|---|
| Values | Codepoints | Values | Codepoints | Values | Codepoints | |||
| 100 | ק | U+05E7 | 10 | י | U+05D9 | 1 | א | U+05D0 |
| 200 | ר | U+05E8 | 20 | כ | U+05DB | 2 | ב | U+05D1 |
| 300 | ש | U+05E9 | 30 | ל | U+05DC | 3 | ג | U+05D2 |
| 400 | ת | U+05EA | 40 | מ | U+05DE | 4 | ד | U+05D3 |
| 500 | תק | U+05EA U+05E7 | 50 | נ | U+05E0 | 5 | ה | U+05D4 |
| 600 | תר | U+05EA U+05E8 | 60 | ס | U+05E1 | 6 | ו | U+05D5 |
| 700 | תש | U+05EA U+05E9 | 70 | ע | U+05E2 | 7 | ז | U+05D6 |
| 800 | תת | U+05EA U+05EA | 80 | פ | U+05E4 | 8 | ח | U+05D7 |
| 900 | תתק | U+05EA U+05EA U+05E7 | 90 | צ | U+05E6 | 9 | ט | U+05D8 |
If the last two digits of a group (when represented in decimal) are 15 or 16, they should be expressed not as יה U+05D9 U+05D4 (10+5) and יו U+05D9 U+05D5 (10+6), but as טו U+05D8 U+05D5 (9+6) and טז U+05D8 U+05D6 (9+7). This is done to avoid a close resemblance to the Tetragrammaton (four-letter name of God) יהוה U+05D9 U+05D4 U+05D5 U+05D4. Although this convention is originally derived from religious practice, it is universally used even in completely secular contexts.
The numerical value of each letter is fixed and not determined by position, so reordering a number group will not change its value. This may be done when a number spells out a word with negative connotations. For instance, 298, רצח U+05E8 U+05E6 U+05D7 (200+90+8), is the Hebrew for "murder", so it is sometimes written as רחצ U+05E8 U+05D7 U+05E6 (200+8+90). Words are sometimes similarly rearranged when a reordered form has especially positive connotations, for example 18, יח U+05D9 U+05D7 (10+8) is often written as חי U+05D7 U+05D9 (8+10), the Hebrew for "alive". Unlike the exception for 15 and 16, using the regular form in these cases is not considered an error.
The suffix for the hebrew numbering system is a dot (. U+002E FULL STOP).
Numbers outside the range of the Hebrew system are rendered using the ''decimal'' counter style.
This table shows the decimal number in the first cell, and the equivalent hebrew number in the second.
| Decimal | Hebrew |
|---|---|
| -3 | -3 |
| -2 | -2 |
| -1 | -1 |
| 0 | 0 |
| 1 | א |
| 2 | ב |
| 3 | ג |
| 4 | ד |
| 5 | ה |
| 97 | צז |
| 98 | צח |
| 99 | צט |
| 100 | ק |
| 101 | קא |
| 944 | תתקמד |
| 945 | תתקמה |
| 946 | תתקמו |
| 999 | תתקצט |
| 1000 | א׳ |
| 1001 | א׳א |
| 1998 | א׳תתקצח |
| 1999 | א׳תתקצט |
| 2000 | ב׳ |
| 2001 | ב׳א |
| 2003 | ב׳ג |
| 2748 | ב׳תשמח |
| 2750 | ב׳תשנ |
This example (like all other examples) is non-normative. If one of the numbers above is inconsistent with the rules described above, then the example should be disregarded.
The Ethiopian numbering system is defined for all positive non-zero numbers. The following algorithm converts decimal digits to ethiopic numbers.
| Tens | Units | ||||
|---|---|---|---|---|---|
| Values | Codepoints | Values | Codepoints | ||
| 10 | ፲ | U+1372 | 1 | ፩ | U+1369 |
| 20 | ፳ | U+1373 | 2 | ፪ | U+136A |
| 30 | ፴ | U+1374 | 3 | ፫ | U+136B |
| 40 | ፵ | U+1375 | 4 | ፬ | U+136C |
| 50 | ፶ | U+1376 | 5 | ፭ | U+136D |
| 60 | ፷ | U+1377 | 6 | ፮ | U+136E |
| 70 | ፸ | U+1378 | 7 | ፯ | U+136F |
| 80 | ፹ | U+1379 | 8 | ፰ | U+1370 |
| 90 | ፺ | U+137A | 9 | ፱ | U+1371 |
This system is defined for all numbers greater than zero. For zero and negative numbers, the decimal system is used instead.
The suffix for the ethiopic-numeric numbering systems is a dot (. U+002E FULL STOP). Is there a better suffix to use? The alphabetic ethiopic systems use a different suffix.
The decimal number 100, in ethiopic, is ፻ U+137B
The decimal number 78010092, in ethiopic, is ፸፰፻፩፼፻፺፪ U+1378 U+1370 U+137B U+1369 U+137C U+137B U+137A U+136A.
The decimal number 780000001092, in ethiopic, is ፸፰፻፩፼፻፼፻፺፪ U+1378 U+1370 U+137B U+1369 U+137C U+137B U+137C U+137B U+137A U+136A.
| Name: | list-style-image |
|---|---|
| Value: | <image> | none |
| Initial | none |
| Applies To: | all elements with ''display: list-item'' |
| Inherited: | yes |
| Media: | visual |
| Computed Value: | specified value |
This property sets the image that will be used as the list item marker. When the <image> resolves to a valid image, it is used as the default contents of ''::marker'' instead of the value specified by 'list-style-type'.
If the value ''none'' is provided, or the <image> doesn't resolve to a valid image, then the default contents are given by 'list-style-type' instead.
The following example sets the marker at the beginning of each list item to be the image "ellipse.png".
LI { list-style-image: url("http://www.example.com/ellipse.png") }
If a ''::marker'' pseudo-element has its 'content' property set to ''normal'', the following algorithm should be used to generate the computed value of the property.
Given the following style sheet:
li { display: list-item; list-style-type: decimal /* initial value */; }
li::marker { content: normal /* initial value */; }
And the following document fragment:
<li> List Item </li>
The computed value of the 'content' property on the ''::marker'' pseudo-element of the list item element is:
counter(list-item, decimal) "."
| Name: | list-style-position |
|---|---|
| Value: | inside | hanging | outside |
| Initial: | outside |
| Applies To: | all elements with ''display: list-item'' |
| Inherited: | yes |
| Media: | visual |
| Computed Value: | specified value |
This property specifies the position of the ''::marker'' pseudo-element's box in the list item. Values have the following meanings:
''hanging'' is meant to emulate what some browsers (IE8, Firefox, Opera) did for the CSS2.1 "outside" value, with somewhat more detail.
''outside'' is meant to emulate what other browsers (Webkit, IE9) did for the CSS2.1 "outside" value, again with more detail. There is a notable behavior change, in that the markers pay attention to the container's direction, not the list item. This arose from the "Requirements for bidi in HTML" group's conclusions - in a mixed-direction list, right now it's impossible to determine ahead of time which side of the container the gutter should go (to contain the bullet). You have to put a gutter on both sides, even if all the items are one direction, just in case.
I'm not sure exactly how to express what I want with the "out-of-flow" comment in ''hanging'' and ''outside''. I want to change how it's positioned, but without invoking the "positioned element" machinery. Is that good/possible? I also don't want to interfere with the author actually setting 'position' on ''::marker''. All this, and the ''::marker'' should still be a child of the list item in the box tree (otherwise the behavior is surprising).
How should I define "first line box" for ''hanging''? The marker is intended to be "magically positioned" - does this invoke the same logic that Positioned Layout defines, where it leaves behind an inline placeholder that will generate a line box? If not, do I descend into children to find the first linebox? If I do that, there's the possibility of conflict, if a list item contains a list item, and both of their markers position off of the same linebox. The consequences of this are well-defined, but is that okay? I get 3 different behaviors out of the 3 hanging-like browsers.
Note that a marker is only generated if the computed value of the 'content' property for the element's ''::marker'' pseudo-element is not ''inhibit''.
For example:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<HTML>
<HEAD>
<TITLE>Comparison of inside/outside position</TITLE>
<STYLE type="text/css">
UL { list-style: outside }
UL.compact { list-style: inside }
</STYLE>
</HEAD>
<BODY>
<UL>
<LI>first list item comes first</LI>
<LI>second list item comes second</LI>
</UL>
<HT>
<UL class="compact">
<LI>first list item comes first</LI>
<LI>second list item comes second</LI>
</UL>
</BODY>
</HTML>
The above example may be formatted as:

In right-to-left text, the markers would have been on the right side of the box.
| Name: | list-style |
|---|---|
| Value: | <'list-style-type'> || <'list-style-position'> || <'list-style-image'> |
| Initial: | N/A (shorthand property) |
| Applies To: | all elements with ''display: list-item'' |
| Media: | visual |
| Computed Value; | N/A (shorthand property) |
The 'list-style' property is a shorthand notation for setting the three properties 'list-style-type', 'list-style-image', and 'list-style-position' at the same place in the style sheet.
For example:
UL { list-style: upper-roman inside } /* Any UL */
UL > UL { list-style: circle outside } /* Any UL child of a UL */
Although authors may specify 'list-style' information directly on list item elements (e.g., LI in HTML), they should do so with care. The following rules look similar, but the first declares a descendant selector and the second a (more specific) child selector.
OL.alpha LI { list-style: lower-alpha } /* Any LI descendant of an OL */
OL.alpha > LI { list-style: lower-alpha } /* Any LI child of an OL */
Authors who use only the descendant selector may not achieve the results they expect. Consider the following rules:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<HTML>
<HEAD>
<TITLE>WARNING: Unexpected results due to cascade</TITLE>
<STYLE type="text/css">
OL.alpha LI { list-style: lower-alpha }
UL LI { list-style: disc }
</STYLE>
</HEAD>
<BODY>
<OL class="alpha">
<LI>level 1
<UL>
<LI>level 2</LI>
</UL>
</LI>
</OL>
</BODY>
</HTML>
The desired rendering would have level 1 list items with 'lower-alpha' labels and level 2 items with 'disc' labels. However, the cascading order will cause the first style rule (which includes specific class information) to mask the second. The following rules solve the problem by employing a child selector instead:
OL.alpha > LI { list-style: lower-alpha }
UL LI { list-style: disc }
Another solution would be to specify 'list-style' information only on the list type elements:
OL.alpha { list-style: lower-alpha }
UL { list-style: disc }
Inheritance will transfer the 'list-style' values from OL and UL elements to LI elements. This is the recommended way to specify list style information.
A URI value may be combined with any other value, as in:
UL { list-style: url("http://png.com/ellipse.png") disc }
In the example above, the 'disc' will be used when the image is unavailable.
A value of ''none'' for the 'list-style' property sets both 'list-style-type' and 'list-style-image' to ''none'', because it sets the 'list-style-type' to ''none'' (that is the first value in the list), and the initial value of the 'list-style-image' property, which isn't listed in that declaration, is ''none''. For this reason,
LI { list-style: none; }
will ensure that no list-item marker is displayed on LI elements, except if a value is explicitly given to the 'content' property of the ''::marker'' pseudo-element. In general, the best way to ensure that no marker is rendered is to not set the 'display' property to list-item.
Markers are created by setting an element's 'display' property to ''list-item''. The ''list-item'' display type is, in every other respect, identical to the ''block'' display type. The marker box is only created if the computed value of the 'content' property for the pseudo-element is not ''none''.
Just like other generated content, markers generate a box when they're created, which has margins, border, padding, and everything else a box normally has. Markers are placed at the beginning of their superior parent's content, immediately before a ''::before'' pseudo-element on the same superior parent. Marker boxes are inline-block by default, and so a value of ''auto'' for 'width' resolves to the width of the marker's content.
In the following example, the content is centered within a marker box of a fixed width. This document:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<HTML>
<HEAD>
<TITLE>Content alignment in the marker box</TITLE>
<STYLE type="text/css">
LI::marker {
content: "(" counter(counter) ")";
width: 6em;
text-align: center;
}
LI {
display: list-item;
counter-increment: counter;
}
</STYLE>
</HEAD>
<BODY>
<OL>
<LI> This is the first item. </LI>
<LI> This is the second item. </LI>
<LI> This is the third item. </LI>
</OL>
</BODY>
</HTML>
should produce something like this:
(1) This is the
first item.
(2) This is the
second item.
(3) This is the
third item.
The next example uses markers to number notes (paragraphs).
The following document:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN">
<HTML>
<HEAD>
<TITLE>Markers to create numbered notes4>/TITLE>
<STYLE type="text/css">
P { margin-left: 12 em; }
P.Note::marker {
content: url("note.gif") "Note " counter(note-counter) ":";
text-align: left;
width: 10em;
}
P.Note {
display: list-item;
counter-increment: note-counter;
}
</STYLE>
</HEAD>
<BODY>
<P>This is the first paragraph in this document.</P>
<P CLASS="Note">This is a very short document.</P>
<P>This is the end.</P>
</BODY>
</HTML>
should produce something like:
This is the first paragraph
in this document.
Note 1: This is a very short
document.
This is the end.
The following example illustrates how markers may be offset from their element. This HTML application and style sheet:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE>Marker example 5</TITLE>
<STYLE type="text/css">
P { margin-left: 8em } /* Make space for counters */
LI::marker { margin: 0 3em 0 0; content: counter(list-item, lower-roman) "."; }
LI { display: list-item }
</STYLE>
</HEAD>
<BODY>
<P> This is a long preceding paragraph ...</P>
<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 ...</P>
</BODY>
</HTML>
should produce something like this:
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 ...
(Note the use of the implicit counter increment.)
This module has two profiles: CSS Level 1 and Full. There is no CSS2 profile because this module is incompatible with the CSS2 list model.
The CSS Level 1 module consists of 'list-style', 'list-style-position', 'list-style-image', and 'list-style-type' (but only the following values: 'disc', 'circle, square', 'decimal', 'lower-roman', 'upper-roman', 'lower-alpha', 'upper-alpha', 'none'). It does not include the ::marker pseudo element.
The Full profile contains everything.
This section is informative, nor normative.
/* Set up list items */
li { display: list-item; /* counter-increment: list-item; (implied by display: list-item) */ }
/* Set up ol and ul so that they reset the list-item counter */
ol, ul { counter-reset: list-item; }
/* Default list style types for ordered lists */
ol { list-style-type: decimal; }
/* Default list style types for unordered lists up to 3 deep */
ul { list-style-type: disc; }
ul ul { list-style-type: square; }
ul ul ul { list-style-type: circle; }
/* The type attribute on ol and ul elements */
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; }
/* The start attribute on ol elements */
ol[start] { counter-reset: list-item attr(start, integer, 1); counter-increment: list-item -1; }
/* The value attribute on li elements */
li[value] { counter-reset: list-item attr(value, integer, 1); counter-increment: none; }
/* The above rules don't fully describe HTML4 lists, since they do not cover
behaviors such as margins and the like. The following rules could be used
for this purpose:
ol, ul { display: block; margin: 1em 0; padding-left: 2.5em; }
ol ol, ol ul, ul ul, ul ol { margin-top: 0; margin-bottom: 0; }
li::marker { margin-right: 1em; text-align: right; }
*/
Another example is required here.
The following people and documentation they wrote were very useful for defining the numbering systems: Alexander Savenkov, Aryeh Gregor, Frank Tang, Jonathan Rosenne, Karl Ove Hufthammer, Musheg Arakelyan, Nariné Renard Karapetyan, Randall Bart, Richard Ishida Simon Montagu
As described in the introduction section, there are significant changes in this module when compared to CSS2.