LessCSS: Nesting functions within concatenated classes - css

I'm having real issues with getting LessCSS to process a file that has a series of nested rules using the "&" concatenation selectors.
For example, the following will work without errors:
.grey-table {
background: #EDEDED;
tr {
th {
background: #DEDEDE;
}
td {
color: #888;
}
&:nth-child(odd) {
td {
background-color: #F9FCFF;
}
}
&:nth-child(even) {
td {
background-color: #EDF5FF;
}
}
&:hover {
td {
background-color: #DFEAF9;
}
};
}
}
However if I change the colours to be a function (of any sort - predefined or mixin), I get the error
"Syntax Error on line 12 - undefined"
.grey-table {
background: desaturate(#EDEDED, 100%);
tr {
th {
background: desaturate(#DEDEDE, 100%);
}
td {
color: desaturate(#888, 100%);
}
&:nth-child(odd) {
td {
background-color: desaturate(#F9FCFF, 100%); <------ Line 12
}
}
&:nth-child(even) {
td {
background-color: desaturate(#EDF5FF, 100%);
}
}
&:hover {
td {
background-color: desaturate(#DFEAF9, 100%);
}
};
}
}
I cannot find any reference material on this but I'm sure I can't be the only one?
Many thanks.

i usually define the colors first and then call them in the functions:
#mycolor: #F9FCFF;
desaturate(#mycolor, 100%);
I am sorry, but there are no errors with your code on the less page:
http://less2css.org/
Try pasting it in (without your <---line 12) and you will see it works.
MAybe you are using some javastript that interacts with the less script on your page.
Edit:
You also have an semicolon at the end that breaks older versions (<=1.3.1) of the less parser.
If I take it out it parses well through al versions ... and I do not manage to reproduce your error.

I'm an idiot and had not noticed the tab on line 12 after the colon.
That's what was causing the error, but only when there was a less css mixin/variable. Apologies to all.

I agree with Martin, I cannot reproduce your error using your code above and the compiler at http://less2css.org/. The only ways I can reproduce a syntax error message on line 12 are:
Remove the colon after the background-color property.
Add some non-comment related characters after the end semi-colon (like your note <--- line 12 is invalid, but I'm sure you put that in for illustration above).
Add an end quote after either (a) the color, (b) the percentage, or (c) the parenthesis. An example of (b) - 100%'. There may be some other characters that would cause it too, but some just print right out into the css wihtout a syntax error.
A character separated by a space or other invalid character for a property name before the property name, like y background-color or *background-color.
Obviously, none of those exist in your code shown above, but you might double check that your actual code does not have some extra characters or missing characters that might be causing the issue.

Related

If statements in SCSS using CSS variables

My JS code sets a variable on the page:
if (error) {
document.querySelector('body')?.style.setProperty('--pickererror', `'${ error }'`);
}
My SCSS code uses that variable for some content:
$error: var(--pickererror);
// ERROR MESSAGE
.picker-toolbar::before {
content: $error;
color: red;
padding: 5px 35px 0px 35px;
text-align: center;
}
.picker-toolbar {
#if str-length($error) > 0 {
order: 1 !important;
}
}
The ::before section works completely. However the #if clause executes even if there is no error, and the .picker-toolbar is always at order: 1.
I have checked that --pickererror is not present when there's no JS error. I've tried any number of permutations, such as
Putting the #if line before the .picker-toolbar line
Simply using #if $error
Using #if var(--pickererror) in place of the $error variable.
How do I make this work?
What if you remove the logic from your stylesheet entirely, and instead rely on the dynamic property value from your JavaScript?
For example:
body {
--pickererror: 0; // Default value for the "order" property
}
If your JavaScript detects an error, the --pickererror is given a value of 1 !important;
if (error) {
document.querySelector('body').style.setProperty('--pickererror', '1', 'important');
}
And in your stylesheet, you only need a single rule that changes the order if the JavaScript says so.
.picker-toolbar {
order: var(--pickererror, 0); // Defaults to "0" also if the variable doesn't exist
}
I realize this only makes sense if you are using --pickererror mostly as a boolean (I thought since you're checking if its length is greater than 0). If you're actually using the string value, it would be better to create an --error-order variable for this single purpose I guess.

How to avoid SASS adding a space to the asterisk (*) symbol?

SASS CODE:
#{'body > *:not(.this)'} {
background: red;
}
EXPECTED RESULT
body > *:not(.this) {
background: red;
}
ACTUAL RESULT
body > * :not(.this) { //<-- SASS adds a space between * and :
background:red;
}
No matter what I try, SASS keeps adding an unnecessary space. How can I avoid this from happening? The space blocks the functionality of the not-selector.
This was not due to SASS. I was using CodeKit 3 and the following SASS setting messed it up:
Output style: Compressed
Put this on any other output style and you can avoid the above.

Passing conditions to mixins in LESS

First of all, I am using LESS 1.7 (and there is no way I can change it). I have the following if-mixin in my less file that is just supposed to set the property and its value if the condition is met:
.if(#condition, #property, #value) when (#condition){
#{property}: #value !important;
}
It works fine if I pass the condition as true/false like this:
.column-header {
font-family: 'Something';
.if(true, color, green);
}
However, I am not able to pass the condition as an expression. If I want to pass a comparison such as 2 > 1, I get a parsing error: expected ')' got '>'. Is this not supported (or was this not supported in 1.7)? Am I doing something wrong? Any workaround? Thanks!
Not shure it's possible to pass contions to mixin.
But you can just write code witout .if mixin:
.column-header {
font-family: 'Something';
& when (2 > 1) {
color: green;
font-size: 20px;
}
}

styling the optional input fields

I have a web form where some input fields are required and some are optional. I can give style the required fields as I expect but can't the optional ones.
When the optional fields have a valid input it will turn green(for instance). And it works with this code
input:optional:valid{
background: #AAB69B
}
But generally like as first loading they will be in another color. For this, I am trying this code
input:optional{
background: #f19999
}
But this doesn't work. I can't select the optional fields when they have no input. Unfortunately, with no input value they get the background as I set for the valid input. When I start typing , it get my expected invalid background. And when the input gets valid, the field gets valid background (it works).
Please, help !
Demo Link : http://bdlance.byethost9.com/front-end%20form%20validation%20with%20html5/
Taking a look at your form styles, I've seen that your background color is similar for both valid and invalid pseudo classes:
input:required:invalid, textarea:required:invalid{
background: #AAB69B; // same
}
input:required:focus:invalid, textarea:focus:invalid{
background: #AAB69B; // same
}
input:required:valid, textarea:required:valid{
background: #AAB69B; // same
}
input:optional, select {
background: #f19999;
}
input:optional:valid{
background: #AAB69B; // same
}
Try this instead:
input:required:invalid, textarea:required:invalid{
background: #f19999;
}
input:required:focus:invalid, textarea:focus:invalid{
background: #f19999;
}
input:required:valid, textarea:required:valid{
background: #AAB69B;
}
input:optional, select {
background: #f19999;
}
input:optional:valid{
background: #AAB69B;
}
Sorry, but your CSS file is not the best, Please do dedicate more time to learn CSS. Here are some good resources (the order matters):
https://developer.mozilla.org/en-US/docs/Learn/CSS
https://flukeout.github.io/
https://smacss.com/
https://en.bem.info/methodology/css/

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.

Resources