How to Override a Less Mixin Variable Based on a Parent's Variable

How to override a LESS mixin variable based on a parent's variable

LESS allows you to define variables. So you can define a variable for the parent's color and then use it within the lighten function like below:

@parentColor: #ff4400;

.jumbotron {
background-color: @parentColor; /* Using the parent color variable */
}

.Myjumbotron {
.jumbotron;
background-color: lighten(@parentColor, 30%); /* Lightening the parent color */
}

Demo

Note: This would produce two background-color setting but that should be fine because CSS takes the last available setting as the value and in this case it would be the lightened value.

Option 1 without using variables: For achieving the lighten or darken effect without using a parent color variable, refer to the work-around answer posted by ScottS in this thread or the demo that seven-phases-max has posted in the comments.

Option 2: (contributed by seven-phases-max in this comment)

Best alternative solution (if you cannot modify the original .jumbotron code to use variables and have the .myJumbotron element as not a child of the parent .jumbotron element) would be the below:

.jumbotron {
background-color: #ff4400;
color: white;
padding: 2em;
}

.Myjumbotron:extend(.jumbotron) {
@back: fade(white, 60%);
background-image: linear-gradient(@back, @back);
}

Demo for Option 2

LESS CSS how to modify parent property in mixin

If you mean the .button-default and .button-warning are those "PARENT"s for the .button-hover-effect-mixin then your friends are variables:

.button-default {
@background-color: rgb(100, 200, 250);
background-color: @background-color;
&:hover {
.button-hover-effect-mixin();
}
}

.button-warning {
@background-color: rgb(250, 100, 0);
background-color: @background-color;
&:hover {
.button-hover-effect-mixin();
}
}

.button-hover-effect-mixin() {
background-color: darken(@background-color, 50%);
}

You also can make this variable to be a parameter of .button-hover-effect-mixin. Additionally don't miss & near :hover selector (without & it expands to .button-default :hover and this probably is not what you need, see Nesting).


And... if this goes in right direction and those colors are the only difference between the buttons I would rewrite the whole snippet to something like this:

.button(default, rgb(100, 200, 250));
.button(warning, rgb(250, 100, 0));

.button(@name, @color) {
.button-@{name} {
background-color: @color;
&:hover {
background-color: darken(@color, 50%);
}
}
}

Overriding css class variables with LESS

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.

LESS CSS How to capture parent selector in variable

You can possible solve your issue by using the parent reference & to (change selector order)[http://lesscss.org/features/#parent-selectors-feature-changing-selector-order]

.media {
&__body{
color: green;
}
&.-reverse & {
&__body {
color: red;
}
}
}

compiles into CSS code as follows:

.media__body {
color: green;
}
.media.-reverse .media__body {
color: red;
}

Overriding in LESS

As commented earlier it is considered best practice to not modify bootstraps less files, and instead add your styles in a stylesheet/less file that will override bootstraps. This way you'll avoid problems when upgrading to new versions of bootstrap - and when you need to track down errors it will be alot easier just looking at your overrides.

Now you might run into problems related to overriding, and trying to figure out why your applied style isn't overriding bootstrap's style. In that case i reccomend you to read up on Andy Clarke's great article - CSS: Specificity Wars (it's a bit old, but still a great explanation of css specificity):

http://www.stuffandnonsense.co.uk/archives/css_specificity_wars.html

EDIT - So to better explain the advantage of multiple class-blocks, here is first an example of using two classes to style one element:

CSS:

.center {
margin: 0 auto;
}
img.center {
display: block;
}

HTML

<div class="center">This will center horizontally</div>
<img class="center" src="foo.png"><!-- this image will also center horizontally -->

In the above example the image will be centered because it will inherit both rules. Now lets say that you want a nested ul to have a lower amount of padding than your regular (parent) ul, you would then override this by targeting its hierarchy (again the link posted above explains this)

ul {
list-style: none;
padding: 5px;
}

ul ul {
padding: 1px;
}

EDIT, answer for @Chris Moschini comment

Yes you can also override Bootstrap default values through LESS if you create your own less file which imports bootstrap.less - and then override the variables you want to change.

@import "less/bootstrap.less";
@brand-primary: red;

To see what you can override look at the file variables.less on git, you can also checkout the mixins.less file if you'r looking to mess around there too.

But in many cases you'll need to do some overriding through css specificity.



Related Topics



Leave a reply



Submit