I'm trying to write a dynamic mixin with LESS to generate the CSS automatically based on an ID. Is it possible with LESS?
// Variables
@body-margin: 50px;
@body-margin-tablet: 30px;
@body-margin-mobile: 20px;
@body-padding: 150px;
@body-padding-tablet: 130px;
// Mixin
#spacing(@id) {
& when ( @{id}-margin ) {
margin: @{id}-margin;
}
& when ( @{id}-padding ) {
padding: @{id}-padding;
}
@media (max-width: 900px) {
& when ( @{id}-margin-tablet ) {
margin: @{id}-margin-tablet;
}
& when ( @{id}-padding-tablet ) {
padding: @{id}-padding-tablet;
}
}
@media (max-width: 500px) {
& when ( @{id}-margin-mobile ) {
margin: @{id}-margin-mobile;
}
& when ( @{id}-padding-mobile ) {
padding: @{id}-padding-mobile;
}
}
}
body {
#spacing('body');
}
Expected result:
body {
margin: 50px;
padding: 150px
@media (max-width: 900px) {
margin: 30px;
padding: 130px;
}
@media (max-width: 500px) {
margin: 20px;
}
}
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;
}
}