stylus筆記


Stylus介紹及特點

基於Node.js的css的預處理框架,其本質上做的事情與 Sass/LESS 等類似, 可以以近似腳本的方式去寫CSS代碼,創建健壯的、動態的、富有表現力的CSS,默認使用 .styl 的作為文件擴展名,支持多樣性的CSS語法。Stylus比LESS更強大,而且基於nodejs比Sass更符合我們的思路。

Stylus的特點如下

  • 基於js

Node.js是一個Javascript運行環境(runtime),是對Google V8引擎進行了封裝,V8引擎執行Javascript的速度非常快,性能非常好。對於不了解Node.js的開發人員,不會增加太多學習成本。Stylus基於Node.js,換而言之,就是借助JavaScript讓CSS更富有表現力,更動態,更健壯!而且還有專門的JavaScript API。

  • 支持Ruby之類框架

雖然Stylus基於Node.js,但是依然支持Ruby之類框架,還有FireBug插件FireStylus, sublimetext插件,便於開發、調試。

  • 功能強大,使用靈活,支持多樣性的CSS語法

Stylus的功能比LESS強大,不遜於Sass。在用法上,支持傳統的CSS,而且相對於傳統的用法,更加簡潔、靈活,像省掉花括號、冒號,分號,甚至使用混合的CSS編程,Stylus都可以接受。

Stylus的優缺點

【優點】

解決樣式覆寫的問題,尤其是mixin式復用

使用純CSS,我們可以抽象出一些常用的布局CSS屬性組合,通過CSS的類組合來達成常見的mixin式復用,然而這種方案存在一些問題,例如:

當頁面重構時,需要頻繁修改class name,這個問題在后端人員掌握着視圖層的時候格外突出,前后端耗費很多溝通成本;

在約束上下文的時候非常無力,比如“只有在ul下面的img.db允許是display:block”的規則,寫成“ul img.db { display: block; }”就完全跑偏了,它違背了創建這個.db類時的本意,造成了代碼的可讀性和可維護性下降。

如果你要改動規則,需要同時修改HTML和CSS,也可能造成新的樣式問題。

而通過Stylus可以建立一種新的代碼風格,只允許CSS Class代表UI模塊的抽象,這樣一來,改動樣式時不至於通知后端改模板,然后在CSS Class內部實現mixin。而這正是CSS的短板,CSS體系內的用法只有復制粘貼。

可緩解多瀏覽器兼容造成的冗余

進入CSS3的時代,舊式CSS hack如filter,新式兼容前綴如-webkit-等,都是冗余,修改的時候也需要修改多處,不容易維護。在Stylus里面,寫個函數就能解決,多次復用也不需要看到如此之多的hack。

提高效率,節約成本

用Stylus開發CSS可以提高效率,它類似於一種CSS的方言,可以用更精簡的語法表達更多的意思。比如,Stylus中可以使用變量,比如和 UED 同學訂好各種樣式的規范,做好變量后開發中直接使用,避免頁面中的各種雜亂樣式。當樣式需求有變動時,也可以重新給變量賦值,一下改掉相關樣式,不用再一點一點的改。

使CSS開發更加靈活

Stylus可以使用變量、條件、循環,兼容傳統的CSS樣式,等等,可以讓CSS的開發和修改更加靈活。

【缺點】

開發過程增加步驟

CSS的好處在於簡便、隨時隨地被使用和調試,使用Stylus,增加了預編譯CSS的步驟,讓我們開發工作流中多了一個環節,調試也多了個步驟。

增加學習成本。

雖然Stylus簡單易學,可以兼容傳統CSS,但是當開發和維護團隊都從CSS過渡到Stylus時,還是需要一點學習成本的,而且初學者使用起來,不一定能明顯提高效率。

語法:

1. 選擇器

Stylus就跟CSS一樣,允許你使用逗號為多個選擇器同時定義屬性。

textarea, input
  border 1px solid #eee
使用新行是一樣的效果:

textarea
input
  border 1px solid #eee
等同於:

textarea,
input {
  border: 1px solid #eee;
}
父級引用

字符&指向父選擇器。下面這個例子,我們兩個選擇器(textareainput)在:hover偽類選擇器上都改變了color

textarea
input
  color #A7A7A7
  &:hover
    color #000
等同於:
textarea,
input {
  color: #a7a7a7;
}
textarea:hover,
input:hover {
  color: #000;
}
消除歧義

類似padding - n的表達式可能既被解釋成減法運算,也可能被釋義成一元負號屬性。為了避免這種歧義,用括號包裹表達式:

pad(n)
  padding (- n)

body
  pad(5px)

編譯為:

body {
  padding: -5px;
}

然而,只有在函數中才會這樣(因為函數同時用返回值扮演混合或回調)。

有Stylus無法處理的屬性值?unquote()可以幫你:

filter unquote('progid:DXImageTransform.Microsoft.BasicImage(rotation=1)')
生成為:
filter progid:DXImageTransform.Microsoft.BasicImage(rotation=1)

2.變量

我們可以指定表達式為變量,然后在我們的樣式中貫穿使用:

font-size = 14px

body
  font font-size Arial, sans-seri

變量甚至可以組成一個表達式列表:

font-size = 14px
font = font-size "Lucida Grande", Arial

body
  font font sans-serif      

編譯為:font: 14px "Lucida Grande", Arial sans-serif;

標識符(變量名,函數等),也可能包括$字符。例如:

$font-size = 14px
body {
  font: $font-size sans-serif;
}
屬性查找

Stylus有另外一個很酷的獨特功能,不需要分配值給變量就可以定義引用屬性。下面是個很好的例子,元素水平垂直居中對齊(典型的方法是使用百分比和margin負值),如下:

#logo
  position: absolute
  top: 50%
  left: 50%
  width: w = 150px
  height: h = 80px
  margin-left: -(w / 2)
  margin-top: -(h / 2)

我們不使用這里的變量w和h, 而是簡單地前置@字符在屬性名前來訪問該屬性名對應的值: #logo position: absolute top:
50% left: 50% width: 150px height: 80px margin-left: -(@width / 2) margin-top: -(@height / 2)

3. 插值

Stylus支持通過使用{}字符包圍表達式來插入值,其會變成標識符的一部分。例如,-webkit-{'border' + '-radius'}等同於-webkit-border-radius.

比較好的例子就是私有前綴屬性擴展

vendor(prop, args)
  -webkit-{prop} args
  -moz-{prop} args
  {prop} args

border-radius() 
  vendor('border-radius', arguments)

box-shadow()
  vendor('box-shadow', arguments)

button
  border-radius 1px 2px / 3px 4px
變身:

button {
  -webkit-border-radius: 1px 2px / 3px 4px;
  -moz-border-radius: 1px 2px / 3px 4px;
  border-radius: 1px 2px / 3px 4px;
}
選擇器插值

插值也可以在選擇器上起作用。例如,我們可以指定表格前5行的高度,如下:

table
  for row in 1 2 3 4 5
    tr:nth-child({row})
      height: 10px * row
也就是:

table tr:nth-child(1) {
  height: 10px;
}
table tr:nth-child(2) {
  height: 20px;
}
table tr:nth-child(3) {
  height: 30px;
}
table tr:nth-child(4) {
  height: 40px;
}
table tr:nth-child(5) {
  height: 50px;
}

4.運算符

運算符優先級:從最高到最低

[]
! ~ + -
is defined
** * / %
+ -
... ..
<= >= < >
in
== is != is not isnt
is a
&& and || or
?:
= := ?= += -= *= /= %=
not
if unless

一元運算符, !,not, -, +,以及~     

-5px
// => -5px

--5px
// => 5px

not true
// => false

not not true
// => true

not的優先級較低
a = 0
b = 1

!a and !b
// => false
// 解析為: (!a) and (!b)
 
         

用:

 
         
not a or b
// => false
// 解析為: not (a or b)

范圍..  ...

同時提供包含界線操作符(..)范圍操作符(...),見下表達式:

1..5
// => 1 2 3 4 5

1...5
// => 1 2 3 4

加減乘除余 + - * / %  :二元加乘運算其單位會轉化,或使用默認字面量值。例如,5s - 2px結果是3s

20mm + 4in
// => 121.6mm

"foo " + "bar"
// => "foo bar"

"num " + 15
// => "num 15"

2000ms + (1s * 2)
// => 4000ms

5s / 2
// => 2.5s

4 % 2
// => 0

當在屬性值內使用/時候,你必須用括號包住。否則/會根據其字面意思處理(支持CSS的line-height)。

font: 14px/1.5;
但是,下面這個卻等同於14px ÷ 1.5: font: (14px/1.5); 只有/操作符的時候需要這樣

指數:**

相等與關系運算:== != >= <= > <

相等運算符可以被用來等同單位、顏色、字符串甚至標識符。這是個強大的概念,甚至任意的標識符(例如wahoo)可以作為原子般使用。函數可以返回yesno代替truefalse(雖然不建議)。

別名:

==    is
!=    is not
!=    isnt
5 == 5
// => true

10 > 5
// => true

#fff == #fff
// => true

true == false
// => false

wahoo == yay
// => false

wahoo == wahoo
// => true

"test" == "test"
// => true

true is true
// => true

'hey' is not 'bye'
// => true

'hey' isnt 'bye'
// => true

(foo bar) == (foo bar)
// => true

(1 2 3) == (1 2 3)
// => true

(1 2 3) == (1 1 3)
// => false

只有精確值才匹配,例如,0 == falsenull == false均返回false.

真與假

Stylus近乎一切都是true, 包括有后綴的單位,甚至0%0px等都被認作true.

