Request For Comments: Importing CSS Files

Posted 9 July 2018 by Natalie Weizenbaum

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.

BackgroundBackground permalink

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.

SummarySummary permalink

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 FeedbackGiving Feedback permalink

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!