CSS Selectors

A selection of CSS selectors mapped to DOM elements. Source: CSS Solid 2020.
A selection of CSS selectors mapped to DOM elements. Source: CSS Solid 2020.

Cascading Style Sheets (CSS) are commonly used to style web content. To style a particular element on a HTML/XHTML page, we have to first select the element. This is done using CSS Selectors. A selector essentially selects or targets one or more elements for styling.

CSS3 specifications standardized by W3C defines a wide variety of selectors. A selector can target a single specific element or target multiple elements. In a good web design, CSS selectors are written to balance clarity, portability, stylesheet size, ease of update, and performance.

Discussion

  • Which are the commonly used CSS selectors?

    A web page is essentially a set of HTML/XHTML tags organized into a hierarchy. It's common to mark elements with identifiers and/or class names. It's therefore common to use the following as CSS selectors:

    • By Tag Name: For instance, a paragraph can be selected with p, such as in p { color: #444; } .
    • By Identifier: An HTML element can have the id attribute that must be unique across the document. Thus, identifier can be used to target a specific element. For example, given the HTML snippet <div id="footer"></div>, the relevant selector is #footer.
    • By Class Name: The class attribute is also common for HTML elements. An element can have one or more classes. Multiple elements can belong to a class. By using a class-based CSS selector, we can target multiple elements. For example, given the HTML snippet <span class="pincode"></span>, the relevant selector is .pincode.

    The above three selector syntaxes can be combined into a single selector. Suppose we wish to target list items of class icon inside the footer, we can write #footer li.icon.

  • How can HTML attributes be used in CSS selectors?
    CSS selectors that use HTML element attributes. Source: Adapted from MDN Web Docs 2020a.
    CSS selectors that use HTML element attributes. Source: Adapted from MDN Web Docs 2020a.

    HTML elements can have attributes and these can be used in CSS selectors. The simplest syntax is to select by presence of the attribute. For example, a[title] targets all anchor elements with title attribute. A more refined selection is to match the value of the attribute. This comes in three variants (also explained in the figure):

    • [attr=value]: exact match: div[class="alert"] will match <div class="alert"></div> but not <div class="alert-info"></div>.
    • [attr~=value]: word match: div[class~="alert"] will match <div class="alert-info alert"></div> but not <div class="alert-info"></div>.
    • [attr|=value]: exact or with hyphen match: div[class|="alert"] will match <div class="alert"></div>, <div class="alert-info"></div> and <div class="alert-info alert"></div> but not <div class="alertinfo"></div> or <div class="alert alert-info"></div>.

    It's possible to match substrings of attribute values. These take the form [attr^=value], [attr$=value] and [attr*=value] to match start, end and any part of the value string respectively.

    HTML element names and attribute names are case insensitive but attribute values are case sensitive. To match value strings in a case-insensitive manner, include the i flag. For example, div[class="alert"] will not match <div class="Alert"></div> but div[class="alert" i] will.

  • What's the difference between pseudo-classes and pseudo-elements?

    Pseudo-classes and pseudo-elements give additional capability to CSS selectors. Neither appears in the document source nor modifies the document tree.

    Pseudo-classes are applied to elements due to their position (eg. last child) or state (eg. read only). Elements can gain or lose pseudo-classes as the user interacts with the document. The syntax is :, such as in :enabled, :hover, :visited, :read-only, :last-child, or :nth-of-type().

    Whereas pseudo-classes represent additional information about an element, pseudo-elements represent elements not explicitly present in the document tree. A pseudo-element is always bound to another element (called originating element) in the document. It can't exist independently. The syntax is ::, such as in ::before, ::after, ::placeholder, ::first-line, or ::first-letter.

    In CSS1 and CSS2, both pseudo-classes and pseudo-elements used single colon syntax for ::before, ::after, ::first-line, and ::first-letter. Thus, browsers today accept either syntax for these special cases.

    Where user actions are involved, the two can be combined. For example, ::first-line:hover matches if the first line is hovered whereas :hover::first-line matches the first line of any originating element (such as second line of the paragraph) that's hovered.

  • Which are the CSS selectors for targeting descendants of an element?
    Examples for selecting descendants in CSS. Source: Adapted from Jeon 2019.
    Examples for selecting descendants in CSS. Source: Adapted from Jeon 2019.

    To select descendants use multiple selectors separated by spaces. For example, p a targets all links within paragraphs; links outside paragraphs are not selected. Selector .agenda ul a targets all links within unordered lists within elements of agenda class.

    A more restrictive syntax selects only immediate children of an element, not grandchildren, great-grandchildren, etc. For example, ul > a is incorrect since children of ul are li elements. The correct selector would be ul > li > a. Another example is a list containing other lists. Selector ul > li selects only first level list items whereas ul li selects list items at every nested level.

    Pseudo-classes provide further control for child selection. Some of these are :first-child, :last-child, :only-child, :nth-child, and :nth-last-child (nth child from the end). Children are one-indexed. To target every third list item from fourth item, use ul > li:nth-child(3n+4). To target exactly the fourth item, use ul > li:nth-child(4). To target the last but one item, use ul > li:nth-last-child(2). To target last three items, use ul > li:nth-child(-n+3)

  • Which are the CSS selectors for targeting siblings of an element?
    Examples for selecting siblings in CSS. Source: Devopedia 2020.
    Examples for selecting siblings in CSS. Source: Devopedia 2020.

    Assume a DOM structure in which elements h1 p p ul p are all children of the same parent and therefore siblings in that order. CSS has two ways to select siblings by combining two selectors:

    • Adjacent Sibling: For example, h1 + p means that we target p if it's the immediate sibling following h1. Though ul is a sibling of h1, it's not the immediate sibling. Hence, h1 + ul will not select ul.
    • General Sibling: For example, h1 ~ p will select all three p elements that are all siblings of h1. The selector p ~ h1 will not select h1 because the way CSS works, we're targeting h1 siblings that follow a p element.

    Combinator + targets only one sibling whereas ~ targets multiple siblings. With ~, it's possible to obtain a specific sibling by using pseudo-classes such as :first-of-type, :last-of-type, :nth-of-type() or :nth-last-of-type(). For example, h1 ~ p:nth-last-of-type(2) will select the second last p sibling of h1.

  • What are quantity selectors in CSS?
    Illustrating quantity selectors in CSS. Source: Adapted from Yank 2016.
    Illustrating quantity selectors in CSS. Source: Adapted from Yank 2016.

    Given a number of children, it's possible to select one or more of them depending on the number of children. Quantity selectors help us do this. Essentially, they are pseudo-classes. Multiple pseudo-classes can be used together. We share a few examples.

    To select a list item if it's the only item in the list, use li:only-child. This logic can be reversed by doing li:not(:only-child).

    To select the first child if there are exactly six children, use li:nth-last-child(6):first-child. This selects the sixth child from the end. This can be the first child only if there are exactly six children. To select children 2-6 if there are exactly six children, use the general sibling combinator, as in li:nth-last-child(6):first-child ~ li.

    If there are six or more children, and we wish to ignore the last 5 children, use li:nth-last-child(n+6). To select only the last 5 children given that there are six or more children, use li:nth-last-child(n+6) ~ li.

  • Which are some uncommon CSS selectors?

    Some CSS selectors are either not widely known or commonly used, but could be useful in some cases:

    • Universal: It's inefficient to select all elements by using the universal selector *. However, it could be used to select all children of an element, such as .footer > *.
    • Empty: Pseudo-class :empty targets elements with no content. HTML comments are not considered. Even if an element has only a single space, it's considered non-empty.
    • Multiple Classes: p.last-section.section targets paragraphs that belong to both classes section and last-section.
    • Selector List: Same CSS styles can be applied to multiple selectors, which are separated by commas. For example, em, i {...} styles em and i tags alike.
    • Inverse Selection: Specify a selector and target the inverse set. For example, :not(p) selects all elements that are not paragraphs. Another example is .nav > div:not(:first-child) to select all (expect the first) div children of .nav.
  • Could you share some best practices for using CSS selectors?

    To keep content separate from styling, avoid inline CSS styles. Put styles in stylesheets. An exception is when emailing HTML content since many mail clients ignore stylesheets.

    Write legible CSS rulesets. Put each declaration on a separate line. Be careful about spaces. For example, selectors #header.callout (header of callout class) and #header .callout (callout descendants of header) target different elements.

    Avoid repetitive rules. If many selectors contain the same style declaration, abstract that into a separate class-based ruleset.

    Move animations to the end of stylesheets so that browsers load and render basic styling first.

    CSS allows the use of !important in the value of a property. This gives precedence to the declaration, overriding even inline styles. CSS specificity determines selector precedence should multiple selectors target the same element. Since !important breaks this precedence order, it can make stylesheets hard to maintain and debug.

    Long selectors resulting in high specificity, including use of identifiers, can break cascading and prevent efficient reuse of styles. Keep selectors to two or three levels deep. For example, replace #header #intro h1.big a.normal with .big .normal.

  • What are some performance considerations when designing CSS selectors?

    Selecting by identifier is fast. Selecting by class, tag, child, descendant, or attribute exact match are fast in that order. These results may vary across browsers. In fact, difference in speed between identifier and class selectors is negligible.

    WebKit developer Dave Hyatt noted back in 2008 that it's best to avoid using sibling, descendant and child selectors for better performance.

    The way browsers parse CSS selectors is different from the way web designers write them. Browsers read selectors in right-to-left order. For example, given #social a browsers will look at all a tags, move up the DOM tree and retain only those that are within #social. This insight can help us write more performant selectors. The rightmost selector is called the key selector.

    The above example can be made more performant by adding a new class social-link to relevant anchor tags and then using the selector #social .social-link. In fact, this selector is overqualified. It can be simplified to just .social-link. A poor selector is div:nth-of-type(3) ul:last-child li:nth-of-type(odd) *. It's four levels deep and its key selector selects all elements of the DOM.

Milestones

Aug
1999

W3C publishes CSS3 module: W3C selectors. In November 2018, W3C publishes this as Selectors Level 3 W3C Recommendation.

Aug
2006

To simplify DOM tree traversal and manipulation John Resig releases a new library named jQuery. In JavaScript code, this allows us to select elements using CSS selectors, thus avoiding many lines of code that call getElementById() or getElementsByClassName(). jQuery itself is partly inspired by cssQuery (September 2005). An earlier effort to use CSS selectors in JavaScript is getElementsBySelector() (March 2003).

Oct
2007

In a W3C Working Draft, new API methods querySelector() and querySelectorAll() are introduced. Browsers/clients must implement them for both DocumentSelector and ElementSelector interfaces. Traditionally, DOM elements were selected using methods getElementById(), getElementsByClassName(), getElementsByTagName(), getElementsByName(), etc. These are cumbersome. The new API methods allow direct use of CSS selectors. This becomes Selectors API Level 1 W3C Recommendation in February 2013.

Mar
2009
IE7 CSS performance drops at about 18K child/descendant CSS rules. Source: Souders 2009.
IE7 CSS performance drops at about 18K child/descendant CSS rules. Source: Souders 2009.

In a study on CSS performance, it's noted that optimizing selectors matters only if a webpage has many thousands of DOM elements. For example, a Facebook page (in 2009) has 2882 CSS rules and 1966 DOM elements, a scale easily handled by browsers. Among a number of popular browsers, IE7 gives best performance. IE7 hits a performance limit only when a page has about 18K child/descendant rules.

Sep
2011

W3C publishes Selectors Level 4 as a Working Draft. As on May 2020, it's still a Working Draft, with the latest version from November 2018. Among the new pseudo-classes are :is(), :has(), :where(), :target-within, :focus-visible, and :focus-within. Temporal pseudo-classes are :current, :past and :future. There are new pseudo-classes for input states and value checking. Grid pseudo-classes include :nth-col() and :nth-last-col().

Jun
2014
Illustrating the Lobotomized Owl selector. Source: Yank 2016.
Illustrating the Lobotomized Owl selector. Source: Yank 2016.

Heydon Pickering proposes at a CSS conference a peculiar CSS selector of three characters that looks like an "owl's vacant stare". He calls it the Lobotomized Owl. This selector is * + *. It selects all elements that follow other elements. For example, this is useful when adding margin between two siblings without margin above the first element or below the last element. The alternative, :not(:first-child):not(:root) has high specificity and can't be easily overridden. The Lobotomized Owl has zero specificity.

References

  1. CSS Solid. 2020. "CSS selectors explained with example, DOM tree and cheat sheet." CSS Solid. Accessed 2020-05-19.
  2. Coyier, Chris. 2014. "Multiple Class / ID and Class Selectors." CSS-Tricks, September 29. Accessed 2020-05-19.
  3. Coyier, Chris. 2015. "Child and Sibling Selectors." CSS-Tricks, February 2. Accessed 2020-05-19.
  4. Coyier, Chris. 2018a. "Beginner Concepts: How CSS Selectors Work." CSS-Tricks, February 24. Accessed 2020-05-19.
  5. Coyier, Chris. 2018b. "::before vs :before." CSS-Tricks, August 29. Accessed 2020-05-19.
  6. Coyier, Chris. 2018c. "Specifics on CSS Specificity." CSS-Tricks, February 26. Accessed 2020-05-20.
  7. DevDocs. 2020a. "CSS." DevDocs, Mozilla Developer Network, April 23. Accessed 2020-05-19.
  8. DevDocs. 2020b. "Pseudo-elements." CSS, DevDocs, Mozilla Developer Network, April 23. Accessed 2020-05-20.
  9. Devero, Alex. 2016. "CSS Best Practices – 14 Steps to Become a CSS Ninja Pt1." Blog, October 24. Accessed 2020-05-20.
  10. Etemad, Elika J., and Tab Atkins, Jr. (eds). 2018. "Selectors Level 4." W3C Working Draft, November 21. Accessed 2020-05-20.
  11. Glazman, Daniel (ed). 1999. "CSS3 module: W3C selectors." W3C Working Draft, August 3. Accessed 2020-05-20.
  12. Hunt, Lachlan, and Anne van Kesteren, (eds). 2007. "Selectors API." W3C Working Draft, October 19. Accessed 2020-05-20.
  13. Jeon, Nana. 2019. "CSS selectors cheatsheet & details." Medium, February 25. Accessed 2020-05-19.
  14. Koblentz, Thierry. 2013. "Challenging CSS Best Practices." Smashing Magazine, October 21. Accessed 2020-05-19.
  15. Kyrnin, Jennifer. 2019. "What Is the Comma for in CSS Selectors?" Lifewire, November 19. Accessed 2020-05-19.
  16. MDN Web Docs. 2018. ":nth-last-child()." MDN Web Docs, Mozilla, September 19. Accessed 2020-05-19.
  17. MDN Web Docs. 2019a. ":nth-last-of-type()." MDN Web Docs, Mozilla, March 23. Accessed 2020-05-19.
  18. MDN Web Docs. 2019b. ":not()." MDN Web Docs, Mozilla, December 20. Accessed 2020-05-19.
  19. MDN Web Docs. 2019c. "Selector list." MDN Web Docs, Mozilla, October 25. Accessed 2020-05-19.
  20. MDN Web Docs. 2020a. "Attribute selectors." MDN Web Docs, Mozilla, April 3. Accessed 2020-05-19.
  21. MDN Web Docs. 2020b. "Document." Web APIs, MDN Web Docs, Mozilla, April 27. Accessed 2020-05-20.
  22. Norton, Samuel. 2018. "Good and Bad CSS Practices for Beginners." SpeckyBoy, May 10. Accessed 2020-05-20.
  23. Parker-Jones, Claire. 2019. "My Misconceptions about the Universal Selector in CSS." Blog, April 21. Accessed 2020-05-19.
  24. Pickering, Heydon. 2014. "Axiomatic CSS and Lobotomized Owls." A List Apart, October 21. Accessed 2020-05-19.
  25. Roberts, Harry. 2011. "Writing efficient CSS selectors." CSS Wizardry Ltd, September 17. Accessed 2020-05-20.
  26. Souders, Steve. 2009. "Performance Impact of CSS Selectors." Blog, March 10. Accessed 2020-05-20.
  27. Way, Jeffrey. 2011. "The 30 CSS Selectors You Must Memorize." Envato Tuts+, Envato Pty Ltd, June 9. Accessed 2020-05-19.
  28. Wikipedia. 2020. "jQuery." Wikipedia, May 6. Accessed 2020-05-20.
  29. Yank, Kevin. 2005. "cssQuery(): query the DOM with CSS selectors." SitePoint, September 19. Accessed 2020-05-20.
  30. Yank, Kevin. 2016. "CSS Selectors Redux." Blog, May 16. Accessed 2020-05-19.
  31. van Kesteren, Anne, and Lachlan Hunt, (eds). 2013. "Selectors API Level 1." W3C Recommendation, February 21. Accessed 2020-05-20.
  32. Çelik, Tantek, Elika J. Etemad, Daniel Glazman, Ian Hickson, Peter Linss, and John Williams (eds). 2018. "Selectors Level 3." W3C Recommendation, November 06. Accessed 2020-05-20.

Further Reading

  1. Coyier, Chris. 2018b. "Beginner Concepts: How CSS Selectors Work." CSS-Tricks, February 24. Accessed 2020-05-19.
  2. Jeon, Nana. 2019. "CSS selectors cheatsheet & details." Medium, February 25. Accessed 2020-05-19.
  3. Way, Jeffrey. 2011. "The 30 CSS Selectors You Must Memorize." Envato Tuts+, Envato Pty Ltd, June 9. Accessed 2020-05-19.
  4. Yank, Kevin. 2016. "CSS Selectors Redux." Blog, May 16. Accessed 2020-05-19.
  5. de León, Inayaili. 2009. "Taming Advanced CSS Selectors." Smashing Magazine, August 17. Accessed 2020-05-19.
  6. Koblentz, Thierry. 2013. "Challenging CSS Best Practices." Smashing Magazine, October 21. Accessed 2020-05-19.

Article Stats

Author-wise Stats for Article Edits

Author
No. of Edits
No. of Chats
DevCoins
4
0
1739
1
0
15
2130
Words
3
Likes
7250
Hits

Cite As

Devopedia. 2020. "CSS Selectors." Version 5, May 20. Accessed 2023-11-13. https://devopedia.org/css-selectors
Contributed by
2 authors


Last updated on
2020-05-20 10:13:28