Overriding CSS property all: unset - css

For a CSS framework I am developing, I am using all: unset, which by itself works fine:
#foo { all: unset; }
However, in certain cases, I want to "undo" the effect of this rule, as in
#foo:hover { all: auto; }
However, this obviously does not work because there is no value of auto for all. Instead, we have the values inherit and initial, which instead of "cancelling" the all property, have different effects: of reverting all values to their parent's value, or their initial (I assume this means system-level default values).
To accomplish what I want, I am currently doing
#foo:not(:hover) { all: unset; }
which works fine, but is not too scalable if I want to do this for multiple pseudo-classes, for example, and I would prefer to override the all: unset property? Is there any way to do so?

It does not appear to be possible to undo the effects of the all property once it has been specified. This may be due to all being a shorthand property (that happens to accept only the CSS-wide keywords as values).
You can't erase a shorthand declaration from the cascade the same way that css-cascade-4's introduction of the revert keyword allows you to erase author-level declarations, and that's because a shorthand property doesn't exist as its own entity in the cascade; instead, it simply represents all of its component properties. Like with the more traditional shorthand properties such as background and font, the only way to override a shorthand declaration that has been applied is to re-specify the values for the longhands that were overridden, either via longhand declarations or via another shorthand declaration. But you can't do the latter with the all property since it only accepts CSS-wide keywords.
As the former is obviously not practical with the all shorthand, since you can't predict which author-level declarations are being overridden to begin with, your only other option is to restrict it via a selector, thereby preventing it from ever applying in specific circumstances in the first place. Hopefully we will see more implementations of level 4 :not() in the near future, which will make writing selectors a little easier.

Additionally to what BoltClock explained, what you want is not currently possible even for non-shorthand properties.
* { color: red; }
#foo { color: unset; }
#foo:hover { color: /* How to revert to red? */ }
Once you add a value which wins the cascade, there is not way to tell the cascade to "go back" and get the previous winner instead. You must set it explicitly, but that's only possible if you know it.
The closest thing is the revert keyword, introduced by CSS Cascade 4, which rolls back the cascade to previous origin level. But rolling the cascade back to the previous winner in the same origin level is currently not possible.
Then, the solution is restricting your selectors to apply only when you want them. This way there is no need to undo.

Have you tried
all: revert
More infos here MDN

Related

all: initial vs. using CSS resets

I know there are many so-called "css resets", e.g.
https://ageek.dev/normalize-css,
https://meyerweb.com/eric/tools/css/reset/, or
https://elad2412.github.io/the-new-css-reset/
But what I don't understand is why it seems it is not possible to use something way more simpler.
As far as I know, the initial keyword resets a property to the value that is defined as the default value of that property in the CSS specification.
And since nowadays we have the all property-like keyword, I expected that I can use something like
* {
all: initial;
}
or
:root {
all: initial;
}
instead of all these reset.csss and normalize.csss. That is, I expected that one of these short snipets will help me to remove styles added to a web page from user agent stylesheet.
But it doesn't really work as I expected it. It seems that
:root, html, body {
all: initial
}
doesn't really remove styles "inherited" from user agent stylesheet at all, and
* {
all: initial
}
removes styles too aggressively. For example, it makes my style and script elements visible! I don't think that CSS specification says that these two elements should be visible. I'm sure that CSS specification says that they should be not visible. That is, it seems that
* {
all: initial
}
instead of resetting my styles to the CSS specification-level, resets them to the absolute-zero-level. This is not what I want.
Can anybody explain what is wrong in my understanding?
You are correct that initial resets to initial values for a given CSS property, but note that CSS properties have no initial value for each element-- they only have an initial value for that property, which will be the same for any and all elements it is applied to. For instance, the color property spec has a single initial value defined-- not a list of initial values to which it should be set for every element. So when you use it in conjunction with all, using:
* {
all: initial
}
...you are telling the browser to take every property of every single element and reset it to the property's default value. So, for instance, the display property spec defines its initial value as inline-- so every single element on your page will be displayed as inline.

why isnt initial value working as I'm expecting it to, what am I not understanding? [duplicate]

