The spec states regarding calculating CSS specificity: (bold mine)
Note: Repeated occurrences of the same simple selector are allowed and do increase specificity.
So for example .class.class {}
has twice the specificity than .class {}
- DEMO
However, regarding the term 'simple selector' the spec has this to say: (bold mine)
A simple selector is either a type selector or universal selector followed immediately by zero or more attribute selectors, ID selectors, or pseudo-classes, in any order.
So since the spec says that repeated occurrences of the same simple selector are allowed - this would imply that you could repeat type selectors as well.
Well quite obviously something like this won't work: h1h1 { }
,
so I tried this: h1[]h1[] {}
- which doesn't work either,
so I'm wondering if there is a way to do this?
Increasing specificity by duplicating selectorDuplicating id, class, pseudo-class or attribute selectors within a compound selector will increase specificity when overriding very specific selectors over which you have no control. Use this sparingly, if at all. If using selector duplication, always comment your CSS.
ID selectors: ID selectors are the most specific. These select an element based on its ID attribute and have the syntax #idname. Class selectors, attribute selectors, and pseudo-class selectors: a) Class selectors select all elements in a CSS class and have the syntax .
Inline styles have the highest specificity. In our specificity weight system, they have a value of 1000. Let's try to make sense of it. The property values of selectors with a higher weight will always be applied over a selector with a lower weight.
ID selectors have a higher specificity than attribute selectors. You should always try to use IDs to increase the specificity. A class selector beats any number of element selectors. The universal selector and inherited selectors have a specificity of 0, 0, 0, 0.
It is possible to increase the specificity of a selector using type selectors, but not conventionally. The reason for this is explained below, but for those who are simply looking for an alternative, there are two of these. You can either chain :not()
pseudo-classes containing type selectors in a single compound selector:
h1 {} /* 1 type -> specificity = 0-0-1 */
h1:not(_) {} /* 2 types -> specificity = 0-0-2 */
h1:not(_):not(_) {} /* 3 types -> specificity = 0-0-3 */
h1:not(_):not(_):not(_) {} /* 4 types -> specificity = 0-0-4 */
Or, if you need to support legacy browsers that don't support :not()
, you can add redundant type selectors such as html
and body
to the beginning of a complex selector, although you are far more limited in this case as you may not be able to account for all elements:
h1 {} /* 1 type -> specificity = 0-0-1 */
body h1 {} /* 2 types -> specificity = 0-0-2 */
html body h1 {} /* 3 types -> specificity = 0-0-3 */
html body tr > td {} /* 4 types -> specificity = 0-0-4, assumes every td is a child of tr */
Needless to say, these are considered specificity hacks; as with all other CSS hacks, use them sparingly, if at all.
A compound selector may only have at most exactly one type selector preceding all other simple selectors. From Selectors 3 (which calls this a sequence of simple selectors):
A sequence of simple selectors is a chain of simple selectors that are not separated by a combinator. It always begins with a type selector or a universal selector. No other type selector or universal selector is allowed in the sequence.
And Selectors 4:
A compound selector is a sequence of simple selectors that are not separated by a combinator. If it contains a type selector or universal selector, that selector comes first in the sequence. Only one type selector or universal selector is allowed in the sequence.
Only type and universal selectors are subject to this rule; you may combine and repeat other simple selectors to increase specificity. Perhaps the spec could have reminded the reader about this in the section on calculating specificity, but I don't think it's absolutely necessary.
The reason for this rule is never stated explicitly, but it is fairly easy to deduce:
Remember that a type selector consists of simply an identifier, e.g. h1
. This is unlike other simple selectors which have their own distinguishing symbols in the grammar, such as an ID (#
), a class (.
), a pseudo-class (:
), or an attribute selector ([]
). You would not be able to have multiple consecutive type selectors without a way to parse them separately.
And even if you could chain type selectors, for example if you had another simple selector between them, the only possible use for this would be as a specificity hack, as described in the question, which means you would only be able to use it if all the type selectors were the same; no other combination of type selectors could work.
This is because Selectors assumes that the document language defines every element to have exactly one element type. For example, in HTML, an h1
is always an h1
; it can never be any other type of element. A compound selector asking for an element that is both an h1
as well as a p
can never match anything, for the same reason something like [type=text][type=password]
can never match anything in a document language that does not support duplicate attributes.
However, with the above points in mind, it is still possible to create a compound selector that contains more than one type selector for specificity — by using the :not()
pseudo-class:
The specificity of a :not()
pseudo-class is equal to its argument. The pseudo-class itself is not counted. This is mentioned in the first link. This means the specificity of :not(h1)
is equivalent to h1
— one type selector.
Since an element can only be of exactly one type, this means :not()
with any other type selector will be a guaranteed match.
Since a compound selector may include any number of pseudo-classes, you can repeat the negation as many times as necessary, even if the negations all use the same type selector.
And since Selectors doesn't care if a selector makes sense in the context of any particular document language, you can use a type selector that is guaranteed to never match any element in a conforming HTML document as long as it satisfies the Selectors grammar for a type selector. A type selector consists of nothing but a CSS identifier, so any CSS identifier is fair game. Including _
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With