It all starts with identifying exactly which part of a page you want to style.

CSS = Selectors + Declarations

A CSS file contains a series of rules describing how an HTML file should be formatted. Each rule consists of two parts: what to style, and how to style it. The first part is controlled using a series of terms known as “selectors.”

Examples in this article include style declarations, but they are not the focus: the selectors themselves are.

Historically, there were three CSS selector levels (or versions) with varying degrees of browser support. In 2020, according to Can I Use, these are all available to over 99 percent of users around the world.

Level 1 Selectors

Level 1 introduced the four fundamental types of selectors that cover a huge number of cases, even today.

Type Selector

The very simplest selector is the “type selector”. It targets all instances of an element, such as a paragraph or bold text:

Class Selector

The class attribute allows further semantics to be added to an HTML element, such as a specific type of paragraph. Such elements can be selected in CSS as follows:

This selector would match:

But note that it would also match:

If you only want it to apply to intro paragraphs, you can combine the type selector and class selector:

ID Selector

The HTML id attribute should be unique within a document, e.g. if you have:

That should be the only element with a “contents” id. An ID selector allows you to target that specific element in a document:

Descendant Selector

Strictly, a “combinator”, because this selector is all about the space in between two others. HTML is hierarchical, as explained in our overview of the DOM. A descendant selector allows an element to be identified by its context inside another element:

Pseudo Classes and Elements

Pseudo selectors target classes or elements that don’t explicitly exist but are made available anyway. Think of them as special content bonuses:

Selector Lists

Use a comma to combine selectors into a list if you want to apply the same set of rules to each. Instead of:

You can write:

Specificity

A style sheet is a series of rules which use a selector to match an element, but what happens when more than one rule matches a given element? The resulting behavior is governed by “specificity” which defines which rule is used in a case such as:

In such cases, the rule taking priority is defined by its specificity, as follows:

ID selectors (#contents) are the most specific. Class selectors (. author) are less specific. Type selectors (p) are the least specific.

When calculating specificity, each level is only considered if two selectors have the same score at the higher level, so “#contents” is more specific than “article.news p.author.special” because the former “wins” on ID selectors.

Level 2 Selectors

The next revision of CSS selectors introduced attribute selectors, expanded on pseudo-classes & pseudo-elements, and added two new combinators.

Universal Selector

The “*” matches any element. It’s not often that useful, but if you want to reset any default margins, for example, you can do so:

Attribute Selectors

Attribute selectors allow styles to be targeted very specifically, filtered by an element’s attribute:

Child Combinator: An Element Immediately Inside Another

Similar to the descendant combinator, but this one only matches immediate children, not descendants any lower down the tree. For example, “ul > li” will match only the “Section 1” text here, and not “Section 1.1”:

Adjacent Sibling Combinator: The Next Sibling

Often useful for controlling margins, or an introductory paragraph without a specific class, this selector matches one element only if it immediately follows another. In the example, only the first paragraph here will be matched, not the second:

Note that this selector only considers elements—not text—when deciding what the next sibling is.

Inheritance

Some CSS properties inherit their value from an ancestor element. In practice, this means—for example—that setting the font face of the “body” element means that every paragraph, table, etc. also uses that same font face.

Of course, this is exactly what you’d expect, but consider a property that doesn’t inherit: “margin”, for example. You wouldn’t want every individual paragraph or bit of bold text to have the same margin as the whole document.

A good rule of thumb is to target elements as generally as makes sense—don’t target every individual element when a simple “body” selector will do.

Level 3 Selectors

Many more pseudo-classes were added in this level, alongside some attribute selectors and a new combinator.

Attribute Selectors

You can select elements with an attribute that starts with a given value: a[href^=“https:”], ends with a given value: img[src$=".gif"], or contains a value: a[*=“value”].

Pseudo Classes

Additional pseudo-classes include “:last-child”, “:empty” (to match an element with no content), and “:checked” which matches an element like a checkbox input, but only when it’s checked.

General Sibling Combinator: A Following Sibling

Similar to the Adjacent Sibling Combinator from Level 2, this matches any sibling that comes after another, not just the next one:

CSS Selectors and How to Use Them

Now you know just about everything there is to know about how to select part of a webpage using CSS. You’re now ready to style your pages with the great variety of CSS properties that cover everything from colors to layout.

Image Credit: Pankaj Patel/Unsplash