I have a SCSS mixin like so:
#for $i from 2 through 4 {
&__layout:nth-child(#{$i}) {
transition: transform 0.4s ease #{$i}s;
}
}
How can I subtract something from #{$1}s? For example, this works:
transition: transform 0.4s ease #{$i+1}s; // <-- adds 1 to value as expected
But this gives an error:
transition: transform 0.4s ease #{$i-1}s; // Undefined variable: "$i-1".
So I assume this is because variables can have dashes in them? So how do I escape the minus sign so I can subtract from the variable?
yes just give the space it works
#for $i from 2 through 4 {
&__layout:nth-child(#{$i}) {
transition: transform 0.4s ease #{$i - 1}s;
}
}
Hope this helps
Related
:) First of all - sory for my English. Second of all - I have an issue or puzzle.
I want to make animation spans with relation time between them. There is the simple code:
span.one { transition: transform 1s ease-out; } /*duration 1s delay 0s*/
span.two { transition: transform 1s ease-out 1s; } /*duration 1s delay 1s*/
span.three { transition: transform 1s ease-out 2s; } /*duration 1s delay 2s*/
So each span appear one by one and it's look ok. Every next element is animated in delay of value duration (let's get name 'time-op'). So if I change values from second to my class 'time-op' it will be like:
span.one { transition: transform time-op ease-out time-op*0; }
span.two { transition: transform time-op ease-out time-op*1; }
span.three { transition: transform time-op ease-out time-op*2; }
If I root my 'time-op' by :root at the beginning of my file, can I multiply this value as I described it above? For example:
span.three { transition: transform var(--time-op) ease-out var(--time-op)*2; }
I know this is available in JavaScript, but maybe there is a way in ONLY CSS :)
Use calc() function in CSS:
span.one { transition: transform time-op ease-out calc(time-op * 0) }
I have a multiple transition problem with scss #mixin.
Im trying to create dynamic transition #mixin with 1-5 different properties. When I'm processing the code below this error shows up:
Error: Mixin transition takes 1 argument but 3 were passed.
on line 758 of style.scss, in `transition'
from line 758 of style.scss Use --trace for backtrace.
This is my code:
#mixin:
#mixin transition($x){
transition: $x;
-webkit-transition: $x;
-moz-transition: $x;
-ms-transition: $x;
-o-transition: $x;
}
#include:
#include transition(visibility 0s ease 0.2s, opacity 0.2s ease, transform 0.3s ease);
I figured it out with this hack but it looks like a very unclean solution to me:
#include transition(visibility 0s ease 0.2s + "," + opacity 0.2s ease + "," + transform 0.3s ease);
Is there a better way to do it?
In your mixin, you have declared a single variable $x as a parameter which means that sass expects the mixin to be called with one argument.
#include transition(visibility 0s ease 0.2s)
When you pass the mixin comma separated values, it causes an error because sass sees these as multiple values instead of a single value which it expects.
#include transition(visibility 0s ease 0.2s, opacity 0.2s ease) //Sees two args instead of one arg
In Sass, comma separated values can be interpreted as a single value if declared as varargs. Varargs are mixin or function parameters declared with 3 dots appended to their name.
Replacing your $x parameter with $x... will ensure that sass interprets the comma separated arguments passed to your mixin as one value.
#mixin transition($x...){
-webkit-transition: $x;
-moz-transition: $x;
-ms-transition: $x;
-o-transition: $x;
transition: $x;
}
It can then be used like this
div {
#include transition(color 1s, background-color 1s, border-color 1s);
}
which compiles to
div {
-webkit-transition: color 1s, background-color 1s, border-color 1s;
-moz-transition: color 1s, background-color 1s, border-color 1s;
-ms-transition: color 1s, background-color 1s, border-color 1s;
-o-transition: color 1s, background-color 1s, border-color 1s;
transition: color 1s, background-color 1s, border-color 1s;
}
By doing this you can pass the values as you normally would in CSS without the hack you are currently using making it much cleaner.
Hope this helps
Since this is the first result on Google, I want to say that this does not solve my problem. I wanted to transition multiple properties, with only one mixin. I came up with this solution: (see link for helper functions)
/*
usage: #include transition(prop1, prop2, ..., 0.5s cubic-bezier(0.16, 0.85, 0.45, 1));
*/
#mixin transition($args...) {
$type: nth($args, length($args));
$props: remove-nth($args, length($args));
$result: ();
#for $i from 1 through length($props) {
$prop: nth($props, $i);
$result: append($result, $prop);
$result: append($result, $type);
#if $i != length($props) {
$result: append($result, unquote($string: ","));
}
}
#include simple_transition($result);
}
I created a short mixin that allows adding multiple transition properties in one declaration. In case number of arguments provided for the timing, easing or delay, is less than number of transition properties, the arguments are repeated.
#mixin transition($prop, $time, $easing: $ease1, $delay: 0s) {
$transition: ();
#for $i from 1 through length($prop) {
#for $j from 0 to (length($prop)) - (length($time)) {
$time: join($time, nth($time, -1));
}
#for $j from 0 to (length($prop)) - (length($easing)) {
$easing: join($easing, nth($easing, -1));
}
#for $j from 0 to (length($prop)) - (length($delay)) {
$delay: join($delay, nth($delay, -1));
}
$transition: append(
$transition,
(nth($prop, $i) nth($time, $i) nth($easing, $i) nth($delay, $i)),
$separator: comma
);
}
transition: $transition;
}
//scss input:
#include transition(height width transform, 0.2s 0.3s, linear, 0s);
//css output:
transition: height 0.2s linear 0s, width 0.3s linear 0s, transform 0.3s linear 0s;
Where time and easing are the same, but with multiple properties:
#mixin transitionPrefixMultiple($time, $properties...) {
$transition: ();
#each $property in $properties {
$transition: append(
$transition, ($property $time cubic-bezier(.42, 0, .58, 1)), $separator: comma
);
}
-webkit-transition: $transition;
-moz-transition: $transition;
-ms-transition: $transition;
-o-transition: $transition;
transition: $transition;
}
Usage:
#include transitionPrefixMultiple(150ms, width, background-color, etc);
Thank you #nidhishs06 as this is a cleaner version of your answer
I have the following mixin:
.transition (#property, #duration: 0.2s) {
-webkit-transition: #property #duration ease-in-out;
-moz-transition: #property #duration ease-in-out;
-ms-transition: #property #duration ease-in-out;
-o-transition: #property #duration ease-in-out;
transition: #property #duration ease-in-out;
}
How can I change the mixin to allow multiple properties (i.e. background and color transition)?
There a lot of similar Q&A here at SO already (for instance) but since most of those are full of really outdated (mis)information and hacks it would make sense to write a new answer I guess:
-
Well, you need to decide if you want the mixin to detect each property value as an individual argument (with optional default value) or just pass them all together (these are sort of incompatible requirements, it's still possible to combine them though - see later).
In the simplest case the mixin should be defined just as:
.transition(#values) {
transition: #values;
}
Nothing more than that, and used like this:
.transition(width);
.transition(color 0.2s ease-in-out);
.transition(opacity 2s ease-in, height 5s ease-out;);
// etc.
See the documetation about using comma separated list as mixin arguments.
-
Now about single values as individual mixin parameters and default options. (Honestly for me this tendency to blindly put some pretty random default value for every singe parameter of every singe mixin looks like a common anti-pattern but either way). As you may notice the above mixin definition does not let you to specify a default value for individual parameters.
Obviously if you define your mixin as:
.transition(#property, #duration: 0.2s, #timing: ease-in-out) {
transition: #arguments;
}
(or similar) it cannot handle multiple properties anymore (#duration and #timing won't match corresponding arguments no matter what syntax you use to call it (with just a few specific exceptions). E.g.
.transition(opacity 2s ease-in, height 5s ease-out;);
would result in
transition: opacity 2s ease-in, height 5s ease-out 0.2s ease-in-out;
etc. which does not make any sense)
So if you still need both (yet again not counting this often makes such mixin usage uncertain and confusing) you have to invent some way to handle both variants somehow. For instance the simplest method (just one of literally zillion possible variants) would be just to provide different definitions for different number of values in the first argument (see conditional mixins), e.g.:
.transition(#property, #duration: 0.2s, #timing: ease-out)
when (length(#property) = 1) {
transition: #arguments;
}
.transition(...) when (default()) {
transition: #arguments;
}
With usage being the same as above except .transition(width); (and similar stuff) now has different result.
-
And as always, regardless of all above if it's only about writing vendor-prefixing mixins (and I guess it is) - just stop doing that.
This ought to work:
.transition (#property; #duration: 0.2s) {
-webkit-transition-property: #property;
-moz-transition-property: #property;
-o-transition-property: #property;
transition-property: #property;
-webkit-transition-duration: #duration;
-moz-transition-duration: #duration;
-o-transition-duration: #duration;
transition-duration: #duration;
-webkit-timing-function: ease-in-out;
-moz-timing-function: ease-in-out;
-o-timing-function: ease-in-out;
timing-function: ease-in-out;
}
.test {
.transition(color, background; 3s)
}
The biggest trick here is using a semicolon as a delimiter for the mixin, so that we can use the comma as delimiter for the transition-property. Also, you don't need the -ms- prefix, IE never had it for transitions.
Why not like this?
Mixin:
.transition(#transition) {
-webkit-transition: #transition;
-o-transition: #transition;
transition: #transition;
}
and use it:
for example: .transition(~"color ease-in-out 1s, background-color ease-in .5s");
Hope it helps
So, I've been messing around with creating a bit of code in CSS that is a list of animations set for one element. It's basically just a loop, but I need to be able to change the timing of each time it goes off. Basically, I'd like something as simple as this:
$intro-duration:1s;
$intro-delay:6.5s;
$intro-separation:0.7s;
$intro-style:ease;
#mixin intro($multiplier) {
-webkit-animation:intro $intro-duration $intro-separation*$multiplier+$intro-delay $intro-style;
}
.intro {
#include intro(-1);
#include intro(0);
#include intro(1);
#include intro(2);
#include intro(3);
}
But having that, it comes out like:
.intro {
-webkit-animation: intro 1s 5.8s ease;
-webkit-animation: intro 1s 6.5s ease;
-webkit-animation: intro 1s 7.2s ease;
-webkit-animation: intro 1s 7.9s ease;
-webkit-animation: intro 1s 8.6s ease;
}
Which would be all fine and dandy, but I obviously need to be able to leave off the "-webkit-animation" as well as the semi-colon in place of a commas, in order to properly combine the string of animation. So it needs to be this:
.intro {
-webkit-animation:
intro 1s 5.8s ease,
intro 1s 6.5s ease,
intro 1s 7.2s ease,
intro 1s 7.9s ease,
intro 1s 8.6s ease; }
I totally feel like I'm really just over complicating it and feel that if I were to simply step away from it for a few hours, I'd come up with the solution, but I've tried a few different things and am coming up short. Any help to simplify this code would be much appreciated!
EDIT: Removed a few lines of the repeating code to try and keep it simple.
You need to create a list:
#mixin intro($multiplier...) {
$collector: ();
#each $i in $multiplier {
$collector: append($collector, intro $intro-duration $intro-separation* $i+ $intro-delay $intro-style, comma);
}
animation: $collector;
}
.intro {
#include intro(-1, 0, 1, 2, 3);
}
Alternately:
#mixin intro($start, $end) {
$collector: ();
#for $i from $start through $end {
$collector: append($collector, intro $intro-duration $intro-separation* $i+ $intro-delay $intro-style, comma);
}
animation: $collector;
}
.intro {
#include intro(-1, 3);
}
And make sure you're providing all prefixes (as appropriate) + non-prefixed properties, not just webkit prefixes.
I currently have -webkit specific attributes in my Less CSS sheet, I am trying to update them with mixins to add -moz attributes, like this:
.transition(#1) {
-webkit-transition: #1;
-moz-transition: #1;
}
div {
.transition(all .5s);
}
The example above works fine, however I also have things like that:
div {
-webkit-transition: border-color .3s, background .3s;
}
And I can’t call the mixin as .transition(border-color .3s, background .3s) because it has more arguments than defined in the mixin. So what I am doing at the moment is this:
.transition(#1) {
-webkit-transition: #1;
-moz-transition: #1;
}
.transition-2(#1, #2) {
-webkit-transition: #1, #2;
-moz-transition: #1, #2;
}
div {
.transition-2(border-color .3s, background .3s);
}
This is annoying, I need to add redundant code in my sheet any time I’m using a number of arguments not previously used before; and I have this problem with others CSS3 properties too, for example box-shadow when I need to add inset at the beginning.
Is there any way to declare mixins flexible in their number of arguments with Less, just like CSS3 properties are?
For this case, the redundant mixin code can be avoided using any one of the below mentioned options.
Option 1: (Simplest solution - thanks to seven-phases-max for highlighting the miss)
We can use semi-colon as a separator/delimiter for arguments and when we add a semi-colon at the end after specifying all properties that need to be transitioned (in a comma separated format), the whole part before it would be considered as one single argument.
Extract from the official Less website:
Using comma as mixin separator makes it impossible to create comma separated lists as an argument. On the other hand, if the compiler sees at least one semicolon inside mixin call or declaration, it assumes that arguments are separated by semicolons and all commas belong to css lists
.transition(#1) {
-webkit-transition: #1;
-moz-transition: #1;
}
div{
.transition(border-color .5s, background .3s, color .3s;);
}
So the above code when compiled would result in
div {
-webkit-transition: border-color 0.5s, background 0.3s, color 0.3s;
-moz-transition: border-color 0.5s, background 0.3s, color 0.3s;
}
Option 2:
Pass the input values to the mixin (how many ever specific properties need to be transitioned) within quotes. Within the mixin, use the ~ or the e() in-built functions to strip the quotes.
.transition(#1) {
-webkit-transition: ~"#{1}";
-moz-transition: ~"#{1}";
}
div {
.transition("border-color .5s, background .3s");
}
div#sample2 {
.transition("border-color .3s, background .3s, color .3s");
}
will produce the below CSS when compiled
div {
-webkit-transition: border-color .5s, background .3s;
-moz-transition: border-color .5s, background .3s;
}
div#sample2 {
-webkit-transition: border-color .3s, background .3s, color .3s;
-moz-transition: border-color .3s, background .3s, color .3s;
}
Option 3:
Less does allow creation of mixins which allow/accept variable number of inputs using the ... option. Hence you can use the same mixin as in your original code by adding the ... to the input variable and calling it as you had originally wanted.
.transition(#args...) {
-webkit-transition: #args;
-moz-transition: #args;
}
div {
.transition(border-color .5s, background .3s);
}
The above will compile successfully but the only problem is that it would produce the below output when compiled. As you can see, the problem is that the parameter values are space separated and not comma separated (as they should be for the CSS to work properly).
div {
-webkit-transition: border-color 0.5s background 0.3s;
-moz-transition: border-color 0.5s background 0.3s;
}
Ofcourse we could write complex replace functions using regular expressions but that would really make the code messy. Instead we could use loops and some built-in functions to achieve the required output (like shown below).
.transition(#args...) {
.loop-args(#argCount) when (#argCount > 0) {
.loop-args(#argCount - 1);
#arg: extract(#args, #argCount);
-webkit-transition+: #arg;
-moz-transition+: #arg;
}
.loop-args(length(#args));
}
div {
.transition(border-color .5s, background .3s, color .3s);
}
Basically what we are doing is use the ... to accept multiple arguments as input to the mixin and then loop over each argument and add it to the CSS property's value. The +: (merge function introduced in Less v1.5.0) is used to produce the comma separated output.
When compiled, it would produce the below output:
div {
-webkit-transition: border-color 0.5s, background 0.3s, color 0.3s;
-moz-transition: border-color 0.5s, background 0.3s, color 0.3s;
}
You could try
.transition(#1) {
-webkit-transition: #1;
-moz-transition: #1;
}
.transition-2(#1, #2) {
.transition(#1); // this includes all the stuff from transition(#1)
color:red; // additional stuff
}
As for your actual question, I dont believe that LESS itself has any sort of "rest" style arguments passing.