Skip to content

noExcessiveSelectorComplexity (CSS)

Language CSS
biome.json
{
"linter": {
"rules": {
"nursery": {
"noExcessiveSelectorComplexity": "error"
}
}
}
}

Limit how complex selectors can be, and disallow chosen parts of selectors.

Long selectors that mix many IDs, element names, attributes, and pseudo-classes are hard to read and hard to override. They also tie styles closely to the structure of the page, so small changes to the HTML can break them.

This rule lets you set a maximum for each kind of selector part, and list combinators, pseudo-classes, pseudo-elements, attributes, and attribute operators that aren’t allowed. The rule does nothing until at least one option is set.

Each selector in a comma-separated list is checked on its own. For example, #a, #b contains two selectors with one ID each.

Selectors inside a pseudo-class such as :not(), :is(), or :has() are checked as separate selectors, and don’t count toward the selector that contains them. For example, #a:not(#b) contains two selectors with one ID each.

Nested selectors are checked as written, without combining them with the selectors of their parent rules.

biome.json
{
"linter": {
"rules": {
"nursery": {
"noExcessiveSelectorComplexity": {
"level": "on",
"options": {
"maxIds": 1,
"disallowPseudoClasses": [
"hover"
]
}
}
}
}
}
}
#main #sidebar {}
code-block.css:1:1 lint/nursery/noExcessiveSelectorComplexity ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚠ This selector has too many ID selectors: it has 2, but the limit is 1.

> 1 │ #main #sidebar {}
│ ^^^^^^^^^^^^^^
2 │

ℹ Complex selectors are hard to read and override, and break easily when the page structure changes.

ℹ Simplify the selector, for example by giving the element a class and selecting it directly.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

button:hover {}
code-block.css:1:7 lint/nursery/noExcessiveSelectorComplexity ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚠ The pseudo-class :hover isn't allowed.

> 1 │ button:hover {}
│ ^^^^^^
2 │

ℹ The rule's configuration disallows this pseudo-class in selectors.

ℹ Rewrite the selector without it, for example by giving the element a class and selecting it directly.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

#main .sidebar,
#footer {}
#main:not(#sidebar) {}
button:focus {}

Default: no limit

The maximum number of ID selectors, such as #main, allowed in a single selector.

biome.json
{
"linter": {
"rules": {
"nursery": {
"noExcessiveSelectorComplexity": {
"level": "on",
"options": {
"maxIds": 1
}
}
}
}
}
}
#main > #sidebar {}
code-block.css:1:1 lint/nursery/noExcessiveSelectorComplexity ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚠ This selector has too many ID selectors: it has 2, but the limit is 1.

> 1 │ #main > #sidebar {}
│ ^^^^^^^^^^^^^^^^
2 │

ℹ Complex selectors are hard to read and override, and break easily when the page structure changes.

ℹ Simplify the selector, for example by giving the element a class and selecting it directly.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

#main .sidebar {}

Default: no limit

The maximum number of type selectors allowed in a single selector. A type selector matches elements by their tag name, such as div or a.

biome.json
{
"linter": {
"rules": {
"nursery": {
"noExcessiveSelectorComplexity": {
"level": "on",
"options": {
"maxTypes": 2
}
}
}
}
}
}
ul li a {}
code-block.css:1:1 lint/nursery/noExcessiveSelectorComplexity ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚠ This selector has too many type selectors: it has 3, but the limit is 2.

> 1 │ ul li a {}
│ ^^^^^^^
2 │

ℹ Complex selectors are hard to read and override, and break easily when the page structure changes.

ℹ Simplify the selector, for example by giving the element a class and selecting it directly.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

li.item a {}

Default: no limit

The maximum number of attribute selectors, such as [type="text"], allowed in a single selector.

biome.json
{
"linter": {
"rules": {
"nursery": {
"noExcessiveSelectorComplexity": {
"level": "on",
"options": {
"maxAttributes": 1
}
}
}
}
}
}
[name="email"][type="text"] {}
code-block.css:1:1 lint/nursery/noExcessiveSelectorComplexity ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚠ This selector has too many attribute selectors: it has 2, but the limit is 1.

> 1 │ [name="email"][type="text"] {}
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^
2 │

ℹ Complex selectors are hard to read and override, and break easily when the page structure changes.

ℹ Simplify the selector, for example by giving the element a class and selecting it directly.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

input[type="text"] {}

Default: no limit

The maximum number of pseudo-classes, such as :hover or :first-child, allowed in a single selector. Pseudo-elements such as ::before don’t count, including the older single-colon forms :before, :after, :first-line, and :first-letter.

biome.json
{
"linter": {
"rules": {
"nursery": {
"noExcessiveSelectorComplexity": {
"level": "on",
"options": {
"maxPseudoClasses": 1
}
}
}
}
}
}
li:first-child:hover {}
code-block.css:1:1 lint/nursery/noExcessiveSelectorComplexity ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚠ This selector has too many pseudo-classes: it has 2, but the limit is 1.

> 1 │ li:first-child:hover {}
│ ^^^^^^^^^^^^^^^^^^^^
2 │

ℹ Complex selectors are hard to read and override, and break easily when the page structure changes.

ℹ Simplify the selector, for example by giving the element a class and selecting it directly.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

a:hover::before {}

Default: no limit

The maximum number of universal selectors (*) allowed in a single selector.

biome.json
{
"linter": {
"rules": {
"nursery": {
"noExcessiveSelectorComplexity": {
"level": "on",
"options": {
"maxUniversals": 1
}
}
}
}
}
}
* > * {}
code-block.css:1:1 lint/nursery/noExcessiveSelectorComplexity ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚠ This selector has too many universal selectors: it has 2, but the limit is 1.

