Using CSS variables in LESS - css

This might seem basic, but I can't figure out how to use CSS variables in LESS?
variables.css:
.root {
--header-color: white;
--content-color: yellow;
}
styles.less:
#import "../variables.css";
.header {
color: #header-color;
}
I get error "#header-color is undefined".

LESS allows you to use normal CSS code, so use one option could be just use the variable as CSS:
#import "../variables.css";
.header {
color: var(--header-color);
}
Also, you can save the css var to a LESS var:
#import "../variables.css";
#header-color: var(--header-color);
.header {
color: #header-color;
}

Related

How to make dynamic variables with less in a CSS file?

Actually I want to use a CSS variable in less...
:root {
--header: #6B66A4;
}
#header: #6B66A4;
How?
Less compiles the following
:root {
--header: #6B66A4;
}
#header: var(--header);
body {
color: #header;
}
to this CSS being generated at build time:
:root {
--header: #6B66A4;
}
body {
color: var(--header);
}
Of course Less doesn't know anything about what var(--header) means or is - it's just a string to Less.

Set a SASS variable depending

I'm searching a way to use a particular color depending on a class on the body tag.
I have a main scss file like this
// variables.scss
$bg-main: white;
$color-first: red;
$color-second: green;
And in my other files, I use the colors
// content.scss
.content {
.some-selector: {
// some styles
color: $color-second;
}
a:hover {
// some styles
color: $color-second;
}
}
// and same goes for menu.scss etc.
Now I have a dynamic class on the body, that changes depending on the current selected menu. I would like $color-second to be different for each body classes, and I don't know how to do that. The only solution I found was to move all the $color-second from each files into one single file, like this:
.body-1 {
.content a:hover, .content .some-selector {
color: green;
}
}
.body-2 {
.content a:hover, .content .some-selector {
color: blue;
}
}
.body-1 {
.content a:hover, .content .some-selector {
color: black;
}
}
So I don't need to write the color in each files. This works well, but if I need to set this $color-second to some other selector, I need to put that in this big file.
Is this possible to do this an other way?
I already checked these answers, but it didn't helped me much:
SASS set variable depending on CSS class
Creating or referencing variables dynamically in Sass
Merge string and variable to a variable with SASS
There are multiple ways to do this. The most obvious two which come to mind are mixins and loops:
Mixins
Just put everything you want into a single mixin, and then use it for every body class:
#mixin colored-content($color) {
.content a:hover, .content .some-selector {
color: $color;
}
/* Any other rules which use $color here */
}
.body-1 {
#include colored-content(green);
}
.body-2 {
#include colored-content('#FF0000');
}
.body-3 {
#include colored-content(darken(red, 20));
}
You can extend this example with any number of arguments (for example, $textColor and $bgColor), conditions or rules.
With this approach you will not have SCSS code repetitions, and any updates will be introduced easily.
Loop
Another way is to use a simple loop:
$body_themes: (
"body-1": green,
"body-2": #FF0000,
"body-3": darken(red, 2)
);
#each $body_class, $color in $body_themes {
.#{$body_class} {
.content a:hover, .content .some-selector {
color: $color;
}
/* Any other rules which use $color here */
}
}
It is even shorter, but imho it is less readable.
P.S. It is possible to combine mixins and loops, by the way :)

Extending the "compound" class name [duplicate]

How do I extend a Less class which is dynamically formed using & combinator?
Less which generates expected output:
.hello-world {
color: red;
}
.foo {
&:extend(.hello-world);
font-size: 20px;
}
Expected CSS output:
.hello-world,
.foo {
color: red;
}
.foo {
font-size: 20px;
}
Less does not generate expected output:
.hello {
&-world {
color: red;
}
}
.foo {
&:extend(.hello-world);
font-size: 20px;
}
Unexpected CSS output:
.hello-world {
color: red;
}
.foo {
font-size: 20px;
}
Extending a dynamically formed selector (loosely using the term) like that is currently not possible in Less. There is an open feature request to support this. Till it is implemented, here are two work-around solutions to it.
Option 1:
Write the contents of .hello and .hello-world selectors into a separate Less file (say test.less), compile it to get the CSS. Create another file for the rules of .foo, import the compiled CSS as a Less file (using the (less) directive) and then extend the .hello-world as you had originally intended to.
test.less:
.hello {
&-world {
color: red;
}
}
extended-rule.less:
#import (less) "test.css";
.foo {
&:extend(.hello-world);
font-size: 20px;
}
Compiled CSS:
.hello-world,
.foo {
color: red;
}
.foo {
font-size: 20px;
}
This method would work because by the time the test.css file is imported, the selector is already formed and is no longer dynamic. The drawback is that it needs one extra file and creates dependency.
Option 2:
Write a dummy selector with rules for all properties that need to be applied to both .hello-world and .foo and extend it like:
.dummy{
color: red;
}
.hello {
&-world:extend(.dummy) {};
}
.foo:extend(.dummy){
font-size: 20px;
}
This creates one extra selector (dummy) but is not a big difference.
Note: Adding my comment as an answer so as to not leave the question unanswered and also because the work-around specified in the thread linked in comments doesn't work for me as-is.

