Title: CSS Pseudo-Elements Module Level 4
Shortname: css-pseudo
Level: 4
Status: ED
Work Status: Refining
Group: csswg
ED: https://drafts.csswg.org/css-pseudo-4/
TR: https://www.w3.org/TR/css-pseudo-4/
Previous Version: https://www.w3.org/TR/2020/WD-css-pseudo-4-20201231/
Previous Version: https://www.w3.org/TR/2019/WD-css-pseudo-4-20190225/
Previous Version: https://www.w3.org/TR/2016/WD-css-pseudo-4-20160607/
Previous Version: https://www.w3.org/TR/2015/WD-css-pseudo-4-20150115/
!Issues List: Tracked in Editor's Draft
Editor: Daniel Glazman, Disruptive Innovations, w3cid 13329
Editor: Elika J. Etemad / fantasai, Apple, http://fantasai.inkedblade.net/contact, w3cid 35400
Editor: Alan Stearns, Adobe Systems Inc., stearns@adobe.com, w3cid 46659
Abstract: This CSS module defines pseudo-elements, abstract elements that represent portions of the CSS render tree that can be selected and styled.
At Risk: the ''::prefix'' and ''::postfix'' sub-elements of ''::first-letter''
Ignored Terms: initial-letter, PseudoElement, pseudo(), selectors
Default Highlight: css
Indent: 2

Introduction

This section is informative. Pseudo-elements represent abstract elements of the document beyond those elements explicitly created by the document language. Since they are not restricted to fitting into the document tree, they can be used to select and style portions of the document that do not necessarily map to the document's tree structure. For instance, the ''::first-line'' pseudo-element can select content on the first formatted line of an element after text wrapping, allowing just that line to be styled differently from the rest of the paragraph. Each pseudo-element is associated with an originating element and has syntax of the form ''::name-of-pseudo''. This module defines the pseudo-elements that exist in CSS and how they can be styled. For more information on pseudo-elements in general, and on their syntax and interaction with other selectors, see [[!SELECTORS-4]].

Typographic Pseudo-elements

First-Line Text: the ''::first-line'' pseudo-element

The ::first-line [=pseudo-element=] represents the contents of the [=first formatted line=] of its [=originating element=].
The rule below means “change the letters of the first line of every p element to uppercase”:
p::first-line { text-transform: uppercase }
The selector ''p::first-line'' does not match any real document element. It instead matches a pseudo-element that the user agent will automatically insert at the beginning of every p element.
Note: Note that the length of the first line depends on a number of factors, including the width of the page, the font size, etc.
For example, given an ordinary HTML [[HTML5]] paragraph such as:
      <P>This is a somewhat long HTML paragraph
      that will be broken into several lines.
      The first line will be styled
      by the ‘::first-line’ pseudo-element.
      The other lines will be treated
      as ordinary lines in the paragraph.</P>
    
Depending on the width of the element, its lines might be broken as follows:
      THIS IS A SOMEWHAT LONG HTML PARAGRAPH THAT
      will be broken into several lines. The first
      line will be styled by the ‘::first-line’
      pseudo-element. The other lines will be 
      treated as ordinary lines in the paragraph.
    
or alternately as follows:
      THIS IS A SOMEWHAT LONG
      HTML paragraph that will
      be broken into several
      lines. The first line will
      be styled by the
      ‘::first-line’ pseudo-
      element. The other lines
      will be treated as ordinary
      lines in the paragraph.
    

Finding the First Formatted Line

In CSS, the ''::first-line'' pseudo-element can only have an effect when attached to a block container: * The first formatted line of a [=block container=] that establishes an [=inline formatting context=] represents the [=inline-level=] content of its first [=line box=]. * The [=first formatted line=] of a [=block container=] or [=multi-column container=] that contains [=block-level=] content (and is not a [=table wrapper box=]) is the [=first formatted line=] of its first [=in-flow=] [=block-level=] child. If no such line exists, it has no [=first formatted line=]. Note: The [=first formatted line=] can be an empty line. For example, the first line of the p in <p><br>First… doesn't contain any letters. Thus the word “First” is not on the first formatted line, and will not be affected by ''p::first-line''. Note: The first line of a [=block container=] that does not itself participate in a [=block formatting context=] cannot be the first formatted line of an ancestor element. Thus, in <DIV><P STYLE="display: inline-block">Hello<BR>Goodbye</P> etcetera</DIV> the first formatted line of the DIV is not the line “Hello”, but rather the line that contains that entire inline block. When a [=first formatted line=] is represented by multiple ''::first-line'' pseudo-elements, they are nested in the same order as their [=originating elements=]. The [=inline-level=] contents of this line-- including its [=root inline box=] fragment-- are nested within the innermost ''::first-line'' [=pseudo-element=].
Consider the following markup:
      <DIV>
        <P>First paragraph</P>
        <P>Second paragraph</P>
      </DIV>
    
