I have 2 sass mixins that I would like to combine, 1 being for transitons and the other to handle vendor prefixes, so basically I want to transition the translateY value of an element so want to do something like the following:
#include transition( #include vendor(transform, .3s ease-in-out) );
Mixins
#mixin vendor($property, $value...){
-webkit-#{$property}:$value;
-moz-#{$property}:$value;
-ms-#{$property}:$value;
-o-#{$property}:$value;
#{$property}:$value;
}
#mixin transition($args...) {
-webkit-transition: $args;
-moz-transition: $args;
-ms-transition: $args;
transition: $args;
}
If anyone could advise how I actually do this or if there is a much better way that would be great. I don't need to use compass in case anyone suggests that.
With Compass
Compass is definitely the way to go about vendor prefixes. Then all you need to do is something like:
#import "compass";
test {
#include transition( transform 0.3s ease-in-out );
}
and the output will look like:
test {
-webkit-transition: -webkit-transform 0.3s ease-in-out;
-moz-transition: -moz-transform 0.3s ease-in-out;
-o-transition: -o-transform 0.3s ease-in-out;
transition: transform 0.3s ease-in-out;
}
DEMO
Own vendor mixins and functions (no Compass)
If for some reason you wouldn't use compass you can try making your vendor mixin a bit more exciting and add some functions (to check if an argument needs to be prefixed). Maybe something along these lines:
// loops through all arguments and prefixes the ones that need it (in this case only transform)
#function vendor-args($arg, $vendor) {
$result: ();
#each $i in $arg {
#if $i == transform { $result: append($result, #{$vendor}$i); }
#else { $result: append($result, $i); }
}
#return $result;
}
// general vendor mixin
#mixin vendor($property, $args...){
#each $vendor in ('-webkit-', '-moz-', '-ms-', '-o-', '') {
$out: null;
#each $arg in nth($args,1) {
$out: ($out, vendor-args($arg, $vendor));
}
#{$vendor}#{$property}: $out;
}
}
// general transition mixin
#mixin transition($args...) {
#include vendor(transition, $args);
}
// test
test {
#include transition( transform .3s ease-in-out, color .2s linear );
}
DEMO
Or if you want to check against a list of properties that need prefixing and not just transform, you can add another tiny function:
#function needs-vendor($p){
$l: transform, another-property-you-want-prefixed, and-another;
#each $i in $l {
#if $i == $p { #return terue; }
}
#return false;
}
and then use needs-vendor($i) instead of $i == transform.
Another thing is ... you don't really need to prefix transitions with -ms-. So you could make the vendor mixin take a list of prefixes as an optional argument, and use it like so:
#mixin transition($args...) {
#include vendor(transition, $args, ('-webkit-', '-moz-', '-o-', ''));
}
and voilá, here you go:
DEMO
But if you go with Compass it will do all the hard thinking for you ;-)
Related
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
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
So I'm trying to do something functionally equivalent to this:
Can a sass #mixin accept an undefined number of arguments?
...with a transitionFast mixin, but I want to be strict about the easing functions and speeds, so I've defined them within the mixin, like so:
#mixin transitionFast($property) {
-webkit-transition:$property ease 0.2s;
-moz-transition:$property ease 0.2s;
-o-transition:$property ease 0.2s;
transition:$property ease 0.2s;
}
How can I pass multiple $properties to this, without passing through the ease 0.2s part? I've tried this:
#mixin transitionFast($properties...) {
#each $property in $properties {
transition:$property ease 0.5s;
}
}
which I'm trying to call like this:
#include transitionFast(background-color, color);
but it doesn't work and only applies the transition to the last passed argument. Any ideas?
In your case there are several ways to go with sass splat-like args:
1) If you define mixin with splat args like so:
#mixin transitionFast($properties...) {
# with iteration on $properties
}
And you include it normal like this:
#include transitionFast(firstArg, secondArg, thirdArg);
Then you get
# compiled
transition: firstArg;
transition: secondArg;
transition: thirdArg;
2) You will also get the same thing when you don't specify splat args
#mixin transitionFast($properties) {
# with iteration on $properties
}
And include them with double parents
#include transitionFast((firstArg, secondArg, thirdArg));
3) If you declare mixin this way:
#mixin transitionFast($properties...) {
# with iteration on $properties
}
and call it whis way:
#include transitionFast(( background-color, color, red ));
you will get behavior similar to default behavior (ie without iteration over splat):
transition: background-color, color, red;
Now, back to your question, you can do this to get what You want:
$ease: ease 0.5s;
#mixin transitionFast($properties...) {
#each $prop in $properties {
transition: $prop $ease;
}
}
html {
#include transitionFast( background-color, color, margin );
}
Edit: instead transition: $prop $ease; go with compass #include transition( $prop $ease ); as Pik_at suggested, its more dry and sexy.
Just for fun:
If you leave (above) mixin as it is and include it like this:
#include transitionFast(( background-color, color ), padding);
it compiles to
transition: background-color, color ease 0.5s;
transition: padding ease 0.5s;
combining iteration and regular 'splatting', very cool stuff :)
Array parameters should be on bracket like:
#include transitionFast((background-color, color));
I made a simple code test to show you:
http://codepen.io/pik_at/pen/wBjgpY
Likewise, using Compass would help you to add transition mixin with browsers prefix:
#mixin transitionFast($properties) {
#each $property in $properties {
#include transition($property 2s ease);
}
}
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 use a #mixin to add different transition properties to elements. Let's say I have this in my .scss:
#mixin transition($prop, $sec){
-webkit-transition: $prop $sec;
-moz-transition: $prop $sec;
-ms-transition: $prop $sec;
-o-transition: $prop $sec;
transition: $prop $sec;
}
then I call:
.sample{
#include transition(background-color, 0.2s);
#include transition(margin, 0.3s)
}
.sample has only got margin transition, but I also want background-color transition: is there any simple way to get it working?
It's important that I have different calls
There is no way in SASS to concatenate properties and I don't know if exists a CSS external tool to do this task. Sass was created to improve CSS capabilities and not to allow programmers to develop bad programming practices. I don't really know the purpose of create multiple CSS declaration statements when you can keep them all in a single statement. Keeping all your transitions in one statement improves considerably your structure, your workflow and the performance of your Sass code.
Ok, that said, and as you have mentioned before "let the horrible kludge be".
Here are two different mixins for you one for shorthand transition declaration and another for the long form, differences between them in processing and even load time are negligible, the only noticeable difference is in the style of your code.
Long form mixin
#mixin transition($properties, $durations, $timing-function: null, $delay: null) {
$declarations: (property, $properties),
(duration, $durations),
(timing-function, $timing-function),
(delay, $delay);
#each $declaration in $declarations {
#if nth($declaration, 2) {
$output: ();
#each $val in nth($declaration, 2) {
$output: append($output, $val, comma);
}
#each $prefix in '-webkit-', '-moz-', '-ms-', '-o-', '' {
#{$prefix}transition-#{nth($declaration, 1)}: $output;
}
}
}
}
It's similar to #LeBen mixin but you can use the include with comma separated arguments without quotes:
#include transition(background-color margin, 0.2s 0.3s);
Shorthand form
#mixin transition($declarations...) {
#each $prefix in '-webkit-', '-moz-', '-ms-', '-o-', '' {
#{$prefix}transition: $declarations;
}
}
Here's the way to implement it in your code
#include transition(background-color 0.2s, margin 0.3s);
And now, to solve your problem with "different calls" the only way to deal with them, in my opinion, is using append() list function.
Let's go with the example. I'm going to use shorthand mixin form because it's easier to implement.
Imagine that you have four pages, three partials (_variables.scss, _page1.scss, _page2.scss, _page3.scss) and a style.scss file which imports the other:
_VARIABLES.SCSS
// Here comes the variable declaration
$transition-list: color 1s;
_PAGE1.SCSS
// Using append($list, $val, $separator:auto) list function
// we can add some items to $transition-list
$transition-list: append($transition-list, margin 2s, comma);
_PAGE2.SCSS
// You can add also the output of a function
#function example(){
#return unquote("background-color 1s")
}
$transition-list: append($transition-list, example(), comma);
STYLE.SCSS
// You can add new values into the same page
$transition-list: append($transition-list, padding 4s, comma);
$transition-list: append($transition-list, border 10s, comma);
// And finally you only need to use the include to generate the final transition
example {
#include transition($transition-list);
}
As I've said before, I don't recommend to use this method, it's not a good practice.
Your mixin is too rigid and don't feel like natural CSS. Personally, I recommend using the mixins provided by Compass, especially since it should handle prefixed values as well. If you just want a simple mixin, you want to use variable arguments like so:
#mixin transition($values...) {
-webkit-transition: $values;
// other prefixes
transition: $values;
}
#mixin transition-property($values...) {
-webkit-transition-property: $values;
// other prefixes
transition-property: $values;
}
#mixin transition-delay($values...) {
-webkit-transition-delay: $values;
// other prefixes
transition-delay: $values;
}
// etc
.foo {
#include transition(background-color, margin); // or transition-property
#include transition-delay(0.2s);
}
Output:
.foo {
-webkit-transition: background-color, margin;
transition: background-color, margin;
-webkit-transition-delay: 0.2s;
transition-delay: 0.2s;
}
Alternate Usage:
.foo {
#include transition(background-color 0.2s, margin 0.3s);
}
Output:
.foo {
-webkit-transition: background-color 0.2s, margin 0.3s;
transition: background-color 0.2s, margin 0.3s;
}
Here is the mixin you could use:
#mixin transition($properties, $durations, $timing-function: null, $delay: null) {
$props: unquote($properties);
$durs: unquote($durations);
-webkit-transition-property: $props;
-moz-transition-property: $props;
-ms-transition-property: $props;
-o-transition-property: $props;
transition-property: $props;
-webkit-transition-duration: $durs;
-moz-transition-duration: $durs;
-ms-transition-duration: $durs;
-o-transition-duration: $durs;
transition-duration: $durs;
#if ($timing-function) {
-webkit-transition-timing-function: $timing-function;
-moz-transition-timing-function: $timing-function;
-ms-transition-timing-function: $timing-function;
-o-transition-timing-function: $timing-function;
transition-timing-function: $timing-function;
}
#if ($delay) {
-webkit-transition-delay: $delay;
-moz-transition-delay: $delay;
-ms-transition-delay: $delay;
-o-transition-delay: $delay;
transition-delay: $delay;
}
}
With the following call
#include transition("background-color, margin", 0.2s);