# 5.2 Sass 和 Asset Pipeline
在新版 Rails 中,最大的變化是增加了 Asset Pipeline,這個功能明顯提升了 CSS、JavaScript 和圖片等靜態資源文件的生成效率,而且還能降低管理成本。本節我們先大致介紹一下 Asset Pipeline,然后說明如何使用強大的 CSS 編寫工具 Sass。
## 5.2.1 Asset Pipeline
Asset Pipeline 對 Rails 做了很多改動,但對 Rails 開發者來說只有三個特性需要了解:靜態資源文件夾,清單文件,以及預處理器引擎。[[11](#fn-11)]下面一一介紹。
### 靜態資源文件夾
在 Rails 3.0 及之前的版本,靜態文件放在 `public/` 文件夾中,并且按照下面的方式組織:
* `public/stylesheets`
* `public/javascripts`
* `public/images`
這些文件夾中的文件通過請求 [http://example.com/stylesheets](http://example.com/stylesheets) 等地址直接發送給瀏覽器。(Rails 3.0 之后的版本也會這么做。)
在最新版 Rails 中,靜態文件可以放在三個標準文件夾中,而且各有各的用途:
* `app/assets`:當前應用的資源文件;
* `lib/assets`:開發團隊自己開發的代碼庫使用的資源文件;
* `vendor/assets`:第三方代碼庫使用的資源文件;
你可能猜到了,這幾個文件夾中都有針對不同資源類型的子文件夾,例如:
```
$ ls app/assets/
http://railstutorial-china.org/book/images/ javascripts/ stylesheets/
```
現在我們知道 [5.1.2 節](#bootstrap-and-custom-css)中 `custom.css.scss` 存放位置的用意了:因為 `custom.css.scss` 只在應用中使用,所以把它存放在 `app/assets/stylesheets` 文件夾中。
### 清單文件
把資源文件放在適當的文件夾中之后,要通過清單文件告訴 Rails 怎么把它們合并成一個文件(通過 [Sprockets](https://github.com/sstephenson/sprockets) gem 實現,而且只能合并 CSS 和 JavaScript 文件,不會合并圖片)。舉個例子,我們來看一下應用默認的樣式表清單文件,如[代碼清單 5.14](#listing-app-css-manifest) 所示。
##### 代碼清單 5.14:應用的樣式表清單文件
app/assets/stylesheets/application.css
```
/*
* This is a manifest file that'll be compiled into application.css, which
* will include all the files listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets,
* vendor/assets/stylesheets, or vendor/assets/stylesheets of plugins, if any,
* can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear
* at the bottom of the compiled file so the styles you add here take
* precedence over styles defined in any styles defined in the other CSS/SCSS
* files in this directory. It is generally better to create a new file per
* style scope.
*
*= require_tree .
*= require_self
*/
```
這里關鍵的代碼是幾行 CSS 注釋,Sprockets 通過這些注釋引入相應的文件:
```
/*
.
.
.
*= require_tree .
*= require_self
*/
```
其中
```
*= require_tree .
```
會把 `app/assets/stylesheets` 文件夾中的所有 CSS 文件(包含子文件夾中的文件)都引入應用的 CSS 。
下面這行:
```
*= require_self
```
會把 `application.css` 這個文件中的 CSS 也加載進來。
Rails 提供的默認清單文件可以滿足我們的需求,所以本書不會對其做任何修改。Rails 指南中有一篇專門[介紹 Asset Pipeline 的文章](http://guides.rubyonrails.org/asset_pipeline.html),說得更詳細。
### 預處理器引擎
準備好資源文件后,Rails 會使用一些預處理器引擎來處理它們,并通過清單文件將其合并,然后發送給瀏覽器。我們通過擴展名告訴 Rails 使用哪個預處理器。三個最常用的擴展名是:Sass 文件的 `.scss`,CoffeeScript 文件的 `.coffee`,ERb 文件的 `.erb`。我們在 [3.4.3 節](chapter3.html#layouts-and-embedded-ruby)介紹過 ERb,[5.2.2 節](#syntactically-awesome-stylesheets)會介紹 Sass。本書不會使用 CoffeeScript,這是一個很小巧的語言,可以編譯成 JavaScript。(RailsCast 中[關于 CoffeeScript 的視頻](http://railscasts.com/episodes/267-coffeescript-basics)是很好的入門教程。)
預處理器引擎可以連接在一起使用,因此
```
foobar.js.coffee
```
只會使用 CoffeeScript 處理器,而
```
foobar.js.erb.coffee
```
會使用 CoffeeScript 和 ERb 處理器(按照擴展名的順序從右向左處理,所以 CoffeeScript 處理器先執行)。
### 在生產環境中的效率問題
Asset Pipeline 帶來的好處之一是,能自動優化資源文件,在生產環境中使用效果極佳。CSS 和 JavaScript 的傳統組織方式是,把不同功能的代碼放在不同的文件中,而且排版良好(有很多縮進)。這么做對編程人員很友好,但在生產環境中使用卻效率低下——加載大量的文件會明顯增加頁面的加載時間,這是影響用戶體驗最主要的因素之一。使用 Asset Pipeline,生產環境中應用所有的樣式都會集中到一個 CSS 文件中(`application.css`),所有 JavaScript 代碼都會集中到一個 JavaScript 文件中(`application.js`),而且還會壓縮這些文件,刪除不必要的空格,減小文件大小。這樣我們就最好地平衡了兩方面的需求,開發方便,線上高效。
## 5.2.2 句法強大的樣式表
Sass 是一種編寫 CSS 的語言,從多方面增強了 CSS 的功能。本節我們要介紹兩個最主要的功能:嵌套和變量。(還有一個功能是“混入”,[7.1.1 節](chapter7.html#debug-and-rails-environments)再介紹。)
[5.1.2 節](#bootstrap-and-custom-css)說過,Sass 支持一種名為 SCSS 的格式(擴展名為 `.scss`),這是 CSS 句法的一個擴展集。SCSS 只為 CSS 添加了一些功能,而沒有定義全新的句法。[[12](#fn-12)]也就是說,所有有效的 CSS 文件都是有效的 SCSS 文件,這對已經定義了樣式的項目來說是件好事。在我們的應用中,因為要使用 Bootstrap,所以從一開始就使用了 SCSS。Rails 的 Asset Pipeline 會自動使用 Sass 預處理器處理擴展名為 `.scss` 的文件,所以 `custom.css.scss` 文件會首先經由 Sass 預處理器處理,然后引入應用的樣式表中,再發送給瀏覽器。
### 嵌套
樣式表中經常會定義嵌套元素的樣式,例如,在[代碼清單 5.5](#listing-universal-css) 中,定義了 `.center` 和 `.center h1` 兩個樣式:
```
.center {
text-align: center;
}
.center h1 {
margin-bottom: 10px;
}
```
使用 Sass 可將其改寫成
```
.center {
text-align: center;
h1 { margin-bottom: 10px;
}
}
```
內層的 `h1` 會自動放入 `.center` 上下文中。
嵌套還有一種形式,句法稍有不同。在[代碼清單 5.7](#listing-logo-css) 中,有如下的代碼
```
#logo {
float: left;
margin-right: 10px;
font-size: 1.7em;
color: #fff;
text-transform: uppercase;
letter-spacing: -1px;
padding-top: 9px;
font-weight: bold;
}
#logo:hover {
color: #fff;
text-decoration: none;
}
```
其中 LOGO 的 ID `#logo` 出現了兩次,一次單獨出現,另一次和 `hover` 偽類一起出現(鼠標懸停其上時的樣式)。如果要嵌套第二組規則,我們要引用父級元素 `#logo`,在 SCSS 中,使用 `&` 符號實現:
```
#logo {
float: left;
margin-right: 10px;
font-size: 1.7em;
color: #fff;
text-transform: uppercase;
letter-spacing: -1px;
padding-top: 9px;
font-weight: bold;
&:hover { color: #fff;
text-decoration: none;
}
}
```
把 SCSS 轉換成 CSS 時,Sass 會把 `&:hover` 編譯成 `#logo:hover`。
這兩種嵌套方式都可以用在[代碼清單 5.13](#listing-footer-css) 中的底部樣式上,改寫成:
```
footer {
margin-top: 45px;
padding-top: 5px;
border-top: 1px solid #eaeaea;
color: #777;
a {
color: #555;
&:hover {
color: #222;
}
}
small {
float: left;
}
ul {
float: right;
list-style: none;
li {
float: left;
margin-left: 15px;
}
}
}
```
自己動手改寫[代碼清單 5.13](#listing-footer-css) 是個不錯的練習,改完后應該驗證一下 CSS 是否還能正常使用。
### 變量
Sass 允許我們自定義變量來避免重復,這樣也可以寫出更具表現力的代碼。例如,[代碼清單 5.6](#listing-typography-css) 和[代碼清單 5.13](#listing-footer-css) 中都重復使用了同一個顏色代碼:
```
h2 {
.
.
.
color: #777; }
.
.
.
footer {
.
.
.
color: #777; }
```
上面代碼中的 `#777` 是淡灰色,我們可以把它定義成一個變量:
```
$light-gray: #777;
```
然后我們可以這樣寫 SCSS:
```
$light-gray: #777;
.
.
.
h2 {
.
.
.
color: $light-gray;
}
.
.
.
footer {
.
.
.
color: $light-gray;
}
```
因為像 `$light-gray` 這樣的變量名比 `#777` 意思更明確,所以把不重復使用的值定義成變量往往也是很有用的。其實,Bootstrap 框架定義了很多顏色變量,[Bootstrap 文檔中有這些變量的 Less 形式](http://getbootstrap.com/customize/#less-variables)。這個頁面中的變量使用 Less 句法,而不是 Sass,不過 `bootstrap-sass` gem 為我們提供了對應的 Sass 形式。二者之間的對應關系也不難猜測,Less 使用 `@` 符號定義變量,而 Sass 使用 `$` 符號。在 Bootstrap 文檔中我們看到已經為淡灰色定義了變量:
```
@gray-light: #777;
```
也就是說,在 `bootstrap-sass` gem 中有一個對應的 SCSS 變量 `$gray-light`。我們可以用它換掉自己定義的 `$light-gray` 變量:
```
h2 {
.
.
.
color: $gray-light;
}
.
.
.
footer {
.
.
.
color: $gray-light;
}
```
使用 Sass 提供的嵌套和變量功能改寫應用的整個樣式表后得到的代碼如[代碼清單 5.15](#listing-refactored-scss) 所示。這段代碼使用了 Sass 變量(參照 Bootstrap Less 變量頁面)和內置的顏色名稱(例如,`white` 代表 `#fff`)。特別注意一下 `footer` 標簽樣式的明顯改進。
##### 代碼清單 5.15:使用嵌套和變量改寫后的 SCSS 文件
app/assets/stylesheets/custom.css.scss
```
@import "bootstrap-sprockets";
@import "bootstrap";
/* mixins, variables, etc. */
$gray-medium-light: #eaeaea;
/* universal */
body {
padding-top: 60px;
}
section {
overflow: auto;
}
textarea {
resize: vertical;
}
.center {
text-align: center;
h1 {
margin-bottom: 10px;
}
}
/* typography */
h1, h2, h3, h4, h5, h6 {
line-height: 1;
}
h1 {
font-size: 3em;
letter-spacing: -2px;
margin-bottom: 30px;
text-align: center;
}
h2 {
font-size: 1.2em;
letter-spacing: -1px;
margin-bottom: 30px;
text-align: center;
font-weight: normal;
color: $gray-light;
}
p {
font-size: 1.1em;
line-height: 1.7em;
}
/* header */
#logo {
float: left;
margin-right: 10px;
font-size: 1.7em;
color: white;
text-transform: uppercase;
letter-spacing: -1px;
padding-top: 9px;
font-weight: bold;
&:hover {
color: white;
text-decoration: none;
}
}
/* footer */
footer {
margin-top: 45px;
padding-top: 5px;
border-top: 1px solid $gray-medium-light;
color: $gray-light;
a {
color: $gray;
&:hover {
color: $gray-darker;
}
}
small {
float: left;
}
ul {
float: right;
list-style: none;
li {
float: left;
margin-left: 15px;
}
}
}
```
Sass 提供了很多簡化樣式表的功能,[代碼清單 5.15](#listing-refactored-scss) 只用到了最主要的功能,這是個好的開始。更多功能請查看 [Sass 的網站](http://sass-lang.com/)。
- Ruby on Rails 教程
- 致中國讀者
- 序
- 致謝
- 作者譯者簡介
- 版權和代碼授權協議
- 第 1 章 從零開始,完成一次部署
- 1.1 簡介
- 1.2 搭建環境
- 1.3 第一個應用
- 1.4 使用 Git 做版本控制
- 1.5 部署
- 1.6 小結
- 1.7 練習
- 第 2 章 玩具應用
- 2.1 規劃應用
- 2.2 用戶資源
- 2.3 微博資源
- 2.4 小結
- 2.5 練習
- 第 3 章 基本靜態的頁面
- 3.1 創建演示應用
- 3.2 靜態頁面
- 3.3 開始測試
- 3.4 有點動態內容的頁面
- 3.5 小結
- 3.6 練習
- 3.7 高級測試技術
- 第 4 章 Rails 背后的 Ruby
- 4.1 導言
- 4.2 字符串和方法
- 4.3 其他數據類型
- 4.4 Ruby 類
- 4.5 小結
- 4.6 練習
- 第 5 章 完善布局
- 5.1 添加一些結構
- 5.2 Sass 和 Asset Pipeline
- 5.3 布局中的鏈接
- 5.4 用戶注冊:第一步
- 5.5 小結
- 5.6 練習
- 第 6 章 用戶模型
- 6.1 用戶模型
- 6.2 用戶數據驗證
- 6.3 添加安全密碼
- 6.4 小結
- 6.5 練習
- 第 7 章 注冊
- 7.1 顯示用戶的信息
- 7.2 注冊表單
- 7.3 注冊失敗
- 7.4 注冊成功
- 7.5 專業部署方案
- 7.6 小結
- 7.7 練習
- 第 8 章 登錄和退出
- 8.1 會話
- 8.2 登錄
- 8.3 退出
- 8.4 記住我
- 8.5 小結
- 8.6 練習
- 第 9 章 更新,顯示和刪除用戶
- 9.1 更新用戶
- 9.2 權限系統
- 9.3 列出所有用戶
- 9.4 刪除用戶
- 9.5 小結
- 9.6 練習
- 第 10 章 賬戶激活和密碼重設
- 10.1 賬戶激活
- 10.2 密碼重設
- 10.3 在生產環境中發送郵件
- 10.4 小結
- 10.5 練習
- 10.6 證明超時失效的比較算式
- 第 11 章 用戶的微博
- 11.1 微博模型
- 11.2 顯示微博
- 11.3 微博相關的操作
- 11.4 微博中的圖片
- 11.5 小結
- 11.6 練習
- 第 12 章 關注用戶
- 12.1 “關系”模型
- 12.2 關注用戶的網頁界面
- 12.3 動態流
- 12.4 小結
- 12.5 練習