Use !default value with #use in SCSS - sass

I am having some difficulty overwriting !default values in SCSS while using #use. When I use #import instead of #use it behaves correctly but while using #use the console gives an error (This module and the new module both define a variable named "$variable-name").
When I change the variable inside the same file where I assign the variable to an element it behaves correctly:
// variables/variable.scss
$color-accent: red !default;
// variables/index.scss
#forward ./variable.scss;
// change.scss
#use './variables/index' as *;
$color-accent: blue;
body {
background-color: $color-accent;
}
// body background color is blue
But when I try overwriting it in a seperate file it won't work:
// change.scss
$color-accent: blue;
// variables/index.scss
#forward ./variable.scss;
#forward ./change.scss;
// base.scss
#use './variables/index' as *;
body {
background-color: $color-accent;
}
// main.scss
#use './base';
// error: Two forwarded modules both define a variable named $color-accent
Also, when I only #forward the variable.scss and #use the change.scss in the main.scss file it doesn't give the right outcome (body background color stays red without an error).
Does anyone have a suggestion? All help is appreciated.
Joop

The error is where you used two #forward in index.scss and these two files have variables with the same name. Just loading the change.scss file with #import can solve the problem.
More Information about the difference between #import, #use and #forward is here: https://www.liquidlight.co.uk/blog/use-and-import-rules-in-scss/.
// variables/index.scss
#forward "./variable.scss";
#import "./change.scss";

Related

Passing on the value CSS variable to SASS variable

When you assign a scss variable to an existing css variable like this
--color: #FFF;
$color: var(--color);
This will result in $color holding the var(--color) as a value. Is there a trick so it would hold the actual CSS value? So $color would save the #FFF?
You can define variable like this
$color: #FFF;
and use it like this for example
p {
color: $color;
}

SASS for each interpolation error when export css in compressed mode

I have a map declared like below
Map Definition
$color-array:(
black:#4e4e4e,
blue:#0099cc,
dark-blue:#14394e,
green:#2ebc78,
white:#ffffff,
orange:#ed6a0e
);
and calling the same in for each loop to generate class for text color and background color like below
#each $color-name, $color-value in $color-array{
.#{$color-name}{
color: $color-value !important;
}
.bg-#{$color-name}{
background: $color-value !important;
}
}
I am using gruntjs for for compilation, when i set output style to compressed it gives below error
You probably don't mean to use the color value #000' in interpolation
here. It may end up represented as #000000, which will likely produce
invalid CSS. Always quote color names when using them as strings (for
example, "#000"). If you really want to use the color value here, use
"" + $color-name'.
Error: Invalid CSS after ".": expected class name, was "#000"
on line 25 of SCSS/_base.scss
from line 5 of scss/style.scss
But when i set output style to expanded it runs fine.
In your colors array, change all the key double-quoted string keys and things should work.
$color-array:(
"black":#4e4e4e,
"blue":#0099cc,
"dark-blue":#14394e,
"green":#2ebc78,
"white":#ffffff,
"orange":#ed6a0e
);
An alternative of changing the SCSS code would be to make sure the variable is a string like the error message mentioned
#each $color-name, $color-value in $color-array{
.#{"" + $color-name}{
color: $color-value !important;
}
.bg-#{"" + $color-name}{
background: $color-value !important;
}
}

SASS Assign by reference

I am building a system to take default stylesheets, and merge with a theme, and a base theme to produce the final site css, however i was hoping to find a way to assign variables by reference, not by value so i can do things like this.
base.vars.scss
$PrimaryFg: blue
$LinkFg: $PrimaryFg
$DefaultFont: opensans
$HeadingFont: $DefaultFont
basetheme.vars.scss
$PrimaryFg: yellow
$CaptionFont: $HeadingFont
theme.vars.scss
$DefaultFont: Verdana
base.rules.scss
body {font: $DefaultFont }
h1,h2,h3,h4,h5,h6 {font: $HeadingFont; }
a {color: $LinkFg }
basetheme.rules.scss
caption {font: $CaptionFont; }
theme.rules.scss
#import 'base.vars.scss';
#import 'basetheme.vars.scss';
#import 'theme.vars.scss';
#import 'base.rules.scss';
#import 'basetheme.rules.scss';
The main problem i have is that, $HeadingFont will be set to opensans, and wont change to Verdana, and the link FG colour will still be blue,
I cant find a solution, i was hoping that the $HeadingFont: $DefaultFont, would not assign the value immediately, but assign the variable, so it could be changed later.
Yes i am aware of !default, however it is a complete mess trying to do this with !default.

Breaking out of a Sass mixin

