Overwrite Less Mixin

Overwrite less mixin

Less works exactly like CSS does in this respect. For example, if you wrote this CSS:

p { border: 1px solid black; }

It would give all paragraphs a black border. If later in the document you added:

p { }

You wouldn't expect it to overwrite your previous definition, right?

So, in this case it's the expected behaviour, you need to specifically overwrite the CSS values you want to overwrite.

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

Dynamic LESS mixin

So there are basically two parts to this question. The first is how to dynamically interpolate your variable names in your mixin, and the second is how to figure out if the variable you interpolated even exists.

The first part can be done like so:

@body-margin: 50px;

.spacing(@id) {
margin: ~"@{@{id}-margin}";
}

If you do that, then using

body {
.spacing('body);
}

Will give you your expected CSS output of

body {
margin: 50px;
}

Read more about that here: Defining Variable Variables using LESS CSS.

The second part, determining whether the interpolated variable even exists, I don't think you can do in LESS. You are going to have to define all possible variables ahead of time, but that doesn't mean you can't get clever with how you define those variables.

Say you don't want to define a variable for @body-padding-mobile. In that case, you can do one of two things, whichever you think is more helpful for you.

The first is that you could set the variable value equal to whatever the default value is in CSS (0, in the case of padding), or else just initial.

Or, if you're afraid that will mean you end up overwriting styles you don't want to overwrite, the more hacky solution is to just make the variable equal to an invalid value, so the browser never applies the style. For example: @body-padding-mobile: fishsticks.


Assuming you've declared all the variables you need for the mixin, you can use this mixin to get what you want:

.spacing(@id) {
margin: ~"@{@{id}-margin}";
padding: ~"@{@{id}-padding}";
@media (max-width: 900px) {
margin: ~"@{@{id}-margin-tablet}";
padding: ~"@{@{id}-padding-tablet}";
}
@media (max-width: 500px) {
margin: ~"@{@{id}-margin-mobile}";
padding:~"@{@{id}-padding-mobile}";
}
}

So if we start with this:

@body-margin: 50px;
@body-margin-tablet: 30px;
@body-margin-mobile: 20px;

@body-padding: 150px;
@body-padding-tablet: 130px;
@body-padding-mobile: 0;

body {
.spacing('body');
}

We'll get this:

body {
margin: 50px;
padding: 150px;
}
@media (max-width: 900px) {
body {
margin: 30px;
padding: 130px;
}
}
@media (max-width: 500px) {
body {
margin: 20px;
padding: 0;
}
}

How to override properties of a CSS class altering the original value (less + mixin)

See https://github.com/twbs/bootstrap/blob/v3.3.7/less/jumbotron.less

So you simply do something like:

@import "bootstrap/variables.less";

.jumbotron {
padding-top: @jumbotron-padding * .5;
}

}

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