I have a component that declares and use a css variable "--test: red"
But I want to re-declare this variable with a new color outside this component.
https://stackblitz.com/edit/js-va9k9q?file=style.css
Is this rule right?
:root *{
--test: green;
}
Why * is required? If I remove this, it doesn't work
:root *{
--test: green;
}
#app {
--test: red;
}
#app h1{
background-color: var(--test);
}
Html
<html>
<body>
<div id="app"><h1>Example</h1></div>
</body>
</html>
The final result must have a green background-color
Use a second variable in case you want to only consider :root
:root {
--new: green;
}
#app {
--test: red;
}
#app h1 {
background-color: var(--new, var(--test)); /* will fallback to "test" if "new" is not defined */
}
<div id="app">
<h1>Example</h1>
</div>
Or you keep using the code you show which is correct since you will target all the elements (with *) to set the variable --test that will get used instead of the one inherited from #app
This is about ordering and priority of css selectors
if you do like this:
:root {
--test: red;
}
.
.
.
:root {
--test: green;
}
the second selector have more priority
but if you do:
:root #app{
--test: green;
}
.
.
.
:root {
--test: red;
}
the first selector will apply for #app.
if another block is defined outside of #app, it would get red color.
:root * {} works because it have more priority.
read more about priority in this link
Related
I have a very simple problem with CSS variables. I would like to swap two CSS variables, basically the CSS equivalent of [a, b] = [b, a] in ES6. Here's a simple example:
<p>White background</p>
<button>Black background</button>
<div>
<p>Black background</p>
<button>White background</button>
</div>
:root {
--primary-color: #fff;
--secondary-color: #000;
}
body {
background-color: var(--primary-color);
}
button {
background-color: var(--secondary-color);
}
div {
/* i'd like to do the following: */
--primary-color: var(--secondary-color);
--secondary-color: var(--primary-color);
/* so here, `--primary-color` would be `--secondary-color` from `:root`
* and any children have these colors swapped as well
*/
background-color: var(--primary-color);
}
However, this fails because CSS var()s are live bindings. Am I missing something here? Or is this the way the spec currently works?
You are creating a cyclic dependence because you are defining each property using the other one and this won't work. Instead you may try something like this by introducing more variables:
:root {
--p:#fff;
--s:#000;
--primary-color: var(--p);
--secondary-color: var(--s);
}
body {
background-color: var(--primary-color);
}
button {
background-color: var(--secondary-color);
}
div {
/* i'd like to do the following: */
--primary-color: var(--s);
--secondary-color: var(--p);
background-color: var(--primary-color);
}
<p>White background</p>
<button>Black background</button>
<div>
<p>Black background</p>
<button>White background</button>
</div>
I have the markup:
<body class="arabic specific-page">
<div class="child">
<div class="grand-child">
</div>
</div>
</body>
In my sass I am already inside .specific-page and .child. I would like to apply a specific property if body is .arabic:
what I already have:
.specific-page {
.child{
.arabic & {
.grand-child{
gets compilet to:
.arabic .specific-page .child .grand-child
I would like to compile to:
.arabic.specific-page .child .grand-child (body has the same class)
without changing the selector at the top of the tree, only at child level
You can do this using #at-root like so:
.specific-page {
.child{
#at-root .arabic#{&} {
.grand-child{
border: 1px solid red;
}
}
}
}
This compiles to: .arabic.specific-page .child .grand-child, see here.
For this to work you're going to need to alter your SASS a bit. Try
.specific-page {
&.arabic {
.child {
.grand-child {
You could use #at-root and break out of your nesting structure.
.specific-page {
.child{
.arabic {
#at-root .arabic.specific-page .child .grand-child{}
}
}
}
I use an #mixin function like this, when i need change some element in middle
of a sass big tree.
The first parameters is the parent element, the target, and the second the class that should have.
SASS
#mixin parentClass($parentTarget, $aditionalCLass) {
#at-root #{selector-replace(&, $parentTarget, $parentTarget + $aditionalCLass)} {
#content;
}
}
Sample,
like I need to improve font size in a strong tag, when .txt-target had .txt-strong too
HTML
<section class="sample">
<h1 class="txt-target txt-bold">Sample<strong>Bold</strong>Text</h1>
</section>
SASS
section{
.txt-target{
strong{
#include parentClass('.txt-target','.txt-bold'){
font-weight:bold;
font-size:30px;
}
}
}
}
2 options:
.arabic.specific-page {
.child{
.grand-child{
Or (you can switch the order of arabic and specific-page):
.arabic{
&.specific-page {
.child{
.grand-child{
I want to output:
.selector.another-selector .selector__block{some declaration}
but i want to nest it:
I am using & at the end so I can nest it under __block,
but how can I make it adjoin class with .selector?
code example:
.selector{
&__block{
// i want to put my .another-selector declaration here
.another-selector &{
//syntax issue
//need to make it .selector.another-selector .selector__block
}
}
thanks in advance.
If you nest your selector, then it has to be in the .selector__block context (&).
You have 2 solutions here :
You can repeat the first selector, as such:
.selector {
&__block {
...
.another-selector.selector & {
// Here `&` means `.selector__block`
}
}
}
You can nest differently:
.selector {
&__block {
...
}
&.another-selector &__block {
// Here `&` means `.selector`
}
}
Maybe the second solution is better since it respects the inception rule and is less dependent of the DOM structure.
BTW, you can also try https://www.sassmeister.com/ to play with your selectors
I would suggest that you don't nest BEM at all. Just go with plain declarations for two valid reasons.
1) error tracking nested BEM is hard, let say you get a class from devtools that is .hero__heading. That will not match anything in your code when doing a search. Now the example above is not that hard to figure out anyway but inheriting a project with nested structure is a pain. I suggest reading Harry Roberts article on code smells in css
2) nesting like this will often complicate when wanting to override with other classes like in your case.
Consider this code:
.selector {
background-color: deepskyblue;
}
.selector__block {
color: lightblue;
.another-selector & {
color: lightcoral;
}
}
#Dejan.S I'm not a big fan of BEM (but that's another rant ;-). If however you are using BEM I think nesting will help to illustrate the hierarchy and what to expect
SCSS:
.selector {
// selector styles
color: red;
// default selector block style
&__block { color: green; }
// selector variant selector block styles
&.foo &__block { color: blue; }
&.bar &__block { color: yellow; }
}
CSS Output:
.selector { color: red; }
.selector__block { color: green; }
.selector.foo .selector__block { color: blue; }
.selector.bar .selector__block { color: yellow; }
HTML:
<div class="selector">
Selector <!-- red -->
</div>
<div class="selector">
Selector <!-- red -->
<div class="selector__block">
Selector Block <!-- green -->
</div>
</div>
<div class="selector foo">
Selector <!-- red -->
<div class="selector__block">
Selector Foo Block <!-- blue -->
</div>
</div>
<div class="selector bar">
Selector <!-- red -->
<div class="selector__block">
Selector Bar Block <!-- yellow -->
</div>
</div>
On our Website we have a section with multiple sites who all uses different color codes. I would like to keep it simple and change the color on a specific value inside a data-attribute, like this:
[data-page-id="site1"] {
#color: #F00;
}
[data-page-id="site2"] {
#color: #D40;
}
.page-title {
color: #color;
}
.page-content {
background: #color;
}
My approach gives me an error, but is there a smiliar method to do this?
When the Less compiler is compiling your code, it would not have any idea of the data attribute that is present in your markup (as Less is compiled separately from your HTML). Hence, you cannot determine the value of the color variable depending on the attribute's value.
You could try and compile your Less code on the client-side but that is not really recommended (even by the official Less website) for production sites. It is better used only for some testing.
Assuming the data-page-id attribute is present in the element that is the parent of the .page-title and .page-content, you could use something like below to statically generate the required rulesets.
#site-colors: #F00, #D40;
[data-page-id="site1"] {
.page-title {
color: extract(#site-colors, 1);
}
.page-content {
background: extract(#site-colors, 1);
}
}
[data-page-id="site2"] {
.page-title {
color: extract(#site-colors, 2);
}
.page-content {
background: extract(#site-colors, 2);
}
}
[data-page-id="site1"] .page-title {
color: #ff0000;
}
[data-page-id="site1"] .page-content {
background: #ff0000;
}
[data-page-id="site2"] .page-title {
color: #dd4400;
}
[data-page-id="site2"] .page-content {
background: #dd4400;
}
<div data-page-id="site1">
<div class="page-title">Site 1 Title</div>
<div class="page-content">Site 1 Content</div>
</div>
<div data-page-id="site2">
<div class="page-title">Site 2 Title</div>
<div class="page-content">Site 2 Content</div>
</div>
If you have many such data-page-id values then you could also make use of a loop to avoid writing the same piece of code multiple times.
Or alternately, you can write one common less file for the common rules applicable for all pages (like below) and one site specific file which will have the #color variables' value and then import the common file.
/* settings.less - common settings */
.page-title {
color: #color;
}
.page-content {
background: #color;
}
/* site specific file - site1.less*/
#import settings.less;
#color: #f00;
Suppose the following code:
<div id="body" class='bodyLogin'>
#body {
background-color: red;
}
I would like to override the background colour through the class attribute, like this:
#body .bodyLogin {
background-color: blue;
}
but this doesn't work.
Similarly:
.bodyLogin {
background-color: blue;
}
doesn't work due to CSS hierarchy.
The space between your two selectors is meaningful. In fact it is a selector: the descendant selector. It means you select all of class bodyLogin descendant of an element with id body.
Get rid of the space and you select elements that are both #body and .bodyLogin:
#body {
background-color: red;
}
#body.bodyLogin {
background-color: blue;
}
<div id="body" class='bodyLogin'>Test</div>