Dynamic prefixed keyframe generation with LESS CSS - css

I'm currently trying to find a way to generate prefixed keyframes with Less.
This is the loop that generates the prefixed versions, and it works. The only problem is when I add a from{} to{} declaration inside the dostuff animation it breaks it and causes Less to treat them like a mixin.
Is there any way to get this to work?
#key-prefix: ~"#-webkit-",~"#-o-",~"#-moz-",~"#";
.generate-keyframes(#i) when (#i > 0) {
.load1-keyframes((#i - 1));
#prefix: extract(#key-prefix,#i);
#{prefix}keyframes dostuff {
}
}
.generate-keyframes(4);

In short, no, an interpolation of the at-rule directive identifiers is not supported (and is not planned to be).
Well, you can get what you want with something like:
.vendorize-keyframes(dostuff, {
0% {color: tomato}
to {color: potato}
});
.vendorize-keyframes(#name, #frames) {
#-webkit-keyframes #name {#frames();}
#-moz-keyframes #name {#frames();}
#-o-keyframes #name {#frames();}
#keyframes #name {#frames();}
}
But in general the recommendation is to consider to use a tool like autoprefixer and stop polluting your Less and/or CSS code with these hardcoded vendor prefixes.

Related

Transform properties/variables clashing in sass and overwriting eachother

I have the code at the bottom of the page in my sass. In my html I am targeting it as follows
class=" transform rotate-5 zoom-2 ......"
the problem is that the transform properties are clashing and aren't applying scale and rotate to the same div tag, I'm either getting one or the other.
I thought I could change this by using the #extend property and something like,
&.rotate-#{$i}
{#extend &.skew-#{$i}, &.zoom-#{$i}, &.zoom--#{$i};
transform: rotate($rotate#{deg});
}
but so far I've had no luck, if anyone can help it'd be greatly appreciated.
.transform {
overflow:hidden;
#for $i from 1 through 360 {
$rotate: $i;
$skew: $i;
$zoom: $i;
&.rotate-#{$i} {
transform: rotate($rotate#{deg});
}
&.skew-#{$i} {
transform: skew($skew#{deg});
}
&.zoom-#{$i} {
transform: scale($zoom,0);
}
&.zoom--#{$i} {
transform: scale(-$zoom,0);
}
}
}
I'm a big fan of utility classes that I thought easier to debug and to build with. But here it doesn't seem to be a good idea:
1) You are creating 360 * 4 selectors, yet you will probably only use 10-20 of them. It is a bit overkill.
2) As you describe it, the transform property values do not "combine" well, at least for what you are looking for. Even atomic CSS, which pushes very far the utility classes approach, specificies that combining different values of filter (for instance) needs creating a custom value / class.
I understand that it is not really a good answer, at least not the answer you were looking for, but if you want to keep your CSS only approach, I suggest you adopt a more "object-oriented" method for this issue and set your transform property directly in the css of your object, for instance with this mixin:
#mixin transform($rotate, $skew, $zoom) {
transform: rotate($rotate#{deg}) skew($skew#{deg}) scale($zoom,0) scale(-$zoom,0);
}

keyframes mixin in LESS

I've been lurking around for a mixin that would create prefixed keyframes declarations, but i couldn't find anything that actually work as it should without ugly fixes.
So far i've managed to create the following mixin:
.keyframes(#identifier, #animation) {
.frames { content: ~"'';} #-webkit-keyframes #{identifier} {#{animation}} #-moz-keyframes #{identifier} {#{animation}} #-ms-keyframes #{identifier} {#{animation}} #-o-keyframes #{identifier} {#{animation}} #keyframes #{identifier} {#{animation}"}
}
Where the usage would be:
.keyframes(fade-in, ~"0% { opacity: 0; }50% { opacity: 0; }100% { opacity: 1; }");
I feel like this is just plain wrong in matters of readability and also it creates a rule ( .frames { content: '' }; ) for each time the .keyframes() mixin is called.
Is there another way of doing this nicely?
Sidenote:
When i type npm info less --version it returns 1.4.28 if that's important.
#seven-phases-max had some really helpful comments regarding this. The fix ended up being to use a post compile processing for css (https://github.com/postcss/autoprefixer), which also helped me/the teams i am currently working with with other tasks as well.
For details, please refer to comments in the question.

Why are placeholder selectors inside #keyframes valid .scss?

I've been using parameterless mixins for pure CSS animations so that my classes and my keyframes don't contain a bunch of repetitive styles, something similar to the following:
//css classes excluded for brevity, compile as expected
#mixin btn() {
color: black;
}
#mixin btn-hover() {
color: white;
}
#keyframes hover {
from {
#include btn();
}
to {
#include btn-hover();
}
}
Recently I converted those mixins to placeholder selectors like so:
//css classes excluded for brevity, compile as expected
%btn {
color: black;
}
%btn-hover {
color: white;
}
#keyframes hover {
from {
extend %btn;
}
to {
extend %btn-hover;
}
}
That didn't work, and in retrospect it's perfectly clear why not. What confuses me is why this compiles in the first place. The resulting CSS is valid #keyframes block that's completely empty:
#keyframes hover {
}
Assuming my understanding of how the extend concept works in Sass is correct and complete, using placeholder selectors in this manner makes no sense. Why is this valid syntax to begin with? Why don't I get a compile error?
It isn't considered valid and it should raise an error.
Error from Sass 3.3:
You may not #extend an outer selector from within #keyframes.
You may only #extend selectors within the same directive.
From "#extend %btn" on line 11.
Error from Sass 3.4:
Extend directives may only be used within rules.
If you are using Sass 3.2 or older, you should upgrade. If you're using LibSass, there's not much you can do about it other than report the issue on their bug tracker if it isn't already there.

Compass $default-animation-duration not being used?

I recently updated to Compass version 1.0.16 and am setting up basic use of the new animation stuff. For some reason, when I try to set the default values for different animation settings, they don't take effect, requiring that I hard-code the values throughout my app.
Specifically:
$default-animation-duration: 0.5s;
#import "compass/css3";
#include keyframes(slideOutLeft) {
0% {
#include transform(translateX(0%));
}
100% {
#include transform(translateX(-100%));
}
}
#id {
#include animation(slideOutLeft); // Doesn't work
}
#id2 {
#include animation(slideOutLeft 0.5s); // Does work.
}
Any thoughts?
Official word from the Compass folks can be found here: https://github.com/chriseppstein/compass/issues/1556
Yeah, currently the defaults are only used in the long-form properties
e.g. animation-duration(), or in when no arguments other are passed
e.g. animation() (where all the defaults are used). Not sure that's
the best way, but the defaults are pretty invasive otherwise.

webkit animation not working, # before # in css

The site where I want my animation to work adds #user-space before any of my tags. So, my animation looks like this:
#user-space #-webkit-keyframes animation-name {
from {
style definition ["Before"-state]
}
to {
style definition ["After"-state]
}
And that #user-space declaration is breaking the css statement and animation is not working. Is there any way, to do that otherwise? For exaple put my keyframes insine -webkit-animation: animation-name 1.1s ease infinite; like
webkit-animation: from {
style definition ["Before"-state]
}
to {
style definition ["After"-state]
} 1.1s ease infinite; like
The solution I see is to get around your problem and do it with javascript.
Simply add a new style in your html file (in the header) and add the #-webkit-keyframes animation inside.
There is a thread which explains it well (see accepted solution): Set the webkit-keyframes from/to parameter with JavaScript

Resources