Less CSS: Reuse Generated .@{Name} Class as a Mixin

LESS CSS: Reuse generated .@{name} class as a mixin

Unfortunately. The selector interpolation is just string interpolation, and the string gets then printed into css, so no class object is generated in the less run.

So you can design a generator/mixin, that includes your operation:

#genMarginTop (@size) {
margin-top: @size;
}

But then build classes by calling the mixins / generators:

.mtStandard {#genMarginTop(40px);}
.mtHalf {#genMarginTop(20px);}

And this way they are class objects that you can use for mixin =)

.someClass {
background-color: #FFF;
.mtStandard;
//more of this stuff
}

This looks a bit silly in this simple example, but maybe something like this:

 #bggenerator (@color) {
background-color: @color;
}
#bggenerator (@color, dark) {
@blend : @color + #842210;
background-color: darken(@blend, 30%);
}
#bggenerator (@color, @url, @rest) {
background: "@{color} url('@{url}') @{rest}";
}

.mtStandard {
#genMarginTop(40px);
}

.someClass {
.mtStandard;
#bggenerator(#FFF, "bgimage.png", left top no-repeat);
//more of this stuff
}

Or something that does even more exciting stuff with the arguments

LESS mixin a variable class name

There are at least 2 problems with what you are trying to do (for LESS >=1.6 see update bellow):

1) Unfortunately it is not possible to call a mixin using selector
interpolation.

With selector interpolation LESS expects the construct to be of
following format:

.@{selector-string} { property:value; }

(the interpolated selector can have also some static string pre or
post the interpolation)

so

.@{selector-string};

is Unrecognised by the LESS compiler. See more here:
How can I call a mixin by reference in LESS?

2) A ruleset with an interpolated selector gets directly printed to the CSS output and does not exist as a mixin that you could reuse in the LESS run

For example:

@foo: test;

.@{foo} {
length: 20px;
}

.bar {
.test;
}

will return:

    Name error: .test is undefined
.bar { .test;}

See more on that here: LESS CSS: Reuse generated .@{name} class as a mixin

Possible solution for your problem would be redifinig the font awesome rules as some kind of reusable mixins (without using interpolation). Something like this:

@fa-var-github: "\f09b";

.fa-mixin() {
display: inline-block;
font-family: FontAwesome;
font-style: normal;
font-weight: normal;
line-height: 1;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.fa-mixin-lg() {
font-size: (4em / 3);
line-height: (3em / 4);
vertical-align: -15%;
}
.fa-mixin-icon(@icon){
@var: "fa-var-@{icon}";
&:before { content: @@var; }
}
i {
.fa-mixin;
.fa-mixin-lg;
.fa-mixin-icon(github);
}

If you don't really need the variables and just want to include the rules, the best way would be just to import the compiled CSS version of the FontAwesome (see answer here):

@import (less) 'font-awesome.css';

and then you can just use the CSS rules like LESS mixins or extend their selectors as you see fit and it should work perfectly.


Update:

As of LESS >= 1.6 rules with interpolated selectors can be accessed as mixins ... so the #2 limitation form above does not apply anymore (but you still can not call a mixin dynamically with interpolation). So you can simply call LESS mixins and variables from the imported font-awesome.less file like so:

i {
.fa;
.fa-lg;
&:before{
content: @fa-var-github;
}
}

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

Less - Defining a class name that conflicts with mixin

This should not be a problem. This is bootstrap's placeholder mixin

// Placeholder text
.placeholder(@color: @input-color-placeholder) {
&:-moz-placeholder { color: @color; } // Firefox 4-18
&::-moz-placeholder { color: @color; // Firefox 19+
opacity: 1; } // See https://github.com/twbs/bootstrap/pull/11526
&:-ms-input-placeholder { color: @color; } // Internet Explorer 10+
&::-webkit-input-placeholder { color: @color; } // Safari and Chrome
}

This is not a mixin class, as it has parenthesis after it. Therfore it will not output anything unless it is referenced. To use this I would need to do something like this.

.input {
.placeholder;
}

Therefore this will not interfere with any .placeholder class you may have.

.placeholder {
color: red;
}

The two should happily co-exist and you should not get any problems.

Edit: see comments

The solution was to use multi class selector to overcome the issue.

Example

.input.placeholder {
color: red;
}

Reusing LESS mixin classes within optional components

As per Harry's comments we can use extend to do this, the only caveat being you must change flex-container to a class from a mixin.

Example

// This now becomes a class
.flex-container{
display: -ms-flexbox; // ie 10
display: -webkit-box; // safari 6-
display: -webkit-flexbox; // safari 6+
display: -webkit-flex;
display: flex;
}

.traffic-box{
&:extend(.flex-container);
}

.comment-box{
&:extend(.flex-container);
}

Extending a class that its name is generated in a mixin

You could do the following to extend a class that was generated in a mixin:

@mixin classGenerator {
.error {
color: red;
font-size: 9px;
}
}

@include classGenerator;

.seriousError {
@extend .error;
font-size: 20px;
}

EDIT

According to the changes in your question:

@mixin errorLevels($x){
.level-#{$x} {
font-size: #{12 + $x}px
}
}

