Open aryan02420 opened 5 days ago
A CSS equivalent to JavaScript's no-restricted-syntax
rule would cover this use case and more.
We couldn't take this approach in Stylelint because the general parser we use is limited to a few node types. We ended up with many separate rules, including selector-max-id
, that disallow or limit things. We turn on only a handful of these in our standard config because we found restricting CSS syntax is rarely universal. There is also the stylelint-no-restricted-syntax
plugin that can target these few node types.
The CSSTree parser is far more granular and id selectors are a node type (IdSelector
):
{
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "IdSelector",
"message": "Id selectors are not allowed."
},
]
}
}
(Mixing AST selectors and CSS selector types could be confusing for people, though.)
The ID selector has high specificity... If using the ID is the only way to target the element — perhaps because you do not have access to the markup and cannot edit it — consider using the ID within an attribute selector, such as
p[id="header"]
.
A rule to limit specificity would complement the no-restricted-syntax
one. In Stylelint, we have selector-max-specificity
, and people use it when they want to limit the specificity of selectors.
A rule to limit specificity would complement the
no-restricted-syntax
one. In Stylelint, we haveselector-max-specificity
, and people use it when they want to limit the specificity of selectors.
Ah interesting, that may be a better way to go than just limited blocking of ID selectors.
Looking into this right now. Would it make sense to ever set a minimum specificity? For instance, would a rule like this have any value?
specificity: ["error". {
max: [0, 3, 5],
min: [0, 1, 0]
}
Rough draft: https://github.com/eslint/css/pull/24
As a +1 to a restricted syntax rule, I'd also want to ban some tag selectors. These selectors tend to be slow with common elements:
.foo > div {} /* must evaluate every div */
or they get abused by developers instead of using classes
dialog > div > span:nth-child(1) > img {}
or they get abused by developers instead of using classes
dialog > div > span:nth-child(1) > img {}
I agree. Classes are always better than tag selectors and less prone to breakage
Not everyone would use a no-id-selector
rule as there's a diverse set of CSS methodologies, and type selectors are sometimes a good fit, especially when the CSS is scoped.
For example, with the @scope
at-rule:
@scope (.component) to (.content) {
a {
color: red;
}
}
Or within the Shadow Dom using (Lit) Web Components:
import {LitElement, html, css} from 'lit';
import {customElement} from 'lit/decorators.js';
@customElement('my-element')
export class MyElement extends LitElement {
static styles = css`
p {
color: green;
}
`;
protected render() {
return html`<p>I am green!</p>`;
}
}
The nice thing about a no-restricted-syntax
rule is that people can configure it for their preferred approach. For example, if they use something like CSS modules for scoping, they'd probably want to disallow:
{
"rules": {
"no-restricted-syntax": [
"error",
{
"selector": "IdSelector",
"message": "Id selectors are not allowed."
},
{
"selector": "TypeSelector",
"message": "Type selectors are not allowed."
},
{
"selector": "Rule > SelectorList > Selector > Combinator",
"message": "Top-level combinators are not allowed."
},
]
}
}
By only disallowing top-level combinators, you'll still be able to use them in powerful pseudo-classes like :has()
. It would allow things like this:
.component {
&:hover {}
}
.child {
&:has(+ .alt) {}
}
While disallowing things like:
#id {
& > div {
& > div {}
}
}
A no-restricted-syntax
rule would cover many of Stylelint's disallow and limit rules, including selector-max-id
and selector-combinator-disallowed-list
.
It turns out that the core no-restricted-syntax
rule can already be used with CSS!
You can disallow id and type selectors with:
import css from "@eslint/css";
export default [
{
files: ["**/*.css"],
language: "css/css",
...css.configs.recommended,
},
{
rules: {
"no-restricted-syntax": [
"error",
{
selector: "IdSelector",
message: "Id selectors are not allowed.",
},
{
selector: "TypeSelector",
message: "Type selectors are not allowed.",
},
],
},
},
];
Rule details
Flag any CSS selector that uses the ID selector
What type of rule is this?
Warns about a potential problem
Example code
The
#id
selector has very high specificity and doesn't always play well with other rules. An alternative is to use a.class
selector instead.When using a component-based UI framework, id selectors are often not very useful. You can hardcode an id into a component, but this makes the component non-reusable. The framework-generated unique ids cannot be referenced in CSS. Therefore, using id selectors in these cases is likely a mistake.
Participation
Additional comments
From MDN: