How to fix an Undefined Variable Error in SCSS? - css

I've run into an Undefined Variable Error writing SCSS.
My file structure is sound (I believe), because it compiles the rest of the files as it should into main.scss.
I'm using #use instead of #import.
color: #f22437 vs color: $clr-primary
Error: Undefined variable.
╷
54 │ color: $clr-primary;
│ ^^^^^^^^^^^^
╵
scss/layouts/_navigation.scss 54:10 #use
scss/layouts/_all-layouts.scss 11:1 #use
scss/main.scss 7:1 root stylesheet
The files that are in question.
File Structure
UPDATE I changed all #use to #import, and it worked.
Please me understand why this worked and how I can #use instead of #import. Seems like an issue related to SASS, but I could still be at fault. For now I'll 'hack' it.

I had the same issue and after reading the docs, they say this:
Members (variables, functions, and mixins) loaded with #use are only visible in the stylesheet that loads them. Other stylesheets will need to write their own #use rules if they also want to access them. This helps make it easy to figure out exactly where each member is coming from. If you want to load members from many files at once, you can use the forward rule to forward them all from one shared file.
Solutions:
Preferred solution: Use #use in the styles file that is going to use the variables and not in the global one and call the variable like:
namespace.variablename
Use the forward rule as docs say
Use #import instead of #use but according to this, "Sass will gradually phase it out over the next few years, and eventually remove it from the language entirely"

First:
#use is currently only available for Dart Sass and not LibSass or Ruby Sass. See https://sass-lang.com/documentation/at-rules/use for the latest compatibility
Second:
_variables.scss
$text-colour: #262626;
_otherFile.scss
#use 'variables';
body {
color: variables.$text-colour;
}
Check #whiscode answer here: https://stackoverflow.com/a/61500282/2470685

This works for me
`#use 'variables';
body {
color: variables.$text-colour;
}`

Related

Accessing custom properties in SASS modules

So, let's say I have a SASS module _module.scss that declares some css variables aka custom properties. When I now load this module in another SASS styleshee, let's call it main.scss, I have access to all SASS-variables, mixins and also rules, but not the custom properties inside of it? Am I missing something?
Example files:
//_module.scss
:root {
--some-variable: red;
}
// main.scss
#use 'module';
div {
background-color: var(module.--some-variable); // won't work, private property because of leading '-'
background-color: module.var(--some-variable); // won't work, would have been horrible syntax as well
}
I could use #import but that is discouraged and deprecated (see SASS Documentation). I've tried including the variables in a pure css file module.css, which compiled but didn't declare any custom properties at runtime as it directly translates the #use 'module' from my SASS file to the exact same in CSS - which browsers don't understand obviously. It should just more or less copy the content of a pure css file but it doesn't. Sure, I could try writing mixins in my modules that set the variables but that's just a workaround.
Am I missing something? Do I really need to write a mixin, that sets the variables and needs to be loaded? This makes the use of custom properties within modules pretty cumbersome.
EDIT
Forgot to mention, that background-color: var(--some-variable) doesn't work either even though it should according to the documentation, since rules should just be applied directly without scoping.
Ugh. The issue is most definitely the fact that my VS Code extension uses LibSass and not Dart Sass. Therefore #use is not yet supported in most environments. The documentation should most definitely be more explicit about this especially when warning about the use of #import.
Since I know it works with #import the issue is resolved though I'd love to see the module system being included in LibSass as well.
tl;dr
Do no use #use if you're not absolutely certain that you use Dart Sass!

How to use a SASS $variable across multiple pages using #use?

