A list of rules for when CSS properties have no effect
In certain situations, CSS properties do not have any effect on an element. This may depend on what other properties are currently applied to it, the type of the element, its parent elements, or which CSS rule the property is included in.\ A simple, but common, example is trying to set
widthon an inline level element like a
There are so many properties in CSS, and so many ways one can combine them that it's nearly impossible for anyone to know which situations are going to lead to CSS properties not doing anything.
The tricky thing is, even if a property and its value apply fine to an element (i.e. there is no syntax error and the property and its value are correct), nothing garanties that it will actually do anything to the element.\ The only thing that knows if a given property should modify the layout or style of an element in a given situation is the layout and style engine of the browsers we use. This information is not readily available and is burried deep into the browser engine's code.
The idea here is to put together a list of rules for when these things happen. No such list exist today in a way that can be used in any meaningful way.\ Such a list should describe the various dependencies that exist between a property and other properties or between a property and the element it's applied on, and should describe when that dependency results in the property not having any effect on the element.
The approach is not one that can easily lead to creating auditing tools. What that means is, the goal isn't to create a list of rules that could be used to run a tool on your entire CSS codebase to detect things that are useless.
The reason for this is that it isn't possible to determine if a property has any effect unless you know which element it is applied to, and you have access to this element, at runtime.
As an example, only at runtime can you know that an element is a grid item and that, therefore, the
floatproperty won't have any effect on it.\ Trying to do the same thing statically would require to detect if the CSS rule that
floatproperty is in even applies to any existing element, and would require to apply all of the other rules in the codebase to know whether the element is a grid item.
What you will find in this repository is a list of rules that can be used by people or programs to know when CSS properties are inactive in certain situations.
The file is written in a custom format. It contains a list of rules, each rule having the following shape:
DeclarationSet = Condition
What the above means is: if
Conditionis truthy, then the properties in the DeclarationSet are inactive.
DeclarationSethas the following shape:
This means that either a property, as a whole, can be inactive, or a property with a specific value only.
Let's look at a simple example:
flex-direction flex-flow flex-wrap = !flexContainer
The above rule means that
flex-wrapare inactive (i.e. have no effect) if the element they are applied to is not a flexbox container element.
Let's look at a more complex example:
float|left float|right = flexItem || gridItem
declarationSetcontains both property names and values. In this example, only
float:righthave no effect if the element they apply to is a flexbox item or a grid item. If the property was
float:none, then it wouldn't have any effect either because this is reseting the
floatproperty to its default, but the fact that it doesn't have effect isn't due to the element being a flexbox or grid item.
It is worth noting that property names and values can have wildcards in them. Let's look at two examples:
*means that a rule applies to all properties.
align-content|*centermeans that a rule applies to all
align-contentproperties that have a value ending with the string
safe centerwould match here too).
That's about it for the format. The only remaining thing is the
[all-but]specifier that may come before a
declarationSetwhich specifies that the rule applies to all properties except the ones listed in the set.
Here is an example of an all-but rule:
[all-but] font font-family font-feature-settings font-kerning font-language-override font-optical-sizing font-size font-size-adjust font-stretch font-style font-synthesis font-variant font-variant-alternates font-variant-caps font-variant-east-asian font-variant-ligatures font-variant-numeric font-variant-position font-variation-settings line-height = firstLetterPseudo || firstLinePseudo || markerPseudo
In the rule above, if the element is a
::first-linepseudo or a
::markerpseudo then all of the properties are inactive except the ones listed in the
As you can see above, each rule has a condition. The conditions use some specific keywords like
Each keyword is implemented by a helper function that has the same name and returns a boolean. If the function returns
true, then the part of the condition the keyword represents is true, otherwise it's false.
For these helper functions to work, they need access to some data. In particular: the element's computed style, the element's parent's computed style (note that by element's parent we mean the rendered parent, so if a parent is
display:contents, we expect to walk up to its parent, and so on), the CSS rule object the property is coming from, and the element itself. This data is given to the helpers as function arguments.
In this repository, you will also find a PEG.js grammar file that can be used to generate a parser for the list of rules, and a simple AST-like JSON file, being the output of that parser.
Back in 2019, I was working at Mozilla on the Firefox DevTools team and we shipped a feature called Inactive CSS then.
That feature was based on the awesome research Sarah Lim and her colleagues had done on the topic, and this Firefox feature went on to becoming quite popular.
We also understood, at the time, that it was dangerous to make this list too complete too eagerly as any false positive would ruin the trust that users would have in the tool. Indeed the feature was, after all, based on a list of heuristics and not a 100% garanteed checker. There was room for mistakes, especially given the complexity of how and when CSS applies.\ So the list in Firefox is not as complete as it could be and is likely not going to evolve very fast.
My goal here is to create a similar list, but in a format that people (and tools) can more easily use, and put it on GitHub with the hope that it could benefit from more people contributing to it and making it as complete and correct as it possibly can.
♥ I would love to accept your PRs if you can think of ways to improve this.