Home > Web Front-end > CSS Tutorial > Selector Specificity with CSS Preprocessors

Selector Specificity with CSS Preprocessors

William Shakespeare
Release: 2025-02-25 11:30:11
Original
306 people have browsed it

Selector Specificity with CSS Preprocessors

Key Points

  • Selector specificity is a recurring problem in medium and large projects that require careful management and understanding. Tools such as interactive calculator and Sass' mixin can help understand and manage specificity.
  • BEM (block, element, modifier) ​​method is a powerful tool for maintaining consistent specificity. By using class names for each styled element, the specificity of each selector remains the same, eliminating the problem of overly specific selectors. However, BEM may not be suitable for all types of projects, especially those that non-developers may need to write partial HTML.
  • CSS preprocessors such as LESS, Sass, and Stylus provide solutions to specific problems. One way is to add an existing selector with a class, attribute, ID, or type selector to improve its specificity. This method has limitations because once the heaviest selector is used, it cannot be overwritten unless a new, heavier selector is created.
  • Another approach is self-chain selector, which works with ID, class, and attribute selectors. This method provides an almost infinitely scalable way to override any selector, but does not work with type selectors. By using the parent reference selector, the same selector can be linked to itself multiple times, each time increasing its specificity.

Selector specificity is a real problem for most medium and large projects, and like any other frequently repeated coding issues, it needs to be handled carefully. Even CSS-Tricks has a recent article on how to keep CSS specificity low. Before you try to use !important, let me remind you: > CSS/Daily Tips: If everything is !important, nothing is !important. ——Tony Nelson (@tonynelson19) November 18, 2010

CSS specificity is not complicated, but the community has done a lot of work to make it as easy to understand as possible, writing guides by using analogies to Fish and Star Wars or using poker terms. There are interactive calculators available online, and even Sass' specific mixin, which allows you to check and output the exact specificity values ​​of the selector. In CSS-specific strategies, the simpler the better, the specific solution in this article (which may feel a little clumsy) is suitable for situations where the architecture does not allow for simple fixes. When deciding which approach is best for your project, apply your judgment and ultimately try to strike the perfect balance between a clean and easy-to-maintain CSS.

Method 0 – BEM

BEM is not just a naming convention, it is a front-end toolkit invented by Yandex, with the idea of ​​being closer to object-oriented programming. In practice, this means using the class name for everything you want to style. While “not casing in a cascading stylesheet” may sound ridiculous to some, avoid using type selectors when creating modules that should be easy to maintain, portable, self-sufficient, easy to modify and extensible And the idea of ​​avoiding nesting is very helpful. However, one of the main advantages of the BEM method is that it keeps the specificity of each selector unchanged, so there are almost no problems caused by overly specific selectors, which is why this method is the No. 0 method— If you adopt it, you actually eliminate any future issues with selector specificity in your project.

Specification of rules

Since you will only use a single class for everything you write, the specificity of each selector will be 0,1,0

BEM is not the answer

There are countless success stories about using BEM's front-end architecture, however, despite its popularity, BEM is not suitable for specific types of projects. It seems to be perfect for front-end developers to be the only project to write HTML. However, if you write content for a CMS for at least part of the content editor, BEM will be severely restricted. The pure form of BEM does not allow nesting and type selectors, such as .Section--dark > a (for example, to make it lighter), but instead requires you to invent a class for the anchor tag. This leads to a problem - the content editor will insert the default link through the graphical interface, which can cause the link to be nearly invisible. This may also apply to all paragraphs, lists, or images in a specific section. Sometimes it is necessary to be able to write pure HTML content without classes, in which case the solution is to have the parent styling it with a descendant selector. This use of cascading allows context flexibility—it has a custom style when something is in a different context. So we need a practical solution for situations where we cannot use pure BEM, which is quite common. CSS preprocessors can help us here, and all 3 popular preprocessors – LESS, Sass and Stylus – are able to simplify our work when we need to override the selector with a more specific selector.

Method 1 – Use the selector to add prefix

When you encounter specificity problems and want to make a selector heavier, you can add a class, attribute, ID, or type selector before an existing selector. In this way, you can slightly increase specificity. Although this feature is mainly used to locate IE using the conditional html tag, it has more features to be developed. Parent Reference Selector (&) in CSS Preprocessor allows us to easily add selector prefix to make it heavier, so we can do the following:

<code>.class {
  body & {
    foo: bar;
  }
}</code>
Copy after login
Copy after login

Created CSS:

<code>.class {
  body & {
    foo: bar;
  }
}</code>
Copy after login
Copy after login

You may want to use the html or body tag to prefix, but you can also use some more specific content that exists on the page, such as .page, #wrapper, html[lang], etc. Sass allows you to place prefixed selectors in variables when changes occur in the future. In addition, for large projects, it may be worth creating a set of prefixed selectors with different weights:

<code>body .class {
  foo: bar;
}</code>
Copy after login

This will generate:

<code>$prepend1: "html &";
$prepend2: "#wrapper &";

.selector {
  #{$prepend1} {
    background: #cacaca;
  }
  #{$prepend2} {
    background: #fefefe;
  }
}</code>
Copy after login

Other popular preprocessors such as LESS and Stylus also offer this feature.

Specification of rules

Adding prefixes our original class selector 0,1,0 with type selector will result in 0,1,1, and prefixes with ID – 1,1,0. The downside here is that once you add a selector prefix with the heaviest selector in your code (i.e. #wrapper), you can't override it anymore unless you invent a new, heavier selector, And this is not always possible.

Method 2 – Self-chain selector

Adding selector prefix is ​​useful, but it is not an infinitely scalable solution – you may have only limited ways to locate the parent. Additionally, once you prefix multiple selectors with the heaviest option in your code, you will limit options to resolve specificity issues later (especially if you use ID). The front-end community has recently been reminded of a very useful CSS feature – self-chain selectors to improve their specificity. Self-chain selectors are suitable for ID, class, and attribute selectors, but not for type selectors. However, if you mainly use classes to style content, the self-chain selector provides you with an infinitely scalable way to override any selector. With the parent reference selector, you can easily link the same selector to itself multiple times (this applies to ID, class, and attribute selectors, but not to type selectors). However, you need to insert each & after the first one, the minimum requirement is Sass 3.4:

<code>html .selector {
  background: #cacaca;
}
#wrapper .selector {
  background: #fefefe;
}</code>
Copy after login
<code>.selector {
  {&} {
    background: #cacaca;
  }
  {&}{&} {
    background: #fefefe;
  }
}</code>
Copy after login

Similarly, you can do this using LESS and Stylus. If this is too ugly for your taste, you can always create a mixin that iteratively improves the specificity of any single selector. This mixin uses some advanced features and also requires Sass 3.4:

<code>.selector.selector {
  background: #cacaca;
}
.selector.selector.selector {
  background: #fefefe;
}</code>
Copy after login

Created CSS:

<code>@mixin specificity($num: 1) {
  $selector: &;
  @if $num > 1 {
    @for $i from 1 to $num {
      $selector: $selector + &;
    }
    @at-root #{$selector} {
      @content;
    }
  } @else {
    @content;
  }
}

.selector {
  @include specificity(2) {
    background: #cacaca;
  }
  @include specificity(3) {
    background: #fefefe;
  }
}</code>
Copy after login

You can create the same mixin in Stylus, unfortunately there is no easy way to create such mixin in LESS.

Specification of rules

The self-chain increases the selector's specificity from 0,1,0 to 0,2,0, and so on, making it almost infinitely scalable.

Final Thoughts

The next natural step in dealing with specificity issues in our smarter CSS than ever is to create a way to identify conflicting statements, using something like David Khourshid's Sass mixin for each entity Specificity, then automatically use one of the above methods to improve specificity. Maybe I'm too optimistic about my dream of self-aware stylesheets, but I think the complex logic in our code will increase as CSS preprocessors develop. Which of the above methods will you use next time you need to deal with specificity issues? What other strategies do you use to solve your specificity problems?

FAQs about CSS preprocessor and selector specificity

What is the selector specificity in the CSS preprocessor?

Selector specificity is a concept in CSS that determines which styles are applied to elements when conflicting rules exist. It is a weight system assigned to different type selectors (such as IDs, classes, and type selectors). In CSS preprocessors such as Sass or Less, this concept remains the same. However, these preprocessors provide additional functionality such as nesting, which affects the specificity of the selector.

How does nesting affect selector specificity in CSS preprocessors?

Nesting is a feature in the CSS preprocessor that allows you to write more organized and easier to read code. However, it also increases selector specificity. Each nesting level adds specificity, making the nested selector more specific than the parent selector. This is useful for overwriting styles, but can also lead to unexpected consequences if not managed properly.

How to calculate the specificity of selectors in CSS preprocessors?

The specificity of the selector is calculated based on the type of selector used. Generally, ID selectors are most specific, followed by class selectors, and then type selectors. Each type of selector is assigned different weights, and the total specificity is the sum of these weights. Some CSS preprocessors, such as Sass, provide functions for calculating selector specificity.

What does "&" mean in CSS styles in preprocessors such as Sass?

The "&" symbol is used in CSS preprocessors such as Sass to reference the parent selector in nested rules. This is useful for creating more specific selectors or applying styles to different states of an element, such as hover or active states.

How to use a dual selector in Sass to increase specific weights?

In Sass, you can improve its specificity by copying the selector. This is called a link or a double selector. For example, the specificity of .class.class will be higher than .class. However, this method should be used with caution, as it will make your CSS more difficult to maintain and overwrite.

What are the potential problems with high specificity in CSS preprocessors?

High specificity will make your CSS more difficult to maintain and cover. It can lead to so-called specificity conflicts, and you have to constantly improve the specificity of the selector to cover the previous style. This can cause CSS to swell and complex.

How to manage specificity in CSS preprocessors?

There are several strategies to manage specificity in CSS preprocessors. One is to use low specificity selectors as much as possible. Another is to avoid unnecessary nesting, as this increases specificity. You can also use the BEM (block, element, modifier) ​​method to keep specificity low and consistent.

Can I use !important to override specificity in CSS preprocessor?

Yes, you can use the !important rule to override specificity in the CSS preprocessor. However, this should be a last resort, as it will make your CSS harder to maintain and can lead to specific conflicts.

How does the order of selectors affect specificity in CSS preprocessors?

The order of selectors affects specificity in the CSS preprocessor. If the specificity of the two selectors is the same, the last selector that appears in the CSS will be applied. This is called source order specificity.

Can I use inline styles to override specificity in CSS preprocessor?

Yes, inline styles have the highest specificity in CSS and can override other styles. However, use them with caution, as they can make your CSS more difficult to maintain and can lead to inconsistent styles.

The above is the detailed content of Selector Specificity with CSS Preprocessors. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Latest Articles by Author
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template