如果你不是 Rails 的開發者
近來有不少開發者使用 Rails 開發網站,因為 Rails 有許多有趣的概念和工具(例如 SASS)可以簡化網站開發的工作。尤其是 SASS,可以讓長得太大而失控的 CSS 被有效的管理。因為實在很好用,SASS 甚至在非 Rails 的前端開發者也流行起來。
雖然 SASS 是非常棒的 CSS 設計工具,但對於不是 Rails 的開發者來說,要使用就不是那麼方便(是的,是有 Grunt 這帖解藥,但總還有一些設定的工作要做)。對於 node.js 的開發者來說,有沒有對應的方案呢?
JASS To The Rescue
node.js 短短幾年爆炸性的成長,幾乎要什麼功能都可以在 npmjs.org 找到了。那麼 node.js 花園裡怎麼可以沒有像 SASS 這樣的東西呢?所以我們決定要建一個 node.js 原生的 CSS 管理套件,讓 node.js 的開發者可以和 Rails 的開發者一樣歡樂。這個 CSS 的管理套件必須具備以下的條件:
- 維持 CSS 原來的語法,讓任何 CSS/Javascript 開發者都能一看就懂,不必學習新的語法。
- 直接以 Javascript 實作,而且越輕便越好
- 如果可能的話,可不可以比 SASS 更強大?
想法是這樣子的:CSS 的設定規則 (rule) 是由選擇器 (selector) 加上屬性 (property set) 所構成。而 CSS 屬性本質上就是一個 Javascript 的物件。如果能直接用 Javascript 物件來表示 CSS 屬性,那麼屬性的管理和使用將會變得非常有彈性。再加上 coServ 原本就可以在 CSS 檔案中嵌入 Javascript。把這二件事整合起來,我們就有了一個比 SASS 還強大的 CSS 管理工具。以下就來比較 SASS 和 JASS 的功能...
JASS vs SASS
我們就根據 SASS 官網上所描述的 SASS 主要特性來做一些比較:
Variables (變數)
SASS 的語法
$font-stack: Helvetica, sans-serif
$primary-color: #333
body
font: 100% $font-stack
color: $primary-color
JASS 的語法
<%
var fontStack = 'Helvetica, sans-serif',
primaryColor = '#333'; %>
body {
font: <%= fontStack %>;
color: <%= primaryColor %>;
}
除了使用 EJS template 的語法來嵌入 Javascript 的程式碼外(<% ... %> 那段原始碼),基本上 JASS 維持了 CSS 的語法,沒有做任何更動。而且 JASS 的變數比 SASS 還強,上面的範例可以直接改寫成:
<% var fontp = {font: 'Helvetica, sans-serif', color: '#333'}; %>
body {
<%= jass.p(fontp); %>
}
<%= 表示要將變數值或函式的回傳值印出來,而 jass.p() 這個函數則幫助我們將 Javascript 物件以 CSS 的語法印出來,而不是一般的 JSON 輸出格式。
Nesting (巢狀疊套)
SASS 官網舉了類似以下的範例來說明巢狀疊套:
nav
ul
margin: 0
padding: 0
list-style: none
li
display: inline-block
JASS 可用以下的方式來處理:
<%
var rTop = jass.r('nav'),
r_ul = jass.r('ul', {margin: 0, padding: 0, 'list-style': 'none'}),
r_li = jass.r('li', {display: 'inline-block'});
rTop.add( [r_ul, r_li] );
%>
<%= rTop.toString(); %>
其中 jass.r() 可以用來建立一條 CSS 規則。在上面的範例中,我們利用 jass.r() 建立了三條 CSS 規則,而且將其中 r_ul 和 r_li 二條規則附加到規則 rTop 之下。最後再將 rTop 印出,就能得到所要的結果。
乍看之下 JASS 的寫法比較繁瑣。但事實上 JASS 可以把 CSS 規則存成一個變數,然後重複使用或再做進一步的處理,讓整個 CSS 的撰寫更有彈性。而上面的範例還有一個進階的用法:如果 r_ul 和 r_li 有共有的屬性,那麼共有屬性可以設在 rTop 中,不必再重複:
<%
var rTop = jass.r('nav', {margin: 0}),
r_ul = jass.r('ul', {'list-style': 'none'}),
r_li = jass.r('li', {display: 'inline-block'});
rTop.add( [r_ul, r_li] );
%>
<%= rTop.toString(); %>
在上面的範例中, r_ul 和 r_li 都會繼承 rTop 的屬性(margin: 0)。
Import (匯入)
將常用的 CSS 設定另外搬到一個檔案之後再匯入到需要的場合,可以避免重複相同 CSS 設定。以下是 SASS 的處理方式:
@import reset
JASS 也有類似的功能:
<% import('reset.css'); %>
Mixins (混用)
SASS 的 mixins 有函式的味道。以下是 SASS 官網提供的範例:
=border-radius($radius)
-webkit-border-radius: $radius
-moz-border-radius: $radius
-ms-border-radius: $radius
border-radius: $radius
.box
+border-radius(10px)
JASS 的寫法:
<%
function borderRadius(radius) {
return {
'-webkit-border-radius': radius,
'-moz-border-radius': radius,
'-ms-border-radius': radius,
'border-radius': radius
};
};
%>
.box { <%= jass.p( borderRadius('10px') ); %>}
因為在 JASS 中 mixins 是以函數處理,所以還可以在函數內做額外的運算(處理)。這是 SASS 做不到的。
Extend (擴充/繼承)
在 SASS 中,一條 CSS 規則可以繼承另一條 CSS 規則的屬性。以下為範例:
.message
border: 1px solid #ccc
padding: 10px
color: #333
.success
@extend .message
border-color: green
事實上,上面的範例是在繼承 CSS 規則中的屬性而已,而不是整個 CSS 規則。JASS 將這個概念表達的更清楚:
<%
var msgProp = {
border: '1px solid #ccc',
padding: '10px',
color: '#333'
};
%>
.message { <%= jass.p(msgProp); %> }
.success {
<%= jass.p(msgProp); %>
border-color: green;
}
Operators (運算元)
既然 JASS 用了類似 ESJ 語法的樣板,所有的 Javascript 功能都在開發者的手中。要在 CSS 設定中叫用運算元當然就是小 case 了。
如何使用
coServ 從 0.9.0 版開始就會支援 JASS,主要就是在 CSS 樣板中加上 jass 這個物件的支援。因此開發者不需要做任何設定或改變。原有的 CSS 檔仍然會正常運作,但開發者可以開始用 JASS 的各項功能,把 CSS 也納入管理吧!