Scoping CSS / Prepend selector with LESS

I have a chunk of CSS that I want to "scope" to a specific block of HTML. I'm generating a unique ID and then setting it on the block of HTML and then would like to wrap the chunk of CSS with the same ID so that those selectors can't match sibling or parent elements. I don't know the contents of the chunk of CSS. Given a chunk of CSS:
.container {
background-color: black;
}
.container .title {
color: white;
}
.container .description {
color: grey;
}
I need it to come out like this:
.theme0 .container, .theme0.container {
background-color: black;
}
.theme0 .container .title, .theme0.container .title {
color: white;
}
.theme0 .container .description, .theme0.container .description {
color: grey;
}
Is there any way to do this with LESS? The first selector is easy, just wrap the CSS chunk with '.theme0 {' + cssChunk + '}'. But I haven't been able to figure out a way to prepend '.theme0' to all of the selectors without the space.
EDIT:
So I should clarify that our intentions are to build such a system into our build process / dependency system. We're attempting to scope a chunk of css to a react component. We have a couple different approaches we're trying out, this is just one of them. Point is, the CSS and HTML we're trying to scope could be anything, we have no control or knowledge of it. The first pattern can easily be achieved by prepending .uniqueID { and appending }. This gives .uniqueID .someSelector {}. I'm wondering if it's possible to do a similar thing but get .uniqueID.someSelector {}? Ideally without having to write the original chunk of CSS with knowledge of our scoping system.
Assuming the component styles are in a separate CSS file, i.e.:
// component.css
.container {
background-color: black;
}
.container .title {
color: white;
}
.container .description {
color: grey;
}
The wrapper code could be:
.theme0 {
#import (less) "component.css";
&.container:extend(.theme0 .container all) {}
}
in less you can nest selectors for selecting inside that element like:
.theme {
color: black;
.container {
color: blue;
}
}
This wil generate:
.theme {
color:black;
}
.theme .container {
color:blue;
}
Creating elements that are connected is easy enof:
.test#badge will select a class test width an id badge
In less this is dont with the & symbol. (this selects the starting property)
.test {
color: blue;
&#badge {
color:black;
}
}
Compiles to:
.test {
color: blue;
}
.test#badge {
color: black;
}
And for the final selector:
To get the output of .test, .container use the function: .test:extends(.container);
.test {
color: black;
&:extends(.conatiner);
}
.container {
color: pink;
}
Compiles to:
.test {
color: black;
}
.test, .container {
color: pink;
}
You can even extend multiple ones in a single line:
.test:extends(.oclas, .tclss);
and its wil work as abose only for both classes. So outputed selectors would be .test, .oclass and .test, .tclass

Foundation customizing scss classes

I am trying to customize scss of foundation to have a two different classes for topbar. I have limited knowledge of scss therefore changing _settings.scss was very easy first step, which has the problem that it changes global style. I would like to do something like following without messing up global styles.
.my-topbar-first {
$topbar-bg-color: $red;
#extend .top-bar;
}
.my-topbar-second {
$topbar-bg-color: $green;
#extend .top-bar;
}
Whats the elegant way to achieve this?
when you are using $topbar-bg-color: $red; it set the $topbar-bg-color variable to what you have in $red variable.when you are using it again, it messed up the last setting.
so instead,
you have to do like this :
.my-topbar-first {
background-color: $red;
#extend .top-bar;
}
.my-topbar-second {
background-color: $green;
#extend .top-bar;
}
First of all you are duplicating code when extending .top-bar in both class names . A more DRY approach would be like this :
.my-topbar-first,
.my-topbar-second {
#extend .top-bar;
}
.my-topbar-first {
background-color: $red;
}
.my-topbar-second {
background-color: $green;
}
When using #extend or #include they should always be on the first line were you declare your properties , example:
my-topbar-second {
#extend .top-bar;
background-color: $green;
color: $white;
font-size: $top-bar-fontsize;
}
If you have more instances of .top-bar-foo you can actually write a for loop, example :
$class-slug: top-bar;
#for $i from 1 through 2 {
.#{$class-slug}-#{$i} {
background-color: $color-#{$i};
}
}
You get :
.top-bar-1 {
background-color: $color-1;
}
.top-bar-2 {
background-color: $color-2;
}
Hope this helped . If you want to learn more about Scss go on Hugo Giraudel's blog http://hugogiraudel.com/ and learn from the best .

Resources