I am trying to use a variable that was declared on one partial inside of another partial, both of which will be loaded into the main.scss file using #use, which will then be compiled into css.
Here's the setup:
style.scss
#use './global';
#use './header';
_global.scss
$black: #262626;
_header.scss
header {
color: $black
}
When I run try to compile style.css, I get this error:
C:\xampp\htdocs\Site\styles>sass style.scss:style.css
Error: Undefined variable.
╷
3 │ color: $black;
│ ^^^^^^
╵
_header.scss 3:10 #use
style.scss 2:1 root stylesheet
It works fine if I use #import instead of #use in my main style.scss, but the developers of Sass advise not to use #import because it is going to be deprecated eventually.
They say to use #use instead, and that #use has many advantages over #import, one of which being that all instances of #use can be loaded at the same time. I think this is what's causing the issue, since _global.scss doesn't get to load before the pages which rely on $black defined in _global.scss, so those pages load without $black defined.
Any ideas?
From the Sass Lang documentation for #use:
Members (variables, functions, and mixins) loaded with #use are only visible in the stylesheet that loads them
Think along the lines of import in JavaScript rather than the traditional global scope of using Sass's #import syntax.
I think you may attempting to do something like the following:
global.scss
$black: #000;
header.scss
#use "global";
.header {
color: global.$black;
}
button.scss
#use "global";
.button {
color: global.$black;
}
index.scss
#use './button';
#use './header';
This might be a bit more verbose/cumbersome than what you're traditionally accustomed to with Sass, but it certainly has tremendous benefits in the long run - especially if you're a framework or library author, or even consuming an existing one with your own modifications on top.
A big pain point with Sass that many developers (myself included) have had to deal with is variables declared at root scope and, indeed, all Sass functions are globally available. While this is convenient at times, it also leads to a large number of collisions when integrating externally-authored libraries or working in larger companies with many distributed teams.
For example: if I'm using Bootstrap as the basis of my website's style, and I load in an additional library that defines its own gradient-bg mixin (also defined in TWBS), which mixin is the correct one to use? Load order has an impact on this, and you may not see any issues, but you may also see huge discrepancies in your expected output which now requires you to dig deep into those libraries to see what's happening.
The #use rule solves this by ensuring that module members (variables, functions, and mixins) are only accessible inside the stylesheets that load them. It also has an added benefit of allowing you to further simplify member names - since they're scoped to a namespace (the last component of the module’s URL) you can go ahead and just define $padding or #mixin flex {}.
Organisation
Ultimately, this can help you to logically organise your own code into a structure that makes it easier to maintain your code going forward (for your colleagues as much as yourself). There's nothing wrong with being explicit in what your code does, especially since you want it to be reliable and predictable when you plan on making updates in the future.
Personally, I'm quite fond of a structure not dissimilar to:
styles
|-- global
| |-- functions.scss
| |-- spacing.scss
| |-- typography.scss
| |-- ...etc...
|-- component
| |-- button.scss
| |-- header.scss
| |-- ...etc...
And in a situation like this, your code would look something like:
button.scss
#use "global/spacing.scss";
#use "global/typography.scss";
.button {
font-size: typography.$standard;
padding: spacing.$standard;
}
Global namespacing
Of course, it all comes down to personal preference and I understand that some people may not be fans of the new namespacing. This can be mitigated somewhat, or ignored entirely.
With #use
When using the new Sass module system, you can't put items in the global namespace when using #use. You can, however, load a module without a namespace by using the #use "path/to/file" as *; syntax. This would allow you to directly access members without needing the <namespace>.<member> syntax.
With #import
If this still doesn't suit your needs, you can of course continue to use the #import rule for the foreseeable future. The team intend to support #import up until some time around October 2022. At this point, you can always pin your version of Sass to the last version that supports #import.
Hello Guys!!
So I've been researching on how to use my SCSS variable in my index style across other style file in my code and I finally figured it out : ). Kindly follow this step carefully and trust me you would get it figured out also
1. Have a index or main file where all your variables are declared in just like this (for me, my file name was "index.scss"
2. After step one is completed now go to any other style file you want to add the variables to. (for me i had a file called "register.scss")
3. import the file where you declared all your scss variable (mine was "index.scss") and do not include the "scss" extension see sample below
NB: You can decide to import it as an alias or without any, if you don't import it as an alias (for me i imported it as 'v') you would have to use the "file_name.variable_name" to use the variable in other file. so as for me i just used "v.$variable_name" since i imported the file as an alias "v".
Boom! You done
I hope this post really helps you! Enjoy and happy coding! : )

How can I import a .scss module within my main.scss with #use

So, let's assume I have the following situation: I have 2 .scss files.
One with a variable, and one that will be actually translated into .css for my webpage, where I want to access to said variable.
vars.scss
$my_color: red;
main.scss
#use 'vars'
body {
color: $my_color;
}
What I am trying to do is to access the variable defined in vars.css and use it.
The reference is correct since if I use #import instead of #use, everything works
I've also tried to reference to the variable with vars.$my_color as was suggested in the documentation, but I keep getting a "undefined variable" error.
Well, if you read the documentation then in the ⚠️ Heads up! section, where the undesirability of further use of the #import rule is written, below, you can read the following:
The #import rule has a number of serious problems:
#import makes all variables, mixins, and functions globally available.
Therefore, the #use rule makes them inaccessible. Which is what you observe in action.
I think to achieve the desired result, combination of #use and #forward rules should be used.
But I am using VSCode Live Sass Compiler (Maybe you're using it too?) where #use is not supported so I couldn't give you the exact howto.
Hope this clarifies a lot.

Variables are global with SASS but not SCSS

I have my application.css.scss set like this:
#import "base/variables";
#import "./application/application";
Like the documentation says I am not using Sprockets' directives (require, require_tree, and require_self) at all so I expect my variables defined inside of base/_variables.scss to be globals and available for my /application/application.scss file but it's not the case:
#content {
margin-top: $big;
}
Will return the error Undefined variable: "$big".
I've tried the same thing with SASS by naming by files application.css.sass and /application/application.sass and while the variables now do seems to be globals I'll like to keep using the SCSS syntax, I've tried that by setting config.sass.preferred_syntax = :scss but I'm still being asked for Sass.
Of course I could just import my variables file everytime I need my variables but that would go against the DRY principle.
Is that possible to use the SCSS syntax while making my variables globally available? What am I missing here? Thanks in advance.
What versions of sprockets, rails and sass-rails gems do you have? There were some problems around undefined variables, maybe try to bump up sass-rails and sprockets (if possible).
My application/application.scss was being precompiled (in assets.rb) by an old rule using a wildcard, which I missed, it's now working correctly.

