Last Updated: February 25, 2016
·
9.904K
· peternixey

How to create scoped and namespaced CSS using SASS

While the asset pipeline in Rails is a terrific way to reduce latency during site loading, it also means that all CSS, regardless of what file it goes into, is applied to every page in our site. All CSS declarations are basically global variables and global variables can have unintended consequences.

Back in the day we could in theory firewall CSS using exclusion. It was always a little clumsy but by only including CSS files with particular HTML files you needed them in you could effectively namespace your CSS. Your CSS was "namespaced" only to the files you actually included it in. The beauty of that namespacing was that you didn't have to worry that that a change you made on one page might adversely affect one of your other pages.

Then along came the asset pipeline and everything got shunted through in one go. Great for latency, not so good for namespacing.

Using SASS to give clear controller/action namespacing

SASS offers a great opportunity to namespace CSS in a much more readable, declarative way by using nested declarations. Because SASS allows all CSS to be nested inside another CSS declaration we can add classes to the body tag and then simply nest the relevant CSS inside the class to which it applies.

<!-- inside your views -->
<body class="controller-users action-edit"

</body>

...inside your CSS files:

// main.css.scss
.controller-users{
  // this CSS will only be applied to html in the users controller

  &.action-edit{
    // this CSS will only be applied to the edit action within the 
    // users controller
  }
}

NB you need the &.action-edit declaration to include an ampersand because it means it applies to the same element that the .controller-users class is applied to and not just a child of it

And here's a helper method you can use to generate the class names

def controller_and_action_as_html_class_names
  "controller-#{params[:controller]} action-#{params[:action]}"
end

Just add this to your body tag:

%body{class: controller_and_action_as_html_class_names }

You can now confidently write modular CSS without worrying about whether it's going to have weird effects elsewhere.

My preference is to namespace tightly until CSS is definitely required elsewhere

Good object oriented programming is about encapsulation and making sure that variables don't leak to where they might cause trouble. Good CSS should, in my opinion, be the same. I therefore prefer to start off with CSS namespaced to the precise controller/action combination I need it in and then only graduate it up the scope chain as required.