I want to apply a number of CSS rules to different selectors, without creating additional selectors. In SCSS, this would be typically done with a mixin, eg:
#mixin gradient-text {
color: transparent;
background-clip: text;
-webkit-background-clip: text;
background-image: linear-gradient(
350deg,
var(--dark-blue),
var(--teal),
var(--bright-green)
);
}
Reading around the internet, there's lots of references to making mixins with the CSS apply syntax, but
https://caniuse.com/sr_css-apply mentions:
#apply was briefly supported behind a flag in Chromium but has since been abandoned in favor of the ::part() selector.
Reading about CSS part though it seems like it's not possible to use CSS part without modifying my HTML and using web components, which have their own issues.
Is it possible to do a mixin in CSS, without modifying my HTML or JS, using part?
According to the MDN article you linked to, ::part can only match elements within a shadow tree. Additionally, the spec for the ::part states
The ::part() pseudo-element only matches anything when the originating element is a shadow host.
Thus, if you wanted to leverage this pseudo-element for CSS mixins, you'd be better working with (developing) a native web component library. You may be able to use the corresponding part HTML attribute outside of the Shadow DOM to implement CSS mixins depending on your requirements.
When in doubt the best thing is to experiment. Here is an example of using ::part() and part (HTML attr) inside and outside of a shadow DOM. Best to test browser support on part as it is a relatively new technology. Moreover, seems there is still ongoing questions about how multiple ident's should be supported, if at all.
customElements.define('custom-thing', class CustomThing extends HTMLElement {
constructor() {
super()
const root = this.attachShadow({ mode: 'closed'})
root.append(document.getElementById('custom').content.cloneNode(true))
}
})
[part~="a"] {
color: red;
}
[part~="b"] {
padding: 20px;
background: gray;
}
p::part(a) {
color: blue !important;
}
custom-thing::part(a) {
color: green;
}
custom-thing::part(a)::after {
content: 'A';
}
custom-thing::part(b) {
color: orange;
}
custom-thing::part(a b) {
/* does multiple ident values work? */
color: blue;
}
<p part="a b">part</p>
<template id="custom">
<style>
p[part="a"] {
color: aqua;
}
</style>
<p part="a">part a</p>
<p part="b">part b</p>
<p part="a b">part a b</p>
</template>
<custom-thing></custom-thing>
Related
I want to be able to not have to use !important and instead simply resolve by just using more specific selectors. Take this element for example:
<div>
<p className={`${headerStyles.headerOuter} ${bodyStyles.something} ${otherStyles.another}`}>Test</p>
</div>
It uses three classes each defined in separate css modular files:
import headerStyles from ‘…’
import bodyStyles from ‘…’
import otherStyles from ‘…’
Let’s say that headerStyles.module.scss contains:
.headerOuter {
color: blue;
}
bodyStyles.module.scss contains:
div .something {
color: red;
}
And otherStyles.module.scss contains:
.another {
color: green;
}
The p will have red text since bodyStyles is more specific.
But I want to be able to do this in headerStyles.module.scss:
.headerOuter {
&.another {
color: blue;
}
}
// or .headerOuter.another
So that headerOuter and another can work together to be higher in specificity than bodyStyles to force the element to apply blue text. But the problem is that headerStyles and otherStyles don’t seem to be able to recognise each other.
How can this be fixed?
I’ve made a similar demo here, where the text should be black but it’s not: https://codesandbox.io/s/css-modules-react-forked-mxtt6 - see another.module.scss and the text should be black
Thank you
From the codepen
The color: black selector is:
._src_another_module__another._src_another_module__something
While the actual element's classes are:
_src_test_module__test
_src_sassy_module__something
_src_another_module__another
The second element's class contains "sassy", it is different from the selector, that's why it doesn't match.
You can check it with the DevTools. The blue and red styles are shown as overwritten, the green has more specificity, but the black one doesn't even apply for the element as shown in the picture below.
Edit
I think there is lack of information about the actual tool behavior or just
a misunderstanding. The way it builds the name is _src + _<file_name> + _<selector_name>.
That being said:
/* The final style from "another.module.scss. */
._src_another_module__something {
color: red;
}
._src_another_module__bling {
background: #eee;
font-family: sans-serif;
text-align: center;
}
._src_another_module__bling button {
background: red;
}
._src_another_module__another {
color: blue;
}
._src_another_module__another._src_another_module__something {
color: black;
}
Notice the #import './sassy.module.scss' has nothign to do with the black stuff, it just duplicates the style with a different naming.
<!-- The final element with it's classes. -->
<p class="_src_test_module__test _src_sassy_module__something _src_another_module__another">
test
</p>
Note: all this code comes from the codepen.
Text isn't black because you are including the selector something from the import of sassy.module.scss with the ${style.something}, therefore the class will be named as _src_sassy_module__something (which is the red one).
If not yet, I encourage you to check the results with the DevTools often.
<p className={`${testStyles.test} ${styles.something} ${anotherStyles.another}`}>test</p>
The reason it is not working is that the latest calssname which is another is being called and it dosent effect what you do with the previous classes that are added to the element which here is something. In the scss file another.modules.scss you are importing the sassy.module.scss, this updates the style on the class something but dosent effect the style on the latest class another.
`#import './sassy.module.scss';
.another {
color: blue;
&.something {
color: black; // should be black
}
}
I see some e.g. div/button style in Chrome console like this:
/* Chrome browser styles tab */
.ItemClass1-0-3-171.ItemClass2-0-3-173: {
background-color: "red"
}
How do I define a new style in CSS ignoring that class numbers? because it can be a different number for other div/button on the page..
/* CSS file */
.ItemClass1.ItemClass2 {
background-color: "blue"
}
You can use two attribute contains selectors for this.
[class*="ItemClass1"][class*="ItemClass2"] {
background-color: red;
}
<p class="ItemClass1-0-3-171 ItemClass2-0-3-173">foo</p>
But keep in mind that this will also select elements with the class fooItemClass2.
You can use an attribute selector with a starts-with value to pick up anything that starts with ItemClass.
Note: This solution assumes ItemClass is the first classname and doesn't account for whether the element has both classes. For these reasons Sven's answer might better suit your needs.
[class^='ItemClass'] {
background-color: blue;
padding: 4rem;
}
<div class="ItemClass1-0-3-171.ItemClass2-0-3-173"></div>
dynamic-text-colors.css
:root {
--title-color: #555555;
}
.text-title-color {
color: var(--title-color);
}
.bg-blue-100 {
--title-color: #999999;
}
.bg-blue-200 {
--title-color: #888888;
}
.bg-blue-300 {
--title-color: #777777;
}
index.html
<div class="bg-blue-100">
<h1 class="text-title-color">I am colored #999999</h1>
</div>
<div class="bg-blue-200">
<h1 class="text-title-color">I am colored #888888</h1>
</div>
<div class="bg-blue-300">
<h1 class="text-title-color">I am colored #777777</h1>
</div>
Question:
I don't understand the process that allows each h1 to have a different color. In this instance, I don't understand how the value of "text-title-color" can be different based the background color.
"Custom properties are scoped to the element(s) they are declared on, and participate in the cascade: the value of such a custom property is that from the declaration decided by the cascading algorithm." - https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties
According to the explanation above of custom props by Mozilla, each variable is scoped to its element its decalred on. As such, would the browser some how convert the code to something like this and if so where is the code below stored?:
.bg-blue-100 .text-title-color{
color: #999999
}
.bg-blue-200 .text-title-color{
color: #888888
}
.bg-blue-300 .text-title-color{
color: #777777
}
The browser doesn't need to do any conversion in the way you describe
The variables are all part of what it understands.
It's not like a preprocessor which has to convert everything to 'real' CSS before anything runs.
When the browser has to render an h1, say, as in your question it will pick up the value for --title-color from whichever style is relevant. Just as it would pick up, say, the color or width if they were set there.
The value of CSS variables is precisely because they can be set at run time, e.g. by Javascript on some user action and the new value will be used 'on the fly'.
We have an Angular Application inside an ASP.NET MVC View,
So inside .cshtml we have this:
<app-root></app-root>
There are styles applied to the entire ASP.NET app which are colliding with the Angular components. Note that, Native ShadowDom encapsulation is not an option for me due to it's limited support of browsers.
I am limiting the scope by having the styles applied to each component (Emulated version),
Assume this is my ASP.NET view with it's own set of styles/stylesheets specified as below and there is <app-root></app-root> is where I am having my app which holds other components, I want to stop the styles in the style tag to bleed over my app-root. How can I achieve this?
<body>
<style>
body {
background-color: powderblue;
}
h1 {
color: blue;
}
p {
color: red;
}
</style>
<app-root></app-root>
</body>
You can either not timport the global stylesheet or you can overrwrite those global styles. Since these rules are written as global, they must be overwritten in some way. (They can’t be ignored).
Eg.
body {
background-color: white;
}
h1 {
color: black;
}
p {
color: black;
}
I'm an old hand with CSS, but have recently decided to take the plunge and begin using BEM. For the most part, I understand the value of using such a flat system, avoiding overly specific selectors etc...
My question is, is the following approach correct. It works, technically, but also seems fragile:
.badge {
/* additional declarations */
background: rgba(0, 0, 0, 0.2);
}
.badge--error {
background: red;
}
.badge--success {
background: green;
}
This works fine, because of the cascading nature of CSS. So the default background is overwritten by the modifier successfully. But if I put the modifier before the initial declaration, the modifier is ignored (because of the equal specificity).
Are there any issues with writing BEM this way? Is it considered bad practice to declare a default value of something like a background within the block, if it's to be overwritten with modifiers? Should the default background in this instance, live in a .badge--default modifier? Or have I written this in a true BEM fashion, and BEM actually relies on CSS' cascading in order to remain flat?
You could make use of CSS variables
.badge {
background: var(--background);
}
.badge--error {
--background: var(--error);
}
.badge--success {
--background: var(--success);
}
:root {
--background: yellow;
--error: red;
--success: green;
}
<div class="badge">
a badge
</div>
<div class="badge badge--success">
a badge success
</div>
<div class="badge badge--error">
a badge error
</div>
<div class="badge" style="--background: purple">
a badge random
</div>
I don't see why a modifier could not modify just a background if it is(n't) set in the initial element.
For BEM I can recommend using a CSS preprocessor like SASS since it make it quite easy to nest elements there is less change of declaring some modifier before the initial declaration. Because of the nesting your CSS becomes much more organised. It is also easier to import different components so each component can live in its own file.
With SASS you can do:
.badge {
&--error {}
&--success {}
}