Sass: Parent Wrapper Classes

  • SCSS
  • Sass
  • CSS

I ran into a small head-scratcher of a problem the other day when I was migrating an old project's Sass stylesheets to use @use and @forward instead of @import. I had a stylesheet that used @import statements inside of a class:

.custom-class {  @import "axioms/space";  @import "axioms/typography";}

This sort of thing worked using @import statements, because those could be thrown just about anywhere in a Sass project, but it won't work with @use because @use statements pretty much have to be at the top-level of the Sass file they are called in. I'll walk through what the solution is below, but first let's get into a little bit of a contrived example project space to demonstrate the issue.

Example project setup

We'll start with our entry point file, styles/styles.scss:

/* styles/styles.scss */.custom-class {  @import "axioms/space";  @import "axioms/typography";}

We saw this above. It's a somewhat contrived example, but not very far off from what I was actually working with. It loads two partial files.

First, styles/axioms/_space.scss:

/* styles/axioms/_space.scss */@use "../functions/pxToRem";
$size--100: 2px;$size--200: 4px;$size--300: 8px;
$space-map: (  0: 0,  100: pxToRem.pxToRem($size--100),  200: pxToRem.pxToRem($size--200),  300: pxToRem.pxToRem($size--300),);
@function Space($value) {  @return map.get($space-map, $value);}
@each $index, $size in $space-map {  .margin-#{$index} {    margin: #{$size};  }}

Second, styles/axioms/_typography.scss:

/* styles/axioms/_typography.scss */$font-size--100: 11px;$line-height--100: 1.7;$font-size--200: 13px;$line-height--200: 1.64;$font-size--300: 16px;$line-height--300: 1.5;$font-size--400: 18px;$line-height--400: 1.48;
$font-size-base: $font-size--400;
@mixin f100 {  font-size: $font-size--100;  line-height: $line-height--100;}
@mixin f200 {  font-size: $font-size--200;  line-height: $line-height--200;}
@mixin f300 {  font-size: $font-size--300;  line-height: $line-height--300;}
@mixin f400 {  font-size: $font-size--400;  line-height: $line-height--400;}
.f100 {  @include f100;}
.f200 {  @include f200;}
.f300 {  @include f300;}
.f400 {  @include f400;}

These two partials define some utility classes (ex. margin-200 or f400) that we want to ultimately compile within the custom-class class. If we run our compile command, we see that this works:

/* compiled css */.custom-styles .f100 {  font-size: 11px;  line-height: 1.7;}.custom-styles .f200 {  font-size: 13px;  line-height: 1.64;}.custom-styles .f300 {  font-size: 16px;  line-height: 1.5;}.custom-styles .f400 {  font-size: 18px;  line-height: 1.48;}.custom-styles .margin-0 {  margin: 0;}.custom-styles .margin-100 {  margin: 0.1111111111rem;}.custom-styles .margin-200 {  margin: 0.2222222222rem;}.custom-styles .margin-300 {  margin: 0.4444444444rem;}.custom-styles .f100 {  font-size: 11px;  line-height: 1.7;}.custom-styles .f200 {  font-size: 13px;  line-height: 1.64;}.custom-styles .f300 {  font-size: 16px;  line-height: 1.5;}.custom-styles .f400 {  font-size: 18px;  line-height: 1.48;}

The problem is that we get this warning when we run that compile step:

Deprecation Warning [import]: Sass @import rules are deprecated and will be removed in Dart Sass 3.0.0.
More info and automated migrator: https://sass-lang.com/d/import
3 │   @import "axioms/typography";  │           ^^^^^^^^^^^^^^^^^^^^^    styles/styles.scss 3:11  root stylesheet

This should look familiar if you read my @use and @forward in Sass post. If it doesn't look familiar and you didn't read that post, and aren't sure what this warning means, please go back and read that post.

Use meta.load-css instead

So how do we fix it? Well we could try to swap @import for @use:

/* styles/styles.scss */.custom-class {  @use "axioms/space";  @use "axioms/typography";}

But we won't get very far. We get this error when we run the compile command:

Error: This at-rule is not allowed here.2 │   @use "axioms/space";  │   ^^^^^^^^^^^^^^^^^^^^^^^  styles/styles.scss 2:3  root stylesheet

Instead, we have to use the sass:meta built-in module:

/* styles/styles.scss */@use "sass:meta";
.custom-class {  @include meta.load-css("axioms/space");  @include meta.load-css("axioms/typography");}

meta.load-css lets you import a Sass file inside of a selector, in this case from a relative path, and includes the CSS as the contents of a mixin, scoped to that parent selector.

With this change made, when I run the compile command, the compiled CSS is exactly what we want, and there are no deprecation warnings:

/* compiled css */.custom-class .f100 {  font-size: 11px;  line-height: 1.7;}.custom-class .f200 {  font-size: 13px;  line-height: 1.64;}.custom-class .f300 {  font-size: 16px;  line-height: 1.5;}.custom-class .f400 {  font-size: 18px;  line-height: 1.48;}.custom-class .margin-0 {  margin: 0;}.custom-class .margin-100 {  margin: 0.1111111111rem;}.custom-class .margin-200 {  margin: 0.2222222222rem;}.custom-class .margin-300 {  margin: 0.4444444444rem;}.custom-class .f100 {  font-size: 11px;  line-height: 1.7;}.custom-class .f200 {  font-size: 13px;  line-height: 1.64;}.custom-class .f300 {  font-size: 16px;  line-height: 1.5;}.custom-class .f400 {  font-size: 18px;  line-height: 1.48;}