Is it possible to break out/return early of a Sass mixin? I'd like to do something like this:
#mixin foo($bar: false) {
#if $bar {
// return early without applying any of the styles below
}
color: red;
}
Edit: Please keep in mind that this example is the simplest thing I could come up with that illustrates my problem. In the real world, my code is much more complex and the use case for this is clear.
Sass doesn't really have the concept of "break", but an #if/#else will get you pretty close:
#mixin foo($bar: false) {
#if $bar {
color: green;
}
#else {
color: red;
}
}
From the Lead Sass developer at https://github.com/nex3/sass/issues/378:
The issue is that the more seldom-used control structures exist in
Sass, the harder it is for something with only passing familiarity
with the language to read stylesheets that use those control
structures. That's why it started out with the bare minimum set of
structures needed to do anything: because in many cases it makes sense
to skew towards a smaller surface area of the language rather than
optimal semantics for writing complex code.
I still thinking that #if/#else statements is the easiest and best solution to deal with your problem in Sass but I've created two different breakout mixins to help you and as a challenge:
Play with this mixin first
Breakout mixin without #includes (link)
#include breakout($styles)
$style should be a list of styles separated by spaces, here are the allowed values:
Styles
Common CSS styles separated by spaces and without colon or semicolons, lists of values should be wrapped by brackets:
#include breakout(
color blue // <property> <value>
width (100 * 20px) // <property> <operation with values>
border (1px solid #fff) // <property> <list of values>
box-shadow (0 0 10px 4px #0000FF , 0 0 20px 30px #008000) // <property> <nested list of values>
)
Breaks
Breaks are styles that are compiled if its condition is true, also when the condition is true the mixin ends without returns all styles after the break value
$foo: true;
#include breakout(
break (false color red) // break (<condition> <property> <value>
break ((3 < 2) border (1px solid #fff)) // breaks also support list and nested lists
break ($foo width 10px) // This breaks is compiled because condition is true
color blue // This style isn't compiled because the $foo break ends the mixin
)
Note that the order of the mixin argument list is important because it determines the compiled and not compiled styles if a break condition is true
Breakout mixin with #includes (link)
This mixin is similar to the above but it introduces mixin values for $styles, break-mixin mixin and #content into the breakout mixin to allow use of #includes.
Mixins
If you want to use other mixins into breakout mixin you need to add some code into $styles and add each mixin into a break-mixin mixin.
#include breakout(
mixin foo // mixin <name of the mixin declared into break-mixin arguments>
mixin bar // mixin name should match break-mixin argument
mixin foobar
) {
#include break-mixin(foo) { // Here your mixin or mixins for mixin foo }
#include break-mixin(bar) { #include mixin1; #include mixin2; #include mixin3}
#include break-mixin(foobar) { #include foobar}
}
Mixin breaks
Now you can also use mixin into breaks. Here the order is still important:
$foo: true
#include breakout(
mixin foobar
mixin bar
break ($foo mixin foo) // This breaks is compiled because condition is true
color blue // This style isn't compiled because the $foo break ends the mixin
) {
#include break-mixin(foo) { // Here your mixin or mixins for mixin foo }
#include break-mixin(bar) { #include mixin1; #include mixin2; #include mixin3}
#include break-mixin(foobar) { #include foobar}
}
So for your specific case copy the Breakout mixin without #includes (link) to your scss file or use it as a partial and then add this to your code;
#include breakout(
break ($bar property value) // The break out statement
color red // If $bar != false this will be compiled if not it won't
);
I'm surprised that the #error statement has not been mentioned yet. According to the documentation (emphasis mine):
When writing mixins and functions that take arguments, you usually want to ensure that those arguments have the types and formats your API expects. If they aren't, the user needs to be notified and your mixin/function needs to stop running.
That said, #error may not be suitable for every situation, because it will stop the Sass compilation completely. This makes it unfit for mixins where breaking out is an expected end intended scenario.
Example from the Sass documentation:
#mixin reflexive-position($property, $value) {
#if $property != left and $property != right {
#error "Property #{$property} must be either left or right.";
}
$left-value: if($property == right, initial, $value);
$right-value: if($property == right, $value, initial);
left: $left-value;
right: $right-value;
[dir=rtl] & {
left: $right-value;
right: $left-value;
}
}
.sidebar {
#include reflexive-position(top, 12px);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// Error: Property top must be either left or right.
}

Pass a block to Sass mixin results in "mixin doesn't accept a content block"

I can't get a mixin to accept a block:
=my-mixin($some-var)
width: $some-var
#content // Is this correct?
+my-mixin(123px)
height: 100px
This results in a "mixin doesn't accept a content block" error. I'm using the current version of Sass. Thanks for help.
syntax is ok with version 3.2 of SASS, double check that
For me the problem was with SASS indentation.
You can't nest another block within a mixin like this:
.button-cta
+button (transparent, tomato)
&:hover
background-color: tomato
color: #fff
instead:
.button-cta
+button (transparent, tomato)
&:hover
background-color: tomato
color: #fff
hover state must not be nested
I was getting this error too. Turned out that somewhere else in my scss I was using #mixin mobile-only instead of #include mobile-only - aka, I was accidentally redefining the mixin later in the code.

Resources