stylus可以简单理解为一个动态的css样式表,在原有W3C规定的基础上增加了编程的能力,在使用前通过插件会再编译成普通的css文件。

本章目标: 掌握stylus样式语法,本章开始我们会从头开始编写自己的博客主题,同样采用pug和styl语法,官方帮助文档:stylus

一、概述

Stylus 语法是python式基于缩进的 空格很重要,使用 缩进突出 来代替 { },可以对比下两种语言的写法,如下所示:

body {
  color: #fff;
}

body
  color: white //省略掉了{}和;

其它常见的例子如下:

foo bar baz,
> input  //这里的>是css的语法,只取最近一层
  border 1px solid

1、安装与运行

安装处理器

$ npm install stylus -g
$ npm install stylus-loader

stylus cli

Usage: stylus [options] [command] [< in [> out]]
              [file|dir ...]

Commands:

  help [<type>:]<prop> Opens help info at MDC for <prop> in
                        your default browser. Optionally
                        searches other resources of <type>:
                        safari opera w3c ms caniuse quirksmode

Options:

  -i, --interactive       Start interactive REPL
  -u, --use <path>        Utilize the Stylus plugin at <path>
  -U, --inline            Utilize image inlining via data URI support
  -w, --watch             Watch file(s) for changes and re-compile
  -o, --out <dir>         Output to <dir> when passing files
  -C, --css <src> [dest]  Convert CSS input to Stylus
  -I, --include <path>    Add <path> to lookup paths
  -c, --compress          Compress CSS output
  -d, --compare           Display input along with output
  -f, --firebug           Emits debug infos in the generated CSS that
                          can be used by the FireStylus Firebug plugin
  -l, --line-numbers      Emits comments in the generated CSS
                          indicating the corresponding Stylus line
  -m, --sourcemap         Generates a sourcemap in sourcemaps v3 format
  --sourcemap-inline      Inlines sourcemap with full source text in base64 format
  --sourcemap-root <url>  "sourceRoot" property of the generated sourcemap
  --sourcemap-base <path> Base <path> from which sourcemap and all sources are relative
  -P, --prefix [prefix]   Prefix all css classes
  -p, --print             Print out the compiled CSS
  --import <file>         Import stylus <file>
  --include-css           Include regular CSS on @import
  -D, --deps              Display dependencies of the compiled file
  --disable-cache         Disable caching
  --hoist-atrules         Move @import and @charset to the top
  -r, --resolve-url       Resolve relative urls inside imports
  --resolve-url-nocheck   Like --resolve-url but without file existence check
  -V, --version           Display the version of Stylus
  -h, --help              Display help information

stylus cli例子

$ stylus --compress < some.styl > some.css

#编译
$ stylus css
$ stylus css --out public/stylesheets # 指定输出目录
$ stylus one.styl two.styl #编译指定文件
$ stylus --prefix foo- #给所有编译好的css文件中的class加一个foo-前缀

#反编译
$ stylus --css < test.css > test.styl
$ stylus --css test.css
$ stylus --css test.css /tmp/out.styl

2、引用文件

@import "reset.css"
@import 'product/*'
@require 'head' //省略文件后缀名

3、代码注释

单行

// I'm a comment!

多行

/* 
 * Adds the given numbers together.
 */

4、代码调试

warn("oh noes!")
error("oh noes!")

二、选择器

1、父级引用

这里的&代表了 textarea, input 这个父类

textarea, input //此处也可以用换行来表示,省去中间的逗号,但不建议省略即使是换行了
  color #A7A7A7
  &:hover
    color #000
    
//会编译为
textarea, input {
  color: #a7a7a7;
}
textarea:hover, input:hover {
  color: #000;
}

2、局部引用

.foo
  &__bar
    width: 10px

    ^[0]:hover &
      width: 20px

//会编译为
.foo__bar {
  width: 10px;
}
.foo:hover .foo__bar {
  width: 20px;
}

3、根引用

textarea
input
  color #A7A7A7
  &:hover,
  /.is-hovered
    color #000
    
//会编译为
textarea,
input {
  color: #a7a7a7;
}
textarea:hover,
input:hover,
.is-hovered {
  color: #000;
}

4、方法引用

pad(n)
  margin (- n)

body
  pad(5px)
    
//会编译为
body {
  margin: -5px;
}

三、自定义变量

1、普通实现

fonts = Helvetica, Arial, sans-serif

body {
  padding: 50px;
  font: 14px/1.4 fonts;
}

但建议变量名称加$前缀

$font-size = 14px
body {
  font: $font-size sans-serif;
}

2、class名称变量化

