css-selectores-y-especificidad

CSS Selectors and Specificity

  • 6 min

A CSS selector is the pattern or rule we use to tell the browser to which HTML element or elements we want to apply a specific set of styles.

We’ve seen that CSS is used to style elements. Basically (spoiler) we’ll say this is red, this has a little border, this has a margin around it…

Logically, we need a way to tell which part of the document we want to change the style for. That is, we need to “select” parts of the document.

In CSS we have many ways to select elements. Let’s review the three fundamental selectors you’ll constantly use, ordered from least to most specific.

Tag selector

The tag selector is the coarsest of all. It directly targets the name of the HTML tag, without caring about anything else.

If we use the p selector, the browser will apply that style to absolutely all paragraphs that exist on the web page.

/* This will paint ALL paragraphs red */
p {
    color: red;
    font-size: 16px;
}

/* This will affect ALL links */
a {
    text-decoration: none;
}
Copied!

Using tag selectors is practical for setting the base styles of your site (for example, defining the general typography for <h1> or <h2> headings).

However, it will become very limiting when you want a specific paragraph to look different from the rest.

Class selector

This is the most used selector. A Class is an attribute we can add to any HTML tag to give it a “group name”.

To target a class from our CSS file, we add a dot (.) before the name.

<p class="highlighted-text">This is an important message.</p>
<button class="primary-button">Accept</button>
<button class="primary-button">Cancel</button>
Copied!
/* In CSS (notice the initial dot) */
.highlighted-text {
    color: blue;
    font-weight: bold;
}

.primary-button {
    background-color: green;
}
Copied!

The great advantage of classes is that they are highly reusable. You can have a hundred different elements with the class primary-button, and they will all share the same appearance.

ID selector

The ID (Identifier) selector is used to target a single, unique element within the entire page.

An ID is a special attribute that an HTML element can have, with the condition that there cannot be two elements with the same id on the web page ^(it is unique).

To call it from CSS, we use the hash or hashtag symbol (#).

<nav id="main-menu">...</nav>
Copied!
/* In CSS (notice the hash) */
#main-menu {
    background-color: black;
}
Copied!

In real life, it’s the least used by a wide margin. The condition that an ID must be unique is too restrictive (imagine adding one to a button; every button would need its own ID).

Combining selectors

Many times one selector alone won’t be enough; we will need to combine them. CSS allows us to make very powerful combinations.

If you want to affect an element only when it is inside another, we use a space. This is the most important and most used combination.

/* This only paints red the links that are INSIDE an element with the class .card */
.card a {
    color: red;
}
Copied!

Unlike the descendant combinator (which affects any element inside, no matter how deep it is), the child combinator affects only elements that are immediately one level below.

/* This paints blue paragraphs that are direct children of .container,
   but will NOT affect a paragraph inside a <div> inside .container */
.container > p {
    color: blue;
}

Copied!

This combinator is used to select an element that is immediately after another, provided both share the same parent element (i.e., they are at the same level).

/* This applies a top margin only to the FIRST paragraph that comes
   right after an <h2>. Ideal for separating the first text from the heading. */
h2 + p {
    margin-top: 20px;
}

Copied!

It’s similar to the adjacent sibling, but less strict. It selects all elements that come after another at the same level (sharing a parent), regardless of whether they are right next to each other or there are other elements in between.

/* This sets the text color to gray for ALL paragraphs that come after
   an image, as long as they are at the same level within the HTML */
img ~ p {
    color: gray;
}

Copied!

Specificity

Who wins when there’s a conflict? This is where the concept of Specificity comes into play. It’s the mathematical system the browser uses to decide which rule carries more weight when there’s a technical tie.

Here comes one of the biggest problems that makes people struggle to understand CSS. What happens if we write contradictory rules for the same element?

The general rule is simple: the most specific selector wins. The order of weight, from lowest to highest, is as follows:

  1. Tags (p, div) are worth 1 point.
  2. Classes (.class) are worth 10 points.
  3. IDs (#id) are worth 100 points.
  4. Inline styles (style="..." in HTML) are worth 1000 points.

Strictly speaking, they don’t exactly add up points. Specificity is formally represented as (0 0 1), (0 1 0), and (1 0 0) respectively. But basically, it’s the same thing.

For example, imagine we have this HTML:

#buy has more weight than .primary, and this has more weight than button. As long as one has more weight than the other (in the widget, if it’s activated), the one with higher specificity wins.

Within the same specificity level, they are added together. That is, if we had:

  • A selector that combines two classes (specificity 0 2 0)
  • It would beat a selector with one class (specificity 0 1 0)
  • But both would lose to an ID selector (specificity 1 0 0)