@include errorLevels(1);

.seriousError {
@extend .level-1;
}

LESS - Interpolation - Using dynamically generated class name AS A MIXIN itself?

You can't. Not like this. The relevant line in the LESS source code is in parser.js, mixin.call- the parser of a mixin call:

e = parserInput.$re(/^[#.](?:[\w-]|\\(?:[A-Fa-f0-9]{1,6} ?|[^A-Fa-f0-9]))+/)

That is, a valid mixin call may only be named as a valid CSS .class or #id identifier. Everything else is unparseable, and doesn't even get to the variable interpolation stage.

If we relax the requirements of the solution, there is a way. Now, we want a function that takes a part of a class name, and calls a mixin with that class name. If can live with that not being totally dynamic, we can simply implement that function with a number of when clauses:

.text-align( @direction ) when (@direction=left) {
.text-left;
}
.text-align( @direction ) when (@direction=center) {
.text-center;
}
.text-align( @direction ) when (@direction=right) {
.text-right;
}

less mixin name is evaluated to colour/color

This is a legacy feature of Less. For the time being, one of the below work-around solutions could be used to overcome this color name to hex code conversion.

.completeColour(~"Orange",1);

or

.completeColour(e("Orange"),1);

Both the options explicitly tell the compiler that the value being passed is a String and not a Color and hence Less compiler would not convert it to the corresponding hex code.

Sources:

  1. Less GitHub - how to avoid color name be translated into color value?
  2. Less GitHub - Compilation of named colors results in hex values being used incorrectly in interpolations

Update: Starting from version 2.0.0, this color name to hex code conversion would not happen if the color is mentioned explicitly as a name and has no other color based operations on it. Version 2.0.0 is currently in beta mode.

(Official Update: V2 Upgrade Guide | Original Source: More consistent named color variables).

How to reuse pseudo class in less?

In Less you can not mixin pseudo classes, see also Allow for pseudo-classes to be used as mixins.

Probably you can use extend to solve your problem as already suggested by @Harry.

.cssClass:before {
content: "test";
}
.lessClass:extend(.cssClass:before){}

The preceding Less code will compile into the following CSS code:

.cssClass:before,
.lessClass {
content: "test";
}

or use: .lessClass:before:extend(.cssClass:before){} that will compile into:

.cssClass:before,
.lessClass:before {
content: "test";
}

How to pass multiple class names to a mixin in LESS

Option 1:

As you mentioned, one option is to pass the value within quotes. But when that is done, you need to make sure to remove them before using them to perform selector interpolation. This can be done by either using the ~() or the e() built-in functions. Both of them will strip out the quotes from the input value. Once this is done, the temporary variable whose value doesnt have the quotes can be used for selector interpolation like below:

.transaction-status(@class, @color) {
@className: ~"@{class}";
table#transactions > tbody > tr@{className} {
color: @color;
}

table#legend > tbody > tr > td@{className} {
color: @color;
}
}

.transaction-status(".credit", limegreen);
.transaction-status(".debit.paid", goldenrod);
.transaction-status(".debit.unpaid", crimson);

Option 2: (a bit round about in my opinion)

You can also use the ... option to pass in as many classes as required (note that this needs a small change to the order in which the inputs are passed) and then convert it to a string and use the replace function to add the .. The replace function is required because the converted string would be of the format class1 class2 (space separator).

.transaction-status(@color, @class...) {
@className: e(replace("@{class}" , " " , ".", 'g' ));
/* arguments: input string, pattern to match, replacement value, regex flags */
table#transactions > tbody > tr.@{className} {
color: @color;
}

table#legend > tbody > tr > td.@{className} {
color: @color;
}
}

.transaction-status(limegreen, credit);
.transaction-status(goldenrod, debit, paid);
.transaction-status(crimson, debit, unpaid);

Note: Option 2 would work only with Less v.1.7.0 and above because the replace function was introduced only in v1.7.0.



Related Topics



Leave a reply



Submit