If we assume a [=fictional tag sequence=] to represent the elements’ ''::first-line'' pseudo elements, it would be something like:
      <DIV>
        <P><DIV::first-line><P::first-line>First paragraph</P::first-line></DIV::first-line></P>
        <P><P::first-line>Second paragraph</P::first-line></P>
      </DIV>
    

Styling the ''::first-line'' Pseudo-element

The ''::first-line'' pseudo-element’s generated box behaves similar to that of an [=inline-level box=], but with certain restrictions. The following CSS properties apply to a ''::first-line'' pseudo-element: User agents may apply other properties as well except for the following excluded properties: Note: Setting 'line-height' on ''::first-line'' inherits to the fragment of the [=root inline box=] that wraps the contents of the first line, and therefore can both increase and decrease the height of the first line box.

Inheritance and the ''::first-line'' Pseudo-element

During CSS [=inheritance=], the [=box fragment|fragment=] of a child that occurs on the first line inherits any standard [=inherited properties=]-- except the properties excluded above-- from the ''::first-line'' pseudo-element. For all other properties, including all [=custom properties=] [[!CSS-VARIABLES-1]], inheritance is from the non-pseudo parent. (The portion of a child element that does not occur on the first line always inherits from the non-pseudo parent.)
In the common case (of standard inherited CSS properties), [=inheritance=] into and from a ''::first-line'' pseudo-element can be understood by writing out a fictional tag sequence to represent ''::first-line''. Consider the earlier example; in case of the first rendering, the fictional tag sequence would be:
      <P><p::first-line>This is a somewhat long HTML paragraph
      that</p::first-line> will be broken into several lines.
      The first line will be styled
      by the ‘::first-line’ pseudo-element.
      The other lines will be treated
      as ordinary lines in the paragraph.</p>
    
And in the case of the second rendering:
      <p><p::first-line>This is a somewhat long</p::first-line> HTML paragraph
      that will be broken into several lines.
      The first line will be styled
      by the ‘::first-line’ pseudo-element.
      The other lines will be treated
      as ordinary lines in the paragraph.</p>
    
If a pseudo-element breaks up a real element, the effect can often be described by a fictional tag sequence that closes and then re-opens the element. Suppose we mark up the earlier example with a span element encompassing the first sentence:
      <p><span>This is a somewhat long HTML paragraph
      that will be broken into several lines.</span>
      The first line will be styled
      by the ‘::first-line’ pseudo-element.
      The other lines will be treated
      as ordinary lines in the paragraph.</p>
    
The effect of the first rendering would be similar to the following [=fictional tag sequence=]:
      <p><p::first-line><span>This is a somewhat long HTML paragraph
      that</span></p::first-line><span> will be broken into several lines.</span>
      The first line will be styled
      by the ‘::first-line’ pseudo-element.
      The other lines will be treated
      as ordinary lines in the paragraph.</p>
    

First-Letter Text: ''::first-letter'' pseudo-element and its ''::prefix'' and ''::postfix'' children

