CSS Class Repetition to Increase Specificity

CSS class repetition to increase specificity

Yes, it is possible and intentionally so. While this is not mentioned in the CSS2 spec, it is explicitly mentioned in the Selectors 3 spec:

Note: Repeated occurrances [sic] of the same simple selector are allowed and do increase specificity.

Therefore browsers must increase the specificity when encountering repeated simple selectors, as long as the selector is valid and applicable. This not only applies to repeated classes, but also applies to repeated IDs, attributes and pseudo-classes.

Given your code, .qtxt.qtxt.qtxt.qtxt.qtxt will have the highest specificity. The other two selectors are equally specific; combinators have no bearing in specificity calculations at all:

/* 5 classes -> specificity = 0-5-0 */
.qtxt.qtxt.qtxt.qtxt.qtxt

/* 2 classes -> specificity = 0-2-0 */
.qtxt.lalgn

/* 2 classes -> specificity = 0-2-0 */
.lalgn .qtxt

Also, the space in your last selector is the descendant combinator; the child combinator is >.

Programmatically set CSS selector specificity

The specificity of a selector is determined solely by its component simple selectors (and pseudo-element, if any). You cannot change the specificity of a selector without altering the selector itself.

If you're worried about changing the meaning of a selector (or its set of potential matches), there are certain dummy simple selectors that you can add while keeping the semantics intact. In your example, you can increase the specificity of UL OL LI to match UL OL LI.red without actually taking a dependency on an arbitrary class name by either adding an unqualified :root to the beginning of the selector (with a descendant combinator) or adding :nth-child(n) to any one of the three type selectors — both are guaranteed matches, and pseudo-classes are equally specific to class selectors.

Also see my answers to the following questions for more options:

  • Can type selectors be repeated to increase specificity?
  • CSS class repetition to increase specificity

There is no similar way to decrease selector specificity, however, neither programmatically nor by altering the selector (except of course by removing redundant selectors like the aforementioned unqualified :root, :nth-child(n), or repeated type/class selectors).

Tersest way of increasing CSS selector' class-level specificity without altering selector scope

The best I can come up with is :nth-child(n), in that it resolves to a meaningless statement which translates into plain English as 'a child element', which will always be the case of nested fractions. The code to implement this looks like this:

.line > :nth-child(1):nth-last-child(4),
.line > :nth-child(2):nth-last-child(3),
.line > :nth-child(3):nth-last-child(2),
.size1of4:nth-child(n):nth-child(n):nth-child(n) {
width:25%;
}

The selector is specified 3 times over such that it trumps the previous selectors by 1, meaning it can also trump the next rule governing .size1of5.

As a SASS mixin:

Because this is a verbose hack, I've packaged it up as a SASS mixin:

@mixin increase-specificity( $depth: 1 ) {
$sel : '';

@while($depth > 0) {
$sel : $sel + ':nth-child(n)';
$depth : $depth - 1;
}

&#{$sel} {
@content;
}
}

Increase specificity weight with double selector via Sass

There's a special trick in SASS for doubling specificity using interpolation brackets (more on that here and here) since two &'s next to each other is invalid SASS syntax.

.parent {
&__child {
&#{&} {
color: red;
}
}
}

// compiles to
// .parent__child.parent__child { color: red; }

// You can also do this with deeper nested elements by
// prefacing the interpolation with the ancestor selectors:
.parent {
&__child {
.some .ancestor .elements &#{&} {
color: red;
}
}
}

// compiles to
// .some .ancestor .elements .parent__child.parent__child { color: red; }

For those of you who stumble upon this and use LESS, double &&'s are allowed:

.parent {
&__child {
&& {
color: red;
}
}
}

Nesting CSS selectors without increasing specificity

These days, in 2018, this is getting close to possible.

First of all, CSS4 will have a way that allows you to create more specific selectors without increasing specificity:

:where(.special-section) p {
color: red;
}

This will set the paragraph color inside .special-section to red, but with a specificity of 001 (i.e. the same specificity that a plain p selector would have).

The spec still calls this special pseudo-class :something(), but chances are it's going to be called :where(). (Side note: I really want this to be known as the "honey badger selector").

But that's still in the future.

However, there is actually a way to achieve this today, if you don't have to support IE anymore (or are happy with less-than-perfect fallbacks), and that is by using custom properties a.k.a. CSS variables.

So you want this:

.special-section p { color: red; }
.weird-font { color: magenta; }
p { color: green; }

but with the first part having a specificity that's lower than any selector with a class in it. You can do it like this:

.special-section p { --low-specificity-color: red; }
.weird-font { color: magenta; }
p { color: var(--low-specificity-color, green); }

If you run the below snippet in a modern browser, you should notice that the second paragraph is red, because it's in a special section, but the third paragraph is magenta, because it's .weird-font -- even though .weird-font has 010 specificity and .special-section p has 011.

.special-section p { --low-specificity-color: red; }.weird-font        { color: magenta; }p                  { color: var(--low-specificity-color, green); }
<p>This is a paragraph.</p>
<section class="special-section"> <p>This is a paragraph inside a special section.</p> <p class="weird-font">This is a paragraph with a weird font inside a special section.</p></section>
<p class="weird-font">This is a paragraph with a weird font.</p>
<div class="weird-font">This is a div with a weird font.</div>

CSS specificity: [parent ID] [descendant combinator (space)] [my class] more specific than [my ID]?

[My ID] is more specific than [parent ID]

No, a lone ID is a lone ID. What's important in your example is which element it is being applied to.

[parent ID] [descendant combinator (space)] [my class] more specific than [my ID]

Yes, it's valid, and it is more specific. Using the W3C's abc model:

#child { // 1, 0, 0 = 100 Specificity }

#parent .foo { // 1, 1, 0 = 110 Specificity }

#parent #child { // 2, 0, 0 = 200 Specificity }

#parent #child.foo { // 2, 1, 0 = 210 Specificity }

So, #parent .foo will trump #child, but #parent #child trumps #parent .foo