How to Pass !Important as Parameter/Option for Lesscss Mixins

Is it possible to pass !important as parameter/option for LESSCSS mixins?

See The !important keyword. E.g. can just use .coloring(red) !important; w/o mixin changes.
Or use escaping for the modified mixin since ! is not allowed symbol in mixin parameter values (i.e. .coloring(red, ~'!important');).

Also note that the default value of '' for the @important parameter is not correct since the mixin call with this parameter omitted will result in invalid color: color ''; CSS (use @important... or @important: ~'' if you need an "empty" default value ).

P.S. Also do not miss that you can supply both color and !important values as a single parameter, i.e. .coloring(red ~'!important'); would be also correct method to invoke your original 1-parameter mixin (if you need only color property to have the !important modifier contrary to .coloring(red) !important; syntax where !important applies to all CSS properties within the mixin).

LESS CSS pass string to mixin

I'm not quite certain what you are seeking to have as output, but this:

.mixin(@paramName) {
background: ~"...@{paramName}";
}

.mixin("Pdcbs/sjdhc+jdjhdf");

Produces this for me:

background: ...Pdcbs/sjdhc+jdjhdf;

LESS: Mixin with optional parameter

So you have

.generated_width (@margins: 40px, @per: 100%)
{
-webkit-width:calc(~"@{per} - " @margins );
-moz-width:calc(~"@{per} - " @margins );
width:calc(~"@{per} - " @margins );
}

When called

.generated_width (40px)
.generated_width (40px, 40%)

I think depending on your LESS version you can also do

.generated_width (@per:40%)

This way you can specify as many optional parameters as you want. This is much more flexible but a little bit more code to type. So if you only have 1 optional param then just leave it at the last spot

Less CSS: Can I call a mixin as an argument when calling another mixin?

As discussed in comments, Less mixins are not functions and the mixin calls cannot return any value. Because of this, one mixin (or its output value) cannot be passed as an argument to another mixin.

Having said that, we can still set a variable within a mixin, call the mixin within each selector block where it is required and make use of the variable defined within it. The mixin call effectively exposes the variable defined within it to the parent scope.

Below is a sample snippet which would call the contrast mixin and assign the calculated value as the text color and border color of the element.

// color variables for user's color
@userColor: #13acae;
@darkUser: hsl(hue(@userColor), saturation(@userColor), lightness(tint(@userColor, 30%)));
@lightUser: hsl(hue(@userColor), saturation(@userColor), lightness(shade(@userColor, 30%)));

// color mixin to alter user's color using Less 'darken' and 'contrast' functions
.contrastColorDark(@percent) {
@color: darken(contrast(@userColor, @darkUser, @lightUser), @percent);
//color: darken(contrast(@userColor, @darkUser, @lightUser), @percent);
}

// border mixin
.border(@width, @color) {
border: @width solid @color;
}

// CSS rule using both mixins
.thing {
.contrastColorDark(10%);
color: @color;
.border(1px, @color);
}

.thing2 {
.contrastColorDark(50%);
color: @color;
.border(1px, @color);
}

LESS CSS Pass mixin as a parameter to another mixin

UPDATED for LESS 1.7.0+ (WAY Simpler)

We can do this far more directly now with the 1.7.0 update and the ability to create rulesets, and to use variables in setting @keyframes.

Now we really can pass a mixin through a parameter by a ruleset, or we can pass in the property stings themselves. So consider this:

LESS (using 1.7)

.keyframes(@name, @from, @to) {
@frames: {
from { @from(); }
to { @to(); }
};
@pre: -moz-keyframes;
@-moz-keyframes @name
{
@frames();
}

@-webkit-keyframes @name
{
@frames();
}

@keyframes @name
{
@frames();
}
}

.keyframes(testName, {color: red; .myMix(0);}, {color: blue; .myMix(1);});

.myMix(@value) {opacity: @value;}

Note that I am passing both a property setting and a mixin call, and my output is:

CSS Output

@-moz-keyframes testName {
from {
color: red;
opacity: 0;
}
to {
color: blue;
opacity: 1;
}
}
@-webkit-keyframes testName {
from {
color: red;
opacity: 0;
}
to {
color: blue;
opacity: 1;
}
}
@keyframes testName {
from {
color: red;
opacity: 0;
}
to {
color: blue;
opacity: 1;
}
}

Note how the rulesets are passed, in brackets {...}, and then called, via @from() and @to() (looking a lot like a mixin call). I'm using these passed rule sets to set another ruleset of @frames which is then itself called to fill the keyframes definitions.

More Generically

Here I pass a private mixin to another mixin and then call it from that other mixin:

LESS

.someMixin(@class; @expectedMixin) {
.@{class} {
@expectedMixin();
.myPrivateMix(0.6);
test: 1;
}
}

.someMixin(newClass; {.myClass;});

.myClass {
.myPrivateMix(@value) {opacity: @value;}
}

CSS Output

.newClass {
opacity: 0.6;
test: 1;
}

Kept the below for legacy info.

Updated (added LESS 1.4.0+ support)

