LESS: Combine multiple CSS3 animation - less

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

Related

Less CSS responsive modifier

I'm trying to create a utility-first collection of CSS classes, similar to Tailwind but in Less. A big part of this is using responsive modifiers, using this className syntax: .large\:text-white.
The code below works great, except for one thing: the \: shouldn't be rendered on the default classes (the classes outside of the media queries. They should render using a period, as expected .foo.
I can't figure out how to solve this.
#screens: {
small: 320px;
medium: 768px;
large: 1024px;
}
#padding: {
0: 0;
10: 1rem;
20: 20rem;
30: 30rem;
}
#colors: {
white: #fff;
silver: hsla(0, 0%, 90%, 1);
}
#responsive-modifiers: true;
#config () {
.generate(pt, padding, #padding);
.generate(py, padding-top, #padding);
.generate(text, color, #colors);
.generate(background, background-color, #colors);
}
// Call the mixin
#config();
each(#screens, {
#media (min-width : #value) {
.#{key} when (#responsive-modifiers = true) {
#config();
}
}
})
.generate(#prefix, #property, #list) {
each(#list, {
&\:#{prefix}-#{key} {
#{property}: #value;
}
});
}
I solved it by adding a period/dot variable. Here's the final code. Works well:
#screens: {
small: 320px;
medium: 768px;
large: 1024px;
}
#padding: {
0: 0;
10: 1rem;
20: 20rem;
30: 30rem;
}
#colors: {
white: #fff;
silver: hsla(0, 0%, 90%, 1);
}
#responsive-modifiers: true;
#config () {
.generate(pt, padding, #padding);
.generate(py, padding-top, #padding);
.generate(text, color, #colors);
.generate(background, background-color, #colors);
}
#period: .;
#{period} {
#config();
}
each(#screens, {
#media (min-width : #value) {
.#{key}&\: when (#responsive-modifiers = true) {
#config();
}
}
})
.generate(#prefix, #property, #list) {
each(#list, {
&#{prefix}-#{key} {
#{property}: #value;
}
});
}

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 - use nth-child variable in string

Surely there's a way to rewrite the following in LESS?
#bg-slider{
li:nth-child(1){
background:url('../images/bg1.jpg');
}
li:nth-child(2){
background:url('../images/bg2.jpg');
}
li:nth-child(3){
background:url('../images/bg3.jpg');
}
}
I've tried:
.bg-image (#slide) {
background:url('../images/bg#{slide}.jpg');
}
#bg-slider{
li:nth-child(n){
.bg-image(n);
}
}
But that just gives '../images/bgn.jpg' for all li's.
#bg-slider {
li {
.bkg(1);
.bkg(2);
.bkg(3);
}
.bkg(#i) {
&:nth-child(#{i}) {
background: url('../images/bg#{i}.jpg');
}
}
}

LESS Preprocessing and null arguments?

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