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
CSS Text Padding Difference Firefox Vs Chrome and Others
How to Use Sass/Scss in Angular Application
Jagged "Border" Showing Due to Background Colour on Wrapper Element with Border-Radius: 50%;
Google Fonts External CSS Vs Copying The Code of External CSS in My CSS
Using Rems with a Pixel Fallback
Google Fonts Font Doesn't Load
Accessing The CSS in Browser Using Question Mark () in End
Bootstrap 4 Float-Right Not Working with The Navbar
Fade Background Images with CSS3
How to Create a Child Theme in Wordpress
:After,: Before Issues in Internet Explorer 11
How to Combine Compass with Bless
Chrome Print Preview Doesn't Load @Media Only Print Font-Face
Why Does Chrome Read The Svg Circle Radius from The Style Attribute