Overriding css class variables with LESS - css

I have a less file which contains a class that defines a few variables for colors:
.some-css-class{
#color1: #E6E6E6
#color2: #808080
/* some other rules follow */
}
Since this is a 3rd party file I don't wont to change it directly. Instead I created my own less file and imported the 3rd party file. Now I want to override the colors defined in the base file but I don't get it working.
I tried to override the colors on root level, but this way I am not able to change the variables since they are defined within a class in the base file:
/* Including base styles */
#import "base.less";
#color1: #DF007B;
#color2: #00A855;
So I tried to override the colors within the class, but apparently I am not able to change them this way, as it is not possible to override variables in the same scope (.som-css-class):
/* Including base styles */
#import "base.less";
.some-css-class {
#color1: #DF007B;
#color2: #00A855;
}
Any hints on how I am able to override the colors?
EDIT: It seems that there isn't a solution for this. In my particular case I was looking for a way to override colors in an angularjs module(angular-wizard).
As i saw now, a pull request to solve this problem already exists:
https://github.com/mgonto/angular-wizard/pull/68

Let's think about the way LESS compiles for a second. If you want, you can try to run any of this in the https://fiddlesalad.com/less editor.
Here in this example, I've just included some arbitrary colors and a 'background' property to make it easier to understand. In your example when you import base.less, you are really just putting some LESS rules before the ones in your file. So, just to clarify, if we "expand" your import, the file might look like this before its compiled to CSS:
.some-css-class{
#color1: red;
background: #color1;
}
.some-css-class {
#color1: purple;
}
What does this output?
.some-css-class {
background: red;
}
Why? You might say "I've redeclared the color variable so shouldn't it recompile the rules?". However, this is fundamentally not how LESS is designed--its backwards compatible with CSS, so a rule must happen later to override a previous rule. Take this example instead:
.some-css-class{
#color1: red;
background: #color1;
}
.some-css-class {
#color1: purple;
background: #color1;
}
Here is the output you get now:
.some-css-class {
background: red;
}
.some-css-class {
background: purple;
}
The rules are split into two outputs, and because the second rule happens later in the cascade, it has a higher precedence--barring this class existing nowhere else, the 'purple' rule will take precedence.
In LESS, you "lazy load" variables -- it will always take the last value found, starting from the inner scope. Thus:
.some-css-class {
#color1: purple;
background: #color1;
#color1: blue;
}
Will output:
.some-css-class {
background: blue;
}
The unfortunate thing though, however, is if we try to extend your previous rule as a mixin, it resolves the values from each class before pulling them into your new class:
.some-css-class{
#color1: red;
background: #color1;
}
.some-css-class {
#color1: purple;
background: #color1;
#color1: blue;
}
.another-css-class {
.some-css-class();
#color1: orange;
}
Outputs:
.some-css-class {
background: red;
}
.some-css-class {
background: blue;
}
.another-css-class {
background: red;
background: blue;
}
The ideal way to "override" these values then, is to turn the original ruleset into a parametric mixin:
.some-css-class(#color1, #color2) {
background: #color1;
color: #color2;
}
.another-css-class {
.some-css-class(red, blue);
}
Finally, your output will look like this:
.another-css-class {
background: red;
color: blue;
}
EDIT: Ultimately I recommend, you copy the original rule out of the file (without modifying that file) and alter it to be a mixin in your version. Ultimately you'll end up with the same net amount of CSS as you would if you could extend and override the variables for your new class.

Did you try to extend it?
.new-some-css-class {
&:extend(.some-css-class);
#color1: #DF007B;
#color2: #00A855;
}

Related

How to refer parent property within nested rule with the same name

I am trying to reuse a background-color definition of the parent rule set in background-color definition of a child rule set. However, Less evaluates the lookup as a recursion.
I would like this:
.button {
background-color: whitesmoke;
&:hover {
background-color: darken($background-color, 10%);
}
}
to work the same way as this:
#the-color: whitesmoke;
.button {
background-color: #the-color;
&:hover {
background-color: darken(#the-color, 10%);
}
}
but without the need for an extra variable.
The documentation isn't very specific on this. Am I missing something or is this just not possible?
I am aware of other solutions to changing the tint of a button on hover (e.g. using the filter property).
EDIT 1:
The closest I can get to is this. I just need it to be background-color instead of color.
.button {
background-color: whitesmoke;
&:hover {
color: darken($background-color, 10%);
}
}
The problem is the lookup of $background-color evaluates to the background-color of the same row (which, I think, doesn't ever make sense) and refuses to compile instead of evaluating to a rule in the parent rule set or just simply evaluating to one of the previous rows.

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 :)

Less inherit "virtual" class

I am using SASS and there is nice feature: I can create "fake/virtual" class and then use it for extend.
Example:
%myFakeClass
{
color:#fff;
background-color:#000;
}
.myRealClass
{
#extend %myFakeClass;
}
.myRealClass2
{
#extend %myFakeClass;
}
Output:
.myRealClass, .myRealClass2
{
color:#fff;
background-color:#000;
}
The question:
Does LESS has something similar? In other words, I want to create a "virtual class" that I can inherit from, but the "virtual class" itself not exists in output.
Not Directly as of Yet
As of this date (11-22-2013) there is still a feature request that would allow this by doing extending on empty parameter mixins (which do not output css themselves). So eventually something like this would be possible (which mirrors almost exactly what you want):
.myFakeClass() {
color:#fff;
background-color:#000;
}
.myRealClass {
&:extend(.myFakeClass);
}
.myRealClass2 {
&:extend(.myFakeClass);
}
And output as you expect.
Workaround for now
This was mentioned by Bass Jobsen, but not explicitly demonstrated. In LESS 1.5, you build a file for your fake classes, say fakeClasses.less, which for our example has this in it:
.myFakeClass {
color:#fff;
background-color:#000;
}
Then in your file that you want to extend to it, let's say styles.less, you do this:
#import (reference) fakeClasses.less;
.myRealClass {
&:extend(.myFakeClass);
}
.myRealClass2 {
&:extend(.myFakeClass);
}
This will import the fakeClasses.less classes but NOT compile them to css (so they are "fake" within the context of styles.less, but "real" in that they can be extended to), and you will get the output you expect.
.myRealClass, .myRealClass2 {
color:#fff;
background-color:#000;
}
Maybe the following helps you img { &:extend(.img-responsive); } from Why gives Grunt / Recess an error and Lessc not when compiling Bootstrap 3 RC1?
update from How do I create a mixin using less.js that doesn't output in the final stylesheet:
.myFakeClass()
{
color:#fff;
background-color:#000;
}
.myRealClass, .myRealClass2
{
.myFakeClass();
}
since LESS 1.5 you could also place you virtual classes in a separate file and use:
#import (reference) "file.less";
We have another import option - reference. This means that any
variables or mixins or selectors will be imported, but never output.
I'm not entirely sure if #extend works the same as a "mixin", but it looks the same.
.myFakeClass(#textColor: #fff, #bgColor: #000 )
{
color:#textColor;
background-color:#bgColor;
}
.myRealClass
{
.myFakeClass();
}
.myRealClass2
{
.myFakeClass();
}
The out put for this would be the same as what you have above. I added variables in the mixin for easier customization for this mixin.
Example:
.myRealClass3
{
.myFakeClass(#369, #00f);
}
The output for all three classes would be:
.myRealClass, .myRealClass2
{
color:#fff;
background-color:#000;
}
.myRealClass3
{
color:#369;
background-color:#00f;
}
Like I said, I'm not entirely sure if there is a big difference between extending a class in SASS and using a mixin in LESS. Hope this helps either way.
Oh, and just to clarify, if the .myFakeClass() class is in a separate .less file that is imported, it will not show up in your CSS unless it is used. I tested this on a website I'm building. I have:
.box-shadow(#a, #b, etc..) {
box-shadow: #a #b etc..;
-webkit-box-shadow: #a #b etc..;
etc: #a...;
}
The class .box-shadow does not show up in my CSS at all.
Link: http://lucienconsulting.com/gs-news/wp-content/themes/TheStone/css/style.css
However, if you write a mixin like this:
.myMixin{
background: #000;
color: #fff;
}
It will show up like a normal class even if not used. Obviously, it looks just like a normal class and could be used by itself, or as a mixin, like so:
.myClass{
.myMixin;
border: 1px solid #fff;
}
This would compile to:
.myClass{
background: #000;
color: #fff;
border: 1px solid #fff;
}
It works, but .myMixin would also show up in your style sheet in this case.
But, like I said, in my original example, it would not.

Sass variables in print stylsheet override variables in "all" stylesheet

I use the latest SASS/Compass versions for developing CSS. I've declared some SASS variables at the beginning of the "media=all" stylesheet like this:
$var1: red;
$var2: blue;
$var3: black;
$var4: green;
Later in this SCSS file i import a print stylesheet (#import 'print.scss';) which looks like this:
#media print {
$var1: black;
$var2: black;
$var4:black;
}
I thought, that the variables in the print stylesheet overrides the "normal" vars only if the Browser is in "print mode". But the variables do override always the "normal" vars declared before.
I'm a little confused and appreciate any help.
Thanks!
As per this questions, it's basically not possible in your current form. If you want to achieve this, you'll have to import each style that makes use of your $varX, like:
$blue: blue;
.test{
color: $blue;
}
#media print {
$blue: pink;
.test{
color: $blue;
}
}
output:
.test{color:blue}#media print{.test{color:pink}}
It's not the ideal solution (you'll get lots of repeated code), but unfortunately it's all you can do due to the way CSS works.
This may be a slightly better solution:
$blue: blue;
$print_blue: pink;
.test{
color: $blue;
text-align: right;
#media print {
color: $print_blue;
}
}
output:
.test{color:blue;text-align:right}#media print{.test{color:pink}}

Reuse CSS class

I should have asked this in my previous question (CSS style declaration reusage), but I didn't think of it at the time. Since that question is answered, I'll start a new one.
I am trying to create color palette in CSS that will be used through out my application.
For example:
.blue { color: #434544; }
.green { color: #G99933; }
I do not want to define colors anywhere else in my CSS. The problem I am running into is how do i use the .blue style when, for example, I need a background-color definition? Take a look at this:
.editor { background-color: #434544 }
I want to reference back to the .blue style instead of defining it here again. How can I do that?
UPDATE
I found the perfect solution for my question:
Chirpy -> http://chirpy.codeplex.com/
There's no way to do this in native CSS. You should look into pre-processing your CSS, since all those pre-processors have support for variables.
Here's what it looks like using (scss-flavored) SASS:
$blue: #434544;
$green: #G99933;
.blue { color: $blue; }
.green { color: $green; }
.editor { background-color: $blue }

Resources