Proper SCSS Asset Structure in Rails

Proper SCSS Asset Structure in Rails

The problem with CSS is, you do not want to automatically add all files.
The order of which your sheets are loaded and processed by the browser is essential. So you will always end up explicitly importing all your css.

As an example, lets say you have a normalize.css sheet, to get a default look instead of all the horrible different browser implementations. This should be the first file the browser loads. If you just randomly include this sheet somewhere in your css imports, it will then not only override the browser default styles, but also any styles defined in all css files that were loaded before it. This goes the same for variables and mixins.

After seeing a presentation by Roy Tomeij at Euruko2012 I decided for the following approach if you have a lot of CSS to manage.

I generally use this approach:

  1. Rename all existing .css files to .scss
  2. Remove all contents from application.scss

Start adding @import directives to application.scss.

If you are using twitters bootstrap and a few css sheets of your own, you have to import bootstrap first, because it has a sheet to reset styles.
So you add @import "bootstrap/bootstrap.scss"; to your application.scss.

The bootstrap.scss file looks like:

// CSS Reset
@import "reset.scss";

// Core
@import "variables.scss";
@import "mixins.scss";

// Grid system and page structure
@import "scaffolding.scss";

// Styled patterns and elements
@import "type.scss";
@import "forms.scss";
@import "tables.scss";
@import "patterns.scss";

And your application.scss file look like:

@import "bootstrap/bootstrap.scss";

Because of the order of the imports, you can now use the variables, loaded with @import "variables.scss"; in any other .scss file imported after it. So they can be used in type.scss in the bootstrap folder but also in my_model.css.scss.

After this create a folder named partials or modules. This will be the place of most of the other files. You can just add the import to the application.scss file so it will look like:

@import "bootstrap/bootstrap.scss";
@import "partials/*";

Now if you make a bit of css to style an article on your homepage. Just create partials/_article.scss and it will be added to the compiled application.css. Because of the import order you can also use any bootstrap mixins and variables in your own scss files.

The only drawback of this method I found so far is, sometimes you have to force a recompile of the partial/*.scss files because rails wont always do it for you.

How do I organize SCSS in rails?

You don't need to use Sprockets comments in your application.scss and must only use @import CSS rules.

From rails-sass documentation:

Sprockets provides some directives that are placed inside of comments
called require, require_tree, and require_self. DO NOT USE THEM IN
YOUR SASS/SCSS FILES. They are very primitive and do not work well
with Sass files. Instead, use Sass's native @import directive which
sass-rails has customized to integrate with the conventions of your
Rails projects.

Then, if you have any other .scss that needs to be precompiled, you will have to explicitly add them using the Rails.Application.config.assets.precompile directive, then the sprockets railtie will do the rest of the job!

To answer your original question, the reason why the open source project do not need to specify assets to precompile is because they are using config.assets.compile = true in the config/environment/production.rb file. This is obviously a very bad practice and I don't recommend you to switch this directive to true in a production environment... you will end up with a slow code making a lot of requests and there a slow page load.

Persisting SCSS variables in rails asset pipeline?

The default manifest syntax isn't powerful enough to give you useful Sass features like shared variables, mixins, etc. Instead, you should:

  1. Rename application.css to application.scss (or application.css.scss in Rails 4 or earlier)
  2. Instead of using the

    /*
    *= require variables
    *= require mixins
    *= require_tree .
    */

    nonsense, you should now use

    @import "variables";
    @import "mixins";
    @import "blah"; // import each SCSS file in your project like this.

    This will ensure you have full benefit of your variables and mixins throughout your project, and you are kept as DRY as Sass allows.

Can we use scss (sass-rails) in rails css.erb view files or is this just a asset pipeline thing?

Its theoretically possible by invoking the sass compiler. Note that you want to be using a request for css and not scss. There is no reason the client needs to know how the file is produced.

<%= stylesheet_link_tag(about_me_user_path(current_user, format: :css), media: 'all', class: "home_about_me_css") %>

class UsersController
def user_profile_stylesheet
respond_to do |f|
f.css do
fn = Rails.root.join('app', 'views', 'home', 'home_stylesheet.css.scss.erb')
# expand ERB template
sass = render_to_string(file: fn)
# run rendered template through the sass compiler
css = SassC::Engine.new(sass, style: :compressed).render
render text: css
end
end
end
end

I'm not so sure its something you really want to do in production as it requires you to compile sass at run-time when responding to requests. And you won't be able reference anything like SASS functions in your assets pipeline since this is compiled outside the pipeline.

Its also a security nightmare since SASS is not just declarative like CSS. And this could be exploited to execute code on your server.

Whatever you're trying to do there has to be a smarter / less complex solution.

Proper syntax for application.scss

You are correct, you should replace require statement to @import. Below is the sample one,

@import 'bootstrap-sprockets';
@import 'bootstrap';
@import 'bootstrap_include';
@import 'dataTables/bootstrap/3/jquery.dataTables.bootstrap';
@import 'jquery-ui/core';
@import 'jquery-ui/theme';
@import 'datepicker';

So, that you should be able to use the predefined sass variables in you scss files.

Accessing Rails Models or Helpers in SCSS

You can chain template processors with Rails 3.1, so you can do my.css.scss.erb, and then embed your variables like so:

$user-background-color: <%= current_user.preferences.background_color %>

Then you can use the Sass variables throughout your SCSS.

I took a different approach to solving this problem for Rails 3.0: Using SASS with user-specified colors

How to import SCSS mixins in a Rails app?

We typically put mixins in a partial file called _mixins.scss directly in the app/assets/stylesheets/ directory, possibly under a subdir like shared if you want more organization. In your application.css you can then do (as you did)

@import 'shared/mixins';
@import 'shared/colors';

or whatever. If you really want them to sit somewhere else, you should look into the load_paths configuration setting for SASS. You can tell SASS where to look when it's importing files and probably lib/assets and vendor/assets are not included by default.

To add this configuration, in your environment.rb or other config file, you can do something like

config.sass.load_paths << File.expand_path('../../vendor/assets/stylesheets/')

which will make SASS look in vendor/assets/stylesheets in addition to all the other directories it searches in by default.



Related Topics



Leave a reply



Submit