CSS precendence in shadow DOM <style> - css

What do the CSS precendence rules say about the <style> tag in shadow DOM?
I have an element <component class="component">, a CSS file included in <head> with:
component {
display: inline-block;
}
and a <style> tag inside some shadow DOM with:
::slotted(.component) {
display: block;
}
If I understand it correctly, the first rule should have a specificity of 0.0.1 as it has one element and the second one specificity of 0.1.1 as it has one pseudo-element and one class. Therefore, the second one is more specific and should override the first one. This doesn't happen though. In the developer's console (Chrome) I see both the rules and neither of them crossed out and in the "computed styles" panel I see 'display: inline-block'.
A more detailed example as requested in the comments:
<head>
<style>
/* "other-component" related styles: */
other-component {
display: inline-block;
}
</style>
</head>
<body>
<some-component>
#shadow-root:
<style>
slot[name=some-slot]::slotted(*) {
display: block; /* Only works with !important. */
}
</style>
<slot name="some-slot"></slot>
<!-- The actual ("light-dom") content: -->
<other-component slot="some-slot"></other-component>
</some-component>
</body>

This behaviour is defined in the CSS Scoping Module Level 1 Draft §3.3:
When comparing two declarations that have different tree contexts, then for normal rules the declaration earlier in the shadow-including tree order [the first, global rule] wins, and for important rules the declaration coming later in the shadow-including tree [the second, ::slotted(*) rule] order wins.
Note: This is the opposite of how scoped styles work.
In other worlds:
Styles that applied before distribution continue to apply after distribution.

We might have the most in-depth explanation of the design at https://github.com/w3c/csswg-drafts/issues/2290#issuecomment-382465643
A few reasons went into the current design:
We purposely didn't involve specificity at all. Doing so would expose implementation details of the component, which makes code fragile - if the component is updated and changes the exact selector it uses, it might start overriding outside rules that previously won, or vice versa, and there's no good way for the component's user to understand or manipulate this.
So we have to decide in some other way. Document order (the final cascade step) doesn't really work here - it adds an unexpected dependency on exactly how you load the custom element, and might have interesting race
So we're left with Cascade Origin, or something close to it, that just unreservedly makes one or the other win. Actually injecting a new origin into the list didn't seem like a great idea; it's unclear how user vs author stylesheets should interact with this. So instead we add another cascade step for this.
And finally, we have to make a decision about which wins. We already know that whatever order we choose, !important should have the reverse order; this is how the cascade origins already work. So we have to decide whether the outer page wins by default, but the component wins in !important, or the reverse. We decided that the former made more sense; this means that the component author's normal styles are "defaults", the component user's styles (!important or not) can override that, and the component author's !important styles can be used to "lock down" styles that need to stay how they are. Going the other way around didn't seem to satisfy use-cases as well: it would mean that component users can't override styles by default; they'd have to use !important to do so, possibly interfering with their other styles; and then component authors would have no way of "locking down" styles.

Related

React changes the sequence of CSS rules applied after the deployment to remote