A drop-cap initial letter, including the opening quotation mark before it.
The ::first-letter [=pseudo-element=] represents the first Letter, Number, or Symbol (Unicode category L*, N*, or S*) [=typographic character unit=] on the first formatted line of its originating element (the first letter) as well as its associated punctuation. Collectively, this text is the first-letter text. The ''::first-letter'' pseudo-element can be used to create “initial caps” and “drop caps”, which are common typographic effects.
For example, the following rule creates a 2-line drop-letter on every paragraph following a level-2 header, using the 'initial-letter' property defined in [[CSS-INLINE-3]]:
h2 + p::first-letter { initial-letter: 3; }
Note: The [=first letter=] may in fact be a digit, e.g., the “6” in “67 million dollars is a lot of money.” To allow independent styling of the [=first letter=] itself and its adjacent punctuation, associated preceding punctuation is represented by the ::prefix [=sub-pseudo-element=] of the ''::first-letter'' [=pseudo-element=] (''::first-letter::prefix''); and associated following punctuation is represented by the ::postfix [=sub-pseudo-element=] of the ''::first-letter'' [=pseudo-element=] (''::first-letter::postfix''). See [[#first-letter-pattern]], below.

First Letters and Associated Punctuation

As explained in [[CSS-TEXT-3#characters]], a typographic character unit can include more than one Unicode codepoint. For example, combining characters must be kept with their base character. Also, languages may have additional rules about how to treat certain letter combinations. In Dutch, for example, if the letter combination "ij" appears at the beginning of an element, both letters should be considered within the ''::first-letter'' pseudo-element. [[UAX29]] When selecting the [=first letter=], the UA should tailor its definition of typographic character unit to reflect the first-letter traditions of the ''::first-letter'' pseudo-element’s [=containing block=]’s [=content language=]. Preceding and following punctuation must also be included as part of the [=first-letter text=] in the ''::first-letter'' pseudo-element as follows:
Informally represented, the [=first-letter text=]’s pattern here can be roughly (ignoring the exclusion of word separators from Zs) represented as (P (Zs|P)*)? (L\|N\|S) ((Zs|P−(Ps|Pd))* (P−(Ps|Pd))? or, alternatively, ([P] [Zs P]*)? [L N S] ([Zs [P--[Ps Pd]]]* [P--[Ps Pd]])?
      Optional:
        Sequence:
          N: P
          ZeroOrMore:
            Choice:
              N: P
              N: Zs
      Choice:
        N: L
        N: N
        N: S
      Optional:
        Sequence:
          N: P − (Ps ∪ Pd)
          ZeroOrMore:
            Choice:
              N: P − (Ps ∪ Pd)
              N: Zs
    
See [[css-text-3#characters]] and [[css-text-3#character-properties]] for more information on [=typographic character units=] and their Unicode properties. [[!CSS-TEXT-3]]

Finding the First-Letter Text

As with ''::first-line'', the ''::first-letter'' pseudo-element can only have an effect when attached to a [=block container=]. Its [=first-letter text=] is the first such [=inline-level content=] participating in the [=inline formatting context=] of its [=originating element=]’s [=first formatted line=], if it is not preceded by any other in-flow content (such as images or inline tables) on its line. For this purpose, any [=marker boxes=] are ignored, as if they were out-of-flow. However, if an element has in-flow ''::before'' or ''::after'' content, the [=first-letter text=] is selected from the content of the element including that generated content.
Example: After the rule p::before {content: "Note: "}, the selector ''p::first-letter'' matches the "N" of "Note".
If no qualifying text exists, then there is no [=first-letter text=] and no ''::first-letter'' pseudo-element. Note: When the [=first formatted line=] is empty, ''::first-letter'' will not match anything. For example, in this HTML fragment: <p><br>First... the first line doesn't contain any letters, so ''::first-letter'' doesn't match anything. In particular, it does not match the “F” of “First”, which is on the second line. Note: As with ''::first-line'', the [=first-letter text=] of a [=block container=] that does not participate in a [=block formatting context=] cannot be the [=first-letter text=] of an ancestor element. Thus, in <DIV><P STYLE="display: inline-block">Hello<BR>Goodbye</P> etcetera</DIV> the [=first letter=] of the DIV is not the letter “H”. In fact, the DIV doesn't have a [=first letter=]. Any portion of the [=first-letter text=] that is wrapped to the next line no longer forms part of the ''::first-letter'' [=pseudo-element=].

Inheritance and Box Tree Structure of the First-Letter Pseudo-elements

The ''::first-letter'' pseudo-element is wrapped immediately around the [=first-letter text=] it represents, even if that text is in a descendant. When a [=first-letter text=] is represented by multiple ''::first-letter'' pseudo-elements, they are nested in the same order as their [=originating elements=]. [=Inheritance=] behaves accordingly.
Consider the following markup:
      <div>
        <p><span>The first few words</span>
        and the rest of the paragraph.
      </div>
    
If we assume a [=fictional tag sequence=] to represent the elements’ ''::first-letter'' pseudo-elements, it would be something like:
      <div>
        <p><span><div::first-letter><p::first-letter>T</…></…>he first few words</span>
        and the rest of the paragraph.
      </div>
    
If any ''::first-letter::prefix'' or ''::first-letter::postfix'' [=pseudo-elements=] exist, they are nested within the innermost ''::first-letter'', and otherwise interpreted similar to ''::first-letter'' itself.
Consider the following markup:
      <div>
        <p><span>“The first few words</span>
        and the rest of the quotation.
      </div>
    
If we assume a [=fictional tag sequence=] to represent the elements’ ''::first-letter'' pseudo-elements, it would be something like:
      <div>
        <p><span><div::first-letter><p::first-letter><div::first-letter::prefix><p::first-letter::prefix></…></…>T</…></…>he first few words</span>
        and the rest of the paragraph.
      </div>
    
If the characters that would form the [=first-letter text=] are not all in the same element (as the ‘T in <p>‘<em>T...), the user agent may create the ''::first-letter'' pseudo-element (and its ''::prefix'' or ''::postfix'' sub-elements, if any) from one of the elements, or all elements, or simply not create the pseudo-element(s). Additionally, if the [=first-letter text=] is not at the start of the line (for example due to bidirectional reordering, or due to a [=list item=] [=marker=] with ''list-style-position: inside''), then the user agent is not required to create the pseudo-element(s). A ''::first-letter'' pseudo-element is contained within any ''::first-line'' pseudo-elements, and thus inherits (potentially indirectly) from ''::first-line'', the same as any [=inline box=] on the same line.

Styling the First-Letter Pseudo-elements

In CSS a ''::first-letter'' [=pseudo-element=] (and its ''::prefix'' and ''::postfix'' sub-elements) is similar to an [=inline box=]. The following properties apply to ''::first-letter'', ''::first-letter::prefix'', and ''::first-letter::postfix'' pseudo-elements: User agents may apply other properties as well. However, in no case may the application of such unlisted properties to ''::first-letter'' change what [=first-letter text=] is represented by that ''::first-letter''. Note: In previous levels of CSS, user agents were allowed to choose a line height, width, and height based on the shape of the letter, to approximate font sizes; and to take the glyph outline into account when performing layout. The possibility of such loosely-defined magic has been intentionally removed, as it proved to be a poor solution for the intended use case (drop caps and raised caps), yet caused interoperability problems. See 'initial-letter' in [[CSS-INLINE-3]] for explicitly handling drop caps and raised caps.

Highlight Pseudo-elements

Selecting Highlighted Content: the ''::selection'', ''::target-text'', ''::spelling-error'', and ''::grammar-error'' pseudo-elements

The highlight pseudo-elements represent portions of a document that have been given a particular status and are typically styled differently to indicate that status to the user. For example, selected portions of the document are typically highlighted (given alternate background and foreground colors, or a color wash) to indicate their selected status. The following highlight pseudo-elements are defined:
::selection
The ''::selection'' pseudo-element represents the portion of a document that has been selected as the target or object of some possible future user-agent operation(s). It applies, for example, to selected text within an editable text field, which would be copied by a copy operation or replaced by a paste operation. css/css-pseudo/active-selection-001-manual.html css/css-pseudo/active-selection-002-manual.html css/css-pseudo/active-selection-004-manual.html css/css-pseudo/active-selection-011.html css/css-pseudo/active-selection-012.html css/css-pseudo/active-selection-014.html css/css-pseudo/active-selection-016.html css/css-pseudo/active-selection-018.html css/css-pseudo/active-selection-025.html css/css-pseudo/active-selection-027.html css/css-pseudo/active-selection-056.html css/css-pseudo/active-selection-057.html css/css-pseudo/active-selection-063.html css/css-pseudo/selection-contenteditable-011.html css/css-pseudo/selection-input-011.html css/css-pseudo/selection-textarea-011.html css/css-pseudo/textpath-selection-011.html
::target-text
The ''::target-text'' pseudo-element represents text directly targeted by the document URL’s [=url/fragment=], if any. Note: When a [=url/fragment|URL fragment=] targets an element, the '':target'' pseudo-element can be used to select it, but ''::target-text'' does not match anything. It only matches text that is itself targeted by the [[=url/fragment=]].
::spelling-error
The ''::spelling-error'' pseudo-element represents a portion of text that has been flagged by the user agent as misspelled. css/css-pseudo/spelling-error-001.html css/css-pseudo/spelling-error-002-manual.html css/css-pseudo/spelling-error-003-manual.html
::grammar-error
The ''::grammar-error'' pseudo-element represents a portion of text that has been flagged by the user agent as grammatically incorrect. css/css-pseudo/grammar-error-001.html css/css-pseudo/grammar-error-002-manual.html css/css-pseudo/grammar-error-003-manual.html
The highlight pseudo-elements do not necessarily fit into the element tree, and can arbitrarily cross element boundaries without honoring its nesting structure. Note: A future level of CSS may introduce ways to create custom highlight pseudo-elements.

Styling Highlights

The highlight pseudo-elements can only be styled by a limited set of properties that do not affect layout and can be applied performantly in a highly dynamic environment-- and additionally (to ensure interoperability) whose rendering within the [[#highlight-bounds|required area]] is not dependent on the exact (UA-determined) bounds of the [=highlight overlay=]. The following properties apply to the highlight pseudo-elements: The 'forced-color-adjust' property cannot be set on [=highlight pseudo-elements=]; however a [=highlight pseudo-element=] must honor any [=forced colors mode=] applied to its [=originating element=] (and is therefore subject to the control of the [=originating element=]’s 'forced-color-adjust' value). Issue: Are there any other properties that should be included here? Note: The 'color' property sets the color of both the text and all line decorations (underline, overline, line-through) and emphasis marks ('text-emphasis') applied to the text by the originating element and its ancestors and descendants. Note: Historically (and at the time of writing) only 'color' and 'background-color' have been interoperably supported.

Default UA Styles

The following additions are recommended for the default UA stylesheet:
    /* Represent default spelling/grammar error styling in an adjustable way */
    :root::spelling-error { text-decoration-line: spelling-error; }
    :root::grammar-error  { text-decoration-line: grammar-error; }
  
Some [=highlight pseudo-elements=] should have paired default highlight colors-- a default 'color' and 'background-color' provided by the UA that are either used or overridden together, see [[#paired-defaults]]. For ''::selection'' they should correspond to ''HighlightText'' and ''Highlight'', while for ''::target-text'' they should correspond to ''MarkText'' and ''Mark''. UAs may apply additional effects to enhance the presentation of highlighted content, for example dimming content other than the highlighted text or transitioning out a highlight style based on user interactions or timing. These are not controlled by CSS. ISSUE: UA tweaks to the presentation of highlights in ways that are controlled by CSS are currently under discussion in Issue 6853.

Paired Defaults

For compatibility reasons, [=paired default highlight colors=] must only be [=used value|used=] when neither 'color' nor 'background-color' yield a [=cascaded value=] from the [=author origin=] (or inherit their value from the author origin). When a highlight color is ''revert'' or ''revert-layer'', the origin after rolling back the cascade determines the [=cascaded value=]’s [=cascade origin|origin=]. Note: Because this rule is for compatibility reasons, it does not apply to other similar properties like 'fill-color' or 'stroke-color'.
For example, given the following markup:
      <p>Highlight this <em>and this</em>.</p>
    
Any of the following rules would suppress the default 'background-color' for ''::selection'' in the <em> element if given by the author:
      em::selection { color: initial; }
      em::selection { color: inherit; }
      em::selection { color: unset; }
      em::selection { color: green; }
      p::selection { color: green; }
    
css/css-pseudo/highlight-paired-cascade-001.html css/css-pseudo/highlight-paired-cascade-002.html css/css-pseudo/highlight-paired-cascade-003.html css/css-pseudo/highlight-paired-cascade-004.html css/css-pseudo/highlight-paired-cascade-005.html css/css-pseudo/highlight-paired-cascade-006.html

Area of a Highlight

For each type of highlighting (see [[#highlight-selectors]]) there exists a single highlight overlay for the entire document, the active portions of which are represented by the corresponding highlight pseudo-element. Each box owns the piece of the overlay corresponding to any text or replaced content directly contained by the box.

Issue: See F2F minutes, dbaron's message, Daniel's thread, Gecko notes, Opera notes, Webkit notes Issue: Not sure if this is the correct way of describing the way things work.

Cascading and Per-Element Highlight Styles

Each element draws its own active portions of the highlight overlays, which receives the styles specified by the corresponding highlight pseudo-element styles for which that element is the originating element. When multiple styles conflict, the winning style is determined by the cascade. When any supported property is not given a value by the cascade, or given a value of ''inherit'' or ''unset'', its [=specified value=] is determined by inheritance from the corresponding highlight pseudo-element of its originating element's parent element. This occurs regardless of whether that property is an inherited property (and regardless of whether that property is a [=custom property=] that is registered to [=CSS/inherit=] or not). Additionally, for [=highlight pseudo-elements=] originating from the [=root element=]: css/css-pseudo/active-selection-051.html css/css-pseudo/active-selection-052.html css/css-pseudo/active-selection-053.html css/css-pseudo/active-selection-054.html css/css-pseudo/cascade-highlight-004.html
For example, if the following rules were applied:
      p::selection      { color: yellow; background: green; }
      p > em::selection { color: orange; }
      em::selection     { color:    red; }
    
to the following markup:
      <p>Highlight this <em>and this</em>.</p>
    
The selection highlight would be green throughout, with yellow text outside the <em> element and orange text inside it.
css/css-pseudo/cascade-highlight-001.html

Authors wanting multiple selections styles should use '':root::selection'' for their document-wide selection style, since this will allow clean overriding in descendants. ''::selection'' alone applies to every element in the tree, overriding the more specific styles of any ancestors.

For example, if an author specified
      ::selection          { background: blue; }
      p.warning::selection { background:  red; }
    
and the document included
      <p class="warning">Some <strong>very important information</strong></p>
    
The highlight would be blue over “very important information” because the <strong> element´s ''::selection'' also matches the ''::selection { background: blue; }'' rule. (Remember that ''*'' is implied when a tag selector is missing.) The style rules that would give the intended behavior (red highlight within p.warning, blue elsewhere) are
      :root::selection     { background: blue; }
      p.warning::selection { background:  red; }
    
css/css-pseudo/cascade-highlight-002.html The following example demonstrates the inheritance of [=custom properties=].
For example, if an author specified
     :root {
        --background-color: green;
        --decoration-thickness: 10px;
        --decoration-color: purple;
      }
      ::selection {
        --decoration-thickness: 1px;
        --decoration-color: green;
      }
      div::selection {
        --decoration-color: blue;
        background-color: var(--background-color, red);
        text-decoration-line: underline;
        text-decoration-style: line;
        text-decoration-thickness: var(--decoration-thickness, 5px);
        text-decoration-color: var(--decoration-color, red);
      }
    
A div's selection highlight would be a green background to the selected content, with a 1px thick blue underline. The ''--background-color'' custom property is not found on the ''div::selection'' nor ''::selection'' so it is taken from the ''::root'' custom property match. The ''--decoration-thickness'' property is inherited from ''::selection'' via the highlight cascade and ''--decoration-color'' is found in ''div::selection'' itself.
Note: This behavior is intended to accomodate the standard practice of defining document-wide custom properties on '':root''.

Painting the Highlight

css/css-pseudo/active-selection-014.html css/css-pseudo/active-selection-041.html css/css-pseudo/active-selection-045.html css/css-pseudo/highlight-painting-001.html css/css-pseudo/highlight-painting-002.html css/css-pseudo/highlight-painting-003.html css/css-pseudo/highlight-painting-004.html

Backgrounds

Each highlight pseudo-element draws its background over the corresponding portion of the highlight overlay, painting it immediately below any positioned descendants (i.e. just before step 8 in CSS2.2§E.2). The ''::selection'' overlay is drawn over the ''::target-text'' overlay which is drawn over the ''::spelling-error'' overlay which is drawn over the ''::grammar-error'' overlay. css/css-pseudo/selection-overlay-and-grammar-001.html css/css-pseudo/selection-overlay-and-spelling-001.html css/css-pseudo/highlight-z-index-001.html css/css-pseudo/highlight-z-index-002.html css/css-pseudo/selection-background-painting-order.html

Shadows

Any 'text-shadow' applying to a [=highlight pseudo-element=] is drawn over its corresponding [=highlight overlay=] background. Such text shadows also stack over each other (and over any original 'text-shadow' applied to the text and its decorations, which continues to apply). Note: Since each [=highlight overlay=] background is drawn over any shadows belonging to the layer(s) below, a [=highlight overlay=] background can obscure lower-level shadows.

Text and Text Decorations

A highlight pseudo-element suppresses the normal drawing of any associated text, and the text decorations (other than shadows) that had been applied to that text. Instead the topmost active highlight overlay redraws that text (and those decorations) over all the highlight overlay backgrounds using that highlight’s own 'color'. Note: This means that unlike shadows, line decorations and emphasis marks won’t be obscured by any highlight overlay backgrounds that are drawn for the associated text. For this purpose, ''currentColor'' on a [=highlight pseudo-element=]’s 'color' property represents the 'color' of the next active highlight pseudo-element layer below, falling back finally to the colors that would otherwise have been used (those applied by the [=originating element=] or an intervening [=pseudo-element=] such as ''::first-line'' or ''::first-letter''). Note: The element’s own text decorations (both line decorations and emphasis marks) are thus drawn in the pseudo-element’s own 'color' when that is not ''currentColor'', regardless of their original color or fill specifications. Any text decorations introduced by each highlight pseudo-element are stacked in the same order as their backgrounds over the text’s original decorations and are all drawn, each decoration in its own color. The normal painting order applies, so as per CSS2 Appendix E, all underlines are drawn below overlines which are drawn below the text which is drawn below any line-throughs. However, text decorations applied by ''::selection'' may instead all be drawn along with the text as a topmost set of layers above all other decorations.
For example, assuming the original text has an underline and a strike-through, that ''::selection'' applies an underline and ''::target-text'' applies both overline and strike-through, the following are both conformant painting orders:
  1. original underline
  2. ''::selection'' underline
  3. ''::target-text'' overline
  4. ''::selection''-colored text
  5. original strike-through
  6. ''::target-text'' strike-through
  1. original underline
  2. ''::target-text'' overline
  3. original strike-through
  4. ''::target-text'' strike-through
  5. ''::selection'' underline
  6. ''::selection''-colored text
Line decorations introduced by [=highlight pseudo-elements=] apply only to the text associated with their [=originating element=], and are not propagated to descendants except via property [=inheritance=] (as described [[#highlight-cascade|above]]). Note: Unlike the originating element’s own decorations, decorations declared on a highlight pseudo-element propagate to [=out-of-flow|out-of-flow elements=] and [=inline blocks=], with thickness and position varying between descendants. css/css-pseudo/selection-originating-underline-order.html css/css-pseudo/selection-originating-decoration-color.html css/css-pseudo/selection-originating-strikethrough-order.html

Replaced Elements

For non-replaced content, the UA must honor the 'color' and 'background-color' (including their alpha channels) as specified. However, for replaced content, the UA should create a semi-transparent wash to coat the content so that it can show through the selection. This wash should be of the specified 'background-color' if that is not ''transparent'', else of the specified 'color'; however the UA may adjust the alpha channel. css/css-pseudo/selection-paint-image.html

Security and Privacy Considerations

Because the styling of spelling and grammar errors can leak information about the contents of a user's dictionary (which can include the user's name and even includes the contents of their address book!) UAs that implement ''::spelling-error'' and ''::grammar-error'' must prevent pages from being able to read the styling of such highlighted segments.

Tree-Abiding Pseudo-elements

Tree-abiding pseudo-elements always fit within the box tree. They inherit any inheritable properties from their originating element; non-inheritable properties take their initial values as usual. [[CSS-CASCADE-4]]

Generated Content Pseudo-elements: ''::before'' and ''::after''

When their computed 'content' value is not ''content/none'', these pseudo-elements generate boxes as if they were immediate children of their originating element, with content as specified by 'content'.
::before
Represents a styleable child pseudo-element immediately before the originating element's actual content.
::after
Represents a styleable child pseudo-element immediately after the originating element's actual content.
These pseudo-elements can be styled exactly like any normal document-sourced element in the document tree; all properties that apply to a normal element likewise apply to ''::before'' and ''::after''.
For example, the following rule inserts the string “Note: ” before the content of every <p> element whose class attribute has the value note:
p.note::before { content: "Note: " }
Since the initial value of 'display' is ''display/inline'', this will generate an inline box. Like other inline children of <p>, it will participate in <p>’s inline formatting context, potentially sharing a line with other content.
As with the content of regular elements, the generated content of ''::before'' and '':after'' pseudo-elements can form part of any ''::first-line'' and ''::first-letter'' pseudo-elements applied to its originating element. Also as with regular child elements, the ''::before'' and ''::after'' pseudo-elements are suppressed when their parent, the [=originating element=], is [=replaced element|replaced=].

List Markers: the ''::marker'' pseudo-element

The ::marker pseudo-element represents the automatically generated [=marker box=] of a [=list item=]. (See [[CSS-DISPLAY-3]] and [[CSS-LISTS-3]].) The contents of a ''::marker'' are ignored (not selected) by ''::first-letter''. ISSUE: Interaction of ''::marker'' and ''::first-line'' is currently under discussion in Issue 4506. Only a limited set of properties can be used on the ''::marker'' pseudo-element. This list is defined in [[css-lists-3#marker-properties]]. The ''::before::marker'' or ''::after::marker'' selectors are valid and can be used to represent the [=marker boxes=] of ''::before'' or ''::after'' pseudo-elements that happen to be [=list items=]. However ''::marker::marker'' is invalid, and the computed value of 'display' on ''::marker'' always loses any ''display/list-item'' aspect. ISSUE: Should ''::marker'' also have ''::prefix'' and ''::postfix'' sub-elements?

Placeholder Input: the ''::placeholder'' pseudo-element

The ::placeholder pseudo-element represents placeholder text in an input field: text that represents the input and provides a hint to the user on how to fill out the form. For example, a date-input field might have the placeholder text “YYYY/MM/DD” to clarify that numeric dates are to be entered in year-month-day order.
For example, according to the semantics of [[HTML]] the <{input/placeholder}> attribute on the <{input}> and <{textarea}> elements provide placeholder text. The ''::placeholder'' [=pseudo-element=] represents such text when it is displayed.
Note: There also exists a '':placeholder-shown'' pseudo-class, which applies to (real) elements while they are showing placeholder text, and can be used to style such elements specially. ''::placeholder'' specifically represents the placeholder text, and is thus relatively limited in its abilities. All properties that apply to the ''::first-line'' pseudo-element also apply to the ''::placeholder'' pseudo-element. ISSUE(5379): Should [[CSS-INLINE-3]] properties be excluded? In interactive media, placeholder text is often hidden once the user has entered input; however this is not a requirement, and both the input value and the placeholder text may be visible simultaneously. The exact behavior is UA-defined. Note that in static media (such as print) placeholder text will be present even after the user has entered input. Issue: Authors seem to want 'text-align' on the list of supported properties. See e.g. comments here. Note: It's been requested that ''::placeholder'' also refer to a placeholder which has a corresponding element in the element tree. It's not clear how this should work, but it may be worth doing. See Issue 2417.

File Selector Button: the ''::file-selector-button'' pseudo-element

The ::file-selector-button pseudo-element targets the ''<button>'' inside an ''<input>'' element with type=file, if the UA renders such a button. There is no restriction on which properties apply to the ''::file-selector-button'' pseudo-element.
For example, the following example should show a green border around the file selector button:
::file-selector-button { border: 3px solid green }

Overlapping Pseudo-element Interactions

Recall that The following CSS and HTML example illustrates how overlapping pseudo-elements interact: <style> p { color: red; font-size: 12pt } p::first-letter { color: green; font-size: 200% } p::first-line { color: blue } </style> <p>Some text that ends up on two lines</p> The first letter of each P element will be green with a font size of ’24pt'. The rest of the first formatted line will be blue while the rest of the paragraph will be red. Assuming that a line break will occur before the word "ends", the fictional tag sequence for this fragment might be: <p> <p::first-line> <p::first-letter> S </p::first-letter> ome text that </p::first-line> ends up on two lines </p>

Additions to the CSS Object Model

{{CSSPseudoElement}} Interface

The {{CSSPseudoElement}} interface allows pseudo-elements to be event targets.
    [Exposed=Window]
    interface CSSPseudoElement : EventTarget {
        readonly attribute CSSOMString type;
        readonly attribute Element element;
        readonly attribute (Element or CSSPseudoElement) parent;
        CSSPseudoElement? pseudo(CSSOMString type);
    };
  
ISSUE: This interface is under design development, and this draft is looking for feedback more than implementation. The CSSWG would particularly appreciate hearing about use cases and problems. The type attribute is a string representing the type of the pseudo-element. This can be one of the following values:
"::before"
Represents the ''::before'' pseudo-element.
"::after"
Represents the ''::after'' pseudo-element.
"::marker"
Represents the ''::marker'' pseudo-element.
The element attribute is the [=ultimate originating element=] of the [=pseudo-element=]. The parent attribute is the [=originating element=] of the pseudo-element. For most pseudo-elements {{CSSPseudoElement/parent}} and {{CSSPseudoElement/element}} will return the same {{Element}}; for [=sub-pseudo-elements=], {{CSSPseudoElement/parent}} will return a {{CSSPseudoElement}} while {{CSSPseudoElement/element}} returns an {{Element}}. The pseudo(type) method returns the {{CSSPseudoElement}} interface representing the [=sub-pseudo-element=] referenced in its argument, if such a [=sub-pseudo-element=] could exist and would be valid, and null otherwise. See {{Element/pseudo()}} below. Note: This interface may be extended in the future to other pseudo-element types and/or to allow setting style information through a {{CSSStyleDeclaration}} style attribute. The current functionality is limited to that which is needed to support [[web-animations-1]].

{{pseudo()}} method of the {{Element}} interface

A new method is added to the {{Element}} interface to retrieve pseudo-elements created by a given element for a given type:
    partial interface Element {
      CSSPseudoElement? pseudo(CSSOMString type);
    };
  
The pseudo(CSSOMString type) method is used to retrieve the {{CSSPseudoElement}} instance of the type matching {{Element/pseudo(type)/type!!argument}} associated with the element. When it is called, execute the following steps: 1. [=CSS/Parse=] the {{Element/pseudo(type)/type!!argument}} argument as a <>, and let |type| be the result. 2. If |type| is failure, return null. 3. Otherwise, return the {{CSSPseudoElement}} object representing the pseudo-element that would match the selector |type| with [=this=] as its [=originating element=].
Return values that represent the same [=pseudo-element=] on the same [=originating element=] must be, insofar as observable, always the same {{CSSPseudoElement}} object. (The UA may drop or regenerate the object for convenience or performance if this is not observable.) ISSUE: The identity, lifetime, and nullness of the return value (and potential error cases) of the {{pseudo()}} method is still under discussion. See Issue 3607 and Issue 3603.

{{Window/getComputedStyle()}}

When the second parameter pseudoElt refers to a [=highlight pseudo-element=], {{Window/getComputedStyle()}} returns styles as if that highlight is active and all other highlights are inactive. This avoids the potential ambiguity and privacy risks of returning a result that depends on the actual highlight state.

Compatibility Syntax

For compatibility with existing style sheets written against CSS Level 2 [[CSS2]], user agents must also accept the previous one-colon notation (:before, :after, :first-letter, :first-line) for the ''::before'', ''::after'', ''::first-letter'', and ''::first-line'' pseudo-elements.

Changes

Significant changes since the 31 December 2020 Working Draft include: Significant changes since the 25 February 2019 Working Draft include: Changes since the 7 June 2016 Working Draft include:

Acknowledgements

The editors would like to specifically thank the following individuals for their contributions to this specification: Tab Atkins, David Baron, Oriol Brufau, Razvan Caliman, Chris Coyier, Anders Grimsrud, Vincent Hardy, François Remy.