# CSS Selectors

## Summary


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?

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?

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?

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?

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

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

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.