I created a page with a resizable panel on the bottom using react-resize-panel lib.
I had to change the alignment of the elements inside the divs generated by the <ResizePanel> component provided by the lib.
<ResizePanel> creates three levels of elements:
I needed to override the margin-bottom property of the child with the class name ResizePanel-module_ResizeBarVertical__2LUZV. Likely, the suffix is generated dynamically, so I had to use the CSS selector to override it:
[class^='ResizePanel-module_ResizeBarVertical'] {
margin-bottom: 0;
}
Tested it locally and it worked as expected. But when I deployed to remote the sequence of the CSS rules applied changed and my custom style was overridden:
I would like to get a better understanding of how CSS is loaded locally and remotely. In particular, is there any rule of thumb for local testing when it comes to React styles and conflicting CSS rules
UPDATE with solution
There are two solutions suitable:
narrow down the selector to div only (selected this one based on best practices)
div[class^='ResizePanel-module_ResizeBarVertical'] {
margin-bottom: 0;
}
use !important in the style
[class^='ResizePanel-module_ResizeBarVertical'] {
margin-bottom: 0 !important;
}
CSS Precedence could be tricky sometimes, there should be 3 "levels", sorted by highest priority:
!important (you can force override; should solve your problem, but probably doesn't fully answer your question)
specification of selector (how much specified the selector is; seems like what you are struggling with – your custom selector is less specified, so it has lower weight)
order; what was declarated first (there could also be problem with cache; but that's probably not your case)
More info about the selector specificity weight in the Mozilla docs:
https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity

Why is the user agent stylesheet overriding my html{} style?

I have the following style on my html element:
html {
font-size: 16px;
font-family: "Harmonia Sans Regular" !important;
}
But even with !important, my font styling is still being overriden in things like inputs.
Why? I thought inherited styles trumped user agent styling?
Nope. If you want your styles to have precedence, they need to apply to the same element. Which, in our case, is input.
You have applied styles to the html element, not to input.
Now, if you changed your selector to html *, to html input, to input or to *, it would be a different story... The two selectors would get compared and yours would have precedence.
The only difference between your selectors and the ones in the default browser stylesheet is yours are loading later, hence, provided you have the same specificity, yours apply. So the minimum selector for yours to apply would be input {}.
But the important bit here is: html {} only styles inheritable input properties which are not defined (not set) at element level. If they are set inheritance does not happen (there's no need to inherit, because the property resolves). The input set value applies, regardless of values and specificity on any of the parents. In fact, if what you're expecting would happen, designing web would be a lot more difficult and a lot less flexible (IMHO).
Which is a reaaaaaly long way of saying: change
html {/* globals here*/}
into:
* {/* globals here */}
... and they'll probably work as intended. But be warned: it will apply to all elements, and you will soon understand why the way inheritance works is, in fact, quite smart (and helpful).

semantic !important modifier interfering with styling

Is there any way to disable all these !important options in semantic-ui?
I keep running into issues with things like:
.ui.right.sidebar {
right: 0!important; /* why is this important */
left: auto!important; /* why is this important */
-webkit-transform: translate3d(100%,0,0); /* why is this NOT important */
transform: translate3d(100%,0,0); /* why is this NOT important */
}
Why does almost every positioning property have !important? Is there a way to compile semantic omitting the !important modifiers? It is interfering with my custom styling, and I have to do extra work that feels hacky (like countering margin: 0!important; with padding-top: NNpx and just hope that at least one isn't marked as !important in any of the states it could be in)
Disabling !important in semantic-ui is a bad idea as it may lead to unpredictable results. To understand more about why there are !important keywords in the framework, here are some statements made by Jack Lukic, the author of SUI:
..CSS should have a specificity property for defining priority (it was
part of the original discussion when creating css), however they left
us with automatic weight calculations from an arbitrary point system.
This is pretty terrible when you run into something that happens to be
classified less ".ui.button" lets say, having to override '.ui.menu
.ui.button' , there are only two solutions, arbitrarily increasing
weight by repeating class names in selectors, or using important...
Source 1
And also here (among other places):
...CSS specificity has always been a terrible sort spot of the
standard, instead of giving developers a way to assign priority to
rules we have to with two options, increase rule specificity or 'drop
the hammer' with !important.
A lot of css rules in semantic aren't able to increase specificity beyond a certain point. The only assumption we can make about a red ui
button is that it will have classes .ui.red.button, no greater
specificity can be gained by altering the selector. If we then have a
rule that appears later with the same or greater specificity we're
stuck without important.
I'm positive that each decision to use important in semantic was after dealing with no other option. This happens a bit more than other
libraries because the specificity is so granular in the library.
If you want to override the behavior, you can do two things:
Use one of the 3000 theming CSS variables in SUI
OR
Override the behavior by using more specific selectors
See this
One way to make your custom CSS more specific is to use an id in the
body tag of your page and use the following selector:
#bodyid .create-new-menu-btn {
//Properties }

Remove all the styling from elements which have inline styling using CSS

Suppose I have some html like this -:
<div style="blah...blah">Hey Nice</div>
<a style="blah...blah">Great</a>
How do I remove all the inline styling applied to the above elements in my stylesheet considering I don't know what all inline styling exists.
Currently I am trying this, but in vain -:
div[style], a[style]{ !important }
You must reset all css properties for elements that have style attribute:
[style] {
position: static !important;
float: none !important;
border: 0 none !important;
margin: 0 !important;
padding: 0 !important;
outline: 0 none !important;
// and so on
}
There are several determining factors determining which CSS property prevails in any situation. In order, these are:
Whether the property value has the !important flag or not.
If the style declaration is applied inline via the style attribute.
The strength of the CSS rule selector
If the rule has any ID clauses, and if so how many
If the rule has class, attribute or pseudo-class clauses, and if so how many
If the rule has any tagname clauses, and if so how many
If the property is parsed later in the source than another property with a rule of the same strength
So the only way to override the properties is to make sure that all the properties applied via style are applied elsewhere in your stylesheet, and have the !important declaration. The most rational way to do this is still very awkward — it would involve applying a very specific reset stylesheet, and including !important on every property on every rule.
But even if this is done, you still couldn't override inline style declarations that have !important themselves.
You've told Mojtaba that there should be a better solution, but that better solution would involve designing CSS to break its own rules. Imagine if there was a simpler solution for overriding inline styles from stylesheets designed into the language of CSS — should there also be another solution for simply overriding the override from inline styles? Where does the cycle end? All in all, I'd recommend using Javascript or giving up. Or describing your specific problem in more detail — there may be another solution!
If you're not happy with using !important overwrites in the CSS (as suggested by others on here), the only way would be to use JavaScript to remove the styles.
This is really easy in jQuery (better if you're able to assign a class name to the elements to select it with):
$('.selector').attr('style', '');
This will simply replace the element's 'style' attribute with nothing, thus removing the inline styles.
This isn't ideal though since it will rely on the visitor having JavaScript enabled, and may well result in the visitor seeing a style 'flash' as the page loads: the styles assigned in-line to the element before the JS kicks in and removes it.

Best-practice approach to reset CSS styles on a specific element?

I'm building an html5/js/css application that will exist inside of a div on my client's existing html. I want to be sure that none of the client's CSS styles are inherited by my app.
Is there a best practice to reset this div and its descendant elements?
I'm thinking I'll use something like:
#my-id * { //styles }
I'm wondering if there is a better/best-practice approach? Thanks.
That will be very difficult/likely impossible to ensure. The type of solutions that Starx is referring to assume no preset styles other than the browser defaults, and "reset" in that context refers to harmonizing the inconsistencies across various browser defaults.
But in your case, your client CSS may already contain highly specific selectors such as
#someDiv .aClass a{float:left;}
... and applying those "CSS reset" solutions simply will not override this.
You can see that Truth's selectors also have lower specificity than this, and therefore will fail to ovetride the client's styles in such cases.
Your question is very similar: How to remove all inherited and computed styles from an element?
So the short answer is: there is no way to ensure this because you cannot "remove all inherited and computed styles from an element" ... update: ...unless you can anticipate and override every preexisting style declaration with new declarations having appropriate specificity.
If you want to only recent this specific div, than what you have is fine. You forgot to reset the div itself though:
#my-id, #my-id * { /* styles */ }
You are probably looking for Eric's CSS Reset as it one of robust resets out there.
But the reset rule is applied to the whole page, instead of the just the box. SO, modify the rules, by keeping #my-id infront.

Resources