Tutorials Bugs Masterclass Free stuff Test pages Proposals

Basic concepts

Advanced concepts

RichInStyle.com CSS2 tutorial - Generated content

Contents

Introduction to generated content

The :before and :after pseudo-elements

Valid values for display on :before and :after

Compact elements with generated content

Counter functions

Naming counter functions

Incrementing counter functions

Initial values and counter resets

The effect of descendant elements on counter resets

Counter styles

Content

Quotes

Markers

Height and alignment of marker boxes

Inheritance into marker boxes

List items as markers

Marker-offset

Generated content

There are three principal types of content; firstly, replaced content, secondly non-replaced content, and thirdly non-replaced content. Here is an illustration of each in HTML.

<P>
Some non-replaced content - directly used
</P>

<IMG src="green.gif"> <!-- Some replaced content - the IMG reference is replaced by an image. -->

<LI>
Some non-replaced content that will be preceded by some generated content - the list marker.
</LI>

Generated content thus includes such things as list item markers in HTML. HTML only includes very basic generated content, but CSS provides a much richer array of properties to specify generated content.

:Before and :after pseudo-elements

Typically, generated content consists of putting a piece of content before or after an element (e.g., a list marker before a list item). To cater for this, CSS provides the :before and :after pseudo-elements. For example, P:before {content: "J"} specifies that P elements should be preceded by a J.

In addition to specifying the content that precedes or follows an element, the :before and :after selectors are also used to specify the formatting of that content; for example, P:before {content: "J"; color: red} would make the 'J' before the element red.

It should be noted that for the purposes of first line and first letter, before is assumed to be the start of the element.

Note that :before and :after inherit style from the element itself so if the element is red then its generated content will also be read.

Subsequent elements consider generated content to be part of the element. Thus:

<P>
The <SPAN></SPAN> sat on the log.
</P>
SPAN:after {content: "dog"}

Would be rendered in exactly the same way as:

<P>
The dog sat on the log.
</P>

Valid values for display on :before and :after

If the element to which :before or :after is applied is a block-level (i.e., table, list-item, compact, run-in or block) element, display may be set to none, inline, block, or marker. Any other value for display will be reset to block.

Inline elements may only have display set to none or inline, with other values reset to inline.

Compact elements with generated content

  1. A compact element that has an inline :before or :after takes it into account when the size of the element's box is considered, and it is included in the same block box as the element.

    DIV:after {display: inline;
    /* Assuming a width of 30% */}
    DIV {display: compact;
    /* Assuming a width of 30% */}
    P {margin-left: 50%}
    <DIV>
    </DIV>
    <P>

    In this example, the DIV has a width of 60%, and therefore cannot fit

  2. A compact element that has a block :before pseudo-element has the pseudo-element formatted as a block above the element.

    DIV:before {display: block;
    width: 30%}
    DIV {display: compact;
    /* Assuming a width of 30% */}
    P {margin-left: 50%}
    <DIV>
    </DIV>
    <P>

    In this example, the DIV has a width of 30%, and therefore fits.

  3. A compact element that has an block :after pseudo-element has the two elements formatted as separate block elements.

    DIV:after {display: block;
    width: 30%}
    DIV {display: compact;
    /* Assuming a width of 30% */}
    P {margin-left: 50%}
    <DIV>
    </DIV>
    <P>

    In this example, the DIV has a width of 30%, and therefore fits.

  4. Where an element following a compact element has a block :before, the compact element considers the :before pseudo-element.

    DIV {display: compact;
    /* Assuming a width of 30% */}
    P:before {display: block;
    margin-left: 50%}
    <DIV>
    </DIV>
    <P>

    In this example, the DIV has a width of 30%, and therefore fits.

  5. Where an element following a compact element has an inline :before, the formatting of the compact element depends on display of the element to which the :before is attached.

    DIV {display: compact;
    /* Assuming a width of 30% */}
    P:before {content: url(green.gif);
    display: inline;
    width: 30%}
    P {margin-left: 50%}
    <DIV>
    </DIV>
    <P>

    In this example, since the :before content is inline, it is positioned inside the P, and there is therefore enough room for the DIV.

Counter functions

Although we have already seen that CSS can generate content that is always the same, it also provides the ability for counter functions. Essentially these are the same as list items except they allow for more advanced numbering schemes.

