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 NOTnode-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 helper.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.
Top comments (3)
Good article! I was just wondering if it would be possible to conserve the namespaces of the individual files when using
@forward
?Good read!
Only thing i would change is to rename the helpers file into _index.scss
if you then @use from vars you don't have to specify the name which makes it imo a little more semantic
thank you, it very clear, concise and useful