Home

Sass Blog

  • 
  • 
  • The Module System is Launched

    Posted by Natalie Weizenbaum 2 months ago

    The Sass team has known for years that the @import rule, one of the earliest additions to Sass, wasn't as good as we wanted it. It caused a litany of problems for our users:

    • It was next to impossible to figure out where a given variable, mixin, or function (collectively called "members") was originally defined, since anything defined in one stylesheet was available to all stylesheets that were imported after it.

    • Even if you chose to explicitly import every stylesheet that defined members you used, you'd end up with duplicate CSS and strange side-effects, because stylesheets were reloaded from scratch every time they were imported.

    • It wasn't safe to use terse and simple names because there was always a possibility that some other stylesheet elsewhere in your application would use the same name and mess up your logic. To be safe users had to manually add long, awkward namespaces to everything they defined.

    • Library authors had no way to ensure that their private helpers wouldn't be accessed by downstream users, causing confusion and backwards-compatibility headaches.

    • The @extend rule could affect any selector anywhere in the stylesheet, not just those that its author explicitly chose to extend.

    We also knew that any replacement we wanted to introduce would have to be designed and developed with the utmost care to ensure it would provide a rock-solid foundation for the future of Sass development. Over the past few years, we've discussed, designed, and developed a brand-new module system that solves these problems and more, and today we're excited to announce that it's available in Dart Sass 1.23.0.

    Please note that the module system is fully backwards-compatible. No existing features have been removed or deprecated, and your current Sass stylesheets will keep working just as they always have. We designed the module system to be fully interoperable with @import to make it easy for stylesheet authors to migrate to it incrementally. We do plan to eventually get rid of @import, but not until long after everyone's had a chance to migrate.

    @use, the Heart of the Module System

    The @use rule is the primary replacement for @import: it makes CSS, variables, mixins, and functions from another stylesheet accessible in the current stylesheet. By default, variables, mixins, and functions are available in a namespace based on the basename of the URL.

    @use "bootstrap";
    
    .element {
      background-color: bootstrap.$body-bg;
      @include bootstrap.float-left;
    }
    

    In addition to namespacing, there are a few important differences between @use and @import:

    • @use only executes a stylesheet and includes its CSS once, no matter how many times that stylesheet is used.
    • @use only makes names available in the current stylesheet, as opposed to globally.
    • Members whose names begin with - or _ are private to the current stylesheet with @use.
    • If a stylesheet includes @extend, that extension is only applied to stylesheets it imports, not stylesheets that import it.

    Note that placeholder selectors are not namespaced, but they do respect privacy.

    Controlling Namespaces

    Although a @use rule's default namespace is determined by the basename of its URL, it can also be set explicitly using as.

    @use "bootstrap" as b;
    
    .element {
      @include b.float-left;
    }
    

    The special construct as * can also be used to include everything in the top-level namespace. Note that if multiple modules expose members with the same name and are used with as *, Sass will produce an error.

    @use "bootstrap" as *;
    
    .element {
      @include float-left;
    }
    
    Configuring Libraries

    With @import, libraries are often configured by setting global variables that override !default variables defined by those libraries. Because variables are no longer global with @use, it supports a more explicit way of configuring libraries: the with clause.

    // bootstrap.scss
    $paragraph-margin-bottom: 1rem !default;
    
    p {
      margin-top: 0;
      margin-bottom: $paragraph-margin-bottom;
    }
    
    @use "bootstrap" with (
    
      $paragraph-margin-bottom: 1.2rem
    
    );
    

    This sets bootstrap's $paragraph-margin-bottom variable to 1.2rem before evaluating it. The with clause only allows variables defined in (or forwarded by) the module being imported, and only if they're defined with !default, so users are protected against typos.

    @forward, for Library Authors

    The @forward rule includes another module's variables, mixins, and functions as part of the API exposed by the current module, without making them visible to code within the current module. It allows library authors to be able to split up their library among many different source files without sacrificing locality within those files. Unlike @use, forward doesn't add any namespaces to names.

    // bootstrap.scss
    @forward "functions";
    @forward "variables";
    @forward "mixins";
    

    Visibility Controls

    A @forward rule can choose to show only specific names:

    @forward "functions" show color-yiq;
    

    It can also hide names that are intended to be library-private:

    @forward "functions" hide assert-ascending;
    

    Extra Prefixing

    If you forward a child module through an all-in-one module, you may want to add some manual namespacing to that module. You can do what with the as clause, which adds a prefix to every member name that's forwarded:

    // material/_index.scss
    @forward "theme" as theme-*;
    

    This way users can use the all-in-one module with well-scoped names for theme variables:

    @use "material" with ($theme-primary: blue);
    

    or they can use the child module with simpler names:

    @use "material/theme" with ($primary: blue);
    

    Built-In Modules

    The new module system also adds built-in modules (sass:math, sass:color, sass:string, sass:list, sass:map, sass:selector, and sass:meta) to hold all the existing built-in Sass functions. Because these modules will (typically) be imported with a namespace, it's now much easier to use Sass functions without running into conflicts with plain CSS functions.

    This in turn makes it much safer for Sass to add new functions. We expect to add a number of convenience functions to these modules in the future.

    Renamed Functions

    Some functions have different names in the built-in modules than they did as global functions. Built-in functions that already had manual namespaces, like map-get(), have those namespaces removed in the built-in modules so you can just write map.get(). Similarly, adjust-color(), scale-color(), and change-color() are now color.adjust(), color.scale(), and color.change().

    We've also taken this opportunity to change a couple confusing old function names. unitless() is now math.is-unitless(), and comparable() is now math.compatible().

    Removed Functions

    Sass's shorthand color functions lighten(), darken(), saturate(), desaturate(), opacify(), fade-in(), transparentize(), and fade-out() all had very unintuitive behavior. Rather than scaling their associated attributes fluidly, they just incremented them by a static amount, so that lighten($color, 20%) would return white for a color with 85% lightness rather than returning a color with 88% lightness (20% closer to full white).

    To help set us on the path towards fixing this, these functions (along with adjust-hue()) aren't included in the new built-in modules. You can still get the same effect by calling color.adjust()—for example, lighten($color, $amount) is equivalent to color.adjust($color, $lightness: $amount)—but we recommend trying to use color.scale() instead if possible because of how much more intuitive it is.

    At some point in the future, we plan to add color.lighten() and similar functions as shorthands for color.scale().

    meta.load-css()

    The new module system comes with a new built-in mixin, meta.load-css($url, $with: ()). This mixin dynamically loads the module with the given URL and includes its CSS (although its functions, variables, and mixins are not made available). This is a replacement for nested imports, and it helps address some use-cases of dynamic imports without many of the problems that would arise if new members could be loaded dynamically.

    @import Compatibility

    The Sass ecosystem won't switch to @use overnight, so in the meantime it needs to interoperate well with @import. This is supported in both directions:

    • When a file that contains @imports is @used, everything in its global namespace is treated as a single module. This module's members are then referred to using its namespace as normal.

    • When a file that contains @uses is @imported, everything in its public API is added to the importing stylesheet's global scope. This allows a library to control what specific names it exports, even for users who @import it rather than @use it.

    In order to allow libraries to maintain their existing @import-oriented API, with explicit namespacing where necessary, this proposal also adds support for files that are only visible to @import, not to @use. They're written "file.import.scss", and imported when the user writes @import "file".

    Automatic Migration

    Concurrent with the launch of the new module system, we're launching a new automated Sass migrator. This tool makes it easy to migrate most stylesheets to use the new module system automatically. Follow the instructions on the Sass website to install it, then run it on your application:

    $ sass-migrator module --migrate-deps <path/to/style.scss>
    

    The --migrate-deps flag tells the migrator to migrate not only the file you pass, but anything it imports as well. The migrator will automatically pick up files imported through Webpack's node_modules syntax, but you can also pass explicit load paths with the --load-paths flag.

    If you want the migrator to tell you what changes it would make without actually making them, pass both the --dry-run flag and the --verbose flag to tell it to just print out the changes it would make without saving them to disk.

    Migrating a Library

    If you want to migrate a Sass library that's meant for downstream users to load and use, run:

    $ sass-migrator module --migrate-deps --forward=all <path/to/index.scss>
    

    The --forward flag tells the migrator to add @forward rules so that users can still load all the mixins, variables, and functions your library defines with a single @use.

    If you added a manual namespace to your library to avoid name conflicts, the migrator will remove it for you if you pass the --remove-prefix flag. You can even choose to only forward members that originally had that prefix by passing --forward=prefixed.

    Filing Issues

    The migration tool is brand new, so it may still have some rough edges. If you run into any problems, please don't hesitate to file an issue on GitHub!

    Try It Now!

    The module system is available as part of Dart Sass 1.23.0. You can install it right now using:

    $ npm install -g sass
    

    Alternately, check out the installation page for all the different ways it can be installed!

    Future Plans

    The Sass team wants to allow for a large amount of time when @use and @import can coexist, to help the ecosystem smoothly migrate to the new system. However, doing away with @import entirely is the ultimate goal for simplicity, performance, and CSS compatibility. As such, we plan to gradually turn down support for @import on the following timeline:

    • One year after both Dart Sass and LibSass have launched support for the module system or two years after Dart Sass launches support for the module system, whichever comes sooner (1 October 2021 at latest), we will deprecate @import as well as global core library function calls that could be made through modules.

    • One year after this deprecation goes into effect (1 October 2022 at latest), we will drop support for @import and most global functions entirely. This will involve a major version release for all implementations.

    This means that there will be at least two full years when @import and @use are both usable at once, and likely closer to three years in practice.

  • Module System Preview

    Posted by Natalie Weizenbaum 3 months ago

    Exciting news, Sass fans! After a year of development and some iteration on the spec, we're ready to launch a beta preview of the new Sass module system! We may still make a few last-minute tweaks based on user feedback, so don't go using itin production just yet, but please do take this opportunity to play around with it and let us know what you think.

    Installing the Preview

    The preview release is available on all the normal distribution channels as version 1.23.0-module.beta.1. You can download it from the GitHub release page, or install it using one of the following commands (depending on your preferred installation channel):

    $ npm install --save-dev sass@1.23.0-module.beta.1
    
    $ npm install -g sass@1.23.0-module.beta.1
    
    $ brew install sass/sass/sass@1.23.0-module.beta.1
    
    $ choco install sass --version 1.23.0.modulebeta-1
    
    $ pub global activate sass 1.23.0-module.beta.1
    

    Note that 1.23.0 may not actually be the final version number for the stable module system release, it's just the next minor version number in Dart Sass's release series.

    How to Use the Module System

    The original summary of the module system is still a great way to learn how it works. You can also check out the official proposal for a much more detailed dive into its behavior.

    Sending Feedback

    If you have opinions on the module system, please file an issue on GitHub or just tweet at @SassCSS. We'll take anything from "it looks awesome" to "it looks awful", although the more specific you can be the more information we have to work with!

  • Request for Comments: Forward Slash as Separator

    Posted by Natalie Weizenbaum 7 months ago

    Early on in Sass's history, the decision was made to use / as a division
    operator, since that was (and is) by far the most common representation across programming languages. The / character was used in very few plain CSS properties, and for those it was an optional shorthand. So Sass defined a set of heuristics that defined when / would be rendered as a literal slash versus treated as an operator.

    For a long time, these heuristics worked pretty well. In recent years, however, new additions to CSS such as CSS Grid and CSS Color Level 4 have been using / as a separator increasingly often. Using the same character for both division and slash-separation is becoming more and more annoying to users, and will likely eventually become untenable.

    As such, we're planning to redefine / to be only a separator. Rather than creating an unquoted string (as it currently does when at least one operand isn't a number), it will create a list with a new slash separator. For example, 1 / 2 / 3 will be a three-element slash-separated list. Division will instead be written as a function, divide() (or math.div() in the new module system).

    Rollout

    This is a major breaking change to existing Sass semantics, so we'll roll it out in a three-stage process:

    1. The first stage won't introduce any breaking changes. It will:

      • Add a divide() function which will work exactly like the / operator does today, except that it will produce deprecation warnings for any non-number arguments.
      • Add slash-separated lists to Sass's object models, without a literal syntax for creating them. That will come later, since it would otherwise be a breaking change.
      • Add a slash-list() function that will create slash-separated lists.
      • Produce deprecation warnings for all / operations that are interpreted as division.
    2. The second stage will be a breaking change. It will:

      • Make / exclusively a list separator.
      • Make divide() throw errors for non-number arguments.
      • Deprecate the slash-list() function, since it will now be redundant.
    3. The third stage will just remove the slash-list() function. This is not a priority, and will be delayed until the next major version release.

    Giving Feedback

    If you want more details on exactly how the proposed behavior will work, head over to the Sass language repo and read the full proposal. You can skip the Background and Summary sections, since they're included above. Be aware, though, that it's written to be a specification; it's a great for figuring out how exactly an edge case should work, but it's not as conversational as the sections quoted above.

    If you have any issues with the proposal as written, or if it doesn't cover a use-case that's important to you, please bring that up in the Sass language issue tracker. We'll be leaving it open for discussion for at least two weeks before we mark the proposal as "accepted" and move on to the implementation phase.

    Please be aware, though, that while we welcome community feedback, the design of Sass is ultimately in the hands of the language team. We'll absolutely consider the perspectives and use-cases of users who speak up, but it's also our job to consider all the users who are new to Sass or even to CSS and who don't yet know to read blogs or comment on issue trackers. Remember that our careful decision-making made Sass what it is today, and have patience with us if we don't make the decisions you would have!

  • Brand New Sass Docs

    Posted by Natalie Weizenbaum 8 months ago

    I'm excited to announce the launch of a full rewrite and redesign of the Sass documentation, going live today after eight months of work by Jina Anne and myself! Jina, the lead of Team Sass Design, is responsible for the layout and visual design of the new documentation. She made everything gorgeous and readable. I wrote all the text, so if you see a typo I'm the one to blame.

    A preview of the function documentation page.

    In addition to reorganizing and rewriting all the documentation, we've added a special example widget that makes it easy to see how Sass stylesheets translate into CSS. It has tabs for both SCSS and the indented syntax, so you can use whichever you prefer, or switch between them to see the difference.

    The example widget.

    The Sass function documentation is included in the rewrite. Functions are now organized into easy-to-understand sections, and Jina designed a super readable layout for them.

    The round() function.

    Best of all, the new documentation has full-text search courtesy of our friends at Algolia. You can search for features, function names, or anything else you want to learn more about and find it in an instant.

    Please take a look and enjoy! And if you find any issues, don't hesitate to file them so we can keep making the website better and better.

  • Ruby Sass Has Reached End-Of-Life

    Posted by Natalie Weizenbaum 8 months ago

    One year has passed since we announced the deprecation of Ruby Sass, and it has now officially reached its end-of-life. We will release one final version of the Ruby Sass gem that will print a warning indicating that it's no longer receiving updates, and then archive the GitHub repository.

    We will then merge the sass/language repo into the sass/sass repo. This means that anyone still depending on Ruby Sass from github.com/sass/sass will break. Going forward, the sass/sass repo will be the location for working on the language specs, and will not contain any code. The sass/language repo will just include links pointing to sass/sass.

    Migrating Away

    If you haven't migrated away from Ruby Sass yet, now is the time. The best way to do that depends on how you use Ruby Sass today.

    If you use Ruby Sass as a command-line tool, the easiest way to migrate is to install Dart Sass as a command-line tool. It supports a similar interface to Ruby Sass, and you can run sass --help for a full explanation of its capabilities.

    If you use Ruby Sass as a plugin for a Ruby web app, particularly if you define your own Sass functions in Ruby, the sassc gem provides access to LibSass from Ruby with a very similar API to Ruby Sass. In most cases, you can just replace the Sass module with the SassC module and your code will continue to work.

    If you're using Rails, we particularly recommend using the sassc-rails gem, which wraps up the sassc gem and integrates it smoothly into the asset pipeline. Most of the time you won't even need to change any of your code.

    Farewell, Ruby Sass!

    On a personal note, I started writing Ruby Sass in 2006 when I was just a college kid coding in between homework assignments. I've worked on it (with varying degrees of focus) continuously for the last 13 years, and I expect it'll take me a long time to match that record with any other codebase. I'm glad to see the language moving forward, but at the same time I'll miss Ruby Sass terribly.

    I also want to take this opportunity to thank our users, especially those in the Ruby community in which Sass was born, for appreciating the language we created and evangelizing it so widely. Sass has an incredible userbase, and I've been so proud to see how large and diverse it's grown over the years. Let's keep it up as we move into a new era of Sass!

  • Request For Comments: Module System

    Posted by Natalie Weizenbaum about 1 year ago

    Many of the most frequently-requested features for Sass have to do with its imports. The import system that we've had since the very early releases of Sass is, to put it simply, not great. It does little more than textually include one Sass file in another, which makes it hard to keep track of where mixins, functions, and variables were defined and hard to be sure that any new additions won't happen to conflict with something elsewhere in the project. To make matters worse, it overlaps with CSS's built-in @import rule, which forces us to have a bunch of heuristics to decide which is which.

    Because of these problems and others, we've wanted to do a full overhaul of the way Sass files relate to one another for a long time. Over the last few years, I've been working with the Sass core team and Sass framework maintainers to create a proposal for a module system that's fit to replace @import. That proposal is now in a place that the core team is pretty happy with, at least as a starting point, so we want to open it up for community feedback.

    If you want to read the full proposal, it's available on GitHub. Feel free to file issues for any feedback you have. The main body of the proposal is written as a spec, so it's very detailed, but the Goals, Summary, and FAQ sections (reproduced below) should be accessible to anyone familiar with Sass.

    Goals

    High-Level

    These are the philosophical design goals for the module system as a whole. While they don't uniquely specify a system, they do represent the underlying motivations behind many of the lower-level design decisions.

    • Locality. The module system should make it possible to understand a Sass file by looking only at that file. An important aspect of this is that names in the file should be resolved based on the contents of the file rather than the global state of the compilation. This also applies to authoring: an author should be able to be confident that a name is safe to use as long as it doesn't conflict with any name visible in the file.

    • Encapsulation. The module system should allow authors, particularly library authors, to choose what API they expose. They should be able to define entities for internal use without making those entities available for external users to access or modify. The organization of a library's implementation into files should be flexible enough to change without changing the user-visible API.

    • Configuration. Sass is unusual among languages in that its design leads to the use of files whose entire purpose is to produce side effects—specifically, to emit CSS. There's also a broader class of libraries that may not emit CSS directly, but do define configuration variables that are used in computations, including computation of other top-level variables' values. The module system should allow the user to flexibly use and configure modules with side-effects.

    Low-Level

    These are goals that are based less on philosophy than on practicality. For the most part, they're derived from user feedback that we've collected about @import over the years.

    • Import once. Because @import is a literal textual inclusion, multiple @imports of the same Sass file within the scope of a compilation will compile and run that file multiple times. At best this hurts compilation time for little benefit, and it can also contribute to bloated CSS output when the styles themselves are duplicated. The new module system should only compile a file once.

    • Backwards compatibility. We want to make it as easy as possible for people to migrate to the new module system, and that means making it work in conjunction with existing stylesheets that use @import. Existing stylesheets that only use @import should have identical importing behavior to earlier versions of Sass, and stylesheets should be able to change parts to @use without changing the whole thing at once.

    Non-Goals

    These are potential goals that we have explicitly decided to avoid pursuing as part of this proposal for various reasons. Some of them may be on the table for future work, but we don't consider them to be blocking the module system.

    • Dynamic imports. Allowing the path to a module to be defined dynamically, whether by including variables or including it in a conditional block, moves away from being declarative. In addition to making stylesheets harder to read, this makes any sort of static analysis more difficult (and actually impossible in the general case). It also limits the possibility of future implementation optimizations.

    • Importing multiple files at once. In addition to the long-standing reason that this hasn't been supported—that it opens authors up to sneaky and difficult-to-debug ordering bugs—this violates the principle of locality by obfuscating which files are imported and thus where names come from.

    • Extend-only imports. The idea of importing a file so that the CSS it generates isn't emitted unless it's @extended is cool, but it's also a lot of extra work. This is the most likely feature to end up in a future release, but it's not central enough to include in the initial module system.

    • Context-independent modules. It's tempting to try to make the loaded form of a module, including the CSS it generates and the resolved values of all its variables, totally independent of the entrypoint that cause it to be loaded. This would make it possible to share loaded modules across multiple compilations and potentially even serialize them to the filesystem for incremental compilation.

    However, it's not feasible in practice. Modules that generate CSS almost always do so based on some configuration, which may be changed by different entrypoints rendering caching useless. What's more, multiple modules may depend on the same shared module, and one may modify its configuration before the other uses it. Forbidding this case in general would effectively amount to forbidding modules from generating CSS based on variables.

    Fortunately, implementations have a lot of leeway to cache information that the can statically determine to be context-independent, including source trees and potentially even constant-folded variable values and CSS trees. Full context independence isn't likely to provide much value in addition to that.

    • Increased strictness. Large teams with many people often want stricter rules around how Sass stylesheets are written, to enforce best practices and quickly catch mistakes. It's tempting to use a new module system as a lever to push strictness further; for example, we could make it harder to have partials directly generate CSS, or we could decline to move functions we'd prefer people avoid to the new built-in modules.

    As tempting as it is, though, we want to make all existing use-cases as easy as possible in the new system, even if we think they should be avoided. This module system is already a major departure from the existing behavior, and will require a substantial amount of work from Sass users to support. We want to make this transition as easy as possible, and part of that is avoiding adding any unnecessary hoops users have to jump through to get their existing stylesheets working in the new module system.

    Once @use is thoroughly adopted in the ecosystem, we can start thinking about increased strictness in the form of lints or TypeScript-style --strict-* flags.

    • Code splitting. The ability to split monolithic CSS into separate chunks that can be served lazily is important for maintaining quick load times for very large applications. However, it's orthogonal to the problems that this module system is trying to solve. This system is primarily concerned with scoping Sass APIs (mixins, functions, and placeholders) rather than declaring dependencies between chunks of generated CSS.

    We believe that this module system can work in concert with external code-splitting systems. For example, the module system can be used to load libraries that are used to style individual components, each of which is compiled to its own CSS file. These CSS files could then declare dependencies on one another using special comments or custom at-rules and be stitched together by a code-splitting post-processor.

    Summary

    This proposal adds two at-rules, @use and @forward, which may only appear at the top level of stylesheets before any rules (other than @charset). Together, they're intended to completely replace @import, which will eventually be deprecated and even more eventually removed from the language.

    @use

    @use makes CSS, variables, mixins, and functions from another stylesheet accessible in the current stylesheet. By default, variables, mixins, and functions are available in a namespace based on the basename of the URL.

    @use "bootstrap";
    
    .element {
      @include bootstrap.float-left;
    }
    

    In addition to namespacing, there are a few important differences between @use and @import:

    • @use only executes a stylesheet and includes its CSS once, no matter how many times that stylesheet is used.
    • @use only makes names available in the current stylesheet, as opposed to globally.
    • Members whose names begin with - or _ are private to the current stylesheet with @use.
    • If a stylesheet includes @extend, that extension is only applied to stylesheets it imports, not stylesheets that import it.

    Note that placeholder selectors are not namespaced, but they do respect privacy.

    Controlling Namespaces

    Although a @use rule's default namespace is determined by the basename of its URL, it can also be set explicitly using as.

    @use "bootstrap" as b;
    
    .element {
      @include b.float-left;
    }
    

    The special construct as * can also be used to include everything in the top-level namespace. Note that if multiple modules expose members with the same name and are used with as *, Sass will produce an error.

    @use "bootstrap" as *;
    
    .element {
      @include float-left;
    }
    
    Configuring Libraries

    With @import, libraries are often configured by setting global variables that override !default variables defined by those libraries. Because variables are no longer global with @use, it supports a more explicit way of configuring libraries: the with clause.

    // bootstrap.scss
    $paragraph-margin-bottom: 1rem !default;
    
    p {
      margin-top: 0;
      margin-bottom: $paragraph-margin-bottom;
    }
    
    @use "bootstrap" with (
    
      $paragraph-margin-bottom: 1.2rem
    
    );
    

    This sets bootstrap's $paragraph-margin-bottom variable to 1.2rem before evaluating it. The with clause only allows variables defined in (or forwarded by) the module being imported, and only if they're defined with !default, so users are protected against typos.

    @forward

    The @forward rule includes another module's variables, mixins, and functions as part of the API exposed by the current module, without making them visible to code within the current module. It allows library authors to be able to split up their library among many different source files without sacrificing locality within those files. Unlike @use, forward doesn't add any namespaces to names.

    // bootstrap.scss
    @forward "functions";
    @forward "variables";
    @forward "mixins";
    
    Visibility Controls

    A @forward rule can choose to show only specific names:

    @forward "functions" show color-yiq;
    

    It can also hide names that are intended to be library-private:

    @forward "functions" hide assert-ascending;
    
    Extra Prefixing

    If you forward a child module through an all-in-one module, you may want to add some manual namespacing to that module. You can do what with the as clause, which adds a prefix to every member name that's forwarded:

    // material/_index.scss
    @forward "theme" as theme-*;
    

    This way users can use the all-in-one module with well-scoped names for theme variables:

    @use "material" with ($theme-primary: blue);
    

    or they can use the child module with simpler names:

    @use "material/theme" with ($primary: blue);
    

    @import Compatibility

    The Sass ecosystem won't switch to @use overnight, so in the meantime it needs to interoperate well with @import. This is supported in both directions:

    • When a file that contains @imports is @used, everything in its global namespace is treated as a single module. This module's members are then referred to using its namespace as normal.

    • When a file that contains @uses is @imported, everything in its public API is added to the importing stylesheet's global scope. This allows a library to control what specific names it exports, even for users who @import it rather than @use it.

    In order to allow libraries to maintain their existing @import-oriented API, with explicit namespacing where necessary, this proposal also adds support for files that are only visible to @import, not to @use. They're written "file.import.scss", and imported when the user writes @import "file".

    Built-In Modules

    The new module system will also add seven built-in modules: math, color, string, list, map, selector, and meta. These will hold all the existing built-in Sass functions. Because these modules will (typically) be imported with a namespace, it will be much easier to use Sass functions without running into conflicts with plain CSS functions.

    This in turn will make it much safer for Sass to add new functions. We expect to add a number of convenience functions to these modules in the future.

    meta.load-css()

    This proposal also adds a new built-in mixin, meta.load-css($url, $with: ()). This mixin dynamically loads the module with the given URL and includes its CSS (although its functions, variables, and mixins are not made available). This is a replacement for nested imports, and it helps address some use-cases of dynamic imports without many of the problems that would arise if new members could be loaded dynamically.

    Frequently Asked Questions

    • Why this privacy model? We considered a number of models for declaring members to be private, including a JS-like model where only members that were explicitly exported from a module were visible and a C#-like model with an explicit @private keyword. These models involve a lot more boilerplate, though, and they work particularly poorly for placeholder selectors where privacy may be mixed within a single style rule. Name-based privacy also provides a degree of compatibility with conventions libraries are already using.

    • Can I make a member library-private? There's no language-level notion of a "library", so library-privacy isn't built in either. However, members used by one module aren't automatically visible to downstream modules. If a module isn't @forwarded through a library's main stylesheet, it won't be visible to downstream consumers and thus is effectively library-private.

      As a convention, we recommend that libraries write library-private stylesheets that aren't intended to be used directly by their users in a directory named src.

    • How do I make my library configurable? If you have a large library made up of many source files that all share some core !default-based configuration, we recommend that you define that configuration in a file that gets forwarded from your library's entrypoint and used by your library's files. For example:

    // bootstrap.scss
    @forward "variables";
    @use "reboot";
    
    // _variables.scss
    $paragraph-margin-bottom: 1rem !default;
    
    // _reboot.scss
    @use "variables" as *;
    
    p {
      margin-top: 0;
      margin-bottom: $paragraph-margin-bottom;
    }
    
    // User's stylesheet
    @use "bootstrap" with (
    
      $paragraph-margin-bottom: 1.2rem
    
    );
    

    Sending Feedback

    This is still just a proposal. We're pretty happy with the overall shape of the module system, but it's not at all set in stone, and anything can change with enough feedback provided by users like you. If you have opinions, please file an issue on GitHub or just tweet at @SassCSS. We'll take anything from "it looks awesome" to "it looks awful", although the more specific you can be the more information we have to work with!

  • Feature Watch: Content Arguments and Color Functions

    Posted by Natalie Weizenbaum about 1 year ago

    Dart Sass 1.15, released today and available on npm and all other distribution channels, brings with it a number of highly-anticipated new Sass features. This is also the first release of Dart Sass with major new language features that aren't just for CSS compatibility. That's a big accomplishment, and we intend to continue that pattern moving forward!

    @content Arguments

    Mixins that take @content blocks can now pass arguments to those blocks. This is written @content(<arguments...>). If a mixin passes arguments to its content block, users of that mixin must accept those arguments by writing @include <name> using (<arguments...>). The argument list for a content block works just like a mixin's argument list, and the arguments passed to it by @content work just like passing arguments to a mixin.

    // style.scss
    @mixin media($types...) {
      @each $type in $types {
        @media #{$type} {
          @content($type);
        }
      }
    }
    
    @include media(screen, print) using ($type) {
      h1 {
        font-size: 40px;
        @if $type == print {
          font-family: Calluna;
        }
      }
    }
    
    /* style.css */
    @media screen {
      h1 {
        font-size: 40px;
      }
    }
    @media print {
      h1 {
        font-size: 40px;
        font-family: Calluna;
      }
    }
    

    For more details, see the feature proposal. This feature is implemented in LibSass, and will be released in version 3.6.0. Since Ruby Sass is deprecated and this isn't a CSS compatibility feature, it won't be implemented in Ruby Sass.

    Color Level 4 Syntax for rgb() and hsl()

    The CSS Color Module Level 4 has introduced new syntax for the rgb() and hsl() functions, which has begun to be supported in browsers. This syntax makes these functions more compact, allows the alpha value to be specified without needing additional rgba() and hsla() functions, and it looks like rgb(0 255 0 / 0.5) and hsla(0 100% 50%).

    To support this function, Sass's rgb() and hsl() functions now accept a space-separated list of components as a single argument. If this last argument is a slash-separated pair of numbers, the first number will be treated as the blue channel or lightness (respectively) and the second as the alpha channel.

    Be aware though that the normal rules for disambiguating between division and / as a separator still apply! So if you want to pass a variable for the alpha value, you'll need to use the old rgba() syntax. We're considering possible long-term solutions for this problem as / is used more prominently as a separator in CSS.

    In addition, the new color spec defines the rgba() and hsla() functions as pure aliases for rgb() and hsl(), and adds support for the four-argument rgba() and hsla() syntax to rgb() and hsl() as well. To match this behavior, Sass is also defining rgba() and hsla() as aliases and adding support for all their definitions to rgb() and hsl().

    All in all, this means that the function calls like all of the following are newly supported in Sass:

    • rgb(0 255 0), rgb(0% 100% 0%), rgb(0 255 0 / 0.5), and rgb(0, 255, 0, 0.5);
    • hsl(0 100% 50%), hsl(0 100% 50% / 0.5), and hsl(0, 100%, 50%, 0.5);
    • rgba(0, 255, 0) and hsla(0, 100%, 50%);
    • and rgb($color, 0.5).

    This change is fully backwards-compatible, so all the arguments to rgb(), hsl(), rgba(), and hsla() that previously worked will continue to do so.

    For more details, see the feature proposal. This feature isn't yet implemented in LibSass or Ruby Sass.

    Interpolated At-Rule Names

    This feature is a little smaller than the last two, but it's been on the to-do list for even longer: adding support for interpolation in the names of at-rules! This works just how you'd expect:

    @mixin viewport($prefixes) {
      @each $prefix in $prefixes {
        @-#{$prefix}-viewport {
          @content;
        }
      }
      @viewport {
        @content;
      }
    }
    

    For more details, see the feature proposal. This feature isn't yet implemented in LibSass. Since Ruby Sass is deprecated and this isn't a CSS compatibility feature, it won't be implemented in Ruby Sass.

  • Feature Watch: CSS Imports and CSS Compatibility

    Posted by Natalie Weizenbaum over 1 year ago

    Dart Sass 1.11 has just been released, and with it a handful of new features. This is an exciting moment, because it marks the first major new feature that's been added to the language since Dart Sass was launched. It's also the first release with features that have gone through the new process, from proposal to tests to implementation.

    CSS Imports

    The biggest feature in Dart Sass 1.11 is support for importing plain CSS files. This is a long-awaited feature, and while we'd initially planned on waiting on it until we launched the upcoming module system, we ended up deciding to implement it earlier.

    You can now import a CSS file, say styles.css, just by writing @import "styles". That file will be parsed as plain CSS, which means that any Sass features like variables or mixins or interpolation will be disallowed. The CSS it defines will become part of your stylesheet, and can be @extended just like any other styles.

    There are a couple caveats: because SCSS is a superset of plain CSS, it will still compile @import "styles.css" (with an explicit extension) to a CSS @import rule. If you want to import a CSS file into your Sass compilation, you must omit the extension.https://github.com/sass/libsass/issues/2699

    Also, this feature isn't fully implemented in LibSass yet. It still has its old behavior, where it imports CSS files but parses them as SCSS, with all the extra Sass features allowed. This behavior will be deprecated soon, and eventually it will produce errors for anything other than plain CSS, just like Dart Sass does today.

    CSS min() and max()

    Dart Sass 1.11 also adds support for CSS's min() and max() mathematical functions. For those unfamiliar, these functions work a lot like calc(), except they return the minimum or maximum of a series of values. For example, you can write width: max(50%, 100px) to make your element either 50% of the parent's width or 100px wide, whichever is greater.

    Because Sass has its own functions named min() and max(), it was difficult to use these CSS functions... until now. Dart Sass 1.11 will intelligently decide whether to use the plain CSS functions or the built-in Sass functions based on whether or not you're passing in dynamic Sass values. For example:

    • The Sass function will be called if you pass a variable, like max($width, 100px).
    • The Sass function will be called if you call another Sass function, like max(compute-width(), 100px).
    • It will compile to a plain CSS function if you just use plain CSS numbers, like max(50% + 10px, 100px).
    • It will still compile to a plain CSS function even if you use interpolation, like max(50% + #{$width / 2}, #{$width}).

    This preserves backwards-compatibility with existing uses of the Sass functions, while also users to use the CSS functions the same way they would in plain CSS.

    This feature isn't yet implemented in LibSass or Ruby Sass.

    Range-Format Media Queries

    CSS Media Queries Level 4 defines a range syntax for defining certain media queries:

    @media (width > 500px) {
      /* ... */
    }
    

    Dart Sass 1.11 adds support for this syntax. It works just like existing media query support: you can either use interpolation or plain Sass expressions to inject Sass logic into the query, and they can still be nested.

    @media (width > $width) {
      @media (height < #{$height}) {
        /* ... */
      }
    }
    

    This feature isn't yet implemented in LibSass or Ruby Sass.

    Normalized Identifier Escapes

    The last compatibility improvement is a bit of an edge case, but it's still worth mentioning: the way Sass parses escapes in identifiers has been improved to better match the CSS spec.

    Escapes are now normalized to a standard format, which means that (for example) éclair and \E9clair are parsed to the same value (in this case, éclair). Prior to this change, if an escape was written, it would always be preserved as-is, so str-length(\E9clair) would return 8 even though that identifier means exactly the same thing to CSS as éclair.

    We don't anticipate this affecting many users, but we always strive to bring Sass as close to the semantics of CSS as possible. This is a small but important step on that path.

    This feature isn't yet implemented in LibSass or Ruby Sass.

  • Request For Comments: Importing CSS Files

    Posted by Natalie Weizenbaum over 1 year ago

    As Dart Sass catches up with Ruby Sass in terms of usability, we're starting work on adding new features to the language. The first feature we're looking at is one that's long been requested by users: adding support for importing plain CSS files without having to rename them to .scss. Not only do we expect this to be very useful, it's already partially implemented in LibSass, so this will help bring the implementations more in line with one another.

    We're also trying out a new process with this feature. In order to help keep the behavior of different implementations in sync, we're starting with a prose specification of the feature before moving on to writing code. We're also taking this as an opportunity to solicit feedback from you, the Sass community! We want to hear your thoughts on the new feature while we have a chance to revise it based on that feedback.

    Background

    Historically, the reference implementations of Sass—first Ruby Sass, then Dart Sass—only supported importing other Sass files. However, LibSass supported importing CSS files as well, interpreting them as though they were SCSS. Although this technically violated the implementation guide's prohibition on unilaterally extending the language, these CSS imports were useful and were widely adopted in the Node.js community.

    This became particularly clear when, at the language team's urging, LibSass added deprecation warnings for CSS imports and users were left without a suitable replacement. The language team came together to discuss the problem, and decided to move towards allowing CSS imports but forbidding the use of non-CSS features in the imported files. The proposal describes the specifics of that idea.

    LibSass's behavior at time of writing is to import files with the extension .css at the same precedence level as those with the .scss and .sass extensions, and to throw an error if an import is ambiguous between a .css file and a .scss or .sass file.

    Summary

    The proposal seeks to strike a balance between preserving compatibility with LibSass's existing behavior and moving towards a more principled scheme for loading CSS. This is particularly important as we intend to allow @use to load CSS files without Sass features, so we want the existing CSS loading support to be as similar as possible.

    Locating CSS files for import works similarly under the proposal as it does in LibSass currently: a relative .css file takes precedence over files with any extension on the load path, a .css file earlier on the load path takes precedence over a file with any extension later on the load path, and foo.css takes precedence over index/foo.scss.

    The only difference in loading scheme occurs when an import is ambiguous between a .css file and a .scss or .sass file at the same path. LibSass currently produces an error here, but in order to maximize compatibility with existing Dart Sass (and Ruby Sass) behavior, the proposal has the .scss or .sass file taking precedence. This is not a breaking change to LibSass's behavior, since it only applies in situations that would previously have produced an error.

    The proposal diverges significantly from LibSass in parsing the imported CSS files, though: it forbids all use of SCSS features in the parsed files. Most SCSS features produce errors (rather than compiling to plain, likely-invalid CSS) in order to help users who accidentally wrote SCSS in their CSS realize what's going wrong. However, features like @import that overlap with plain CSS continue to be rendered as CSS.

    In order to avoid a sudden backwards-incompatible change in LibSass, this also includes a proposal for a set of deprecation warnings that can be added to LibSass's existing behavior to steer users away from using Sass features in their imported CSS without entirely breaking their build process.

    Giving Feedback

    If you want more details on exactly how the proposed behavior will work, head over to the sass/language repo and read the full proposal. You can skip the Background and Summary sections, since they're included above. Be aware, though, that it's written to be a specification; it's a great for figuring out how exactly an edge case should work, but it's not as conversational as the sections quoted above.

    If you have any issues with the proposal as written, or if it doesn't cover a use-case that's important to you, please bring that up in the sass/language issue tracker. We'll be leaving it open for discussion for at least two weeks before we mark the proposal as "accepted" and move on to the implementation phase.

    Please be aware, though, that while we welcome community feedback, the design of Sass is ultimately in the hands of the language team. We'll absolutely consider the perspectives and use-cases of users who speak up, but it's also our job to consider all the users who are new to Sass or even to CSS and who don't yet know to read blogs or comment on issue trackers. Remember that our careful decision-making made Sass what it is today, and have patience with us if we don't make the decisions you would have!

  • Ruby Sass is Deprecated

    Posted by Natalie Weizenbaum over 1 year ago

    With the release of Dart Sass 1.0.0 stable last week, Ruby Sass was officially deprecated. I'll continue to maintain it over the next year, but when 26 March 2019 rolls around it will reach its official end-of-life. I encourage all users to start migrating away sooner rather than later.

    The Deprecation Period

    Over the next year, I'll continue to work on Ruby Sass in a limited capacity. I'll triage and fix any bugs that are reported, unless they're minor or obscure enough to be unlikely to pose a practical problem over the next year. I'll also add support for any new CSS features that require changes to the Sass parser or other parts of the language.

    I won't be working on language features that aren't necessary for CSS support, though. The latest and greatest features will be appearing exclusively in Dart Sass and LibSass from here on out.

    I also won't be accepting pull requests for new Ruby Sass features. While pull requests are a great way to contribute to projects, they still take work on my part to merge in, and it just doesn't make sense to spend time on that work when the project is being turned down. If you're interested in contributing to Sass, I highly recommend contributing to Dart Sass—Dart is an extremely easy language to learn!

    We're also be migrating the Ruby Sass repository to https://github.com/sass/ruby-sass, so be sure to update your Git URLs. The old repository URL will continue to work during the deprecation period, but it will be frozen; all ongoing maintenance will happen at the new URL. Once the deprecation period is over, the Git history for the old URL will be wiped and replaced with feature specifications. See this issue for the full plan.

    Migrating Away

    We want to make it as easy as possible to migrate from Ruby Sass onto an actively-maintained implementation. The best way to do that depends on how you use Ruby Sass today.

    If you use Ruby Sass as a command-line tool, the easiest way to migrate is to install Dart Sass as a command-line tool. It supports a similar interface to Ruby Sass, although it currently doesn't support the --watch or --update flags—adding them is high priority, though!

    If you use Ruby Sass as a plugin for a Ruby web app, particularly if you define your own Sass functions in Ruby, the sassc gem provides access to LibSass from Ruby with a very similar API to Ruby Sass. In most cases, you can just replace the Sass module with the SassC module and your code will continue to work.

    If you're using Rails, I particularly recommend using the sassc-rails gem, which wraps up the sassc gem and integrates it smoothly into the asset pipeline. Most of the time you won't even need to change any of your code.

    We're also planning to add support to Dart Sass for embedding it in Ruby (and other programming languages). This will allow Ruby users to get the latest and greatest features as soon as they're implemented.

    End of Life

    On 26 March 2019, the deprecation period for Ruby Sass will end and it will no longer be maintained. The new sass/ruby-sass repository will be archived, which means no changes will be made and no new issues or pull requests will be accepted. The old sass/sass repository will have its Git history replaced with feature specifications that have historically just been scattered around issue comments.

    Leading up to the end of life, we'll be migrating the user-focused reference documentation from the Ruby Sass repository to the Sass website. We could use some help doing the migration and touching up the documentation, so if you're interested please chime in on the tracking issue!

    Unless...

    We're turning down support for Ruby Sass because the Sass team just doesn't have the bandwidth to maintain it along with the other major implementations. But there could be another solution. If someone from the community is willing to step up and take on the mantle of maintainer, we'd be more than happy to show them the ropes and help them keep Ruby Sass going.

    Maintaining a language implementation isn't necessarily easy. It requires keeping up with features as they're added to Dart Sass, as well as fixing bugs and fielding pull requests. But it's also a great opportunity to work on a big project with a lot of impact, and I'm happy to help get a new maintainer up to speed. If you're interested, please email me and Chris and we'll talk about how to get started.

Next

Copyright © 2014 nex3 . Theme iaawd by poying