Is it possible to override the display property with its default value? For example if I have set it to none in one style, and I want to override it in a different with its default.
Or is the only way to find out what the default of that element is and then set it to that? Would like to not have to know if the element is usually block, inline or whichever...
A browser's default styles are defined in its user agent stylesheet, the sources of which you can find here. Unfortunately, the Cascading and Inheritance level 3 spec does not appear to propose a way to reset a style property to its browser default. However there are plans to reintroduce a keyword for this in Cascading and Inheritance level 4 — the working group simply hasn't settled on a name for this keyword yet (the link currently says revert, but it is not final). Information about browser support for revert can be found on caniuse.com.
While the level 3 spec does introduce an initial keyword, setting a property to its initial value resets it to its default value as defined by CSS, not as defined by the browser. The initial value of display is inline; this is specified here. The initial keyword refers to that value, not the browser default. The spec itself makes this note under the all property:
For example, if an author specifies all: initial on an element it will block all inheritance and reset all properties, as if no rules appeared in the author, user, or user-agent levels of the cascade.
This can be useful for the root element of a "widget" included in a page, which does not wish to inherit the styles of the outer page. Note, however, that any "default" style applied to that element (such as, e.g. display: block from the UA style sheet on block elements such as <div>) will also be blown away.
So I guess the only way right now using pure CSS is to look up the browser default value and set it manually to that:
div.foo { display: inline-block; }
div.foo.bar { display: block; }
(An alternative to the above would be div.foo:not(.bar) { display: inline-block; }, but that involves modifying the original selector rather than an override.)
If using javascript is allowed, you can set the display property to an empty string. This will cause it to use the default for that particular element.
var element = document.querySelector('span.selector');
// Set display to empty string to use default for that element
element.style.display = '';
Here is a link to a jsbin.
This is nice because you don't have to worry about the different types of display to revert to (block, inline, inline-block, table-cell, etc).
But, it requires javascript, so if you are looking for a css-only solution, then this is not the solution for you.
Note: This overrides inline styles, but not styles set in css
Unset display:
You can use the value unset which works in both Firefox and Chrome.
display: unset;
.foo { display: none; }
.foo.bar { display: unset; }
No, it is generally not possible. Once some CSS (or HTML) code sets a value for a property on an element, there is no way to undo it and tell the browser to use its default value.
It is of course possible to set a property a value that you expect to be the default value. This may work rather widely if you check the Rendering section of HTML5 CR, mostly reflecting what browsers actually do.
Still, the answer is “No”, because browsers may have whatever default values they like. You should analyze what was the reason for wanting to reset to defaults; the original problem may still be solvable.
What worked for me was revert!
revert resets the property to its inherited value if it inherits from its parent or to the default value established by the user agent's stylesheet.
If you have access to JavaScript, you can create an element and read its computed style.
function defaultValueOfCssPropertyForElement(cssPropertyName, elementTagName, opt_pseudoElement) {
var pseudoElement = opt_pseudoElement || null;
var element = document.createElement(elementTagName);
document.body.appendChild(element);
var computedStyle = getComputedStyle(element, pseudoElement)[cssPropertyName];
element.remove();
return computedStyle;
}
// Usage:
defaultValueOfCssPropertyForElement('display', 'div'); // Output: 'block'
defaultValueOfCssPropertyForElement('content', 'div', ':after'); // Output: 'none'
Concerning the answer by BoltClock and John, I personally had issues with the initial keyword when using IE11. It works fine in Chrome, but in IE it seems to have no effect.
According to this answer IE does not support the initial keyword:
Div display:initial not working as intended in ie10 and chrome 29
I tried setting it blank instead as suggested here:
how to revert back to normal after display:none for table row
This worked and was good enough for my scenario. Of course to set the real initial value the above answer is the only good one I could find.
According to my understanding to your question, as an example: you had a style at the beginning in style sheet (ex. background-color: red), then using java script you changed it to another style (ex. background-color: green), now you want to reset the style to its original value in style sheet (background-color: red) without mentioning or even knowing its value (ex. element.style.backgroundColor = 'red')...!
If I'm correct, I have a good solution for you which is using another class name for the element:
steps:
set the default styles in style sheet as usual according to your desire.
define a new class name in style sheet and add the new style you want.
when you want to trigger between styles, add the new class name to the element or remove it.
if you want to edit or set a new style, get the element by the new class name and edit the style as desired.
I hope this helps. Regards!