Variable Name Error "is undefined" even though "variables.less" imported

I started using LESS today. But it's kinda weird. This code does not work. I get an error:
! Variable Name Error: #linkColor in a is undefined.
My bootstrap:
#import "variables.less";
#import "normalize.less";
variables.less:
#linkColor: #08c;
#linkColorHover: darken(#linkColor, 15%);
normalize.less:
a {
color: #linkColor;
}
a:visited {
color: #linkColor;
}
a:hover {
color: #linkColorHover;
}
When I make an
#import "variables.less"
in the normalize.less file, everything works fine.
Thanks for your help :)
This other question ultimately led me to the right answer.
It looks like the LESS compiler is silently failing if files are encoded with a BOM. (That's a Byte Order Mark for those not familiar with the term.) This is the default setting in some editors, such as Visual Studio.
The compiler barfs up an error on the BOM if it's in your root file, but seems to fail silently for #import-ed files.
Try saving your files as UTF-8 without a BOM, and see if that solves your problem.
This error can also occur via bad imports in the files you're importing.
I also encountered this issue, when using multiple layers of import, and the 'lessc' compiler from Node.js:
The original file imported a file (which we will call 'child')
The child file imported a file (which we will call 'grandchild')
The grandchild was imported
I attempted to compile the original file, and received the same 'undefined variable' behavior. I could see the variable was defined in the child and the syntax lookedcorrect.
No prior errors were displayed.
The problem turned out that the child was not importing the grandchild properly. Ie,
#import grandchild.less
rather than:
#import "grandchild.less";
Fixing the child importing the grandchild made the original see the variables defined in the child.
This seems like a bug in less - ie, the bad import should show up in the 'lessc' output, so one day it will probably be fixed. Until then, I hope this helps.
There may be another possible root cause.
Here is my original Gruntfile.js:
less: {
compile: {
files: {
'css/less.css': 'less/**/*.less'
}
}
},
The wildcard makes LESS compiler compile all .less files under that folder and merge all results into one CSS. And I got errors running grunt less:compile:
NameError: .transition is undefined in less/core/html.less on line 38, column 3
Once I changed 'less/**/*.less' into 'less/css.less', the compilation succeeds.
I encountered the same problem using Winless compiler.
Some of the .less files i was importing into master.less were empty. when i removed these from the list of imported files my variables were recognized!
To help any others that may come across this not want duplicate CSS generated from multiple imports, you have two options.
Either #import-once the variables / mixins files you need in each file you need to use them in.
Use #import-once "filename.less"; to prevent duplicates.
Upgrade to LESS > 1.4.0, when it arrives; From the less website:
"The statement #import acts differently before and after 1.4.0. It acts as #import-multiple in all older versions and as #import-once in all less.js versions after 1.4.0."
You can also get this error if you are trying to import the file twice (not a good idea) and the first import is before your variables referenced in your.less file have been loaded
Note: I'm using django compress
in index.html i had:
{% compress css %}
<link href="{{ STATIC_URL }}less/timepicker.less" rel="stylesheet" type="text/less">
<link href="{{ STATIC_URL }}less/style.less" rel="stylesheet" type="text/less">
{% endcompress %}
then in styles.less i had
...
#import "timepick.less";
I think it is because of which master less file you are compiling. Likewise
If you have Less/Project_name/project.less and in this project.less you import the variable less and all the other files which has in the directory.
You just have to compile project.less into your css, not all less files. If you try to compile project.less and variables.less at a time you will have this error. And you can avoid redundant declaration of importing the variable less files
I would use the nested rules in the normalize.less :
a {
color: #linkColor;
&:visited {color: #linkColor;}
&:hover {color: #linkColorHover;}
}
And in the #import, you don't need to use the ".less", it's optional :
#import "variables";
#import "normalize";
I don't know if this can help...
One other weirdly specific situation in which this occurs: if you're using .NET and dotless, the compiler will choke on nested media queries with variable specifiers. If you have code like this:
#media (min-width: #aVariable) {
.some-class{
margin: 10px;
#media (min-width: #anotherVariable) {
margin: 20px;
}
}
... then dotless will tell you that it can't find the definition for #anotherVariable, even if it's used three lines above.
For me its happened when using #Import-once and nothing help.
but with #Import its worked.
as i read in the last version of the Less the Import will work as Import-once.

Resources