SCSS doesn't compile when function is commented out - CompileSass - css

Unfortunately I'm having to go back through my CSS and re-write some styling to make sure it works for IE8 (client needs it). I have a function that adds z-index to elements,
.mobile-pane {
....
....
/* won't work for IE8 */
/* #for $i from 1 through 4 {
&:nth-child(#{$i}) {
z-index: #{$i};
}
} */
&:first-child {
z-index: 1;
& + .mobile-pane {
z-index: 2;
& + .mobile-pane {
z-index: 3;
& + .mobile-pane {
z-index: 4;
}
}
}
}
}
As you can see, the function is clearly commented out. However (I'm using CompileSASS for Visual Studio), in the output window, I see this:
CompileSass 8:35:55 AM:Sass compilation failed for main.
Error: C:/projectFolder/source/sass/components/header:219: unbound variable $i
In Google WebDev, I'm seeing the function's output, ....:nth-child(2) { z-index:2; } ... and so on, not
.mobile-pane:first-child+.mobile-pane {
z-index: 2;
}
, as I would expect. I'm some-what new to SCSS, so I don't know if this is a known problem, or if CompileSass is not reading the comments correctly.
I understand that I could leave the function in, and just have the IE8 z-index CSS below it, and it will still work, but I wanted to leave the function, in case in the future IE8 was no longer a requirement.
My question - is it normal for SCSS to do this, or is it the extension?

Accessing variables within CSS comments is expected, declaring variables within comments is not.
$i: 100;
/* commenting about #{$i} */
Output:
/* commenting about 100 */
Meanwhile:
/*
$j: 100;
commenting about #{$j} */
Raises an error:
Undefined variable: "$j".
If you want to comment out blocks of code that access variables that don't exist due to being commented out, use double slashes instead:
$j: 100;
.foo {
// content: $j;
}

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 Assign CSS Variable Value to scss Variable or Expression

I'm trying to build my own tiny scalable grid in CSS / scss.
So far I found this decision:
:root {
--page-width: 1170px;
--gutter: 15px;
--columns: 12;
}
.wrapper {
max-width: var(--page-width);
margin-right: auto;
margin-left: auto;
padding-left: var(--gutter);
padding-right: var(--gutter);
}
.row {
margin-left: calc(-1 * var(--gutter));
margin-right: calc(-1 * var(--gutter));
}
.col {
display: block;
margin-left: var(--gutter);
margin-right: var(--gutter);
}
Then I tried to use scss to shorten columns classes description (which at the same time will allow me to change number of columns in one single place in whole code - in CSS Variable --columns) like this
#for $n from 1 through var(--columns) {
.col-#{$n} {width: calc( #{$n} / var(--columns) - var(--gutter) * 2 ); }
}
but it didn't work. The interesting detail is that when I change #for statement from #for $n from 1 throughvar(--columns)`` to #for $n from 1 through12 it compiles well. And there is no problem in compiling CSS-Variable inside #for body. .col-#{$n} {width: calc( #{$n} / var(--columns) - var(--gutter) * 2 ); } compiles well into needed series of classes.
If I use scss variable $columns instead of CSS variable then I'll need to import my grid.scss file into all other scss files of the project.
It's my first question on StackOverflow, so let me know if any other details are needed.
CSS and SCSS variables are two very different things (please see this pen)
To make it work you need a static variable for SCSS to compile
// static (SCSS) variables used produce CSS output
$page-width: 1170px;
$gutter : 15px
$columns: 12;
// dynamic (CSS) variables used at run-time
// note the values are interpolated
:root {
--page-width: #{$page-width};
--gutter : #{$gutter};
--columns: #{$columns};
}
// the for loop is aimed at producing CSS output
// ... why you need the static variable
#for $n from 1 through $columns {
// the content becomes CSS output
// ... why you can use dynamic variables
.col-#{$n} {width: calc( #{$n} / var(--columns) - var(--gutter) * 2 ); }
}
You need to use interpolation (eg. #{$var}) on your variable in order for Sass to treat it as a CSS property. Without it, you're just performing variable assignment.
#mixin w_fluid($property_name, $w_element, $w_parent:16) {
#{$property_name}: percentage(($w_element / $w_parent));
}
The accepted answer is no longer valid. Newer versions of SASS require interpolation to be used for variables.
Refer here for more details
$accent-color: #fbbc04;
:root {
// WRONG, will not work in recent Sass versions.
--accent-color-wrong: $accent-color;
// RIGHT, will work in all Sass versions.
--accent-color-right: #{$accent-color};
}

