Introducing Sass Modules
Sass just launched a major new feature you might recognize from other languages: a module system. This is a big step forward for @import. one of the most-used Sass-features. While the current @import rule allows you to pull in third-party packages, and split your Sass into manageable “partials,” it has a few limitations: @import is also a CSS feature, and the differences can be confusing If you @import the same file multiple times, it can slow down compilation, cause override conflicts, and generate duplicate output. Everything is in the global namespace, including third-party packages – so my color() function might override your existing color() function, or vice versa. When you use a function like color(). it’s impossible to know exactly where it was defined. Which @import does it come from? Sass package authors (like me) have tried to work around the namespace issues by manually prefixing our variables and functions — but Sass modules are a much more powerful solution. In brief, @import is being replaced with more explicit @use and @forward rules. Over the next few years Sass @import will be deprecated, and then removed. You can still use CSS imports, but they won’t be compiled by Sass. Don’t worry, there’s a migration tool to help you upgrade! Import files with @use @use ‘buttons’; The new @use is similar to @import. but has some notable differences: The file is only imported once, no matter how many times you @use it in a project. Variables, mixins, and functions (what Sass calls “members”) that start with an underscore (_) or hyphen (-) are considered private, and not imported. Members from the used file (buttons.scss in this case) are only made available locally, but not passed along to future imports. Similarly, @extends will only apply up the chain; extending selectors in imported files, but not extending files that import this one. All imported members are namespaced by default. When we @use a file, Sass automatically generates a namespace based on the file name: @use ‘buttons’; // creates a `buttons` namespace @use ‘forms’; // creates a `forms` namespace We now have access to members from both buttons.scss and forms.scss — but that access is not transferred between the imports: forms.scss still has no access to the variables defined in buttons.scss. Because the imported features are namespaced, we have to use a new period-divided syntax to access them: // variables: <namespace>.$variable $btn-color: buttons.$color; $form-border: forms.$input-border; // functions: <namespace>.function() $btn-background: buttons.background(); $form-border: forms.border(); // mixins: @include <namespace>.mixin() @include buttons.submit(); @include forms.input(); We can change or remove the default namespace by adding as <name> to the import: @use ‘buttons’ as *; // the star removes any namespace @use ‘forms’ as ‘f’; $btn-color: $color; // buttons.$color without a namespace $form-border: f.$input-border; // forms.$input-border with a custom namespace Using as * adds a module to the root namespace, so no prefix is required, but those members are still locally scoped to the current document. Import built-in Sass modules Internal Sass features have also moved into the module system, so we have complete control over the global namespace. There are several built-in modules — math, color, string, list, map, selector, and meta — which have to be imported explicitly in a file before they are used: @use ‘sass:math’; $half: math.percentage(1/2); Sass modules can also be imported to the global namespace: @use ‘sass:math’ as *; $half: percentage(1/2); Internal functions that already had prefixed names, like map-get or str-index. can be used without duplicating that prefix: @use ‘sass:map’; @use ‘sass:string’; $map-get: map.get((‘key’: ‘value’), ‘key’); $str-index: string.index(‘string’, ‘i’); You can find a full list of built-in modules, functions, and…
Like to keep reading?
This article first appeared on css-tricks.com. If you'd like to keep reading, follow the white rabbit.