Less mixin is not working for parameters with comma - less

I tried to use Less mixin but its not working because I'm passing multiple linear values:
.MultiStepGradient(#multigrad) {
background-image: -moz-linear-gradient(#multigrad);
background-image: -webkit-linear-gradient(#multigrad);
background-image: -o-linear-gradient(#multigrad);
background-image: -ms-linear-gradient(#multigrad);
background-image: linear-gradient(#multigrad);
}
.test {
.MultiStepGradient(135deg,#202f7c 0%, #7f3689 52%, #7f3689 100%);
}
Error:
No matching definition was found for .MultiStepGradient(135deg, #202f7c 0%, #7f3689 52%, #7f3689 100%)

Pass it like this, escaping it
.MultiStepGradient(~"135deg,#202f7c 0%, #7f3689 52%, #7f3689 100%")
you could change the mixin to take multiple values if you want to pass it the way you are doing it now
http://lesscss.org/functions/#string-functions-escape
Scroll down a little to see the e section
CSS escaping, replaced with ~"value" syntax.
It expects string as a parameter and return its content as is, but
without quotes. It can be used to output CSS value which is either not
valid CSS syntax, or uses proprietary syntax which Less doesn't
recognize.

Related

2 Less Parameter with one being null by default

Hey I have 2 sets of icon styles. Black and White
settings-icon-white.png or settings-icon.png
Now I am using a Less mixin which takes a text parameter:
//The mixin
.icon-finder(#url){
background-image: url("../images/icons/backend/#{url}-icon.png");
background-size: cover;
}
//generated class:login-icon.png
.icon-login{
.icon-finder(login);
}
Now the challenge is that I want to also have an option to select a white icon if the parameter gets passed a white. Is there a way to have a default null parameter, but can be used if need be?
So for example:
.icon-finder(#url,#white){
background-image: url("../images/icons/backend/#{url}-icon#{white}.png");
background-position: center center;
}
But I don't want white the whole time, so can this be null? #white = "" I did see this #_ being used before - is that right?
So the code would be like:
.icon-admin{
.icon-finder(admin);
}
.icon-admin-white{
.icon-finder(admin,white);
}
Am I missing something? Thanks in advance!
Yes, you can set a default value to a mixin argument by just specifying it in the mixin declaration like in the below code block. The #white: '' part means that the mixin will take the value for #white as an empty string when no value is provided in the call.
.icon-finder(#url,#white: ''){
background-image: url("../images/icons/backend/#{url}-icon#{white}.png");
background-position: center center;
}
.icon-admin{
.icon-finder(admin);
}
.icon-admin-white{
.icon-finder(admin,white);
}
There is no need to use the #_ syntax that is mentioned in the link.
Note that if you are writing something like a mixin library and want to restrict the values for the second parameter to white or nothing (the above mixin allows you to send any value for second param), then you could use one of the following options also:
Option 1: Two separate mixins, one with a hard-coded white value (note that it is not a variable) and another with only one parameter. This way if the user tries to pass any other value it will be rejected.
.icon-finder(#url,white) {
background-image: url("../images/icons/backend/#{url}-iconwhite.png");
background-position: center center;
}
.icon-finder(#url){
background-image: url("../images/icons/backend/#{url}-icon.png");
background-position: center center;
}
.icon-admin{
.icon-finder(admin);
}
.icon-admin-white{
.icon-finder(admin,white);
}
Option 2: Using guards and checking if the value is white or not. If it is then use the white background image, else use the default.
.icon-finder(#url,#white: '') {
& when (#white = white){
background-image: url("../images/icons/backend/#{url}-iconwhite.png");
background-position: center center;
}
& when not (#white = white){
background-image: url("../images/icons/backend/#{url}-icon.png");
background-position: center center;
}
}
.icon-admin{
.icon-finder(admin);
}
.icon-admin-white{
.icon-finder(admin,white);
}
The advantage of the first option is that if any value other than white is given, the compiler would throw an error and alert the user that a wrong value is provided whereas the second one will silently switch to the default.

Is it possible to manipulate css variables using LESS?

With preprocessor variables it's easy to set up one variable and manipulate it so that I can use it to set multiple properties. (demo)
While experimenting with native css variables, I noticed that I could combine them with preprocessor variables, so in the following example: (use firefox)
h1 {
--length: 40px;
#length: var(--length);
line-height: #length;
border: 5px solid tomato;
}
line-height was correctly rendered at 40px
But, when I tried to manipulate the preprocessor variable - like this:
h1 {
--length: 40px;
#length: var(--length);
#length2: #length*2;
line-height: #length;
padding: #length2;
border: 5px solid tomato;
}
... the code failed.
Is this possible somehow?
As mentioned in my comment, my understanding of CSS variables is that the variable is resolved into its actual value by the UA. This happens after the Less compiler compiles the file and thus it wouldn't be aware of what is the actual value contained by the CSS variable.
To the compiler, the value of #length is only var(--length). Since this is not a number, an error is thrown during compilation indicating that the math operation is being done on an invalid type.
OperationError: Operation on an invalid type on line 4, column 3:
One way to fix this would be to make the Less compiler output the variable name as it is and have the multiplier appended to it (like string concatenation). This would then leave the control to the UA.
But since all CSS math operations have to be given within calc() function, the entire thing has to be wrapped within it. So, the below code would work fine.
h1 {
--length: 40px;
#length: var(--length);
#length2: ~"calc(#{length} * 2)";
line-height: #length;
padding: #length2;
border: 5px solid tomato;
}
Or, even the below would be enough if --strict-math is enabled during compilation:
h1 {
--length: 40px;
#length: var(--length);
#length2: calc(#length * 2);
line-height: #length;
padding: #length2;
border: 5px solid tomato;
}
Above code when compiled produces an output similar to the one in Example 11 of the specs and so it should be a reasonably good way of doing this :)
... Note, though, that calc() can be used to validly achieve the same thing, like so:
.foo {
--gap: 20;
margin-top: calc(var(--gap) * 1px);
}
var() functions are substituted at computed-value time...

Improve Less nesting for this rule?

I need the following CSS output. The ie* classes must be there for specificity and the body class also needs to be there without them as they won't always be added.
body.my-class,
html.ie7 body.my-class,
html.ie8 body.my-class,
html.ie9 body.my-class {
background: red;
}
I can get the same thing with this in my Less. However its not a good idea as I have to write the style of background: red twice. So if it was updated it would need to be updated in 2 places.
body.my-class {
background: red;
html.ie7 &,
html.ie8 &,
html.ie9 {
background: red;
}
}
Can I write my Less in a different way so that I'm not repeating the style, but so that the compiled CSS is exactly the same?
Simply add the & (parent selector) as one of the comma separated selector list within the top level nesting. Less compiler would automatically replace it with the full parent selector as it always does.
body.my-class {
&, /* this will replaced with body.my-class as is always the case with parent selectors */
html.ie7 &,
html.ie8 &,
html.ie9 &{
background: red;
}
}
The above code when compiled would result in exactly the same CSS output as required.
body.my-class,
html.ie7 body.my-class,
html.ie8 body.my-class,
html.ie9 body.my-class {
background: red;
}

How to pass a list as separate arguments to a mixin in SASS?

I'm having some elements that are using a compass shadow mixin. As the arguments are the same I want to have them in a variable. I thought this is what variable arguments are for, but obviously I'm doing something wrong as the following does not work:
// my shadow style
$shadow: #000000, 0px, 0px, 20px;
.list {
#include single-box-shadow($shadow...);
}
This should be the same as
.list {
#include single-box-shadow(#000000, 0px, 0px, 20px);
}
But while the second example works, the first one is compiling to
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
What am I doing wrong here?
Compass version is 0.12.2 and SASS is 3.2.3.
edit: I'm compiling with yeoman, maybe it uses a different (older) version? How can I check that?
The single-box-shadow mixin does not use variable arguments (see: http://compass-style.org/reference/compass/css3/box_shadow/#mixin-single-box-shadow).
When you invoke the mixin using your variable, what you're essentially doing is this:
#include single-box-shadow((#000000, 0px, 0px, 20px));
The entire list is being passing as the first argument of the mixin: $color. If you want to reuse specific box-shadow values either use the box-shadow mixin with a space delimited list or create your own custom box-shadow mixin.

How to pass argument from mixin to another in lesscss?

I'm using the LESS CSS module 7.x-2.4 in Drupal 7.8
I would like to use style mixins which pass arguments to another mixin. In the example passing the color as a string "#CC00CC" works ok, but not as an variable like that "darken(#col, 10%)".
#bg(#colBg){
background-color: #colBg;
}
#style(#col){
border: 2px solid lighten(#col, 10%); // ok
#bg(#CC00CC); // ok - color is passed
#bg(darken(#col, 10%)); // Color is not being passed to #bg
}
.buttonSubmit{
#style(#FF00FF);
}
How can I achieve cascading variables from the css-class to a mixnin which passes the argument to another mixin?
Your syntax is incorrect. Check the docs on mixins. The code you have should be written like this:
.bg(#colBg){
background-color: #colBg;
}
.style(#col){
border: 2px solid lighten(#col, 10%);
.bg(#CC00CC);
.bg(darken(#col, 10%));
}
.buttonSubmit{
.style(#FF00FF);
}