How to use a SASS $variable across multiple pages using @use?
Asked Answered
H

2

13

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?

Hemelytron answered 1/2, 2020 at 0:29 Comment(3)
Does it work if you write it like: ‚color: global.$black;‘ ? Reading the docs it looks to me you have to namespace the vars dependingbon the filename containing the varsPageantry
@Pageantry No, when I change the code inside of _header.scss to color: global.$black; and try to compile I get Error: There is no module with the namespace "global". Adding an underscore before global doesn't work either.Hemelytron
Ok, but have a look here - that should help somehow: sass-lang.com/documentation/at-rules/use there is more about namespacing when using @usePageantry
D
20

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.

Decurrent answered 1/2, 2020 at 0:52 Comment(3)
This seems inefficient compared to import. Why do I have to put Use "global"; at the top of every module if I'm already loading it at the top of my main.scss? Furthermore, why must I specify the namespaces once 'global' is loaded in them? With Import, all I have to do is Import 'global'; at the top of my main.scss, and then all of the subsequent imports have access to the variables defined in _global.scss, whereas with Use I have to load _global.scss at the top of every other partial, and then additionally specify the namespace in those partials.. Import seems superior in this respect.Hemelytron
I understand your point. I've updated my answer with more information to address your concerns!Decurrent
Nice and detailed explanationPageantry
S
1

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"

SCSS VARIABLE

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". enter image description here

Boom! You done

I hope this post really helps you! Enjoy and happy coding! : )

Snobbish answered 24/9, 2022 at 15:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.