LESS Preprocessing and null arguments? - less

This might be difficult to explain. Is there a way to have less not write out the #child argument without overloading the mix-in? I really don't want two mix-ins. If I use "" double quotes are outputted. I would like the LESS compiler to leave it blank.
LESS CODE
.build-on(size, #child)
{
&--1-1 #{child}
{
width: 100%;
}
&--1-2 #{child}
{
width: 50.0%;
}
&--1-3 #{child}
{
width: 33.3%;
}
&--1-4 #{child}
{
width: 25.0%;
}
&--1-5 #{child}
{
width: 20.0%;
}
}
// I might need to provide a child element
.data-table
{
.build-on(size, table);
}
// I might not
.grid
{
.build-on(size, "");
}

Pass it like so:
.yourClass
{
.build-on(size, ~'');
}
Or Better Yet...
Define a default: .build-on(size, #child: ~'') { ... } then no second is needed:
.yourClass
{
.build-on(size);
}

Related

Can't define reusable comma separated selector lists in Less

Consider the following Less code:
.a {
button,
input[type='button'],
input[type='submit'],
input[type='reset'] {
background: red;
}
}
.b {
button,
input[type='button'],
input[type='submit'],
input[type='reset'] {
background: blue;
}
}
What I'd like to be able to do is define the four possible types of buttons in a reusable way. I used to be able to do this easily in SASS, but have switched to Less in order to use Semantic UI. I can't find a syntax to do this in Less - is it possible?
Okay, I have a solution to this now, derived from this post:
#all-buttons: {
button,
input[type='button'],
input[type='reset'],
input[type='submit'] {
.get-props()
}
};
.set-props(#selectors; #rules; #extension: ~'') {
#selectors();
.get-props() {
&#{extension} { #rules(); }
}
}
.all-buttons(#rules; #extension: ~'') {
.set-props(#all-buttons; #rules; #extension);
}
.a {
.all-buttons({
background: red;
});
}
.b {
.all-buttons({
background: blue;
});
}
// Also enables an extension such as a pseudo selector for each button type
.c {
.all-buttons({
background: green;
}, ~':hover');
}

Apply class to all instances of parent selector in LESS

I've got this LESS stylesheet. The idea it to alias a lot of icon classes to my local classnames in our "namespace".
// base-icons.less
.base-icon {
display: block;
font: "myFont.otf"
}
.base-icon-foo { content: 'foo' }
.base-icon-bar { content: 'bar' }
.base-icon-fiz { content: 'fiz' }
// my-icons.less
.my-icon {
&-foo { .base-icon; .base-icon-foo; }
&-bar { .base-icon; .base-icon-bar; }
&-fiz { .base-icon; .base-icon-fiz; }
}
Is there a way to prevent having to add the .base-icon class to each single line in the my-icons.less file? I want to apply the css to all classes that start with .my-icon but it would be cleaner to not have to type the .base-icon class each time.
Learn mixins and extend. E.g. (assuming you can't modify base-icons.less):
// base-icons.less
.base-icon {
display: block;
font: "myFont.otf"
}
// my-icons.less
.i(foo);
.i(bar);
.i(baz);
.i(#name) {
.my-icon-#{name} {
&:extend(.base-icon);
content: '#{name}';
}
}
Also see stuff like In LESS, can I loop over class/mixin "patterns"?

LESS: Combine multiple CSS3 animation

I have 2 CSS animations defined in LESS:
.color_animation (#color, #time:1s)
{
#stop-1:~"#{color}_SOPRA";
#stop-2:~"#{color}_SOTTO";
#name: ~"blink-#{color}";
animation:#name #time ease-in-out infinite alternate;
.steps()
{
0% { color:##stop-1; }
50% { color:##stop-2; }
100% { color:##stop-1; }
}
#keyframes #name { .steps(); }
}
.zoom_animation (#ratio, #time:1s)
{
#zoom-ratio:round(#ratio*100);
#name: ~"zoom-#{zoom-ratio}";
animation:#name #time ease-in-out infinite alternate;
.steps()
{
0% { .scale(1.0); }
50% { .scale(#ratio); }
100% { .scale(1.0); }
}
#keyframes #name { .steps(); }
}
each one is called by a different CSS class:
.blink
{
.color_animation(red);
}
.animated-zoom
{
.zoom_animation(1.05);
}
I would like to be able to execute one of them or both in the same time, adding one or both css classes to a DOM element, for example:
<p class='blink'>Loading...</p>
<p class='animated-zoom'>Highlight</p>
<p class='blink animated-zoom'>Data not Saved!!!</p>
But in last case, second animation overrides the first one.
How to combine them in the special case in which both classes are added?
Thanks to #seven-phases-max's suggestion, I elaborated a possible solution, pipelining animations in case more than one CSS class is assigned to an element.
Here my original (now slightly modified) code, in which I move common parts in dedicated COMMONS mixins:
.color_animation (#color, #time:1s)
{
#stop-1:~"#{color}_SOPRA";
#stop-2:~"#{color}_SOTTO";
#name: ~"blink-#{color}";
.steps()
{
0% { color:##stop-1; }
100% { color:##stop-2; }
}
#value:#name #time ease-in-out infinite alternate;
.INITIALIZE_keyframes();
.CALL_animation();
}
.zoom_animation (#ratio, #time:1s)
{
#zoom-ratio:round(#ratio*100);
#name: ~"zoom-#{zoom-ratio}";
.steps()
{
0% { .scale(1.0); }
100% { .scale(#ratio); }
}
#value:#name #time ease-in-out infinite alternate;
.INITIALIZE_keyframes();
.CALL_animation();
}
Here the COMMONS mixins declaration (I'm missing browsers browsers prefix for simplicity, but they could be added here):
.INITIALIZE_keyframes()
{
#keyframes #name { .steps(); }
}
.CALL_animation()
{
animation+:#value;
}
Please, note the '+' sign in animation declaration, it's the secret of my solution, coupled with the following CSS classes declaration:
.blink
{
.color_animation(red);
}
.animated-zoom
{
.zoom_animation(1.05);
}
.blink
{
&.animated-zoom
{
.color_animation(red);
.animated-zoom;
}
}
The answer that was posted was great and helped me find my own solution to the problem. I use a generic keyframe and animation mixin to create my animations like this:
// Generic keyframe class
.keyframes(#name; #arguments) {
#-moz-keyframes #name { #arguments(); }
#-webkit-keyframes #name { #arguments(); }
#-ms-keyframes #name { #arguments(); }
#-o-keyframes #name { #arguments(); }
#keyframes #name { #arguments(); }
}
// Generic animation class
.animation(#arguments) {
-webkit-animation+: #arguments;
-moz-animation+: #arguments;
-ms-animation+: #arguments;
-o-animation+: #arguments;
animation+: #arguments;
}
Note the + in the .animation class. Then I can build animations quickly like so:
// Fade in animation
.fadeIn() {
.keyframes(fade-in; {
from { opacity: 0; }
to { opacity: 1; }
});
.animation(fade-in 1.5s);
}
// Pan animation
.pan() {
.keyframes(pan; {
from { transform: translateX(-2%); }
to { transform: translateX(2%); }
});
.animation(pan 5s infinite alternate ease-in-out);
}
Now if I want to use animations together, I can simply add them to an existing class, element, etc.:
.multipleAnimations {
.fadeIn();
.pan();
}

set parent selector as a variable

div .mymixin('red','green')
.mymixin(#a, #b){
a {
color: #a;
span {
color: #b;
}
}
}
This code will produce the following css:
div a{color:red;}
div a span{color: green;}
I need it to produce this:
div a{color:red;}
div:not(.open) a span{color: green;}
I was trying to do something like this:
div .mymixin('red','green')
#parent: &;
.mymixin(#a, #b){
a {
color: #a;
#{parent}:not(.open) span {
color: #b;
}
}
}
But it doesn't work the right way, producing
div a &:not(.open) span{color:green;}
Is there a way to assign parent to a variable or do it some other way to achieve what I am after?
Thank you.
P.S. Here is the actual nesting I have:
.icfld(#name, #width, #height, #opacity, #open) {
> a {
...
> .icon {
...
}
&.disabled > .icon {
...
}
//&:not(.open) :not(.disabled):hover... will NOT work, because & at this point refers to
//"parent" > a and makes it "parent" > a:not(.open), while I need "parent":not(.open)
//the following line, however, works
&:not(.disabled):hover {
& when (#open=false) {
...
> .icon {
...
}
}
}
}
Came up with the following work around:
.mymixin2(#a, #b, #open){
a {
color: #a;
& when(#open = false){
span {
color: #b;
}
}
}
}
.mymixin1(#a,#b){
&.open {.mymixin2(#a,#b,true);}
&:not(.open) {.mymixin2(#a,#b,false);}
}
div .mymixin1('red', 'green');
This seems to do the trick.

Strange operations behaviour with LESS

This one compiles:
.myclass {
.mymixin(2);
}
.mymixin(#parameter) {
width: ((#parameter*1)*12px);
}
This one does not:
.myclass {
.mymixin(2);
}
.mymixin(#parameter) {
width: ((#parameter-1)*12px);
}
Does anyone have a clue what's the problem with the second one?
Less treats #parameter-1 as a variable as you can tell from the compiler error:
Error line 2: variable #parameter-1 is undefined
If you insert spaces it works as expected:
.mymixin(#parameter) {
width: ((#parameter - 1)*12px);
}