> 1 │ * > * {}
│ ^^^^^
2 │

ℹ Complex selectors are hard to read and override, and break easily when the page structure changes.

ℹ Simplify the selector, for example by giving the element a class and selecting it directly.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

.list > * {}

Default: no limit

The maximum number of compound selectors allowed in a single selector. A compound selector is a group of selectors written together without spaces or combinators. For example, nav a.link:hover has two compound selectors: nav and a.link:hover.

biome.json
{
"linter": {
"rules": {
"nursery": {
"noExcessiveSelectorComplexity": {
"level": "on",
"options": {
"maxCompounds": 2
}
}
}
}
}
}
nav ul a {}
code-block.css:1:1 lint/nursery/noExcessiveSelectorComplexity ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚠ This selector has too many compound selectors: it has 3, but the limit is 2.

> 1 │ nav ul a {}
│ ^^^^^^^^
2 │

ℹ Complex selectors are hard to read and override, and break easily when the page structure changes.

ℹ Simplify the selector, for example by giving the element a class and selecting it directly.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

nav a.link:hover {}

Default: no limit

The maximum number of combinators allowed in a single selector. A combinator is the symbol between two compound selectors: a space, >, +, ~, or ||.

biome.json
{
"linter": {
"rules": {
"nursery": {
"noExcessiveSelectorComplexity": {
"level": "on",
"options": {
"maxCombinators": 1
}
}
}
}
}
}
.menu > .item > a {}
code-block.css:1:1 lint/nursery/noExcessiveSelectorComplexity ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚠ This selector has too many combinators: it has 2, but the limit is 1.

> 1 │ .menu > .item > a {}
│ ^^^^^^^^^^^^^^^^^
2 │

ℹ Complex selectors are hard to read and override, and break easily when the page structure changes.

ℹ Simplify the selector, for example by giving the element a class and selecting it directly.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

.menu > .item {}

Default: []

Combinators that aren’t allowed. Accepted values are " " (a space, which selects elements inside another element), ">", "+", "~", and "||".

biome.json
{
"linter": {
"rules": {
"nursery": {
"noExcessiveSelectorComplexity": {
"level": "on",
"options": {
"disallowCombinators": [
">"
]
}
}
}
}
}
}
.menu > .item {}
code-block.css:1:7 lint/nursery/noExcessiveSelectorComplexity ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚠ The combinator > isn't allowed.

> 1 │ .menu > .item {}
│ ^
2 │

ℹ The rule's configuration disallows this combinator in selectors.

ℹ Rewrite the selector without it, for example by giving the element a class and selecting it directly.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

.menu .item {}

Default: []

Pseudo-classes that aren’t allowed, written without the leading colon. Names are compared without regard to letter case.

biome.json
{
"linter": {
"rules": {
"nursery": {
"noExcessiveSelectorComplexity": {
"level": "on",
"options": {
"disallowPseudoClasses": [
"hover"
]
}
}
}
}
}
}
a:not(.active):hover {}
code-block.css:1:15 lint/nursery/noExcessiveSelectorComplexity ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚠ The pseudo-class :hover isn't allowed.

> 1 │ a:not(.active):hover {}
│ ^^^^^^
2 │

ℹ The rule's configuration disallows this pseudo-class in selectors.

ℹ Rewrite the selector without it, for example by giving the element a class and selecting it directly.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

a:not(.active) {}

Default: []

Pseudo-elements that aren’t allowed, written without the leading colons. Names are compared without regard to letter case. The older single-colon forms :before, :after, :first-line, and :first-letter are checked as well.

biome.json
{
"linter": {
"rules": {
"nursery": {
"noExcessiveSelectorComplexity": {
"level": "on",
"options": {
"disallowPseudoElements": [
"before"
]
}
}
}
}
}
}
a:before {}
code-block.css:1:2 lint/nursery/noExcessiveSelectorComplexity ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚠ The pseudo-element :before isn't allowed.

> 1 │ a:before {}
│ ^^^^^^^
2 │

ℹ The rule's configuration disallows this pseudo-element in selectors.

ℹ Rewrite the selector without it, for example by giving the element a class and selecting it directly.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

input::placeholder {}

Default: []

Attribute names that aren’t allowed in attribute selectors. Names must match exactly, including letter case.

biome.json
{
"linter": {
"rules": {
"nursery": {
"noExcessiveSelectorComplexity": {
"level": "on",
"options": {
"disallowAttributes": [
"class"
]
}
}
}
}
}
}
[class*="button"] {}
code-block.css:1:2 lint/nursery/noExcessiveSelectorComplexity ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚠ The attribute class isn't allowed.

> 1 │ [class*="button"] {}
│ ^^^^^
2 │

ℹ The rule's configuration disallows this attribute in selectors.

ℹ Rewrite the selector without it, for example by giving the element a class and selecting it directly.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

input[type="text"] {}

Default: []

Operators that aren’t allowed in attribute selectors. Accepted values are "=", "~=", "|=", "^=", "$=", and "*=".

biome.json
{
"linter": {
"rules": {
"nursery": {
"noExcessiveSelectorComplexity": {
"level": "on",
"options": {
"disallowAttributeMatchers": [
"*="
]
}
}
}
}
}
}
[class*="button"] {}
code-block.css:1:7 lint/nursery/noExcessiveSelectorComplexity ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

⚠ The attribute operator *= isn't allowed.

> 1 │ [class*="button"] {}
│ ^^
2 │

ℹ The rule's configuration disallows this attribute operator in selectors.

ℹ Rewrite the selector without it, for example by giving the element a class and selecting it directly.

ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.

[class="button"] {}