Change variable with different attribute - css

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;

Related

CSS Variables - Swapping values?

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>

Is there a way to individually target multiple CSS classes at once? [duplicate]

This question already has answers here:
Is there a CSS selector by class prefix?
(4 answers)
combined multiple classes into one css rule
(3 answers)
Closed 4 years ago.
For instance, I have the following code in a .less file, and would like to simplify it. Each nav is an individual navigation point. When the user hovers over that nav point, I only want that particular nav point's background color to change. Not every single one of them.
.nav-1:hover {
background:#fc9426;
}
.nav-2:hover {
background:#fc9426;
}
.nav-3:hover {
background:#fc9426;
}
.nav-4:hover {
background:#fc9426;
}
.nav-5:hover {
background:#fc9426;
}
.nav-6:hover {
background:#fc9426;
}
.nav-7:hover {
background:#fc9426;
}
.nav-8:hover {
background:#fc9426;
}
.nav-9:hover {
background:#fc9426;
}
Use a comma.
.nav-1:hover,
.nav-2:hover,
.nav-3:hover {
color: #fc9426;
}
Although I don't have any markup to go off of, it looks like you could create a helper/modifier class instead of defining the same thing over and over again.
It might look something like this:
[class^="nav-"] {
margin: 1rem 0;
padding: 0 1rem;
min-height: 3rem;
color: #333;
font: 1rem/3rem Arial, sans-serif;
border-bottom: 1px solid black;
}
/**
* Utility/Modifier style properties that
* any nav could add to their base of styles.
*/
.nav-branded {
color: white;
background-color: #fc643c;
}
.nav-branded:hover {
background-color: hotpink;
}
/**
* These classes have styles specific to
* each class (acts like an ID but
* without the specificity).
*/
.nav-1 {
/* Waiting for some styles. */
}
.nav-2 {
border-bottom-width: 4px;
}
.nav-3 {
border-bottom-style: dashed;
}
<nav class="nav-1 nav-branded">Nav One</nav>
<nav class="nav-2">Nav Two</nav>
<nav class="nav-3 nav-branded">Nav Three</nav>
CSS classes are meant to be re-used so you don't have to define a bunch of different ones to get the same styling.
The point of classes is for a given property to apply to a variety of elements. So you should give each <nav> the same class.
<nav class='color-change'>
.
.
.
</nav>
Then in your CSS / LESS:
.color-change:hover {
background:#fc9426;
}
I think you imagine that you have a code like this
<div class="nav-1"> </div>
<div class="nav-2"> </div>
<div class="nav-3"> </div>
<div class="nav-4"> </div>
If so, you could simplify the code with a better advanced selector
[class*='nav-']{
background:#fc9426;
}
In this way, you will select the elements that in the 'class' attribute have in any part of the code the word 'nav-', which is the piece of the name of the class in common
In the case that in the HTML they have a father
<div class="nav">
<div class="nav-1"> </div>
<div class="nav-2"> </div>
<div class="nav-3"> </div>
<div class="nav-4"> </div>
</nav>
you can use this CSSs
.nav > div{}
.nav [class*='nav-']{}
.nav > div:nth-of-type(1){} /* the number of the son */
.nav > div:nth-of-type(2n){} /* all the pairs */
.nav > div:nth-of-type(2n+1){} /* all the odd */
If you can't change your markup to avoid the redundancy of selectors, you can use an attribute selector to catch all of those classes with a single specifier:
*[class*="nav-"]:hover, *[class*=" nav-"]:hover {
background:#fc9426;
}
The question was originally tagged with less, so if using less, you can also use recursion to generate those classes individually. This task is featured in the manual:
.generate-navs(9);
.generate-navs(#n, #i: 1) when (#i =< #n) {
.nav-#{i}:hover {
background:#fc9426;
}
.generate-navs(#n, (#i + 1));
}

Sass "semantically" nesting tags and classes

I am trying to enforce some kind of semantic css class nesting in Sass. I want to enforce that css code for sections can only be used in sections, to make sure that the <section /> tag is used where it should semantically.
But I am running in troubles with the use of & in my Sass files. Consider the following html:
<section class="section-home">
<h1 class="section-home__heading">Section heading</h1>
<p class="section-home__intro">This is some random text</p>
</section>
I would assume I could use the following code in Sass, but no:
section {
&.section-home {
background-color: white;
&__heading {
font-size: 5rem;
}
&__intro {
color: grey;
}
}
}
Sass renders it into the following CSS:
section.section-home{background-color:#fff}
section.section-home__heading{font-size:5rem}
section.section-home__intro{color:grey}
And that is not what I expect or need, I want:
section.section-home{background-color:#fff}
section.section-home .section-home__heading{font-size:5rem}
section.section-home .section-home__intro{color:grey}
Is this a bug? Am I doing something wrong here?
Simply change the CSS to:
section {
&.section-home {
background-color: white;
.section-home {
&__heading {
font-size: 5rem;
}
&__intro {
color: grey;
}
}
}
}
This way Sass will interpret this as:
section.section-home
section.section-home .section-home__heading
section.section-home .section-home__intro
This will solve your problem, but why call it ".section-" when you can simply call it ".home" when it already is restricted with the html tag.
section {
&.section-home {
background-color: white;
.section-home__heading {
font-size: 5rem;
}
.section-home__intro {
color: grey;
}
}
}

Set style to all classes starting with "mark-as-" dynamically in angular 2

I would like to be able to set dynamically in my component, whether or not an element with a class name that starts with "mark-as" (e.g "mark-as-car", "mark-as-cat") will have a yellow background.
I can add the following to the component css file:
*[class^="mark-as-"] {
background: #ffff00;
}
But I would like to know how to enable/disable it dynamically in the component logic without changing the elements class names.
You can use below css approach.
You can visit css selectors for more knowledge of css selectors.
[class*="mark-as-"] {
background: #ffff00;
}
Below an example to make more understandable.
.mark-as-red {
color:#fff;
}
.yellow-mark {
color:#fff;
}
p[class*="-as-red"] {
background: #999;
}
p[class^="yellow-"] {
background: yellow;
}
<p class="mark-as-red ">
HELLO
</p>
<p class="yellow-mark ">
HELLO
</p>

How I can change a variable in a div in a CSS, using SASS?

I wonder if there is any way to change the assignment of a variable inside a div.
Viewing the code, I think it is more visible what I want:
## CSS ##
.div-name-1 {
$cor: #f00;
}
.div-name-2 {
$cor: #d1d1d1;
}
.div-name-3 {
$cor: #fff;
}
.whatever{
background: $cor;
}
<div class="div-name-2>
<div class="whatever">
</div>
<div class="div-name-3>
<div class="whatever">
</div>
IIRC, variables in SASS are scoped to the block they appear in. Since .div-name-1 and .whatever are different blocks, they are different scopes and cannot transfer values of variables between them.
You will need to reorganize your SASS code so they are in the same block, or introduce a mixin in order to create the same effect:
.div-name-1 {
$cor: #f00;
.whatever {
background: $cor;
}
}
.div-name-2 {
$cor: #d1d1d1;
.whatever {
background: $cor;
}
}
Alternatively:
#mixin whatever($cor) {
.whatever {
background: $cor;
}
}
.div-name-1 { #include whatever(#f00); }
.div-name-2 { #include whatever(#d1d1d1); }

Resources