Use a mixin named parameter in LESS as a pseudo selector - less

My idea here is to create a LESS mixin that could add a pseudo element :before or :after to any element in my page.
I have tried to use the "Named parameter" of LESS mixins to create a generic mixin in which the user could specify whether the pseudo element should be a :before or an :after.
When I compile, I get an error: "Unrecognized input".
Here is my code:
.setInlineIcon(#iconx: 0; #icony: 0; #pos: before; #margin: 0; #margindir: right) {
&:#{pos} {
.setStructure(#h: 16px; #w: 16px; #d: inline-block; #va: middle);
.getIcon(#iconx; #icony);
content:"";
margin-#{margindir}: #margin;
}
}
Where .setStrucutreand .getIcon are two already existing and functioning mixins. Can you spot what's wrong?
Is it because I cannot use a variable as a selector in this way?

: alone is not recognized as valid selector identifier. The workaround is to concatenate it to the identifier before selector interpolation:
.mixin(#pos) {
#name: ~':#{pos}';
&#{name} {
/* ... */
}
}
usage {
.mixin(before);
}

Related

Can whole declaration be stored as #variable value in Less?

All my Less variables are editable within a CMS-module and are assigned to the Less compiler. It works, if I only use the values like color, font-size, etc.:
body {
background-color: #bgColor;
}
I've created another field for custom Less, which I would like to add at the end of my Less file, like:
body {
background-color: #bgColor;
}
#customLess /* desired OUTPUT: body { color: white; }*/
Unfortunately this leads to an ParseError.
I'd like to avoid to merge the existing Less and custom Less. I'm not looking for mixins, I guess.
Is it possible to put whole declarations in a #variable?
It is very much possible to put whole declarations (including the selector, property + value pair) inside a variable. Those are called as detached rulesets.
While calling them, braces (()) must be added. If not, the call will fail and result in compilation error. Below is an extract from the official website.
Parentheses after a detached ruleset call are mandatory. The call #detached-ruleset; would NOT work.
#customLess: {
body{
color: white;
}
};
#bgColor: red;
body {
background-color: #bgColor;
}
#customLess();

Overriding mixins in LESS

when defining a mixin multiple times in LESS, and later calling that mixin as follows
.background-color() {
background: red;
}
.background-color() {
background: yellow;
}
body {
.background-color;
}
the result will be a combined output from all the defined mixins
body {
background: red; // << output from mixin #1
background: yellow; // << output from mixin #2
}
while when you apply the same scenario in both Sass & Stylus ( using their own syntax of course ), when you call a mixin that is defined multiple times across your stylesheets, Only the last defined one will be executed ( it will override all previously defined mixins ) as follows.
result Sass and Stylus
body {
background: yellow; // << output from mixin #2
}
how can I override a mixin in LESS so that the output will be from the last defined mixin ?
You can not override them, alternatively use a variable to define the 'background-color'. For Less variables the last declared win.
Also read Pattern-matching
In Less all matching mixins are compiled in the source. You can use namespace to prevent name collisions, for instance:
#ns1 {
.background-color() {
background: red;
}
}
#ns2 {
.background-color() {
background: yellow;
}
}
than you can use:
body {
#ns2 > .background-color;
}
Double properties are also not removed to make some browser hacks possible, example:
#myElement {
width: 300px;
width: 500px\9;
}
To find a solution for your use case you should reformulate your question and explain why you have these same named mixins in the first place.

Less mixin variable call mixin

I have this very simple example as you can see:
.large{
color: blue;
}
.a(#va){
.large;
~".#{va}()";
}
a{
.a(large)
}
I keep trying to get the .large() or .large; to work by calling the .large mixin. I keep getting error:
Parse error: Unrecognised input
.large; ~".#{va}()";}
How can I fix this?
You can't call a mixin by its name stored in a variable. You can achieve the goal by wrapping mixin call into "detached ruleset" though, e.g.:
.large {
color: blue;
}
.a(#va) {
#va();
}
a {
.a({.large})
}
There're other methods of doing similar things (might be more useful/suitable depending on a use-case).

How can I target an element within a class using less?

I would like to target specific elements within a class using less.
In this case, I would like to target elements of class button, but within that I would like to target an anchor tag a.
Currently I have:
.button {
/* lots of bits and pieces go here, hence
the need to keep it at a class level
*/
/* further down, but still in .button */
/* Attempt 1 - fails: compiled = a .button (note the space)
a& {
height:20px;
}
/* Attempt 2 - fails: compiled = .buttona
&a {
height:20px;
}
}
I basically want it to compile to:
a.button
This is so I can create elements such as:
<a class="button">
<button class="button">
But slightly alter it when its an anchor. I don't want to throw in the it's a bug in less! card too early, but if I use &.another-class it works as expected (compiled: .button.another-class, but not when targeting elements
You're using an old version of less. The code below generates the correct CSS using less 1.3.3
.button {
a& {
height:20px;
}
}
generates:
a.button {
height: 20px;
}
#Allen Bargi answer is correct, yet only for this specific scenario. I am a little confuse about what you want to achive.
As #Allen Bargi pointed out, this will target "a" lements with a "button" class and generates a
.button {
a& {
height:20px;
}
}
It generates:
a.button {
height: 20px;
}
Meanwhile, this below will target "a" elements contained whitin an element with a "button" class. which seems to me was your original objective.
.button {
a {
height:20px;
}
}
It generates:
.button a {
height:20px;
}
Both solutions migt work fine in this case because you are using the same "button" class for both the parent and the child elements, but they are not targeting the same elements.
I hope this helps.

Reusing LESS nested styles

Let's say that I have a style defined using Less:
ul.unstyled,
ol.unstyled {
margin-left: 0;
list-style: none;
}
Later on, I want to re-use the unstyled class:
.my-list {
.unstyled;
}
This doesn't work, however, and I can't figure out the magic to make it work. Any thoughts?
You can't re-use arbitrary class definitions, only mixins (those starting with a dot). In this case you'll need to duplicate it.
Try this:
.unstyled {
margin-left: 0;
list-style: none;
}
.my-list {
.unstyled;
}
You won't be able to nest .unstyled if it's defined as ul.unstled and ol.unstyled.
Since you can't reuse .unstyled when it's a nested style and you probably don't want to edit the Bootstrap source code, I'd suggest you just assign both classnames to your list:
<ul class="unstyled my-list" />