How to concatenate two variables as selector in Less - css

I'm trying to do something like this
#foo: lorem;
#bar: ipsum;
.#{foo}-#{bar} {
// css-here
}
Expecting result:
.lorem-ipsum {
/** css-here
}
I only found out the Interpolation with one Variable,
.lorem-#{bar} { }

I think I just found the answer, but don't know if it's the best or the only way to do it.
I tried appending & like this
.#{foo}&-#{bar} { ... }
and it worked.

Related

SASS loop to generate chained :not() from variables string

I have a long list of classes I wish to use in a couple of ways.
The list looks something like this (but much longer):
$my-components: '.some-component', '.some-other-component', '.another-component';
One of the ways I need to use this list of class names in SASS (scss), which I can't figure out, is to create a long chained selector of :not()s. The final rendered output should look like this:
.parent {
> * {
&:last-of-type:not(.some-component):not(.some-other-component):not(.another-component):not(etc) {
// style rules
}
}
}
(The goal being to select the last child element of .parent that doesn't have one of the classes in the list).
Question: How can I make the above code DRY by using the $my-components variable?
Note 1: The loop's output needs to be able to be appended to that &:last-of-type, as in above example.
Note 2: I'm using the $my-components variable already in a different function, so I'd like to keep it in the same format if possible.
Note 3: I know this seems hacky and stupid, and that I should just give all of those elements a common shared class instead. But unfortunately I can not currently modify that part of the DOM.
Use a #each loop
scss:
$my-components: '.some-component', '.some-other-component', '.another-component';
.parent {
> * {
$selector: '';
#each $component in $my-components {
$selector: $selector + ":not(#{$component})"
}
&:last-of-type#{$selector} {
color: blue;
}
}
}
css:
.parent > *:last-of-type:not(.some-component):not(.some-other-component):not(.another-component) {
color: blue;
}
What's happening ?
I define a new string variable $selector.
During the #each loop, I'm concatening the string with :not(#{$component}) to add your new selector.

Should I use a `&` when selecting direct children using `>`?

While writing less, I noticed that the following two snippets:
A.
.parent-el {
& > .direct-child { ... }
}
B.
.parent-el {
> .direct-child { ... }
}
will produce exactly the same css:
.parent-el > .direct-child {
...
}
I have several questions:
Are there any differences between A and B?
Is this intentional and by design?
Which one should I use, and why?
Are there any differences between A and B?
There will be no difference in the compiled CSS. The & in LESS is replaced with the outer selector in compiled CSS. So, A is really the same as doing:
.parent-el {
.parent-el > .direct-child { ... }
}
This, of course, is redundant and defeats the purpose of using LESS in the first place.
Is this intentional and by design?
The & really is not used as I believe it was intended in your example. A good example of using a & in LESS would be something like this:
.parent-el {
// define .parent-el styles
&__child {
// define .parent-el__child styles
}
}
In the above example, the & allows you to shorten the declaration of .parent-el__child.
Which one should I use, and why?
You should use B. In this case, using the & is redundant and unnecessary.
the use of the "&" is optional, when you insert the selector inside another becomes implicit that the intention is to start from your "parent".
Although I get less code when we do not use "&" I prefer to use it because the code is cleaner

SCSS and direct nesting

I'm stuck on this one. I know I have an ability to reach all the way outside of the nested operators to add a prefix class like:
.myEl {
html.no-touch & {
}
}
and that will output:
html.no-touch .myEl {}
but I'm wondering if there is a way to escape by only one level, rather than all of them. Given this sort of input:
.myEl {
.myEl3 {
.myEl2 {} /* direct parent operator goes here? */
}
}
I would expect this sort of output:
.myEl1 .myEl2 .myEl3 {}
Is this possible?
Unfortunately, this is not possible in SASS. You'd probably have to do something like this if you don't want to nest further (which I'm sure you already knew).
.myEl1 {
.myEl3 {
/* Base styles here */
}
.myEl2 .myEl3 {
/* Specific styles here */
}
}

SASS Loop to output classes with unique number and background-image

I've stumbled across a situation where a SASS loop would be great. I have a load of <div>'s, each one has the a unique class that follows the pattern of .band-(number), a simplified version of my HTML would look like this...
<div class="band-1"></div>
<div class="band-2"></div>
<div class="band-3"></div>
etc.
Each of these elements has a unique background-image, but the naming convention of the image follows that of the divs themselves. My CSS needs to output this...
.band-1 {
background-image:url('../img/image_01.png');
}
.band-2 {
background-image:url('../img/image_02.png');
}
.band-3 {
background-image:url('../img/image_03.png');
}
How would I go about outputting this in a concise way? Thanks in advance.
You can solve your problem with a for loop:
#for $i from 1 through 15 {
#if $i < 10 {
.band-#{$i} {
background-image:url("../img/image_0#{$i}.png");
}
} #else {
.band-#{$i} {
background-image:url("../img/image_#{$i}.png");
}
}
}
DEMO

Concatenate String for class name in LESS

I am converting LESS to CSS, there I want to run the LESS function below:
.myPL( #val ) {
.pL #val{
padding-left:#val;
}
}
Function Call:
.myPL( 20px );
Expected result:
.pL20px{padding-left:20px}
But actual result is Syntax Error.
Please help me to concatenate the strings in class name in LESS.
What you are looking for is called selector interpolation ... you can find it here: http://lesscss.org/#-selector-interpolation
Your mixin would need to look like this for it to work:
.myPL( #val ) {
.pL#{val} {
padding-left: #val;
}
}
What you are trying to achieve does not work in LESS:
You could do:
.myPL( #val ) {
padding-left: #val;
}
Why on earth would you manually define each possible variant of padding left with the classname itself? That's not what LESS was designed for, and doesn't really make much sense with the context you've given.
The idea of mixins is to make them reusable, but I can't understand why you'd call a classname in the middle of that mixin. Use LESS mixins properly, and do the following:
.pl(#val) {
padding-left: #val;
}

Resources