不過,0在算術上本身是false.

表達式(或“列表”)長度大於1被認為是真。

true例子:

0% 0px
1px 
-1
-1px
hey
'hey'
(0 0 0)
('' '')

false:

0 
null
false
''
邏輯操作符:&& || 和 or

邏輯操作符&&||別名是and / or。它們優先級相同。

存在操作符:in

檢查左邊內容是否在右邊的表達式中。

元組同樣適用:

vals = (error 'one') (error 'two')
error in vals
// => false

(error 'one') in vals
// => true

(error 'two') in vals
// => true

(error 'something') in vals
// => false

混合書寫適用例子:

pad(types = padding, n = 5px)
  if padding in types
    padding n
  if margin in types
    margin n

body
  pad()

body
  pad(margin)

body
  pad(padding margin, 10px)
對應於:
body {
  padding: 5px;
}
body {
  margin: 5px;
}
body {
  padding: 10px;
  margin: 10px;
}
條件賦值:?= :=

條件賦值操作符?=(別名?:)讓我們無需破壞舊值(如果存在)定義變量。該操作符可以擴展成三元內is defined的二元操作。

例如,下面這些都是平起平坐的:

color := white
color ?= white
color = color is defined ? color : white
如果我們使用等號=, 就只是簡單地賦值。
color = white
color = black

color
// => black

但當使用?=,第二個相當就嗝屁了(因為變量已經定義了): color = white color ?= black color // => white
實例檢查:is a

Stylus提供一個二元運算符叫做is a, 用做類型檢查。

15 is a 'unit'
// => true

#fff is a 'rgba'
// => true

15 is a 'rgba'
// => false
另外,我們可以使用type()這個內置函數。

type(#fff) == 'rgba'
// => true

注意:color是唯一的特殊情況,當左邊是RGBA或者HSLA節點時,都為true.

變量定義:is defined   用來檢查變量是否已經分配了值。

該操作符必不可少,因為一個未定義的標識符仍是真值,如:

body
  if ohnoes
    padding 5px
當未定義的時候,產生的是下面的CSS:

body {
  padding: 5px;
}
顯然,這不是我們想要的,如下書寫就安全了:

body
  if ohnoes is defined     padding 5px

三元   

num = 15
num ? unit(num, 'px') : 20px
// => 15px

5.混合書寫(Mixins)

混入 混入和函數定義方法一致,但是應用卻大相徑庭。

例如,下面有定義的border-radius(n)方法,其卻作為一個mixin(如,作為狀態調用,而非表達式)調用。

border-radius()選擇器中調用時候,屬性會被擴展並復制在選擇器中。

border-radius(n)
  -webkit-border-radius n
  -moz-border-radius n
  border-radius n

form input[type=button]
  border-radius(5px)
編譯成:

form input[type=button] {
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  border-radius: 5px;
}

我們可以利用arguments這個局部變量,傳遞可以包含多值的表達式。

border-radius()
  -webkit-border-radius arguments
  -moz-border-radius arguments
  border-radius arguments

現在,我們可以像這樣子傳值:border-radius 1px 2px / 3px 4px!

另外一個很贊的應用是特定的私有前綴支持——例如IE瀏覽器的透明度:

support-for-ie ?= true

opacity(n)
  opacity n
  if support-for-ie
    filter unquote('progid:DXImageTransform.Microsoft.Alpha(Opacity=' + round(n * 100) + ')')

#logo
  &:hover
    opacity 0.5
渲染為:

#logo:hover {
  opacity: 0.5;
  filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50); }

父級引用

混合書寫可以利用父級引用字符&, 繼承父業而不是自己築巢

例如,我們要用stripe(even, odd)創建一個條紋表格。evenodd均提供了默認顏色值,每行也指定了background-color屬性。我們可以在tr嵌套中使用&來引用tr,以提供even顏色。

stripe(even = #fff, odd = #eee)
 tr
   background-color odd
   &.even
   &:nth-child(even)
       background-color even
然后,利用混合書寫,如下:

table
  stripe()
  td
    padding 4px 10px

table#users
  stripe(#303030, #494848)
  td
    color white
另外,stripe()的定義無需父引用:

stripe(even = #fff, odd = #eee)
  tr
    background-color odd
  tr.even
  tr:nth-child(even)
    background-color even
如果你願意,你可以把stripe()當作屬性調用。

stripe #fff #000
混合書寫中的混合書寫

自然,混合書寫可以利用其它混合書寫,建立在它們自己的屬性和選擇器上。

例如,下面我們創建內聯comma-list()(通過inline-list())以及逗號分隔的無序列表。

inline-list()
  li
    display inline

comma-list()
  inline-list()
  li
    &:after
      content ', '
    &:last-child:after
      content ''

ul
  comma-list()

渲染:

ul li:after {
  content: ", ";
}
ul li:last-child:after {
  content: "";
}
ul li {
  display: inline;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM