DEV Community

Habdul Hazeez
Habdul Hazeez

Posted on • Updated on

CSS Selectors

Welcome, In this section, we will be taking a tour of CSS Selectors which are myriad of ways of targeting HTML Elements for styling purposes, some of these stylings can include:

  • increasing or decreasing the font size of an element
  • adding some colors (background, text e.t.c)
  • organizing the page layout. e.t.c

I will be your companion for this tour but our guide will be the CSS Specification specifically Chapter 5 of the CSS Specification Level 2.1 and Selectors Level 3 Specification. Why two Specifications?

Selectors were part of CSS2.1 Specification specifically Chapter 5, but Selectors Level 3 is an independent Specification on its own. Now, what is the difference between these two? Chapter 1.3 of the Selectors Level 3 Specification states the difference as follows:

  • an optional namespace component is now allowed in element type selectors, the universal selector and attributes selectors.
  • a new combinator has been introduced.
  • new simple selectors including substring matching attribute selectors, and new pseudo-classes.
  • new pseudo-elements, and introduction of the "::" convention for pseudo-elements.
  • the grammar has been rewritten.
  • profiles to be added to specifications integrating Selectors and defining the set of selectors which is actually supported by each specification
  • Selectors are now a CSS3 Module and an independent specification; other specifications can now refer to this document independently of CSS.
  • the specification now has its own test suite.

What this means is that you will find some information that is the same in CSS 2.1 specification Chapter 5 and Selectors Level 3 Specification. Examples include code samples and tabular information.

Before we proceed into selectors in detail, there is a particular thing that caught my interest in the specification that we need to discuss and that's on the subject of pattern matching in CSS2.1 specification:

In CSS, pattern matching rules determine which style rules apply to elements in the document tree. These patterns, called selectors, may range from simple element names to rich contextual patterns. If all conditions in the pattern are true for a certain element, the selector matches the element.

The case-sensitivity of document language element names in selectors depends on the document language. For example, in HTML, element names are case-insensitive, but in XML they are case-sensitive.

I have highlighted some points of interest, but what this paragraph is trying to tell us is simple. Selectors can be HTML elements name like h1, div, aside, footer or rich contextual patterns. Now you might ask, what patterns and why are they considered "rich"? Let's take some examples from the spec:

E[foo^=bar] - This will match an Element E whose "foo" attribute begins exactly with a string "bar". Why at the beginning? if we break the example into pieces we get:

E [ foo ^ = bar ]

The symbol ^ before the equals sign (=) is what makes this selector match a foo attribute with the string "bar" at the beginning. It's called the caret sign (symbol) and it's used in Regular Expressions for Pattern Matching. We will not be discussing Regular Expressions, but you should note that.

Another Example is E[foo$=bar]. This is the opposite of our previous example, but in this case, it will match the foo attribute value that ends with exactly the string bar. The dollar symbol ($) is responsible for this i.e matching element at the end of a string.

Another example i will like to add:

div > p:first-child span.highlight

This will match a span element with a class of highlight located in the first paragraph inside the div element. The ability to do this in CSS is why the Spec refereed to them as rich contextual patterns.

Now, let's discuss the selectors you can use in your web pages, we will start with selectors that you will use quite often to the ones you might use sparingly. Lets begin with the Universal Selector.

Before that, to follow along with the code snippets in this section, please create a skeleton page similar to the one in HTML Elements and Tags with one modification: create an empty file and save it with the .css extension, and link to this file in your head element

<head>
  <!-- the 'href' attribute should point to the location of your css file -->
  <link rel="stylesheet" href="pseudo-class.css">
</head>
Enter fullscreen mode Exit fullscreen mode

UNIVERSAL SELECTOR

Universal Selectors are covered in Section 5.3 of the CSS2.1 spec and Section 6.2 of the Selector level 3 spec.

The CSS2.1 Spec states:

The universal selector, written "*", matches the name of any element type. It matches any single element in the document tree. The code snippet below will add an outline to all page elements.

The word "universal" here means this selector denoted with '*' matches every element in the document. The CSS code snippet below will apply to all elements in the documents.

The following CSS snippet will give all the page element an outline color of blue.

* {
  outline: 2px solid #1560bd;
}
Enter fullscreen mode Exit fullscreen mode

The image below is an example of this selector when applied to an HTML document.

The CSS outline property applied to an HTML document

TYPE SELECTORS

The definition of type selectors are phrased differently in both specs, but that of the CSS2.1 Specification seems to be quiet straight forward for a beginner:

A type selector matches the name of a document language element type. A type selector matches every instance of the element type in the document tree.

The "document language element type" the Spec is referring to are HTML Elements which can include h1, h2, div, aside, p, or span elements. For example:

<p>This is a paragraph with an hello class</p>
Enter fullscreen mode Exit fullscreen mode
p {
    background-color: #1560bd;
    color: #ffffff;
    padding: 0.6em;
}
Enter fullscreen mode Exit fullscreen mode

CLASS SELECTORS

Class Selectors are quite common and their usage is encouraged by the Web Development community as they have a lower specificity compared to the id selector (discussed next). The spec states (emphasis mine):

Working with HTML, authors may use the "period" notation (also known as "full stop", U+002E, .) as an alternative to the ~= notation when representing the class attribute. Thus, for HTML, div.value and div[class~=value] have the same meaning. The attribute value must immediately follow the full stop (.).

This statement roughly translates to: the class attribute you give your HTML Element should start with a full stop sign ( . ) in CSS. If you give your HTML Element a class attribute of sunshine, then to use it in CSS, it will be .sunshine then the curly braces. The code snippet below demonstrates this.

<p class="sunshine">This is a paragraph with a sunshine class</p>
Enter fullscreen mode Exit fullscreen mode
.sunshine {
    background-color: #1560bd;
    color: #ffffff;
    padding: 0.6em;
}
Enter fullscreen mode Exit fullscreen mode

ID SELECTORS

The Spec states:

Document languages may contain attributes that are declared to be of type ID. What makes attributes of type ID special is that no two such attributes can have the same value in a conformant document regardless of the type of the elements that carry them; whatever the document language, an ID typed attribute can be used to uniquely identify its element

This is telling us that we can only use an id once per page with a unique value and they can never match more than one element in a single document. Unlike class names that start with (.) in CSS, id's start with the pound sign (#).

<p id="sunshine">This is a paragraph with an id of sunshine</p>
Enter fullscreen mode Exit fullscreen mode
#sunshine {
    background-color: #1560bd;
    color: #ffffff;
    padding: 0.6em;
}
Enter fullscreen mode Exit fullscreen mode

ATTRIBUTE SELECTORS

Attributes defined in an HTML document can be targeted for styling in CSS by placing them between two square brackets ( [] ). As defined in CSS2.1 Specification, Attribute Selectors may match in four ways:

  • [att] - Match when the element sets the "att" attribute, whatever the value of the attribute.
  • [att=val] - Match when the element's "att" attribute value is exactly "val".
  • [att~=val] - Represents an element with the att attribute whose value is a whitespace-separated list of words, one of which is exactly "val".
  • [att|=val] - Represents an element with the att attribute, its value either being exactly "val" or beginning with "val" immediately followed by "-".

The following CSS will target elements that have a class attribute.

[class]{
  /* your properties here */
}
Enter fullscreen mode Exit fullscreen mode

Let's discuss these examples in more detail.

Given an HTML Element with a title attribute, the following selector will match an element with the title attribute.

<p>This is <span title="Hypertext Markup Language">HTML</span></p>
Enter fullscreen mode Exit fullscreen mode
[title] {
  text-decoration: underline;
  cursor: help;
}
Enter fullscreen mode Exit fullscreen mode

In the following example, an element with a class attribute of 'hello' will be selected.

<p class="hello">This is a paragraph with an hello class</p>
Enter fullscreen mode Exit fullscreen mode
[class="hello"] {
  font-weight: bold;
  text-decoration: underline;
}
Enter fullscreen mode Exit fullscreen mode

For the third example, lets use [class~="second"] which will match an element with multiple attribute values, but one of them is exactly the string 'second' as demonstrated in the code snippet below.

<p class="first second third">This is a paragraph with three classes</p>
Enter fullscreen mode Exit fullscreen mode
[class~="second"] {
  color: brown;
  border: 2px solid green;
}
Enter fullscreen mode Exit fullscreen mode

To demonstrate the fourth example, if we have an element with an attribute value separated by a hyphen we can use this selector.

<p class="fruit-juice">This is a paragraph of fruit juice</p>
Enter fullscreen mode Exit fullscreen mode
[class |= "fruit"] {
  color: orange;
  font-weight: bold;
}
Enter fullscreen mode Exit fullscreen mode

