Rails 中适当的 SCSS 资产结构

所以,我有一个 app/assets/stylesheets/目录结构,看起来像这样:

   |-dialogs
|-mixins
|---buttons
|---gradients
|---vendor_support
|---widgets
|-pages
|-structure
|-ui_elements

在每个目录中,有多个 sass 部分(通常是 * . css.scss,但有一个或两个 * . css.scss.erb)。

我可能假设了很多,但是因为 application.css 中的 *= require_tree .,Rails 应该自动编译这些目录中的所有文件,对吗?

最近,我尝试重新构造这些文件,删除所有颜色变量,并将它们放在根 app/assets/stylesheets文件夹(_ colors. css.scss)中的一个文件中。然后,我在根 app/assets/stylesheets文件夹中创建了一个名为 master. css.scss 的文件,如下所示:

// Color Palette
@import "colors";


// Mixins
@import "mixins/buttons/standard_button";
@import "mixins/gradients/table_header_fade";
@import "mixins/vendor_support/rounded_corners";
@import "mixins/vendor_support/rounded_corners_top";
@import "mixins/vendor_support/box_shadow";
@import "mixins/vendor_support/opacity";

我并不真正理解 Rail 如何处理资产编译的顺序,但它显然对我不利。似乎没有一个文件意识到它们导入了任何变量或混合,所以它抛出了错误,我无法编译。

Undefined variable: "$dialog_divider_color".
(in /home/blah/app/assets/stylesheets/dialogs/dialog.css.scss.erb)


Undefined mixin 'rounded_corners'.
(in /home/blah/app/assets/stylesheets/widgets.css.scss)

变量 $dialog_divider_color在 _ color. css.scss 中明确定义,_master.css.scss导入颜色和所有混合。但很显然 Rails 没有收到那份备忘录。

有没有什么方法可以修复这些错误,或者我需要将所有的变量定义放回到每个单独的文件,以及所有的混合导入?

不幸的是,这家伙似乎认为这是不可能的,但我希望他是错的。任何想法都非常感谢。

58353 次浏览

According to this question, you can ONLY use application.css.sass in order to define import and share variables between your templates.

=> It seems to be only a matter of name.

An other way can be to include everything and disable this pipeline.

Create the following folder structure:

+ assets
|
--+ base
| |
| --+ mixins (with subfolders as noted in your question)
|
--+ styles
|
--+ ...

In folder base create a file "globals.css.scss". In this file, declare all your imports:

@import 'base/colors';
@import 'base/mixins/...';
@import 'base/mixins/...';

In you application.css.scss, you should then have:

*= require_self
*= depends_on ./base/globals.css.scss
*= require_tree ./styles

And as the last step (this is important), declare @import 'base/globals' in every style file where you want to use variables or mixins. You might consider this overhead, but I actually like the idea that you have to declare the dependencies of your styles in every file. Of course, it is important that you only import mixins and variables in the globals.css.scss as they do not add style definitions. Otherwise the style definitions would be included multiple times in your precompiled file ...

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.

I had a very similar problem. What helped me was to put in the underscore to the @import statement when importing the partial. So

@import "_base";

instead of

@import "base";

It might be a strange bug...

to use variables and such across files, you need to use the @import directive. files are imported in order specified.

then, use application.css to require the file that declares the imports. this is the way to achieve the control you want.

finally, in your layout.erb file, you can specify which "master" css file to use

example will be more helpful:

let's say you have two modules in your app that need different sets of css: "application" and "admin"

the files

|-app/
|-- assets/
|--- stylesheets/
|     // the "master" files that will be called by the layout
|---- application.css
|---- application_admin.css
|
|     // the files that contain styles
|---- config.scss
|---- styles.scss
|---- admin_styles.scss
|
|     // the files that define the imports
|---- app_imports.scss
|---- admin_imports.scss
|
|
|-- views/
|--- layouts/
|---- admin.html.haml
|---- application.html.haml

here's what the files look like inside:

-------- THE STYLES


-- config.scss
// declare variables and mixins
$font-size: 20px;


--  app_imports.scss
// using imports lets you use variables from `config` in `styles`
@import 'config'
@import 'styles'


-- admin_imports.scss
// for admin module, we import an additional stylesheet
@import 'config'
@import 'styles'
@import 'admin_styles'


-- application.css
// in the master application file, we require the imports
*= require app_imports
*= require some_other_stylesheet_like_a_plugin
*= require_self


-- application_admin.css
// in the master admin file, we require the admin imports
*= require admin_imports
*= require some_other_stylesheet_like_a_plugin
*= require_self




-------- THE LAYOUTS


-- application.html.haml
// in the application layout, we call the master css file
= stylesheet_link_tag "application", media: "all"


--  admin.html.haml
// in the admin layout, we call the admin master css file
= stylesheet_link_tag "application_admin", media: "all"

My solution was to have an application.css.scss with all the imports:

@import "./inputs";
@import "./buttons";
@import "./rails";
@import "./base";
@import "./checked-border";
@import "./tailwind-extended";
@import "./helpers";
@import "./custom";
@import "./overrides";

And then add:

@import "./constants";

to the files that use the constants