Ruby on Rails CSS File Structure

Ruby on Rails CSS File Structure

Ruby on Rails is an amazing framework. At BiteSite, we started using it back in 2011 and haven’t stopped since. Its combination of technical ability and software philosophy has kept it our framework of choice when it comes to web development and it only gets better with time.

One of the things we appreciate most about Ruby on Rails is its convention over configuration philosophy. In short, it basically says, “If you follow our conventions, you don’t have to configure your code”. This allows for less boilerplate code and is, in my opinion, the best way to enforce coding conventions.

With convention over configuration, one of the best benefits you get is a well designed architecture for your code. Every Rails app puts all of its controllers in the same folder, all of its models in the same folder and so on. It makes developing Rails so easy to jump into.

That being said - it’s not perfect. While convention over configuration is in so many places in Ruby on Rails - there are areas it doesn’t exist and you’re left to come up with your own design or structure.

One of these places is CSS.

While Rails does suggest how to structure your CSS when you use scaffolding, it doesn’t really have a strict convention over configuration policy about how to split up your CSS into multiple files and where to put them (aside from the ‘stylesheets’ folder).

When apps get big, this can become a problem.

Over the years, we have come up with a system that has served us pretty well that we thought we’d share. It’s not perfect, but it does work.

Definition

To be clear, this system only dictates how to split up your files and where to put them. It does not cover how to actually structure your CSS selectors and CSS code within those files.

Driving Forces

When we set out our to improve our CSS File structure, there were really two driving forces. One, as with most coding, we wanted our code to be DRY (Don’t Repeat Yourself) where possible. Now, notice I said “where possible” vs. “as much as possible”. We found that overtime, it was hard to keep track of CSS code and so many times you would change some CSS code to fix one problem, but not realize it was being used in 5 other places. We were consistently breaking pages without realizing it and so we implemented our second driving principle: make our file structure easy to follow and easy to figure out what pages it was affecting.

We realized this was breaking DRY code, but it kept our codebase sane and predictable. 

(Incidentally, we found out later on, that this true separation of concerns vs separation of technologies was being embraced in future frameworks like React and Vue where you can scope CSS to individual components).

SCSS vs CSS

Note, at BiteSite, we use SCSS to help with a lot of this, but a lot of the learnings can be applied to vanilla CSS.

CSS File Structure

With those two driving forces in places, we came up with the following CSS file structure:

app
↳ assets
  ↳ stylesheets
    ↳ base
    ↳ common
    ↳ components
    ↳ views

The 4 folders we’ve introduced are base, common, components, views. Let’s explore each of these.

base

The base folder is where we put our UI Kit CSS. So all your standard buttons, links, typography, tables and other CSS that would apply to most or all web apps we put in here. To complement this, we also include things like globals and colorswatches which we can import into the rest of the files. We’ll usually split each of these into its own file. Examples include:

app
↳ assets
  ↳ stylesheets
    ↳ base
      ↳ globals.scss
      ↳ colorswatches.scss
      ↳ buttons.scss
      ↳ links.scss
      ↳ typography.scss
      ↳ forms.scss
      ↳ tables.scss

common

The common folder is how we achieve ‘DRY’ code outside of UI Kit elements. While we generally try to scope our CSS to specific pages (or components if using React), there are definitely some cases where it’s better to re-use CSS within HTML/JS code. We have a dedicated folder for these to help remind developers. It tells the developer, “Hey, if you’re editing something in the common folder, be careful, because it most likely affects more than just the part of the web app that you’re working on.” Additional to some reusable CSS that’s specific to your app, we also include things like layout CSS here. Examples include:

app
↳ assets
  ↳ stylesheets
    ↳ common
      ↳ layout.scss
      ↳ shopping_cart_line_item.scss
      ↳ pricing_badge.scss

components

This is specific to web applications that use Webpacker + React. If you don’t use React, you can skip this part. When we create components and want to scope some CSS specifically to the component. Now I’m sure there are better JS ways to do this, but to be honest we haven’t quite figured them out yet, so we do this instead.

To make this work, we add a CSS ID/class selector to the outer most element of the component that starts with “component-”. Here is an example:

/* product_card.jsx */

...

function ProductCard() {

  return (

    <div className=’component-product-card’>

      ...

    </div>

  );

}

Then we place it’s corresponding CSS in this folder:

/* app/assets/stylesheets/components/product_card.scss */

.component-product-card {

  ...


}

views

This is the last folder and we use this for page specific CSS. To do this scoping, we surround every view template in a <div> or <span> that has an ID in the form of “controller-view”. Here is an example:

<!-- app/views/products/show.html.erb -->

<div id=”products-show”>

  ...


</div>

With the page scoped, we then place the CSS files in a file structure that’s similar to the regular app/views/ folders. We create a folder for each controller and a file for each view.

/* app/assets/stylesheets/views/products/show.scss */

#products-show {

  ...


}

Conclusion

We’ve been using this file structure for over 5 years now and while we know of some shortfalls (e.g. React components named the same but within different folders), it has worked out very well for us. Hopefully this will help others as well!

To view or add a comment, sign in

More articles by Casey Li

  • I'm sick of successful tech companies.

    I’m sick of successful tech companies. Throughout my entire life, I’ve been heavily into tech, but in the past 10 years…

    9 Comments
  • RSpec with Resque

    So one of the gems we use a lot in our Ruby on Rails applications is Resque. For those who don't know, it's a library…

  • Why choose Off-the-shelf Software over Custom Software?

    For those who don’t know, my name is Casey Li, and I run a business that provides Custom Software services. So it might…

  • Custom Software - Software Built Specifically to Solve Your Problem

    So we’ve written many articles about Custom Software. We’ve talked about what it is and what the pros and cons are, but…

  • Why we don’t believe in fixed term contracts

    BiteSite was founded in the summer in 2012 and we’ve worked with a ton of clients on a lot of projects. With that comes…

  • How to build your Software Startup Product

    So you’ve decided to start a company Alright. So you’re toying around with the idea of starting a company -…

  • Software developers of the world, thank you.

    Something dawned on me the other day - something pretty amazing. So I've been a Software Engineer, Developer - whatever…

    5 Comments
  • Our first hire is moving on.

    When I started BiteSite, I was really excited to see what I could do with the company. As a business owner, I found…

    3 Comments
  • The Ultimate Investor Pitch Guide

    When first asked to work with Anil Dilawri, I'll admit I was nervous. I am very passionate about pitches and…

    2 Comments

Others also viewed

Explore content categories