Why does the UA's link color beat an author's color for (say) body?

I'm looking for the portion of the CSS standard that explains this (rather sensible) behavior. That is, if I write the property body { color: green; } I'd expect (reading the documentation, not from experience) all of body's children to have green color, including (visited and not visited) as. I'm aware there are user agent definitions, but the order of the cascade, in ascending order of preference, is:
user agent declarations
user normal declarations
author normal declarations
author important declarations
user important declarations
Why, then, isn't the inherited value of color used for links? I realize this would greatly limit the usefulness of the user agent's default style sheets, but I'm just curious about why this isn't a violation of the standard. I'm clearly missing something!
Edit: My "why" refers strictly to explicit support in the CSS standard, not to why it would make sense.
This is the cascade order (taken from w3.org)
To find the value for an element/property combination, user agents must apply the following sorting order:
Find all declarations that apply to the element and property in question, for the target media type.
Sort according to importance (normal or important) and origin (author, user, or user agent). In ascending order of precedence:
user agent declarations
user normal declarations
author normal declarations
author important declarations
user important declarations
Sort rules with the same importance and origin by specificity of selector: more specific selectors will override more general ones. Pseudo-elements and pseudo-classes are counted as normal elements and classes, respectively.
Finally, sort by order specified: if two declarations have the same weight, origin and specificity, the latter specified wins. Declarations in imported style sheets are considered to be before any declarations in the style sheet itself.
Apart from the "!important" setting on individual declarations, this strategy gives author's style sheets higher weight than those of the reader. User agents must give the user the ability to turn off the influence of specific author style sheets, e.g., through a pull-down menu.
So the behaviour you are observing happens because of specificity.
There is a second order to the cascade and that's the order of which selectors override which other selectors.
For example, if you define in your stylesheet:
body { color: green; }
h1 { color: purple; }
the h1 has higher order of importance and will OVERRIDE the greenness of the body.
As to the general order of the cascade, this is the correct order, but you have to realize that user agent declarations vs. the things you define in a stylesheet are overridden SEPERATELY FOR EACH ELEMENT.
For example, let's say that the user agent has defined:
body { font-size: 10px; }
h1 { font-size: 20px; }
a { color: purple; }
and you are defining in your stylesheet:
body { font-size: 30px; color: green; }
Everything in the body will be 30px green except for those other two tags that the user agent stylesheet has already defined. You have to override ALL of them. Not just one user agent definition must be overridden but ALL OF THEM have to be overridden. Your styles WILL take precedence over the user agent stylesheet. Just gotta be careful to catch them all.
This is officially termed "inheritance". You're right, I guess the writers of w3 didn't specify explicitly how only one element at a time from the UA stylesheet gets overridden by your own personal stylesheet. They maybe thought it was obvious but they should probably add into the official documentation how the two should "mesh together", here, in this official documentation of inheritance: w3.org/TR/CSS2/cascade.html
They did mention it in the wiki, I think we've discussed, so I'll include it in the answer, as well: w3.org/wiki/Inheritance_and_cascade
I'm rather embarrassed... I tried deleting this question but it was too late. In case another person finds the same issue, the answer is pretty clearly explained at the beginning of the section I quoted in the standard. Namely, the definition of specified value:
User agents must first assign a specified value to each property based on the following mechanisms (in order of precedence):
If the cascade results in a value, use it.
Otherwise, if the property is inherited and the element is not the root of the document tree, use the computed value of the parent element.
Otherwise use the property's initial value. The initial value of each property is indicated in the property's definition.
So, inheritance only applies if there is no prior definition, be it provided by the user agent, the user or the author (only then do we get to point 2)... Pretty clear, and again I'm embarrassed to have missed it!
I will not choose my own answer. Feel free to copy and paste!

Can display:auto replace initial keyword on IE? [duplicate]