Less variables in selector with &

I want to use the & to attach a pseudo :not to the parent class however I don't know how to do this when using mixins and variable selectors.
.hideElement(#selector, #maxWidth) {
#media (max-width: #maxWidth) {
#{selector} {
display: none;
}
}
}
.jp-sleek.jp-audio:not(.jp-state-no-volume-support) {
.hideElement(~':not(.jp-state-full-screen) .jp-title-container', 580px);
}
The output I want is:
.jp-sleek.jp-audio:not(.jp-state-no-volume-support):not(.jp-state-full-screen) .jp-title-container {
display: none;
}
The current output is (notice the space in the :not):
.jp-sleek.jp-audio:not(.jp-state-no-volume-support) :not(.jp-state-full-screen) .jp-title-container {
display: none;
}
I know I need to use the & selector but this doesn't work:
.hideElement(~&':not(.jp-state-full-screen) .jp-title-container', 580px);
How do I do this?
Full code for context:
.jp-sleek.jp-video,
.jp-sleek.jp-audio.jp-state-no-volume-support {
.hideElement(~'.jp-repeat', 400px);
.hideElement(~':not(.jp-state-full-screen) .jp-title-container', 530px);
.hideElement(~'.jp-download', 580px);
}
.jp-sleek.jp-audio:not(.jp-state-no-volume-support) {
.hideElement(~'.jp-full-screen', 400px);
.hideElement(~'.jp-repeat', 450px);
.hideElement(~':not(.jp-state-full-screen) .jp-title-container', 580px);
.hideElement(~'.jp-download', 630px);
}
The & cannot be used as a parameter to a mixin or as part of the parameter to a mixin. When used in that way the & would have no special meaning. It wouldn't resolve to the parent selector and will just remain as &. Plus the below line is incorrect because the ~ must be followed by a ".
.hideElement(~&':not(.jp-state-full-screen) .jp-title-container', 580px);
I'd strongly urge you to have a look at the alternate method suggested by seven-phases-max in his comment. But a very simple solution to your problem while retaining your code-base as-is will be the following. Just take the &:not(...) part out, put it as its own block and then invoke .hideElement mixin within this block with just the other part of the selector (the child selector) as input.
.jp-sleek.jp-video,
.jp-sleek.jp-audio.jp-state-no-volume-support {
.hideElement(~'.jp-repeat', 400px);
&:not(.jp-state-full-screen){ /* take the not part out and put it as a block */
.hideElement(~'.jp-title-container', 530px);
}
.hideElement(~'.jp-download', 580px);
}
.jp-sleek.jp-audio:not(.jp-state-no-volume-support) {
.hideElement(~'.jp-full-screen', 400px);
.hideElement(~'.jp-repeat', 450px);
&:not(.jp-state-full-screen) { /* take the not part out and put it as a block */
.hideElement(~'.jp-title-container', 580px);
}
.hideElement(~'.jp-download', 630px);
}

Adding asterisk to placeholder in Firefox, -moz-placeholder::before no longer works

