Preface 😏

One of the most common questions in front end interviews is the priority of CSS selectors. On Monday, I thought this thing was pretty simple, just recognize the class selector, id selector and tag inside, and then it’s gone. But little do we know that most of the time we are lost to the “I thought”, the fact that everything is not as simple as imagined.

When I finished the book, I realized that priorities need to be calculated, and then there are all kinds of calculations like wildcard selectors, selectors, and logical combinatorial pseudo-classes.

Before I read the book, I might have thought something like this:

So, write this article to summarize priorities in CSS selectors. Let’s learn ⑧~💡

🧐 first look at the content of the article

Before we begin, let’s use a mind map to understand the structure of this article. See the picture below 👇 for details

Next, enter the explanation of this article ~

🤐 I. Basic knowledge

1. Why are CSS selectors strong

  • Traditional programming language emphasizes clear logic, distinct hierarchy, and mainly serves functions.
  • butCSSIt’s for style, it’sHeavy performance.Light logicLike human thoughts, they collide with each other to produce sparks.
  • forCSSIn terms of selectors, it acts asCSSThe pillars of the worldThe human spine, andHTMLStructure, browser behavior, user behavior, and the wholeCSSThe world depends on each other and interacts with each otherCSSSelectors have become very powerful.

2. Some basic concepts of CSS selectors

(1) Four basic concepts

CSS selectors can be divided into four categories: selectors, selectors, pseudo-classes, and pseudo-elements. The differences between these four types are described below.

Ⅰ. Selector

Selectors refer to the tags, class names, and so on that precede the CSS declaration blocks we normally use. Such as:

body{
    background: # 333;
}
Copy the code

The body in the above code is a selector, it’s a type selector, it’s also called a tag selector.


Such as:

.container{
	background-color: #fff;
}
Copy the code

The.container in the above code is also a selector, which is one of the property selectors and is often referred to as a class selector.

Ⅱ. Selectors

CSS has five types of selectors, which are:

selector define
Spaces () Represents the relationship between descendants
Angle brackets (>) Represents the parent-child relationship
Plus sign (+) Indicates the sibling relationship between neighboring brothers
Tilde (~) Brotherly relationship
Double pipe (| |) Represent column relationship

Let’s do some examples to better understand these types of selectors. The specific code is as follows:

/* Descendants */
.container img {
    object-fit: contain;
}

/* The relationship between father and son */
ol > li {
    margin: 0 auto;
}

/* Adjacent brothers */
button + p {
    margin-right: 10px;
}

/* Brotherhood */
button ~ p {
    margin-left: 10px;
}

/* 列 */
.col || td {
    background-color: gray;
}
Copy the code

The important thing to notice here is the difference between a neighboring sibling relationship and a sibling relationship, these two look so similar that it’s easy to confuse them.

For the adjacencies of +, this refers to the style of the current button and the next element p at the same level; For ~, this is the style of the current button and all p elements at its level.

You can say that + is a one-to-one relationship, and ~ is a one-to-many relationship.

Ⅲ. Pseudo class

A pseudo-class is characterized by a colon before it:. For pseudo-classes, which are often associated with browser behavior and user behavior, think of it as javascript in the CSS world. Such as:

a:hover{
	color: gray;
}
Copy the code

Ⅳ. Pseudo elements

Pseudo-elements are typically preceded by two colons ::, such as :before, ::after, ::first-letter and ::first-line.

(2) The namespace of the CSS selector

CSS selectors also have the concept of a namespace. So called namespace, is we often see @namespace, the main role is to avoid conflicts.

For example, if we use links in BOTH HTML and SVG, conflicts are likely to occur. Then the problem comes, the conflict is created, and how to solve it? In this case, we can use the namespace @namespace.

Let’s take a look at some code to make namespaces more intuitive. The specific code is as follows:

<p> this is the text: < a > click refresh < / a > < / p > < p > this is an SVG: < SVG > < a xlink: href > < path d ="M433.109 23.694 c... 2.706 z"/>
		</a>
	</svg>