Is it possible to override the display property with its default value? For example if I have set it to none in one style, and I want to override it in a different with its default.
Or is the only way to find out what the default of that element is and then set it to that? Would like to not have to know if the element is usually block, inline or whichever...
A browser's default styles are defined in its user agent stylesheet, the sources of which you can find here. Unfortunately, the Cascading and Inheritance level 3 spec does not appear to propose a way to reset a style property to its browser default. However there are plans to reintroduce a keyword for this in Cascading and Inheritance level 4 — the working group simply hasn't settled on a name for this keyword yet (the link currently says revert, but it is not final). Information about browser support for revert can be found on caniuse.com.
While the level 3 spec does introduce an initial keyword, setting a property to its initial value resets it to its default value as defined by CSS, not as defined by the browser. The initial value of display is inline; this is specified here. The initial keyword refers to that value, not the browser default. The spec itself makes this note under the all property:
For example, if an author specifies all: initial on an element it will block all inheritance and reset all properties, as if no rules appeared in the author, user, or user-agent levels of the cascade.
This can be useful for the root element of a "widget" included in a page, which does not wish to inherit the styles of the outer page. Note, however, that any "default" style applied to that element (such as, e.g. display: block from the UA style sheet on block elements such as <div>) will also be blown away.
So I guess the only way right now using pure CSS is to look up the browser default value and set it manually to that:
div.foo { display: inline-block; }
div.foo.bar { display: block; }
(An alternative to the above would be div.foo:not(.bar) { display: inline-block; }, but that involves modifying the original selector rather than an override.)
If using javascript is allowed, you can set the display property to an empty string. This will cause it to use the default for that particular element.
var element = document.querySelector('span.selector');
// Set display to empty string to use default for that element
element.style.display = '';
Here is a link to a jsbin.
This is nice because you don't have to worry about the different types of display to revert to (block, inline, inline-block, table-cell, etc).
But, it requires javascript, so if you are looking for a css-only solution, then this is not the solution for you.
Note: This overrides inline styles, but not styles set in css
Unset display:
You can use the value unset which works in both Firefox and Chrome.
display: unset;
.foo { display: none; }
.foo.bar { display: unset; }
No, it is generally not possible. Once some CSS (or HTML) code sets a value for a property on an element, there is no way to undo it and tell the browser to use its default value.
It is of course possible to set a property a value that you expect to be the default value. This may work rather widely if you check the Rendering section of HTML5 CR, mostly reflecting what browsers actually do.
Still, the answer is “No”, because browsers may have whatever default values they like. You should analyze what was the reason for wanting to reset to defaults; the original problem may still be solvable.
What worked for me was revert!
revert resets the property to its inherited value if it inherits from its parent or to the default value established by the user agent's stylesheet.
If you have access to JavaScript, you can create an element and read its computed style.
function defaultValueOfCssPropertyForElement(cssPropertyName, elementTagName, opt_pseudoElement) {
var pseudoElement = opt_pseudoElement || null;
var element = document.createElement(elementTagName);
document.body.appendChild(element);
var computedStyle = getComputedStyle(element, pseudoElement)[cssPropertyName];
element.remove();
return computedStyle;
}
// Usage:
defaultValueOfCssPropertyForElement('display', 'div'); // Output: 'block'
defaultValueOfCssPropertyForElement('content', 'div', ':after'); // Output: 'none'
Concerning the answer by BoltClock and John, I personally had issues with the initial keyword when using IE11. It works fine in Chrome, but in IE it seems to have no effect.
According to this answer IE does not support the initial keyword:
Div display:initial not working as intended in ie10 and chrome 29
I tried setting it blank instead as suggested here:
how to revert back to normal after display:none for table row
This worked and was good enough for my scenario. Of course to set the real initial value the above answer is the only good one I could find.
According to my understanding to your question, as an example: you had a style at the beginning in style sheet (ex. background-color: red), then using java script you changed it to another style (ex. background-color: green), now you want to reset the style to its original value in style sheet (background-color: red) without mentioning or even knowing its value (ex. element.style.backgroundColor = 'red')...!
If I'm correct, I have a good solution for you which is using another class name for the element:
steps:
set the default styles in style sheet as usual according to your desire.
define a new class name in style sheet and add the new style you want.
when you want to trigger between styles, add the new class name to the element or remove it.
if you want to edit or set a new style, get the element by the new class name and edit the style as desired.
I hope this helps. Regards!

Reset CSS display property to default value