In Selector level 3 Spec three additional attributes are provided for matching substrings. They are:

  • [att^=val] - This will match an element with the "att" attribute whose value starts with the string "val", and if "val" is empty the selector does not represent anything
  • [att$=val] - This is the opposite of [att^=val], and will match an element with "att" attribute whose value ends with the string "val".
  • [att*=val] - This will match an element with an "att" attribute which contains at least one occurrence of the string var.

Let's take some examples.

The selector [att^=val], the code snippet below will select an Element with attribute value beginning with "he".

<p class="hello">This is a paragraph with an hello class</p>
Enter fullscreen mode Exit fullscreen mode
[class ^= "he"] {
  color: red;
  border: 2px solid blue;
}
Enter fullscreen mode Exit fullscreen mode

The code snippet below demonstrates the selector [att$=val] and it will match element whose attribute value ends wit the string "ing":

<p class="ending">This ends with ing</p>
Enter fullscreen mode Exit fullscreen mode
[class $= "ing"] {
  color: brown;
  border: 2px solid blue;
}
Enter fullscreen mode Exit fullscreen mode

The snippet below will match element whose attribute value contains "ple" demonstrating the Selector [att *= val]

<p class="multipleclasses">This paragraph has a class name of multipleclasses</p>
Enter fullscreen mode Exit fullscreen mode
[class *= "ple"] {
  background-color: #1560bd;
  color: #ffffff;
  padding: 0.6em;
}
Enter fullscreen mode Exit fullscreen mode

PSEUDO CLASSES

Sometimes you might find yourself in a situation that a class or id might seem to you as an overkill when you want to style just a specific and limited section of your document or the exact styling you want just falls out of the document structure, this is where pseudo-classes can be of great help.

From Selectors Level 3 spec:

The pseudo-class concept is introduced to permit selection based on information that lies outside of the document tree or that cannot be expressed using the other simple selectors.

A pseudo-class always consists of a "colon" (:) followed by the name of the pseudo-class and optionally by a value between parentheses

I think this explanation is quite straight forward.

The specification further classifies pseudo-classes into two categories:

  • Dynamic Pseudo-classes and
  • Structural Pseudo-classes

DYNAMIC PSEUDO-CLASSES

Dynamic Pseudo-classes do not appear in the document source i.e your HTML document, and they classify elements on characteristics other than their name.

These characteristics can change based on user interaction with the Element. Example include:

  • :link - This applies to link in your document that has not been visited
  • :visited - This applies to links visited by the user.
  • :hover - The :hover pseudo-class applies while the user designates an element with a pointing device on an element ( e.g a mouse ), but does not necessarily activate it.
  • :focus - You will use this on an element that accepts keyboard or mouse events e.g form inputs.
  • :active - As the name implies, it applies when an element is activated by the user.
  • :checked - Radio and checkboxes in form can be toggled and this is when the :checked pseudo-class applies.

Some examples that demonstrate these selectors.

The following snippet will underline and change the color of all links on a page to blue.

<a href="https://google.com">Google</a>
Enter fullscreen mode Exit fullscreen mode
a:link {
  color: #1560bd;
  text-decoration: underline;
}
Enter fullscreen mode Exit fullscreen mode

This snippet will change the visited links on a page to a variant of red.

<a href="https://google.com">Google</a>
Enter fullscreen mode Exit fullscreen mode
a:visited {
  color: #ea3c53;
  text-decoration: underline;
}
Enter fullscreen mode Exit fullscreen mode

When you move your pointing device over an element with the following CSS, the background color will be changed to red.

<p>This is a paragraph with an hello class</p>
Enter fullscreen mode Exit fullscreen mode
p:hover {
  background-color: red;
}
Enter fullscreen mode Exit fullscreen mode

If you accept data from your users, you can use the following snippet that will indicate to the user that the input is selected and active.

<form>
  <input type="text" name="example">
</form>
Enter fullscreen mode Exit fullscreen mode
input:focus {
  border: 2px solid blue;
}
Enter fullscreen mode Exit fullscreen mode

Checkboxes have a default color of a slight blue when they are checked, this snippet will change that.

<form>
  <input type="checkbox" name="simplecheckbox">
</form>
Enter fullscreen mode Exit fullscreen mode
input[type="checkbox"]:checked {
  outline: 1px solid red;
}
Enter fullscreen mode Exit fullscreen mode