Wow, this took some doing, but I think I have something you can work with. However, it does take some special defining of your mixins in your modules, specifically, using pattern matching. So...

First, Define Your Module Mixins

Note how the module mixins intended to be used in a specific future mixin are defined with the same mixin name, but with a different pattern name. This was key to making this work.

// define one animation in a module
.from(my-from){ color: red; }
.to(my-to) { color: blue; }

// define one animation in another module
.from(another-from){ font-size: 1em; }
.to(another-to) { font-size: 2em; }

If you also want individual mixin names in the modules, you should be able to do this:

// define one animation in a module
.my-from(){ color: red; }
.my-to() { color: blue; }

.from(my-from){ .my-from() }
.to(my-to) { .my-to() }

// define one animation in another module
.another-from(){ font-size: 1em; }
.another-to() { font-size: 2em; }

.from(another-from){ .another-from() }
.to(another-to) { .another-to() }

This should allow one to call either the straight mixin .my-from() or, to make it variably accessible within later mixins that access the singular .from() mixin group through the pattern matching.

Next, Define Your Mixin

For your @keyframes example, that was extremely difficult. In fact, a stack overflow answer was vital to helping me solve an issue with applying the @name, which was not applying under normal LESS rules because of it following the @keyframes definition. The solution to apply the @name looks nasty, but it works. It does have the, perhaps, unfortunate necessity of also defining a selector string to play the animation by (because it uses that string to help build the last } of the keyframes). This naming limitation would only be true of css strings that begin with @ like @keyframes and probably @media.

Further, because we have a standard mixin name used in our module files, we can access that consistently within our new mixin, while at the same time passing a variable in to select the proper variation of that mixin through a pattern match. So we get:

LESS 1.3.3 or under

// define mixin in mixin file

.keyframes(@selector, @name, @from, @to) {
@newline: `"\n"`; // Newline
.setVendor(@pre, @post, @vendor) {
(~"@{pre}@@{vendor}keyframes @{name} {@{newline}from") {
.from(@from);
}
to {
.to(@to);
}
.Local(){}
.Local() when (@post=1) {
(~"}@{newline}@{selector}") {
-moz-animation: @name;
-webkit-animation: @name;
-o-animation: @name;
-ms-animation: @name;
animation: @name;
}
}
.Local;
}
.setVendor("" , 0, "-moz-");
.setVendor(~"}@{newline}", 0, "-webkit-");
.setVendor(~"}@{newline}", 0, "-o-");
.setVendor(~"}@{newline}", 0, "-ms-");
.setVendor(~"}@{newline}", 1, "");
}

LESS 1.4.0+

.keyframes(@selector, @name, @from, @to) {
@newline: `"\n"`; // Newline
.setVendor(@pre, @post, @vendor) {
@frames: ~"@{pre}@@{vendor}keyframes @{name} {@{newline}from";
@{frames} {
.from(@from);
}
to {
.to(@to);
}
.Local(){}
.Local() when (@post=1) {
@animationSector: ~"}@{newline}@{selector}";
@{animationSector} {
-moz-animation: @name;
-webkit-animation: @name;
-o-animation: @name;
-ms-animation: @name;
animation: @name;
}
}
.Local;
}
.setVendor("" , 0, "-moz-");
.setVendor(~"}@{newline}", 0, "-webkit-");
.setVendor(~"}@{newline}", 0, "-o-");
.setVendor(~"}@{newline}", 0, "-ms-");
.setVendor(~"}@{newline}", 1, "");
}

Now Call Your Mixin

You can give it your own name, and just pass the straight pattern (all are no dot [.] and no quotes) for the pattern matches on the module mixins, but don't forget that you also need a selector string (which is quoted) to get the mixin to work right:

.keyframes('.changeColor', some-name, my-from, my-to);
.keyframes('.changeFontSize', another-name, another-from, another-to);

Which Gives You the Desired Output

@-moz-keyframes some-name {
from {
color: red;
}
to {
color: blue;
}
}
@-webkit-keyframes some-name {
from {
color: red;
}
to {
color: blue;
}
}
@-o-keyframes some-name {
from {
color: red;
}
to {
color: blue;
}
}
@-ms-keyframes some-name {
from {
color: red;
}
to {
color: blue;
}
}
@keyframes some-name {
from {
color: red;
}
to {
color: blue;
}
}
.changeColor {
-moz-animation: some-name;
-webkit-animation: some-name;
-o-animation: some-name;
-ms-animation: some-name;
animation: some-name;
}
@-moz-keyframes another-name {
from {
font-size: 1em;
}
to {
font-size: 2em;
}
}
@-webkit-keyframes another-name {
from {
font-size: 1em;
}
to {
font-size: 2em;
}
}
@-o-keyframes another-name {
from {
font-size: 1em;
}
to {
font-size: 2em;
}
}
@-ms-keyframes another-name {
from {
font-size: 1em;
}
to {
font-size: 2em;
}
}
@keyframes another-name {
from {
font-size: 1em;
}
to {
font-size: 2em;
}
}
.changeFontSize {
-moz-animation: another-name
-webkit-animation: another-name;
-o-animation: another-name;
-ms-animation: another-name;
animation: another-name;
}