Is it possible to override the display property with its default value? For example if I have set it to none in one style, and I want to override it in a different with its default.
Or is the only way to find out what the default of that element is and then set it to that? Would like to not have to know if the element is usually block, inline or whichever...
A browser's default styles are defined in its user agent stylesheet, the sources of which you can find here. Unfortunately, the Cascading and Inheritance level 3 spec does not appear to propose a way to reset a style property to its browser default. However there are plans to reintroduce a keyword for this in Cascading and Inheritance level 4 — the working group simply hasn't settled on a name for this keyword yet (the link currently says revert, but it is not final). Information about browser support for revert can be found on caniuse.com.
While the level 3 spec does introduce an initial keyword, setting a property to its initial value resets it to its default value as defined by CSS, not as defined by the browser. The initial value of display is inline; this is specified here. The initial keyword refers to that value, not the browser default. The spec itself makes this note under the all property:
For example, if an author specifies all: initial on an element it will block all inheritance and reset all properties, as if no rules appeared in the author, user, or user-agent levels of the cascade.
This can be useful for the root element of a "widget" included in a page, which does not wish to inherit the styles of the outer page. Note, however, that any "default" style applied to that element (such as, e.g. display: block from the UA style sheet on block elements such as <div>) will also be blown away.
So I guess the only way right now using pure CSS is to look up the browser default value and set it manually to that:
div.foo { display: inline-block; }
div.foo.bar { display: block; }
(An alternative to the above would be div.foo:not(.bar) { display: inline-block; }, but that involves modifying the original selector rather than an override.)
If using javascript is allowed, you can set the display property to an empty string. This will cause it to use the default for that particular element.
var element = document.querySelector('span.selector');
// Set display to empty string to use default for that element
element.style.display = '';
Here is a link to a jsbin.
This is nice because you don't have to worry about the different types of display to revert to (block, inline, inline-block, table-cell, etc).
But, it requires javascript, so if you are looking for a css-only solution, then this is not the solution for you.
Note: This overrides inline styles, but not styles set in css
Unset display:
You can use the value unset which works in both Firefox and Chrome.
display: unset;
.foo { display: none; }
.foo.bar { display: unset; }
No, it is generally not possible. Once some CSS (or HTML) code sets a value for a property on an element, there is no way to undo it and tell the browser to use its default value.
It is of course possible to set a property a value that you expect to be the default value. This may work rather widely if you check the Rendering section of HTML5 CR, mostly reflecting what browsers actually do.
Still, the answer is “No”, because browsers may have whatever default values they like. You should analyze what was the reason for wanting to reset to defaults; the original problem may still be solvable.
What worked for me was revert!
revert resets the property to its inherited value if it inherits from its parent or to the default value established by the user agent's stylesheet.
If you have access to JavaScript, you can create an element and read its computed style.
function defaultValueOfCssPropertyForElement(cssPropertyName, elementTagName, opt_pseudoElement) {
var pseudoElement = opt_pseudoElement || null;
var element = document.createElement(elementTagName);
document.body.appendChild(element);
var computedStyle = getComputedStyle(element, pseudoElement)[cssPropertyName];
element.remove();
return computedStyle;
}
// Usage:
defaultValueOfCssPropertyForElement('display', 'div'); // Output: 'block'
defaultValueOfCssPropertyForElement('content', 'div', ':after'); // Output: 'none'
Concerning the answer by BoltClock and John, I personally had issues with the initial keyword when using IE11. It works fine in Chrome, but in IE it seems to have no effect.
According to this answer IE does not support the initial keyword:
Div display:initial not working as intended in ie10 and chrome 29
I tried setting it blank instead as suggested here:
how to revert back to normal after display:none for table row
This worked and was good enough for my scenario. Of course to set the real initial value the above answer is the only good one I could find.
According to my understanding to your question, as an example: you had a style at the beginning in style sheet (ex. background-color: red), then using java script you changed it to another style (ex. background-color: green), now you want to reset the style to its original value in style sheet (background-color: red) without mentioning or even knowing its value (ex. element.style.backgroundColor = 'red')...!
If I'm correct, I have a good solution for you which is using another class name for the element:
steps:
set the default styles in style sheet as usual according to your desire.
define a new class name in style sheet and add the new style you want.
when you want to trigger between styles, add the new class name to the element or remove it.
if you want to edit or set a new style, get the element by the new class name and edit the style as desired.
I hope this helps. Regards!

Resources