If your users decide to copy part of the text on your web page using their keyboard and mouse to select the content, the following snippet will change the font-weight to bold giving the impression that the text is currently being selected.

  <span>Lorem ipsum dolor sit amet, consectetur adipisicing elit,</span>
Enter fullscreen mode Exit fullscreen mode
span:active {
  font-weight: bold;
}
Enter fullscreen mode Exit fullscreen mode

Some dynamic pseudo-classes not discussed are:

  • :target
  • :lang
  • :enabled
  • :disabled

STRUCTURAL PSEUDO-CLASSES

From Section 6.6.5 of Selector Level 3 specification:

Selectors introduces the concept of structural pseudo-classes to permit selection based on extra information that lies in the document tree but cannot be represented by other simple selectors or combinators.

The literal translation of this sentence is:

You might find yourself in situations where using a class, id, attribute selectors or dynamic pseudo-class is not fit or might be an overkill for the element you want to style, then you can result to its structural position in the document by asking yourself questions like:

  • is the element the only child of its parent?
  • is the element the first child of its parent?

Let's discuss five of the most common structural pseudo-classes, they are

  • :first-child
  • :last-child
  • :first-of-type
  • :last-of-type
  • :only-child
:first-child

First the Spec States:

The :first-child pseudo-class represents an element that is first in a list of siblings.

This is simply telling us if we have a parent element ( e.g a div ) and many child elements like paragraphs ( p ), we can use this pseudo-class to select the first one.

<div>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p>
</div>
Enter fullscreen mode Exit fullscreen mode
div p:first-child {
  background-color: red;
  font-size: 20px;
}
Enter fullscreen mode Exit fullscreen mode
:last-child

You might consult the spec if you want to, but I think this is quite straight forward. It selects the last element from a list of child elements.

<ol>
  <li>Item one</li>
  <li>Item two</li>
  <li>Item three</li>
  <li>Last item</li>
</ol>
Enter fullscreen mode Exit fullscreen mode
ol li:last-child {
  background-color: #1560bd;
  font-weight: bold;
}
Enter fullscreen mode Exit fullscreen mode
:first-of-type

Section 6.6.5.8 of Selector Level 3 Spec:

:first-of-type pseudo-class represents an element that is the first sibling of its type.

This translate to: if you have many child elements that are of the same type e.g span, or paragraph, you can use this selector to get the first occurrence of such element. The code snippet below indicates that we have three paragraphs but only the first is selected.

<div>
  <span>Lorem ipsum dolor sit amet, consectetur adipisicing elit</span>     
  <span>Lorem ipsum dolor sit amet, consectetur adipisicing elit</span>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit</p>
  <span>Lorem ipsum dolor sit amet, consectetur adipisicing elit</span>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit</p>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit</p>
</div>
Enter fullscreen mode Exit fullscreen mode
p:first-of-type {
  background-color: #1560bd;
  color: #ffffff;
}
Enter fullscreen mode Exit fullscreen mode
:last-of-type

This is the opposite of the :first-of-type pseudo-class and it selects elements that are last of its type. if you have multiple paragraphs in your document this can be used to grab the last paragraph.

<div>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit</p>
  <span>Lorem ipsum dolor sit amet, consectetur adipisicing elit</span>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit</p>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit</p>
</div>
Enter fullscreen mode Exit fullscreen mode
p:last-of-type {
  background-color: #1560bd;
  color: #ffffff;
}
Enter fullscreen mode Exit fullscreen mode
:only-child

This can be used to target elements that has no siblings. Which means Just one parent element and a single child element. This selector won't select anything if the parent has more than one child element.

<div>
<!-- p is the only child of div, and we can select using :only-child -->
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit..</p> -->
</div>
Enter fullscreen mode Exit fullscreen mode
p:only-child {
  background-color: red;
  color: #ffffff;
}
Enter fullscreen mode Exit fullscreen mode

Listed below are other structural pseudo-elements, I consider them tricky (or intimidating?) for a beginner to understand which is the reason I chose not to discuss them but if you are curious or feeling adventurous you can read them up in the Selector Level 3 Specification.

  • :root pseudo-class
  • :nth-child() pseudo-class
  • :nth-last-child() pseudo-class
  • :nth-of-type() pseudo-class
  • :nth-last-of-type() pseudo-class
  • :only-of-type pseudo-class
  • :empty pseudo-class

Next, CSS Units.

Top comments (0)