I'm trying to add an asterisk before the placeholders of required inputs. I was using input::-moz-placeholder:before which I found on this StackOverflow post and it was working the last time I checked in January. However, it seems that it is no longer supported. Here's what I have going:
div.interactFieldRequired {
input::-webkit-input-placeholder:before {
content:'* ';
color: $error-color;
}
input:-moz-placeholder:before {
content:'* ';
color: $error-color;
}
input::-moz-placeholder:before {
content:'* ';
color: $error-color;
}
input:-ms-input-placeholder:before {
content:'* ';
color: $error-color;
}
input::-moz-selection:before {
content:'* ';
color: $error-color;
}
input[type="text"]:before {
content:'* ';
color: $error-color;
}
}
This is working in every browser except Firefox and IE10. I cannot alter the HTML, although I can use Javascript. However, I'd prefer to do this with scss.
That is strange indeed. I haven't found any reasons why placeholder css support has been removed from Firefox - this applies for Developer Edition too. So if you are OK with JS, you can take advantage of JavaScript document.getElementsByTagName() method and loop through this list and concat() each input's placeholder to an asterisk , like so:
var asterisk = "* ",
inputList = document.getElementsByTagName("input");
for(i=0; i < inputList.length; i++) {
inputList[i].placeholder = asterisk.concat(inputList[i].placeholder);
}
It has a wide support amongst the browsers. I've made an example of that on jsfiddle
Hope this helps

Basic arithmetic in GWT CssResource

I'm looking for a way to do something like this:
// style.css
#def borderSize '2px';
.style {
width: borderSize + 2;
height: borderSize + 2;
}
where the width and height attributes would end up having values of 4px.
Sometimes I use the following:
#eval BORDER_SIZE_PLUS_2 2+2+"px"; /* GWT evaluates this at compile time! */
Oddly, this only works, if you don't put any spaces between the + operator and the operands. Also, in #eval you can't use constants that were previously defined by #def. You can however use constants that are defined as static fields in one of your Java classes:
#eval BORDER_SIZE_PLUS_2 com.example.MyCssConstants.BORDER_SIZE+2+"px";
Or you could let the calculation be performed completely by Java:
#eval WIDTH com.example.MyCssCalculations.width(); /* static function,
no parameters! */
#eval HEIGHT com.example.MyCssCalculations.height();
.style {
width: WIDTH;
height: HEIGHT;
}
But what I would actually like to do is very similar to your suggestion:
#def BORDER_SIZE 2;
.style {
width: value(BORDER_SIZE + 2, 'px'); /* not possible */
height: value(BORDER_SIZE + 3, 'px');
}
I don't think that's possible in GWT 2.0. Maybe you find a better solution - here's the Dev Guide page on this topic.
Mozilla kind-of-sort-of-not-really supports this with it's CSS calc() function.
This example shamelessly stolen (with attribution!) from Ajaxian
/*
* Two divs aligned, split up by a 1em margin
*/
#a {
width:75%;
margin-right: 1em;
}
#b {
width: -moz-calc(25% - 1em);
}
It's not cross-browser, and it's probably only barely supported by even bleeding-edge versions of Firefox, but there's at least being progress made in that direction.
You could also calculate in your provider method, if you put a parameter in the function:
#eval baseFontSize com.myexample.CssSettingsProvider.getBaseFontSize(0)+"pt";
#eval baseFontSize_plus_1 com.myexample.CssSettingsProvider.getBaseFontSize(1)+"pt";
com.myexample.CssSettingsProvider would look like this:
public static int getBaseFontSize(int sizeToAdd) {
if (true) {
return 9 + sizeToAdd;
}
return baseFontSize;
}
I would also love somehting like that, but it's not possible.
Even in CSS 3 their is nothing planned like this.
If you really want to make something like that, one possibility is to use
php and configure your webserver, so that .css files are parsed by php.
So you could do something like
<?
$borderSize = 2;
?>
.style {
width: <? borderSize+2 ?>px;
height: <? borderSize+2 ?>px;
}
But as this is no 'standard' way, i think its better to not do it.

Resources