Resourceful CSS with Sass and Rails

Preview:

DESCRIPTION

CSS is weird. How can we reign in some order over it in our Rails projects?

Citation preview

Resource-Oriented CSSwith Sass and Rails

@alxjrvs

Alex Jarvis

Terrible Labs (Sic Semper Tyrannosaurus)

Css is Weird. When we’re building front-ends, it’s necessary, and useful. It’s also…well, not code.

When we think in code, it’s functional. It’s planar reasoning - smart objects floating around a formless cloud. But css…

…css is different. It’s got a lot of quirks. It deals with positional and relational reasoning, and it just, well, doesn’t feel like code.

How can we make it feel more like our code?

Rails believes strongly in convention over configuration. We can lean on our familiar rails patterns to provide an easy way to organize our styles.

gem ‘sass-rails’ !!

We’re also going to be using Sass, a css extension language that gives us a number of powerful benefits that we’ll go into. We can install it with the sass-rails gem. It comes pre-installed with the latest versions of rails!

Lets start by building a strong intuition. Rails already gives us an enforced organization system for our files, so lets borrow from that.

Lets start by building a strong intuition. Rails already gives us an enforced organization system for our files, so lets borrow from that.

stylesheets/application.css.sass

To set this up, we’re going to rename our Application.css stylesheet to ‘application.css.sass’ and @import all those files we just made into it. You could set it to auto-import all of the files in /stylesheets, but I like to be more explicit.

views/layouts/application.html.erb

helpers/application_helper.rb

Rails gives us magic by default, but for CSS, we’ll have to make out own magic. This method in our helper will return a string that we can pass to the layout template. We’ve effectively just namespaced our css.

Now when I visit a route, [C] our View knows the exact controller and action we’re using to get there.

Now when I visit a route, [C] our View knows the exact controller and action we’re using to get there.

stylesheets/posts/index.css.sass

Sass lets us use indents to scope our CSS. We do this by applying a body element scoped with our controller name and action. When we nest a style underneath it, it will only effect pages When you nest something under another selector, it applies itself *and* all parent selectors to the resulting css. Sass lets me nest all of my css selectors underneath a top-level selector - in this case, body.posts.index. This establishes scope: the nested styles will only be applied to the views that we explicitly declare them to be in.

stylesheets/posts/index.css.sass

Sass lets us use indents to scope our CSS. We do this by applying a body element scoped with our controller name and action. When we nest a style underneath it, it will only effect pages When you nest something under another selector, it applies itself *and* all parent selectors to the resulting css. Sass lets me nest all of my css selectors underneath a top-level selector - in this case, body.posts.index. This establishes scope: the nested styles will only be applied to the views that we explicitly declare them to be in.

Now when I look at the compiled css, I can see that the styles I defined for that page, scoped directly to their corresponding view. The resulting css clearly shows my [C] top level selector, and my [C] nested selector for the given element. What’s even neater is the [C] comment above: It actually gives us the line number and file that it was generated from.

Top-Level Selector (Scope)

Now when I look at the compiled css, I can see that the styles I defined for that page, scoped directly to their corresponding view. The resulting css clearly shows my [C] top level selector, and my [C] nested selector for the given element. What’s even neater is the [C] comment above: It actually gives us the line number and file that it was generated from.

Top-Level Selector (Scope)

Nested Selector

Now when I look at the compiled css, I can see that the styles I defined for that page, scoped directly to their corresponding view. The resulting css clearly shows my [C] top level selector, and my [C] nested selector for the given element. What’s even neater is the [C] comment above: It actually gives us the line number and file that it was generated from.

Top-Level Selector (Scope)

Source File

Nested Selector

Now when I look at the compiled css, I can see that the styles I defined for that page, scoped directly to their corresponding view. The resulting css clearly shows my [C] top level selector, and my [C] nested selector for the given element. What’s even neater is the [C] comment above: It actually gives us the line number and file that it was generated from.

stylesheets/posts/index.css.sass

Now, Lets say I want to style what a post looks like. I’m going to add some thing to our Index.css.sass file. I like using basic descriptive names in my styles, and I just learned about nesting, so here’s my css - you can see I’ve basically mirrored my View.

This is actually a bad pattern.

tinyurl.com/sassinception

The Sass Way has a great post about the dangers of frivolous indenting. In short, it chains you to the DOM and makes your styles very fragile. I encourage you all to go check out the post, which goes into significantly more detail.

stylesheets/posts/_post.css.sass

I’m going to move this into a partial. As a soft rule, consider making a new file any time you feel like scoping (nesting) your styles to something other than body. Here, you can see I’ve added a top-level selector that includes both the post class *and* the body attributes, so that it keeps its scope tight. Following the inception rule, all the of nested selectors are on a single indentation. NOTE: I could have double-indented here, but I prefer a single indentation. YMMV.

stylesheets/posts/_post.css.sass

I’m going to move this into a partial. As a soft rule, consider making a new file any time you feel like scoping (nesting) your styles to something other than body. Here, you can see I’ve added a top-level selector that includes both the post class *and* the body attributes, so that it keeps its scope tight. Following the inception rule, all the of nested selectors are on a single indentation. NOTE: I could have double-indented here, but I prefer a single indentation. YMMV.

stylesheets/posts/_post.css.sass

Changing scope is easy, too. If I want to share my posts partial styles with the rest of my controller views, I can just remove the controller action class from body.

stylesheets/posts/_post.css.sass

Changing scope is easy, too. If I want to share my posts partial styles with the rest of my controller views, I can just remove the controller action class from body.

stylesheets/shared/_avatar.css.sass

If I want to create styles with a global scope, I can just not include the body element as part of my top-level selector. This means that this style will try to apply itself to any element with the class ‘avatar’. These work best for site-wide partials, so I’ve put them in a stylesheets/shared folder, just like our rails site-wide partials.

stylesheets/global.css.sass

There may be a case in which you want to define global styles meant to not pertain to a certain aspect or section of the view, but rather, defaults styles for certain selectors. site-wide fonts or styles on the HTML element are some examples. They are largely unrelated, so it wouldn’t make sense to define them by a top level selector. I put these in a ‘global.css.sass’ file so that they don’t pollute the rest of our nice clean scoped stylesheets.

stylesheets/application.css.sass

And, to turn them on, I @import them into my application.css.sass file. Note the order I import them: styles read from the top-down, and when it compiles into a single file, lower styles will override ones higher in the file. Our globals are our default styles, so we want them to be able to be overwritten. Therefore they go first.

+MIXINS

FUNCTIONS()

$VARIABLES

%EXTENSIONS

Now, Sass overs a great deal more to help us DRY up our code, and provide some great readability and flexibility. I don’t have time to go over them all now, but I’d be happy to talk about them more with you all.

@alxjrvs

More over, these have been opinions of mine, and I’d be very happy to talk about why they are awful. I also like comics, board games, card games, Pugs, whatever.

Thanks to the organisers! Etc.