Environment
ESLint version: v10.7.0
@eslint/css version: v1.4.0
Node version: v22.15.0
npm version: v11.12.1
Operating System: Windows 11
Which language are you using?
stylesheet
What did you do?
I enabled use-layers while adopting cascade layers in a project that contains CSS animations, and every @keyframes block immediately produced errors on its keyframe steps.
Configuration
import css from "@eslint/css";
export default [
{
files: ["**/*.css"],
plugins: { css },
language: "css/css",
rules: {
"css/use-layers": "error",
},
},
];
@keyframes spin {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
The from / to form and vendor-prefixed keyframes (@-webkit-keyframes) produce the same errors.
What did you expect to happen?
No errors. Keyframe steps (0%, 100%, from, to) are not style rules that participate in the cascade — they are keyframe selectors inside an at-rule — so requiring them to be "within a layer" doesn't apply to them.
Wrapping the @keyframes in @layer does silence the errors, but that's not a real resolution: @keyframes has no relationship to cascade layers, so the rule effectively forces authors to either wrap every animation in a layer or disable the rule around keyframes.
What actually happened?
Each keyframe step is reported as a rule that should be within a layer:
2:3 error Expected rule to be within a layer css/use-layers
5:3 error Expected rule to be within a layer css/use-layers
Root cause: css-tree parses keyframe steps as Rule nodes, and the Rule handler in src/rules/use-layers.js reports any Rule whenever layerDepth is 0, without checking whether the node is inside a @keyframes block:
Rule(node) {
if (layerDepth > 0) {
return;
}
context.report({
loc: node.loc,
messageId: "missingLayer",
});
},
A possible fix is to track keyframes the same way no-duplicate-keyframe-selectors does - an Atrule[name=/^(-(o|moz|webkit)-)?keyframes$/i] enter/exit pair maintaining a keyframesDepth, and an early return in the Rule handler when inside one. Rules nested in other at-rules (@media, @supports) should still be reported, since those do participate in the cascade.
Link to Minimal Reproducible Example
https://stackblitz.com/edit/stackblitz-starters-ru1f8tzx?description=Starter%20project%20for%20Node.js,%20a%20JavaScript%20runtime%20built%20on%20Chrome%27s%20V8%20JavaScript%20engine&file=eslint.config.mjs,test.css&title=node.new%20Starter
Participation
AI acknowledgment
Additional comments
No response
Environment
ESLint version: v10.7.0
@eslint/css version: v1.4.0
Node version: v22.15.0
npm version: v11.12.1
Operating System: Windows 11
Which language are you using?
stylesheet
What did you do?
I enabled
use-layerswhile adopting cascade layers in a project that contains CSS animations, and every@keyframesblock immediately produced errors on its keyframe steps.Configuration
The
from/toform and vendor-prefixed keyframes (@-webkit-keyframes) produce the same errors.What did you expect to happen?
No errors. Keyframe steps (
0%,100%,from,to) are not style rules that participate in the cascade — they are keyframe selectors inside an at-rule — so requiring them to be "within a layer" doesn't apply to them.Wrapping the
@keyframesin@layerdoes silence the errors, but that's not a real resolution:@keyframeshas no relationship to cascade layers, so the rule effectively forces authors to either wrap every animation in a layer or disable the rule around keyframes.What actually happened?
Each keyframe step is reported as a rule that should be within a layer:
Root cause: css-tree parses keyframe steps as
Rulenodes, and theRulehandler insrc/rules/use-layers.jsreports anyRulewheneverlayerDepthis0, without checking whether the node is inside a@keyframesblock:A possible fix is to track keyframes the same way
no-duplicate-keyframe-selectorsdoes - anAtrule[name=/^(-(o|moz|webkit)-)?keyframes$/i]enter/exit pair maintaining akeyframesDepth, and an early return in theRulehandler when inside one. Rules nested in other at-rules (@media,@supports) should still be reported, since those do participate in the cascade.Link to Minimal Reproducible Example
https://stackblitz.com/edit/stackblitz-starters-ru1f8tzx?description=Starter%20project%20for%20Node.js,%20a%20JavaScript%20runtime%20built%20on%20Chrome%27s%20V8%20JavaScript%20engine&file=eslint.config.mjs,test.css&title=node.new%20Starter
Participation
AI acknowledgment
Additional comments
No response