</p>
@namespace url(http://w3.org/1999/xhtml);
@namespace svg url(http://www.w3.org/2000/svg);
/* Pipe character */
svg|a {
    color: black;
    fill: currentColor;
}
/* Tag selector */
a {
    color: gray;
}
Copy the code

You can see, SVG has a pipeline operator | | a, then pipe the appellation of the character representation is in front of the namespace, and pipe, the back of the content is selector. The final display of this code looks like this:

If we were to follow our preorder, maybe some people would think that the lower the style is, the higher the priority is. Why is the A in SVG still shown in black instead of gray?

, in fact, you can see the above namespace in the code above is said, all under the namespace http://www.w3.org/2000/svg < a > color is black, black, and because of the XHTML namespace (everyone positioning to the first namespace) was specified. As a result, tags in SVG are not affected by tag selector A, even if the pure tag selector A has a higher priority.


With that said, let’s make a summary of the CSS selector namespace:

In fact, CSS selector namespaces are very compatible and have been supported by browsers for at least 10 years. However, very few people use it in their projects. Why is that?

The reasons are as follows:

  • The use of inline SVG in HTML is relatively rare. Do you think that when we refer to An Ali icon, we will directly import SVG resources into our own pages? I don’t think anyone does that. So, it’s more of a stand-alone resource.

  • Another reason is that there are better alternatives. Such as:

    svg a{
    	color: black;
    }
    Copy the code

    The only downside to this is that it increases the priority of the A element in SVG. But most of the time, it has little impact on our development.

So, you can choose to understand the CSS selector namespace, at least in large-scale conflict scenarios, to give yourself a solution ~ ~

😲 2. Priority of CSS selectors

Almost all CSS style conflicts, style overlays, and so on, are related to the misplaced priority of CSS declarations. Next, we’ll look at the priorities of CSS selectors, starting with the CSS priority rules and the calculation of priorities.

1. Overview of priority rules

(1) Selector weight

CSS priorities have an apparently insurmountable hierarchy, so we can divide them into six levels ranging from 0 to 5. The first four levels are determined by CSS selectors, and the last two levels are determined by writing form and specific syntax. Let’s understand the differences between these six hierarchies, as shown in the following table:

level define Calculated value
Level 0 Wildcard selectors, selectors, and logical combination pseudo-classes 0
Level 1 Label selector 1
Level 2 Class selectors, property selectors, and pseudo-classes 10
Level 3 The ID selector 100
Level 4 Inline the style property 1000
Level 5 ! important 10000

(2) Description of selectors

Moving on, let’s take a look at the selector styles for each of the six levels. The details are as follows:

Level 0: Wildcard selectors, selectors, and logical combination pseudo-classes

/* The wildcard selector refers to the asterisk (*) */
* {
    color: #fff;
}

/* ------------------ Dividing line ------------------- */

/ * selector refers to +, >, ~, Spaces and | | specific do detailed above, no longer thin * /
.container img {
    /* Descendants */
}

ol > li {
    /* The relationship between father and son */
}

button + p {
    /* Adjacent brothers */
}

button ~ p {
    /* Brotherhood */
}

.col || td {
    /* 列 */
}

/* ------------------ Dividing line ------------------- */

/* The logical combination pseudo-classes are :not(), :is(), and :where(). Note that only the logical combination pseudo-classes have a priority of 0. The other pseudo-classes do not
:not() {
    color: #fff;
}
Copy the code

Level 1: Label selector

/* Tag selectors are similar to the body,p,span,div, and so on
body {
    color: # 333;
}
Copy the code

Level 2: class selectors, property selectors, and pseudo-classes

/* Class selector refers to class */
.container {
    color: # 666;
}

/* ------------------ Dividing line ------------------- */

/* Attribute selectors specify the attributes within a tag. For example, the following means that only anchors (a elements) with href attributes should be styled */
a[href] {
    color:# 666;
}

/* ------------------ Dividing line ------------------- */

/* Hover */
a:hover {
    color: # 666;
}
Copy the code

Level 3: ID selector

#container {
    color: # 999;
}
Copy the code

Level 4: Inline style property

<span style="color: #ccc;">priority</span>
Copy the code

Level 5:! important

/ *! Important is the top priority and can be used to reset js Settings. The only recommended scenario is to invalidate js Settings (don't abuse them) */
#container {
    color: # 999 ! important;
}
Copy the code

2. Priority calculation

Now that we’ve seen a lot about CSS selectors, let’s take a look at how they work.

(1) Selector priority calculation

Let’s use a table to list some common calculations. Of course, you can also pick up your little book and look at it and calculate it. The details are as follows:

The selector Calculated value Calculation rules
*{ } 0 1 level 0 wildcard selector, the numerical calculation of priority is 0
p { } 1 1 level 1 wildcard selector, the calculation result is 1
ul > li { } 2 Two level 1 label selectors, one level 0 selector, the calculation result is 1+0+1
li > ol + ol { } 3 Three level 1 label selectors, two level 0 selectors, the calculation result is 1+0+1+0+1
.foo { } 10 1 level 2 class name selector, the calculation result is 10
a:not([rel=nofollow]) { } 11 1 tag selector, 10 level negative pseudo-class, 1 2 level attribute selector, the calculation result is 1+0+10
a:hover { } 11 One level 1 label selector, one level 2 pseudo class, the calculation result is 1+10
ol li.foo { } 12 Two level 1 label selectors, one level 2 class name selector, one level 0 space selector, the result is 1+0+1+10
li.foo.bar { } 21 1 level 1 label selector, 2 level 2 class name selector, the calculation result is 1+10+10
#foo { } 100 1 level 3 ID selector, the calculation result is 100
#foo .bar p { } 111 1 level 3 ID selector, 1 level 2 class name selector, 1 level 1 label selector, 2 level 0 space selector, the calculation result is 100+10+1+0+0

(2) “catch up” principle

The other thing that might happen is, if we have the same result, what do we do? Such as:

<html lang="Useful - CN">
	<body class="foo">The color is</body>
</html>

<style>
    body.foo:not([dir]) {
        color: red;
    }
    
    html[lang] > .foo {
        color: blue;
    }
</style>
Copy the code

Let’s examine the above code. First, in the first CSS, there is a tag selector body, a class name selector.foo, a negative pseudo-class :not, and a property selector [dir]. So it’s going to be 1 plus 10 plus 0 plus 10, which is 21.

In HTML [lang] >.foo, there is a tag selector HTML, an attribute selector [lang], and a class name selector. Foo, where the level 0 selector is ignored. So the final calculation is 1+10+10=21.

So, as you can see, both end up being 21. So which style should we use?

Confirming what the title says, following the principle of “coming from behind” **, this code is finally shown in blue.

(3) Tips for prioritizing

In actual development, we will inevitably encounter scenarios where we need to increase the priority of CSS selectors. Little do you know that many small partners may directly and inline! The consequences might be a little scary.

So, we need to look at several ways to increase the weight of the selector. The details are as follows:

Suppose NOW I want to add weight to the following code, for example:

.foo {
	color: # 333;
}
Copy the code

A lot of times we might be adding nesting or adding a tag selector, such as:

/* Add nesting */
.father .foo{}/* Add tag selector */
div.foo{}Copy the code

But this is often not the best approach because it increases the coupling of the code and reduces the maintainability of the code. Just think, if the class name changes, or the tag changes, your style will have to change back, which might be a little unfriendly.


So, let’s introduce two ways to solve this problem. The details are as follows:

First: repeat the selector itself

.foo.foo{}Copy the code

Second: use an existing attribute selector

.foo[class]{}#foo[id]{}Copy the code

It looks a lot friendlier.

🥳 3. Conclusion

In this article, we covered the basics of CSS selectors, the various ways to calculate the priority of CSS selectors, the rule of “coming from behind” and some tips on how to improve the priority.

This concludes the discussion of CSS selector priorities. Hope to help you ~

🐣 Easter Eggs One More Thing

🏷️ Previous recommendations & References

Position and Z-index 👉 You may have some misconceptions about position and Z-index

Book 👉 “CSS Selector World” by Zhang Xinxu

🏷 ️ set pieces

  • Follow the public account Monday research, the first time to pay attention to quality articles, more selected columns for you to unlock ~
  • If this article is useful to you, make sure you leave footprints before you go
  • That’s all for this article! See you next time! 👋 👋 👋