There are basically five issues relating to counters:

  1. The name of the counter function - used to identify the counter so that references can be made to it.
  2. The increment of the counter - is it 1, 2, 3 or 1, 7, 13?
  3. The initial value of the counter - is it 1, 2, 3 or 126, 127, 128?
  4. The trigger to reset the counter to its initial value.
  5. The way in which the counter is formatted - is it 1, 2, 3 or i, ii, iii?

1. Naming counter functions

In order to refer to counter functions, you specify something like P {content: counter(myCounter)}. Note that counter names are, as with all CSS, case-insensitive.

2. Incrementing counter functions

In order to specify the increment of a counter function, you use the counter-increment property. This property specifies the increment of a counter on encountering an instance of an element. The initial value is 'none', so initially no element increments a counter.

To specify an increment, you declare the name of the counter function followed by the increment (which can be any integer). For example, H1 {counter-increment: HeadingCounter 1}. If the increment is omitted, 1 is assumed, so H1 {counter-increment: HeadingCounter} is also valid.

If you wish to specify that an element should increment more than one counter function, simply separate them with spaces. For example, H1 {counter-increment: HeadingCounter 10 HeadingCounter2}.

Counter-increment is not inherited. It applies to all elements.

Note that counter values are used after any increment specified for that element.

3. Initial values and counter resets

To specify the element that resets a counter function, the counter-reset property is used.

It follows an identical syntax to counter-increment. It is used to reset the given counter to the given number (if a number is omitted, 0 is assumed).

Counter-reset is not inherited. Its initial value is 'none'. It applies to all elements.

Here's an example: H1 {counter-reset: counter1 counter2 -26} (this would reset counter1 to 0 and counter2 to -26).

Like counter-increment, counter-reset may only be set to integer values.

Note that counter values are used after any reset specified for that element, and that counters are incremented after they have been reset. Thus H1:before {counter-reset: counter; counter-increment: counter; content: counter(counter)} would result in 1 since it would first be reset, then incremented, and then finally used.

The effect of descendant elements on counter-reset

Counter-reset only affects sibling and descendant elements. For example:

OL {counter-reset: licounter}
LI {content: counter(licounter);
counter-increment: licounter}

<OL> - licounter reset to 0
<LI> - licounter incremented to 1
<LI> - licounter incremented to 2
<LI> - licounter incremented to 3
<LI> - licounter incremented to 4
<OL> - licounter reset to 0, but since counter-reset only affects siblings and descendants, this won't affect the old counter
<LI> - licounter incremented to 1
</OL>
<LI> - licounter incremented to 5
</OL>

4. Counter styles

Once you have a counter function, you will probably want to style it. This is done using counter(). For example, P:before {content: counter(counter, lower-alpha); counter-increment: counter} with <P>Hello <P>Hello would be rendered as:

aHello

bHello

Thus the counter function can be followed by a list style type, which will convert the integer into a value. Thus if the counter function was running at 26, z would be rendered. If the list type is unordered, it will always result in the same thing - content: counter(counter, disc) would always result in a disc.

content

This property is used in conjunction with the :before and :after pseudo-elements to provide generated content.

In its simplest form, content is a string; e.g., :before {content: "Hello"}, which would cause Hello to appear before every element.

However, the content can also be set to a keyword, such as open-quote.

Valid values are (one or more of each)

  1. a string of text enclosed within quote marks (such as content: "My text")
  2. an external resource, designated by url(resourcename.type), e.g., content: url(green.gif)
  3. a counter function, e.g., content: counter(counterfunct, decimal)
  4. a compound counter function. Compound counter functions are used for situations like this:

    1.

      1.1
      1.2

    They take the following form - content: counters(mycounter, "string", type) or content: counters(mycounter, "string"). Essentially, the number used is the level of the counter - in

    <OL>
    <LI>
    <OL>
    <LI>
    <OL>
    <LI>
    </OL>
    </OL>
    </OL>

    , the result would be 1 for the outermost, 1.1 for the next one in, and 1.1.1 for the next one in from that (given content: counters(mycounter, ".")).

  5. attr(x), where x is the name of the attribute (such as title in <IMG title="A picture of my zucchini">; attr(title) would return "A picture of ...")
  6. open-quote
  7. close-quote
  8. no-open-quote
  9. no-close-quote

