Glad You're Ready. Let's Get Started!

Let us know how we can contact you.

Thank you!

We'll respond shortly.

Structure your SASS files with @import

For my first blog post at Pivotal, I decided to pick a small topic that I am pretty confident about: why to structure your SASS files with the @import rule.

If you are still using Sprockets directives in Asset Pipeline to combine your SASS files, I highly recommend to switching over to using the SASS @import rule instead.

Consider this simple CSS setup:

application.css (using Sprockets Directives)

 *= require partials/variables
 *= require partials/typography
 *= require partials/elements

 *= require vendor/grid
 *= require vendor/mixins

 *= require pages/home
 *= require pages/listing
 *= require pages/detail
(NOTE: I am intentionally not using "*= require_tree" right now.)

The same setup using SASS @import rule would look like this:

application.sass (using SASS @import)

@import partials/variables
@import partials/typography
@import partials/elements

@import vendor/grid
@import vendor/mixins

@import pages/home
@import pages/listing
@import pages/detail

The main advantages come from the fact that SASS @import creates a global namespace, while the Sprockets directives do not.

Using the Sprockets Directives method, working in the ‘pages/home.sass’ file, you have to do this:

home.sass (using Sprockets method)

@import partials/variables
@import partials/typography
@import vendor/mixins

  color: CornflowerBlue

While, using the SASS @import method, you don’t need to re-@import at all. All files @import’ed lower in the order already have access to all the variables and mixins defined in the files loaded above it in application.sass.

Some may not call this a “problem”, but aside from being annoying to do every time, there also a more serious problem; any file that contains renderable CSS (anything excluding variables, placeholders and mixin definitions) will be rendered every time it is @import’ed. This can quickly grow your final CSS output (I’ve seen some minified CSS > 1MB because of this error) and create a mass of duplicate selectors, putting undue load on the browser.

Softer Benefits:

  • Using the @import global namespace creates a Whorfian effect where the developers on the team tend to define and reuse their variables where they should (in the variables files), and not in more specific files. For example, z-indexes can become a nightmare if not defined in a global variables file.
  • Compilation will speed up a bit in development, because it won’t have to re-compile  all the vendor mixins every time each partial @import’s it.
  • SASS @import syntax is easier to read than the Sprockets CSS comments syntax, IMO.

And Lastly…

Just to appeal to higher authority (why not?), this practice is recommended on the Rails Asset Pipeline guide:

Rails Asset Pipeline advice on @import

And in CAPS on the sass-rails gem readme:

Sass-rails gem advice on @import

 Thanks for reading!

  1. Chris Hough says:

    How do you address view specific sass that should only be imported when that view is rendered in a rails 4 app? i.e. view specific overrides.

  2. Ward Penney says:

    Hey Chris,

    Ideally, you don’t need to do any view specific overrides in your app. Scoping the page will just create more closets with more skeletons in them and create headaches for you later.

    But, if you need to for a special reason, you can do them just fine with this structure. Maybe add another folder called “pages” and place it at peer-level with the other folders. You would import them before or after the “sections” folder (where order is unimportant).

    Hope that helps!

  3. Steve says:

    So how do you deal with debugging CSS?

    When you `@import` everything in application.css instead of `require`ing it with Sprockets, it all gets dumped into application.css, even in development.

    If I inspect an element, how can I tell that a given rule came from ‘app/assets/stylesheets/some/random/stylesheet.css’? This is a constant problem as you fix bugs and implement enhancements, and it is non-trivial due to scss/sass nesting capabilities. You can’t just search search your project for ‘.widget .title span > :hover’ or whatever, because this rule is likely the result some rule nesting.

    IMO, it’s not difficult to put global vars & mixins in a _global.scss partial, which you can then `@import` everywhere — being careful not to add renderable CSS there (a problem which I’ve encountered first-hand). This establishes your global namespace while retaining the excellent debugging capabilities of Sprockets.

    Unless maybe you can enable similar debugging with scss/sass? I’m not aware of such a possibility though, personally.

  4. Steve says:

    A friend pointed me to but unfortunately sass-rails gem is currently broken and doesn’t enable configuration of these options (see:

    The monkey patch in the issue does work, however so I guess that addresses my issue with this approach. And sass-rails will probably be eventually fixed.

    So… good deal! I prefer this approach over Sprockets, assuming we can figure out the development/debugging situation. ;)

  5. Ward Penney says:

    Hey Steve,

    Yes, you definitely want to set the debug info to true so that way it doesn’t minify the CSS in development (and maybe even staging). Then it will return the line number for you.

    Does the sass-rails 4.0.0 gem work for you? We all used to use a fork until 4.0 got released.

    Glad you like the approach! My general folder structure is still very similar and does break out any non-rendering SASS (variables and mixins) into a libraries folder. That’s the lifesaver.


Post a Comment

Your Information (Name required. Email address will not be displayed with comment.)

* Copy This Password *

* Type Or Paste Password Here *