LESS mixins with multiple arguments - css

I have this little mixin set up:
.linear-gradient(#direction:top, #color1:#fff, #color2:#000)
{
background-image: -webkit-linear-gradient(#direction, #color1, #color2);
}
Then, in my main.less I'm trying something like this:
a { .linear-gradient(top, #999, #666); }
That works fine, by say I want to do something like this:
a { .linear-gradient(top, , #666); }
Now, the first color should default to its default mixin color. How do I do this? Is this even possible

You can also explicitly pass the arguments, where the remaining arguments assume their default values.
a { .linear-gradient(#direction:top, #color2:#666); }

Less isn't quite that clever. You can either be explicit:
.linear-gradient(top, #fff, #000);
or use a variable as an abstraction to pass in the defaults.
#colorVar1: #fff;
.linear-gradient(top, #colorVar1, #000);
Less doesn't know how to handle an empty space, and will treat is as invalid.

Related

Use value from list as selector SCSS

I'm passing a list into a mixin to reduce the number of parameters I have to pass into my mixin. The mixin code can be seen below.
#mixin colorMedal($medalData) {
background-image: linear-gradient(
45deg,
nth($medalData,2) 0%,
nth($medalData,2) 50%,
nth($medalData,1) 50.1%,
nth($medalData,1) 100%
);
#{nth($medalData,0)} ~ .medal__ribbon--left {
background: nth($medalData,3);
}
#{nth($medalData,0)} ~ .medal__ribbon--right {
background: nth($medalData,4);
}
}
The list that im passing looks something like this
$platinum: ".medal__platinum", $medal-platinum, $medal-platinum-dark,
$medal-platinum-ribbon, $medal-platinum-ribbon-dark;
And the call of the mixin is :
#include colorMedal($platinum);
The code that seems to be causing a compile error is
#{nth($medalData,0)}
There must be a way to do this since you can pass in multiple values on their own. Is there a way to use a value from a list as a selector?
sass list starts at index 1 not 0
so change this from
#{nth($medalData,0)}
to
#{nth($medalData,1)}
you can debug the changes in codepen
https://codepen.io/srajagop/pen/wvBrzjO?editors=0102

How to add a LESS class to a LESS variable?

I wrote a class in LESS, which looks like this:
.horizontal-gradient (#startColor: #eee, #endColor: white) {
background: linear-gradient(red, yellow);
}
I tried to call it inside a LESS variable with this:
#primary-color: .horizontal-gradient(#35a1e5, #0172b9);
However, when running I get the error
NameError: variable #primary-color is undefined
But when I initialize the #primary-color as this:
#primary-color: #000;
Then it works just fine. So somehow, .horizontal-gradient class is causing the error.
DEMO I coudn't get LESS working within the SO fiddle. So I created a fiddle on jsFiddle.
http://jsfiddle.net/T2Xe9/828/
How can I use a LESS class inside a variable?
What you are using is not a variable, but a mixin: http://lesscss.org/features/#mixins-feature.
Without changing your .horizontal-gradient mixin, you can just use it:
div#background {
.horizontal-gradient(#35a1e5, #0172b9);
// The rest of your style
}
So: you cannot register a mixin result into a variable.

Using a Sass variable mapped to an hsl value doesn't work when trying to use it with hsla

I have a Sass variable which mapped to an hsl value. When I try to use it with hsla to add a little transparency, doesn't work. I'm doing this:
$white:hsl(100, 100%, 100%);
.thing{
color:hsla($white,.9);
}
Using gulp-sass to build my CSS, I get this error: "required parameter $lightness is missing in call to function hsla on line {line number} in {file's path}"
If I replace the hsla with rgba it works fine and, yes, I can do that, but I'd like to keep all my colors in hsl. Is there a workaround or is this a Sass issue?
It's not an issue with SASS, the functionality simply doesn't exist. If you look at the documentation, there are two versions of rgba(), one that accepts all of the parameters separately and one that accepts a Color object.
rgba($red, $green, $blue, $alpha)
rgba($color, $alpha)
If you look at the documentation for hsla(), it only accepts the values separately.
hsla($hue, $saturation, $lightness, $alpha)
To achieve your goal, you could do this:
$white:hsl(100, 100%, 100%);
.thing{
color: hsla(hue($white), saturation($white), lightness($white), .9);
}
Or... if you want to pass the Color object, you can create your own function since you can't overload functions; e.g. hslac($color, $alpha)
#function hslac($color, $alpha) {
#if(type-of($color) == "color") {
#return hsla(hue($color), saturation($color), lightness($color), $alpha);
}
#else {
#error "You didn't pass a color object";
}
}

Creating variable groups in Sass

On the site I'm working on we were using Scaffold, which is a PHP-based system similar to Sass. It also can process Sass functions\files. Unfortunately that system is now abandonware, and we are looking on a way to move completely to Sass. There is one big feature with Scaffold though that I'm not finding a way to port to Sass, the variable groups.
Variable in Scaffold can be organized in groups and used with a point-separated markup. For example I would define them as:
#variables vargroup1{
variable1: ####;
variable2: ####;
variable3: ####;
variable4: ####;
}
And later use on the code as, for example.
body{ width: vargroup1.variable1; margin: vargroup1.variable2 + 10;}
This helps development a lot, since you can group together variables from a system and reading the CSS files you can easily know what to reference. I didn't find anything like that on the Sass documentation, anyone knows if it is possible? Or if there is anyway using Mixins to do this?
Thanks
I came across this somewhat clunky solution (see Chris Eppstein's reply) using zip and index. Apparently a maintainer of SASS added these built-in functions in response to a similar question.
To quote his reply:
$border-names: a, b, c;
$border-widths: 1px, 1px, 2px;
$border-styles: solid, dashed, solid;
$border-colors: red, green, blue;
$borders: zip($border-widths, $border-styles, $border-colors);
#function border-for($name) {
#return nth($borders, index($border-names, $name))
}
#each $name in $border-names {
.border-#{$name} {
border: border-for($name);
}
}
Would generate:
.border-a { border: 1px solid red; }
.border-b { border: 1px dashed green; }
.border-c { border: 2px solid blue; }
The "naming your variables" comes from the list "-names" at the top; you then use the index of a desired variable name from that variable list to get the nth value from another variable lists. zip is used to mush separate lists together, so that you can retrieve the same index from all lists at the same time. Wrapping that behavior in a function makes it easier to retrieve a set.
There is no equivalent in Sass. But I can think in two workarounds:
1) Sass lists and its related list functions.
Your code could look like the following:
$variables = 40px 30px 20px 10px;
body {width: nth($variables, 1); margin: nth($variables, 2) + 10;}
It's not the same because list indexes can't be strings, so you haven't any way to name your variables.
2) Define a custom function. Look at Function Directives section in Sass reference
#function variables($variable_name) {
#if ($variable_name == 'variable1') {
#return 40px;
} #else if ($variable_name == 'variable2') {
#return 30px;
}
}
body {width: variables('variable_1'); margin: variables('variable_2') + 10;}
This way is less intuitive and uglier but you can 'name your variables'.
You could use the scss/sass map function:
#use "sass:map";
$variables: (
"variable1": ####;
"variable2": ####;
"variable3": ####;
"variable4": ####;
}
body {
width: map.get($variables, "variable1");
margin: map.get($variables, "variable2") + 10;
}
Documentation
You can use SASS lists a it's related functions on a way similar to that:
// List order: top, bottom, left, right, width, height, ...
$Header: 10px,auto,10px,auto,100%,50px;
$Footer: auto,0px,0px,auto,100%,20px;
#function getVar($variable,$name:top){
$var_index:1;
#if $name==bottom {
$var_index:2;
} #else if $name==left {
$var_index:3;
}
// Continue de if else for each property you want.
return nth($variable,$var_index);
}
That way calling something like:
getVar($Header,left)
Should return the value of the left property for the list of Header, but changing it to getVar($Footer,top) would return the value for the top property of the "Footer Group" (Footer List of Values).
That works for the time of using the values, but a the definition, you must follow the exact order and cannot leave any empty value, the nearest to an empty value that I found is #{''} what means "Empty String with no quotes", an empty value, but is added to the CSS.

less css, define empty string variable

I want to define a variable, which could be empty in some cases
#prefix: "";
and to use it like this
src: url("#{prefix}/path/to/something");
the problem is that it compiles into
src: url("""/path/to/something");
How to define an empty string variable, that can be compiled in
src: url("/path/to/something");
Update:
Issue closed
https://github.com/cloudhead/less.js/issues/532
Just found a way to do this... escape an empty string #prefix: ~'';
I ran into this with the box-shadow inset option that will often remain empty.
I'm not sure this is possible in less. You could make a mixin function which returns the path with the prefix prepended to it. This would be useful if you want to change the prefix once in awhile and only have to do it in one place.
.prefixRed(#path: #defaultpath) {
background: transparent url("red/#{path}");
}
.prefixBlue(#path: #defaultpath) {
background: transparent url("blue/#{path}");
}

Resources