I have been working with CSS over the years and love it. I have tried various libraries, toolsets like Bourbon (yes, I am that old), and pre-processors like SASS & Less.
Talking about the CSS pre-processors, lately, I was reading about how node-sass will be deprecated soon, and hence, I checked out the dart-sass documentation.
While reading the documentation, I came across an exciting way of importing the SASS files instead of the traditional way of importing the stylesheets using @import statements.
Yes, just like me, you must have thought the same, that what would be better than using @import statements to import the Stylesheets? Well, dart-sass has to offer two new ways of importing them, namely @use and @forward.
Important: Make sure that you have sass installed, and NOT node-sass
Before we try out the new ways to handle the imports using SCSS, we will first define the Files & the Folder structure.
/project
|-- /vars
|---- _colors.scss
|---- _fonts.scss
|-- app.scss
Let’s try out @use
As you know, we can import the files in SCSS using the @import statement. @use pretty much does the same thing, EXCEPT, that it namespaces your variables, thus, preventing the name collisions.
Starting with some simple code here, we will create a file to hold some variables, and then we will require this in our App file.
// _colors.scss
$h1-color: #f00;
$component-color: #0f0;
And then, we will use @import first, in app.scss to test if everything’s in place.
// app.scss
@import 'vars/colors';
h1 {
color: $h1-color;
}
The above should work as expected. Now, without any further ado, we will go ahead and modify the @import statement to @use.
// app.scss
@use 'vars/colors';
h1 {
color: $h1-color;
}
@use helps you namespace your SCSS files
Now that we are using @use it to import the stylesheet will result in an error. Reason? Remember, in the beginning; I mentioned that @use helps us namespace our variable names, thus preventing collisions if any. Hence, we need to modify the above code like:
// app.scss
@use 'vars/colors';
h1 {
color: colors.$h1-color;
}
Viola, the SCSS is now compiled. All we did was, prefixed the @h1-color variable using colors that are nothing but the file name.
@use(ing) Alias
Now, what if we have a file name of _colors_for_theme_blue.scss (not pretty at all but assuming some worst-case scenario), and then writing it like colors_for_theme_blue.$h1-color will be super annoying.
To cut short the filename, you can use the keyword as that will help you create an alias for the _colors.scss file. E.g.:
// app.scss
@use 'vars/colors' as c;
h1 {
color: c.$h1-color; //note that now we are using only c here
}
as helps you define an alias for the file name you are importing using the @use keyword.
Alternatively, you could also use an * as an alias which will result in behavior similar to the one which @import provides. For, e.g.:
// app.scss
@use 'vars/colors' as *;
h1 {
color: $h1-color;
/* note, you need not have to specify colors prefix before you use $h1-color variable. */
}
I would not recommend you doing the above since it misses the point in having name-spaced variables.
Scope using @use vs. @import
There is another benefit of using @use instead of the @import is the scope. When we use @import statement to import certain files, then this file has access to the declared variables before importing the component file. For, e.g.: (we will introduce a new folder here, say components, and create a sample component file like _my_component.scss)
/project
|-- /components
|---- _my_component.scss
|-- /vars
|---- _colors.scss
|---- _fonts.scss
|-- app.scss
Here, we will try to import _my_component.scss using the @import statement and then using the @use and see the difference.
// app.scss
// using @import
@import 'vars/colors';
@import 'components/_my_component';
h1 {
color: $h1-color;
}
And here we have some code in the _my_component.scss file
// _my_component.scss
.my-component {
color: $component-color;
}
In the above example, the code will be compiled as expected, where even the _my_component.scss has access to the variables declared in the app.scss file, create issues as the codebase grows.
The above results in the following compiled CSS
// compiled output
.my-component {
color: #0f0;
}
h1 {
color: #aaa;
}
If you notice, the .my-component can access the colors defined in a separate file imported before importing the component file.
If we make use of @use instead of the @import, here’s what will happen.
// app.scss
// using @use
@use 'vars/colors' as c;
@use 'components/_my_component';
h1 {
color: c.$h1-color;
}
Tweaking the component file a bit:
// _my_component.scss
.my-component {
color: c.$component-color;
}
The above will result in an error:
Error: There is no module with the namespace “c”.
Say if we remove the namespace, which is c, then the error which we will get is
Error: Undefined variable.
Hence, using @use helps you control the scope of your variables instead of @import which makes the variables globally accessible to the files which are imported post the variable file. Still, if you wish to use the same variable file in the _my_components.scss then you need to require the variables in the components file as well.
// _my_component.scss
@use '../vars/colors' as c; //note the filepath here,have added ../
.my-component {
color: c.$component-color;
}
.my-component {
color: c.$component-color;
}
Using @forward
You must be having multiple helper files, say for variables, mixins, fonts, extends, etc. Having to require them in every single file (since using @use, it will not make these files globally available) required in components and other SASS files will be tedious.
Hence, we could use @forward which acts like a pipe. It takes many files and makes the contents of those files available where this file is required. Let us take an example:
/project
|-- /components
|---- _my_component.scss
|-- /vars
|---- _colors.scss
|---- _fonts.scss
|---- helpers.scss
/* we will add this file here, which will contain forwards of _colors.scss & _fonts.scss */
|-- app.scss
And now we will add the @forward to the helpers.scss file.
// helpers.scss
@forward 'colors';
@forward 'fonts';
Now instead of requiring every helper file in app.scss you would instead import the helpers.scss which will make the other files like _colors.scss & _fonts.scss available.
// app.scss
@use "vars/helpers";
@use "components/my_component";
h1 {
color: helpers.$h1-color;
/* note that you need to modify the namespace, or use * and you could simply use $h1-color */
}
and subsequently, we can now modify the _my_component.scss file as well.
// _my_component.scss
@use "../vars/helpers";
.my-component {
color: helpers.$component-color;
}
Using @forward will make it simple for you to import multiple files without specifying them separately and instead use the common file.
The above is a basic intro for using @use and @forward. There is much more to it, like Private Members, Index Files, Visibility Control, etc. I’ll be attaching a few references where you could refer to these features in detail.