Its initial value is "", and it applies only to :before and :after. It is not inherited.

You can specify several items of content. For example, content: "(" counter(counterfunction, lower-alpha) ".) " would result in (a.) , (b.) , (c.) , etc.

The open-quote are used to specify that the language-appropriate quotation mark should be inserted. For example, Q:before {content: open-quote} Q:after {content: close-quote}. The appropriate quotation mark can be set using the quotes property. Since this allows different levels of quotes (e.g., She said, "He was so rude - he said, 'Go away'"), the purpose of no-open-quote and no-close-quote is to decrement or increment the quote level without actually inserting quotes.

For example:

BLOCKQUOTE P:before {content: open-quote}
BLOCKQUOTE P:after {content: no-close-quote}
BLOCKQUOTE P.last:after {content: close-quote}

Given:

<BLOCKQUOTE>
<P>
Some text from a quote.
<P>
Another paragraph from a quote.
<P class="last">
The final paragraph from a quote.
</BLOCKQUOTE>

Would result in:

'Some text from a quote.
'Another paragraph from a quote.
'The final paragraph from a quote.'

Initially, content is "". It is not inherited.

Quotes

This property instructs the web browser on the appropriate method of displaying the aforementioned open-quote and close-quote, and can take one of the following values: none (don't render open-quote and close-quote); one or more sets of quotation marks, where the first quote mark is the opening quote mark, the second the closing quote mark; if more than one set of quotes is specified, the first set applies to the first set of open quote marks, the second to the second set, etc. The initial value is browser dependent. Quotes is inherited.

For example:

Q {quotes: '"' '"' "'" "'" }

Q:before {content: open-quote}
Q:after {content: close-quote}

Markers

Markers are used to create effects such as:

  1. A list item
  2. A list item

Without them, you could only do something like.

9. A list item
10. A list item

Thus they allow you to line text up correctly. They are specified using display: marker, and are only valid in association with the :before and :after pseudo-elements.

In order to this, marker boxes are placed outside the border edge of an element (i.e., in the element's margin). This means that BODY, LI, OL {margin: 0} would result in the marker boxes being pushed off the left of the canvas.

Marker boxes may not have margins, but they may have padding and borders.

For example:

OL {margin: 0;
background: red;
counter-reset: counterfunc}
LI {margin-left: 5%;
background: green}
LI:before {display: marker;
marker-offset: auto
content: counter(counterfunc);
counter-increment: counterfunc}

Results in a green background for the content of the LI, and red for the marker, since the marker is placed in LI's margin.

Only block-level elements may have display: marker. Block-level elements are tables, list-items, block, compact and run-in elements.

Note that when list items have :before set to display, display is set to block.

Height and alignment of marker boxes

The height of marker boxes is determined by line-height, and the marker box is taken into consideration for the purposes of calculating the height of the line box with which it is aligned in the principal box.

If applied on :before, the baseline of the marker is aligned with the baseline of the first line of content in the principal box. If there is no such content in the principal box, the top of the marker is aligned with the top of the principal box.

If applied on :after, the baseline of the marker is aligned with the baseline of the last line of content in the principal box. If there is no such content in the principal box, the bottom of the marker is aligned with the bottom of the principal box.

Inheritance into marker boxes

As with other pseudo-elements, marker box inherit inheritable style; for example, given:

ELEMENT {color: red;
background: green}
ELEMENT:before {display: marker}

, the marker box would have red text; it would not have a green background, because backgrounds are not inherited.

List items as markers

Note that list items as specified via the LI element are markers - when you set ELEMENT {display: list-item}, you are effectively setting ELEMENT {display: block} ELEMENT:before {display: marker; content: counter(function); counter-increment: function}.

As a result, elements with display: list-item must have margins in which to place the counter.

In addition, given LI {background: red}, the marker box will not be red since background is not inherited. To see whether this is correctly followed in your browser, have a look at this:

  1. A list item

Marker-offset

This property specifies the distance between the border edge of the marker box and the border edge of the thing that it is marking to be specified.

It can be specified as a length (including negative lengths) or as auto but not a %. It is not inherited and is intially auto (= UA defined).

The next section deals with dynamic effects.