How to use an & (AND selector) via a LESS function? - less

Here's what the output needs to be:
div.star_mask {
&.fill-0 {
width: 0%;
}
&.fill-50 {
width: 50%;
}
}
I'm doing this many times, so I made a function to generate it:
#star {
.star-fill(#width) {
(~"&.fill-#{width}") {
div { width: ~"#{width}%" }
}
}
}
div.star_mask {
#star > .star-fill(0)
}
This generates the following CSS:
div.star_mask &.fill-0 instead of what I need: div.star_mask.fill-0
So is there a way to do this? Can I put the & where the function is called?
I ended up fixing the problem by coding the selector myself: div.star_mask.fill-#{width} and placing the function calls one level above. It would still be very cool to nest them though!

when less comes across (~"") as a selector it does not parse the contents but accepts it verbatim, so you cannot use & in it.
I don't think there is a way to do exactly what you want at the moment, though remember you can use & at the end of a selector, e.g.
.a {
div& {
foo:bar;
}
}
becomes
div.a {
foo: bar;
}
not sure that helps though.

Related

Eliminate need for & inside less wrapper to prepend to selector without adding space

Here is my code:
.html-default-tag-color {color: #99cdff}
.html_specific-tag-colors() {
.cm-m-xml.cm-tag- {
&img {color: #909}
&table, &th, &td, &tr {color: #099}
&form {color: orange; font-weight: bold}
}
}
... Above used latter in the following mixin ...
Only interested in eliminating "&" in ABOVE
#makeImportant()
{
.HTML {
&.cm-m-xml.cm-tag {.html-default-tag-color};
.html_specific-tag-colors();
}
// important required to override usage in code outside my control
} & { #makeImportant() !important}
Must be done in less -- runs inside Dreamweaver configured less environment.

LESS: how to convert a list of called mixins to a for loop with a unique call

I crated many mixins to generate different kinds of classes for various purposes. Specifically I have to use a unique colorizer set using the standard bootstrap variable name, such as (only an example):
#type-primary: #fff;
#type-success: #f00;
#type-info: #ff0;
#type-default: #000;
#type-warning: #0f0;
#type-danger: #0ff;
Actually I created my mixins in the following form, with a "mother" as prefix to which I attached various suffixes
.text
{
&-primary { .color_text(#type-primary); }
&-success { .color_text(#type-success); }
&-info { .color_text(#type-info); }
&-default { .color_text(#type-default); }
&-warning { .color_text(#type-warning); }
&-danger { .color_text(#type-danger); }
}
After this, I can then create the final called mixin such as (so simple because it's only an example)
.color_text (#color)
{
color:#color;
}
I woud like to automate and optimize .text mixin to avoid many repeated rows, I think with a for loop. How could be possible?
Final results should be (in this case)
.text-primary {
color: #fff;
}
.text-success {
color: #f00;
}
.text-info {
color: #ff0;
}
.text-default {
color: #000;
}
.text-warning {
color: #0f0;
}
.text-danger {
color: #0ff;
}
In PSEUDO-CODE something like this could be ideal
#type-primary: #fff;
#type-success: #f00;
#type-info: #ff0;
.createContextClass("classNamePrefix",{#type-primary,#type-success,#type-info},mixinToBeCalled);
// Another call could be
.createContextClass("otherClassNamePrefix",{#type-primary,#type-success},otherMixinToBeCalled);
where, in relation to my original code, classNamePrefix should be the name of first part of final CSS class, then is passed an array with all kind of suffix that I wish in final CSS code, and mixinToBeCalled is the mixin that creates all css rules for final .text-primary, .text-success, .text-info.
For the moment, following Seven-Phases-Max' suggestion, I improved his solution in the following way

LESS Variable Interpolation

I'm trying to simplify my CSS even further than I already have with LESS by using functions and variable interpolation. I was completely unaware of variable interpolation until I took a look at Hover.css' less files which is no surprise as to why I'm screwing up now.
I'm working on Reddit to make a flair system and I am encountering problems using variable interpolation.
I am currently using the below as a test:
.flair.flair-one { color: red; }
.flair.flair-two { color: green; }
.flair.flair-three { color: blue; }
.custom(#a; #b; #c) {
&::before { .flair.flair-#{a}; }
.flair.flair-#{b};
&::after { .flair.flair-#{c}; }
}
.this-flair {
.custom(one; two; three);
}
That's the basic structure of what I'm doing. While testing in online compilers, .this-flair isn't working.
Is someone able to tell me what I can do to resolve this? I'm looking through the LESS functions and it appears as though this is the correct way to do it.
As mentioned in comments above you can't interpolate either mixin or function calls. In a quick glance, parametric mixins (with pattern matching) are what you actually need to use for such snippets:
.flair-flair(one) {color: red}
.flair-flair(two) {color: green}
.flair-flair(three) {color: blue}
.custom(#a, #b, #c) {
.flair-flair(#b);
&::before {.flair-flair(#a)}
&::after {.flair-flair(#c)}
}
.this-flair {
.custom(one, two, three);
}

How do I make a list of CSS rules in LESS based on an unknown number of input arguments?

I'd like to make a LESS mixin for translating images like so:
.translate('/images/image.png', de, en-uk);
with an output that looks like this:
background-image: url('/images/image.png');
&:lang(de){ background-image: url('/images/image_de.png') }
&:lang(en-uk){ background-image: url('/images/image_en-uk.png') }
This would be easy if we were always translating the same number of languages, but unfortunately we are not (the content is the same across certain locales). I'm not sure how to make this number variable (which would future-proof the solution).
I guess what I'm looking for is a way to loop over each element in an array I pass and return another LESS rule for each.
Any ideas?
See Variadic mixin arguments, Loops, List Functions. For example it could be implemented somewhat like:
.test {
.translate('/images/image.png', grc, lat, san);
}
.translate(#image, #langs...) {
background-image: #image;
.-(length(#langs));
.-(#i) when (#i > 0) {
.-((#i - 1));
#lang: extract(#langs, #i);
&:lang(#{lang}) {
background-image: replace(#image, "\.", "_#{lang}.");
}
}
}
replace function requires Less 1.7.0 but for earlier versions you can use plain string interpolation/concatenation or format function as in #helderdarocha answer.
(Also note that the #langs... mixin parameter above can also accept the language list as a single variable), e.g.:
#languages: de, fr, es, ru, en-uk; // in fact commas here are optional too
.test {
.translate('/images/image.png', #languages);
}
And just in case, the same mixin using for wrapper (just to show that Less loops don't have to be that scary :):
#import "for";
.translate(#image, #langs...) {
background-image: #image;
.for(#langs); .-each(#lang) {
&:lang(#{lang}) {
background-image: replace(#image, "\.", "_#{lang}.");
}
}
}
This mixin uses target languages from a variable. It will loop through them and generate the code you want for each one:
.image-replace(#languages; #image-prefix) {
#count: length(#languages);
.loop(#count; #image-prefix);
.loop(#count; #image-prefix) when (#count > 0) {
.loop(#count - 1; #image-prefix);
#lang: extract(#languages, #count);
#image: %('%a_%a.png', #image-prefix, #lang);
&:lang(#{lang}){
background-image: url(#image);
}
}
}
To use it:
#languages: ~'de', ~'fr', ~'es', ~'ru', ~'en-UK', ~'pt-BR';
.section {
.image-replace(#languages; ~'/images/image');
}
Result:
.section:lang(de) {
background-image: url('/images/image_de.png');
}
.section:lang(fr) {
background-image: url('/images/image_fr.png');
}
.section:lang(es) {
background-image: url('/images/image_es.png');
}
.section:lang(ru) {
background-image: url('/images/image_ru.png');
}
.section:lang(en-UK) {
background-image: url('/images/image_en-UK.png');
}

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.