mySelectors = '#foo,#bar,.baz'

{mySelectors}
  background: #000

#foo,
#bar,
.baz {
  background: #000;
}

3、变量占位符

empty = ()
body {
  font: empty sans-serif;
}

//Compiles to:
body {
  font: sans-serif;
}

4、属性引用

可以直接使用已定义的属性

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

四、插值

注意看自定义的vendeor函数

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;
}

另一个例子

box-shadow(args...)
   -webkit-box-shadow args
   -moz-box-shadow args
   box-shadow args

 #login
   box-shadow 1px 2px 5px #eee

 #login {
    -webkit-box-shadow: 1px 2px 5px #eee;
    -moz-box-shadow: 1px 2px 5px #eee;
    box-shadow: 1px 2px 5px #eee;
  }

1、Mixins

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;
}

五、运算符

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

1、例子

!0  //true
not not true //true

list = 1 2 3
list[0] //1 
list[-1] //3

六、自定义函数

1、函数定义

//基本定义--------
add(a, b)
  a + b
  
body 
   padding add(10px, 5)  

输出为:
 body {
   padding: 15px;
 }


//参数带默认值函数--------
add(a, b = a)
   a + b
add(10, 5) //15
add(10) //20


//参数命名函数--------
subtract(a, b)
  a - b
  
subtract(b: 10, a: 25)

//多个返回值--------
   sizes()
     15px 10px

   sizes()[0]
   // => 15px

2、函数参数

box-shadow(args...)
  -webkit-box-shadow args
  -moz-box-shadow args
  box-shadow args

#login
  box-shadow 1px 2px 5px #eee

3、复杂一点的自定义函数

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;
  }

4、if / else if / else

//例子一
stringish(val)
   if val is a 'string' or val is a 'ident'
     yes
   else
     no

 stringish('yay') == yes// => true
 stringish(yay) == yes// => true
 stringish(0) == no// => true
 

//例子二,这里注意padding是一个函数
overload-padding = true

if overload-padding
  padding(y, x)
    margin y x

body
  padding 5px 10px

5、unless

disable-padding-override = true

 unless disable-padding-override is defined and disable-padding-override
   padding(x, y)
     margin y x

 body
   padding 5px 10px

6、for...in

for <val-name> [, <key-name>] in <expression>

for i in range(10px, 50px, 10)
  .col-{i}
    width: i

//输出为
.col-10 {
  width: 10px;
}
.col-20 {
  width: 20px;
}
.col-30 {
  width: 30px;
}
.col-40 {
  width: 40px;
}
.col-50 {
  width: 50px;
}

七、内置函数

1、颜色函数

