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
}
}
Related
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>
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>
I have two components called GroceryItem and BasketItem. Since these components share quite a few styles and I didn't want to write the same properties in different stylesheets, I set up a stylesheet called _item-layout.scss that has all the common styles and then imported this in both BasketItem.scss and GroceryItem.scss.
The core difference between these components is that the BasketItem icon is meant to switch from white to red when the enclosing div is hovered upon, whereas the GroceryItem icon is meant to switch to green. To enable this functionality, I set the hover property to change colour in the BasketItem and the GroceryItem stylesheets.
The thing is, both components change icon colour to red when hovered on. This is especially confusing for me because in my GroceryItem.js file, I've only imported GroceryItem.scss. So how can it match a selector that isn't even present in the stylesheet that has been imported?
item-layout.scss:
.root {
background-color: rgba(230, 230, 230, 1);
margin: 10px 0px;
user-select: none; //standard syntax
-webkit-user-select: none; //webkit (safari, chrome) browsers
-moz-user-select: none; //mozilla browser
-khtml-user-select: none; //webkit (konqueror) browser
-ms-user-select: none; //IE10+
.p {
font-weight: 500;
}
}
.icon {
margin-right: 10px;
color: whitesmoke;
}
.row-content {
display: flex;
padding: 15px;
}
GroceryItem.scss:
#import "./../../styles/_item-layout";
.root:hover .icon {
color: green;
}
BasketItem.scss:
#import "./../../styles/item-layout";
.root:hover .icon {
color: red;
}
GroceryItem.js:
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faPlusSquare } from "#fortawesome/free-solid-svg-icons";
import "./GroceryItem.scss";
import React from "react";
function GroceryItem(props) {
return (
<div className="root" onClick={props.onClick} >
<div className="row-content">
<FontAwesomeIcon icon={faPlusSquare} className="icon"/>
<p>{props.title}</p>
</div>
</div>
)
}
export default GroceryItem;
I think the problem is that you have hover styles for the root class and you're using this class in both components.
If you import BasketItem.js or GroceryItem.js, their respective scss files will also be imported. Each of these scss files sets the color of elements with class root on hover to either red or green. So whichever js file is imported last will indirectly decide the root class hover color.
Since you say both components have a red hover color BasketItem.js is probably imported after GroceryItem.js based on the code in your question. If you switch the import order around you will probably see both components turn green.
The simple solution here is to just use separate classes for GroceryItem and BasketItem so there is no collision / involuntary overwriting of styles.
Both declarations of icon styles are in the same scope so the last loaded scss file overwrites the first one.
You could add an additional classname in both components and use them as a kind of color flag. Lets say in first component you add the css classname green next to your icon classname and in the second one add red next to your icon classname. So you have:
... className="icon green" ... and
... className="icon red"
In you main scss file you do
.root {
.icon {
&:hover {
&.green {
color: green;
}
&.red {
color: red;
}
}
}
}
Of course add the other styles you have set for your root class
Yesterday I decided to try Polymer 1.0 and I'm already facing difficulties when trying to styling the paper-toolbar.
The documentation says that the background colour can be changed by using:
--paper-toolbar-background
But how can I use it on CSS?
I tried the following:
paper-toolbar {
--paper-toolbar-background: #e5e5e5;
}
Also this:
paper-toolbar {
--paper-toolbar {
background: #e5e5e5;
}
}
But neither worked. What is the correct way to do it?
Thanks.
If you are styling it on your main page, then you have to apply styles using <style is='custom-style'>. This is to make Custom CSS Properties work.
Applying is relatively easy. paper-toolbar provides 2 custom properties and one mixin. --paper-toolbar-background is a property that changes the background color of the toolbar while --paper-toolbar-color changes its foreground color. --paper-toolbar is a mixin applied to the toolbar.
To use these properties is just the same as applying styles in your elements. As an example
<style is="custom-style">
paper-toolbar {
--paper-toolbar-background: #00f; /* changes the background to blue*/
--paper-toolbar-color: #0f0; /* changes the foreground color to green */
--paper-toolbar: {
font-size: 40px; /* Change default font size */
}; /* Notice the semicolon here */
}
</style>
I couldn't find a solution to this problem either until recently. I have two toolbars and I didn't want to change the CSS for all toolbars just the header toolbar.
To change the CSS for every toolbar, in your external css file add the following:
paper-toolbar.paper-toolbar-0 {
background: orange;
color: red;
}
However, that doesn't address the problem. To change a single paper toolbar based on a class like the following:
<paper-toolbar class="header">
...
</paper-toolbar>
The above uses the class called "header" so in my CSS I added:
paper-toolbar.header {
background: orange;
color: red;
}
... and it worked! Yay! That means with this you should be able to override any CSS of any of the other elements doing the same thing. This is completely untested but I think it should work like:
<elementName>.<classname> {
...
}
Hope this all helps!
I understand CSS basics, but I keep running into trouble with conflicting styles. Consider the following styles.
First, the default font color in my style sheets is black. I want that color applied to all picture captions - unless they're contained in divs with a class CoolL or CoolR...
.CoolL .Caption, .CoolR .Caption { color: #900; }
Now all the captions in the Cool series have brown text. But there are situations where I want the captions to have a black background with white text, so I created this rule:
.Black { background: #000; color: #fff; }
Now consider the following HTML. Class Caption by itself should have black text. However, this is inside a div with a class CoolR, so it displays brown text instead. But I added the class Black to the last div, which should change the background to black and the text color to white...
<div class="CoolR Plus Max300">
<div class="Shadow2">
<img src="">
<div class="Caption Black">Text</div>
</div>
</div>
In fact, the background is displaying black, but the text color is still brown.
I get these problems all the time, and the only way I can fix them is to write long, detailed styles, like this...
.Black, .Caption .Black, .CoolR .Caption.Black, .EverythingElseThatCouldBeBlack .Black { background: #000; color: #fff; }
What am I missing? Thanks.
I think you are over complicating things. This will become a maintenance issue as you add more styles. I would define separate classes and keep things simple. It's also important to understand CSS specificity.
.caption {
color: #000;
}
.cool-caption {
color: #900;
}
.caption-with-background {
background-color: #000;
color: #fff;
}
You could try :
.Black { background: #000 !important; color: #fff !important; }
There are a few fixes, but as previously recommended you should mark all of the settings you want to override previous ones with !important. With that, your code would look like this:
.Black {
background: #000;
color: #fff;
}
Also, not sure if you asked this, but you can apply CSS to all components by using the *, like so:
* {
//blahblahblah
}
you are defining the first case with a descendant selector which overrides the second class, which is merely a class. every answer given already will work but are entirely unnecessary. just add this to your style sheet:
.CoolR1 .Black, .Black{ background: #000; color: #fff;}
/** you could also chain your classes for specificity power **/
.Black.Caption{color:#fff}
that should do it. you can read more about selectors here:
http://docs.webplatform.org/wiki/css/selectors
I think that generally a more specific rule overrides a more general one, thus the more specific '.CoolR .Caption' is overriding the more general .Black. You'll probably be able to override this with !important, but a better style might be to reduce the complexity of your rules:
.Cool .caption { color: #900; }
.Cool .caption.black { color: background: #000; color: #fff; }
And put .L and .R in separate classes
.Cool.L { . . . } /* For things specific to CoolL, but not CoolR */
.Cool.R { . . . } /* and vice-versa */