pass property name as an argument in a mixin LESS

I think this is what you are trying to do:

//A simple Border Mixin to start
.borderMixin(@color: #ddd){
border: 1px solid @color;
}
//Using the Mixin
.border{
.borderMixin(@color: #ddd);
&-right {
.borderMixin(@color: #F01);
}
&-left {
.borderMixin(@color: #000);
}
}

So first I've declared the Mixin helper to be used and then I used it and re-use it exending the class name with the & character

That will output this in your CSS:

/*********
*The resulted css code:
*/
.border {
border: 1px solid #dddddd;
}
.border-right {
border: 1px solid #ff0011;
}
.border-left {
border: 1px solid #000000;
}

UPDATE:


+Harry suggests this:

.borderMixin(@position: left, @color: #ddd){
border-@{position}: 1px solid @color;
}

.border{
width: 200px;
.borderMixin(right,#222);
.borderMixin(left,#222);
}

How to declare a variable as !important with LESS?

I think your declaration of @fontColor: #000000 !important; indeed make no sense, what do you assign? a string, a list of something?
Most reasonable it a string, which should quoted and indeed escaped when used:

For that reason the following code seems correct (for me)

@fontColor: "#000000 !important";

p {
color: ~"@{fontColor}";
}

I also found that the following code:

@wrong: red noncolor;
selector {
property: @wrong;
}

@wrongtoo: red !important;
selector {
propertytoo: @wrongtoo;
}

output:

selector {
property: red noncolor;
}
selector {
propertytoo: red;
}

The compiler (Less v2) does not throw a error in both cases. But in the second case !important is not compiled in the CSS code. Also red !noncolor compiles into the CSS code. Probably !important is some kind of keyword, but for me it seems an inconsequence in the compiler for now.

Also notice that the docs describe how to use !important with mixins at http://lesscss.org/features/#mixins-feature-the-important-keyword

Conditional mixin based on parameter existence

1:

In general, when you need to generate different things for different number of arguments passed you don't need to use default argument values at all, e.g.:

.margin(@top, @bottom, @right, @left) {
/* right and left are passed */
}

.margin(@top, @bottom) {
/* right and left are not passed */
}

.margin() {
/* no arguments passed */
}

// etc.

Note that each of these mixins can reuse the others, for example .margin(@top, @bottom) can do something special for the "no right and left case" and then call .margin(@top, @bottom, 0, 0) to perform the main job.

2:

But if you still need these defaults for some reason you can use some special default value that can't be a valid margin, e.g. something like this:

.margin(@top: undefined, @bottom: undefined, @right: undefined, @left: undefined) {
.test-args();

.test-args() when (@right = undefined) {
/* right is not passed */
}
.test-args() when (@left = undefined) {
/* left is not passed */
}

.test-args()
when not(@right = undefined)
and not(@left = undefined) {
/* right and left are passed */
}

// etc.
}

3:

And the third option would be to use variadic arguments and test their count, but this one is the most verbose and dumb I guess:

.margin(@args...) {
.eval-args(length(@args)); // requires LESS 1.5.+
.eval-args(@nargs) {
// default values:
@top: not passed;
@bottom: not passed;
@right: not passed;
@left: not passed;
}
.eval-args(@nargs) when (@nargs > 0) {
@top: extract(@args, 1);
}
.eval-args(@nargs) when (@nargs > 1) {
@bottom: extract(@args, 2);
}
.eval-args(@nargs) when (@nargs > 2) {
@right: extract(@args, 3);
}
.eval-args(@nargs) when (@nargs > 3) {
@left: extract(@args, 4);
}

args: @top, @bottom, @right, @left;
}

Though it may probably have its pros in some special use-cases.

Use mixin argument to create class name in LESS

I think I have the solution using Variable Names.

Less

@green: #5FBEAA;

.text-color(@colorname) {
@color: ~"@{colorname}";
.text-@{color}{
color: @@color;
}
}

.text-color(green);

Output

.text-green {
color: #5FBEAA;
}

Can I define a LESS mixin to generate a transition-property with a variable number of parameters?

I've managed to figure it out thanks to Luke Page pointing me towards the ... syntax.

The solution was to use the following:

  • ... to allow variable parameters
  • Backticks for JavaScript evaluation
  • Variable string interpolation
  • A ~ prefix to escape the resulting expression (i.e. stop LESS from enclosing it in a string)
  • Good old regular expressions

Phew. Here's the resulting mixin:

.transition-properties(...) {
-webkit-transition-property: ~`"@{arguments}".replace(/[\[\]]/g, '')`;
}

And here's the full version with a complete set of browser extensions:

.transition-properties(...) {
@props: ~`"@{arguments}".replace(/[\[\]]/g, '')`;
-webkit-transition-property: @props;
-moz-transition-property: @props;
-o-transition-property: @props;
transition-property: @props;
}


Related Topics



Leave a reply



Submit