red(#c00)  red(#000, 255) //返回204和设置颜色#f00,类似的还有green、blue
alpha(rgba(0,0,0,0.3)) //.3
alpha(#fff, 0.5) //rgba(255,255,255,0.5)

rgba(255,0,0,0.5) //rgba(255,0,0,0.5)
rgb(255,204,0) //#ffcc00

invert(#d62828) //#29d7d7
spin(#ff0000, 90deg) //#80ff00
grayscale(#fd0cc7) //#0cfd42
tint(#fd0cc7,66%) //#feaceb,Mix the given color with white

shade(#fd0cc7,66%) //#560443
transparentify(#91974C, #F34949, 0.5) //rgba(47,229,79,0.5)

dark(color) //检查是否是常色,比如dark(#005716)返回true
light(color)

2、路径函数

basename('images/foo.png') //foo.png
basename('images/foo.png', '.png') //foo
dirname('images/foo.png')//images
extname('images/foo.png')//.png
pathjoin('images', 'foo.png') //images/foo.png

3、集合函数

//stack
nums = 1 2
push(nums, 3, 4, 5)
nums //1 2 3 4 5

nums = 4 5 3 2 1
num = pop(nums)
nums // => 4 5 3 2
num // => 1

//list
list = 1 2 3
index(list, 2) //2

//map
pairs = (one 1) (two 2) (three 3)
keys(pairs)//one two three
values(pairs) // 1 2 3

length((1 2 3 4)) //4

4、hash表

foo = {
  bar: baz,
  baz: raz
}
foo.bar baz

for key, value in foo
  {key}: value

bar in foo //true
keys(foo)
values(foo)
remove(foo, 'bar')

5、单位函数

typeof(12) // => 'unit'
typeof(#fff)// => 'rgba'

unit(10) // => ''
unit(15in) // => 'in'
unit(15%, 'px') // => 15px

//other
percentage(.5) //50%
percentage(4 / 100) //4%

6、数学函数

abs(-5px) //5px
ceil(5.5in) //6in
floor(5.6px) //5px
round(5.5px) //6px
sin(30deg) //0.5
cos(180deg) //-1
tan(45deg) //1
min(1, 5) //1
max(1, 5) //5
even(6px) //true
odd(5mm) //true
sum(1 2 3) //6
avg(1 2 3) //2
range(1px, 3px, 0.5px) //1px 1.5px 2px 2.5px 3px

八、字符串操作

1、match(pattern, string[, flags])

match('^(height|width)?([<>=]{1,})(.*)', 'height>=1024px')
// => 'height>=1024px' 'height' '>=' '1024px'

match('^foo(?:bar)?', 'foo')
// => 'foo'

match('^foo(?:bar)?', 'foobar')
// => 'foobar'

match('^foo(?:bar)?', 'bar')
// => null

match('ain', 'The rain in SPAIN stays mainly in the plain')
// => 'ain'

match('ain', 'The rain in SPAIN stays mainly in the plain', g)
// => 'ain' 'ain' 'ain'

match('ain', 'The rain in SPAIN stays mainly in the plain', 'gi')
// => 'ain' 'AIN' 'ain' 'ain'

2、replace(pattern, replacement, val)

replace(i, e, 'griin')// => 'green'
replace(i, e, griin)// => #008000

3、 join(delim, vals…)

join(' ', 1 2 3)// => "1 2 3"
join(',', 1 2 3)// => "1,2,3"
join(', ', foo bar baz)// => "foo, bar, baz"
join(', ', foo, bar, baz)// => "foo, bar, baz"
join(', ', 1 2, 3 4, 5 6)// => "1 2, 3 4, 5 6"

4、split(delim, val)

split(_, bar1_bar2_bar3)// => bar1 bar2 bar3
split(_, 'bar1_bar2_bar3')// => 'bar1' 'bar2' 'bar3'

5、substr(val, start, length)

substr(ident, 1, 2)// => de
substr('string', 1, 2)// => 'tr'
val = dredd
substr(substr(val, 1), 0, 3)// => #f00

6、slice(val, start[, end])

slice('lorem' 'ipsum' 'dolor', 1, 2)
slice('lorem' 'ipsum' 'dolor', 1, -1)
// => 'ipsum'

slice('lorem ipsum', 1, 5)// => 'orem'
slice(rredd, 1, -1)// => #f00

slice(1px solid black, 1)// => solid #000

7、unquote(str | ident)

unquote("sans-serif")// => sans-serif
unquote(sans-serif)// => sans-serif
unquote('1px / 2px')// => 1px / 2px

8、convert(str)

unit = convert('40px')
typeof(unit)// => 'unit'

color = convert('#fff')
typeof(color)// => 'rgba'

foo = convert('foo')
typeof(foo)// => 'ident'

9、s(fmt, …)

s('bar()');// => bar()
s('bar(%s)', 'baz');// => bar("baz")
s('bar(%s)', baz);// => bar(baz)
s('bar(%s)', 15px);// => bar(15px)
s('rgba(%s, %s, %s, 0.5)', 255, 100, 50);// => rgba(255, 100, 50, 0.5)
s('bar(%Z)', 15px);// => bar(%Z)
s('bar(%s, %s)', 15px);// => bar(15px, null)

九、特殊处理

1、图像处理

image-size(path)
image-size('tux.png') 405px 250px
image-size(img)[0] 405px

background: embedurl('logo.png')
background: url("data:image/png;base64,…")

2、原样输出CSS

不管什么原因,如果遇到 Stylus 搞不定的特殊需求,你都可以使用 @css 直接书写普通的 CSS 代码:

@css {
    .ie-opacity {
        filter: progid:DXImageTransform.Microsoft.Alpha(opacity=25);
        -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(opacity=25)";
    }
}

.ie-opacity {        
        filter: progid:DXImageTransform.Microsoft.Alpha(opacity=25);
        -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(opacity=25)";
}

3、比较特殊的几个符号

@MEDIA

原样输出

@media print
   #header
   #footer
     display none

@font-face

原样输出

font-family Geo
   font-style normal
   src url(fonts/geo_sans_light/GensansLight.ttf)

 .ingeo
   font-family Geo

@extend

.a
  color: red

.b
  width: 100px

.c
  @extend .a, .b
  height: 200px
  
//输出为
.a,
.c {
  color: #f00;
}
.b,
.c {
  width: 100px;
}
.c {
  height: 200px;
}

@block

foo = @block {
  width: 20px
  height: 20px
}
.icon
  {foo}

//输出为
.icon {
  width: 20px;
  height: 20px;
}