A dynamic, expressive, powerful language compiling to CSS.
SLIDE:
tj holowaychuk
- github.com/visionmedia
- @tjholowaychuk
- express
- connect
- cluster
- jade
- stylus
- node-canvas
- soda
- ...
SLIDE:
SLIDE:
SLIDE:
button,
a.button {
padding: 5px 10px;
color: #888;
}
or
button,
a.button
padding: 5px 10px
color: #888
or
button
a.button
padding 5px 10px
color #888
SLIDE:
form
padding 10px
input[type='text']
padding 5px
border 1px solid
to:
form {
padding: 10px;
}
form input[type='text'] {
padding: 5px;
border: 1px solid;
}
SLIDE:
a
color: white
background: black
&:hover
color: black
background: white
to:
a {
color: #fff;
background: #000;
}
a:hover {
color: #000;
background: #fff;
}
SLIDE:
gray = #888
$fonts = helvetica, arial, sans-serif
body
font 14px/1.5 $fonts
color gray
to:
body {
font: 14px/1.5 helvetica, arial, sans-serif;
color: #888;
}
SLIDE:
stripe(even = #eee, odd = #fff)
background-color: odd
&.even
&:nth-child(2n)
background-color: even
table
tr
stripe(#888, #eee)
to:
table tr {
background-color: #eee;
}
table tr.even,
table tr:nth-child(2n) {
background-color: #888;
}
SLIDE:
stripe(even = #eee, odd = #fff)
background-color: odd
&.even
&:nth-child(2n)
background-color: even
table tr
stripe #888 #eee
to:
table tr {
background-color: #eee;
}
table tr.even,
table tr:nth-child(2n) {
background-color: #888;
}
SLIDE:
border-radius()
-webkit-border-radius arguments
-moz-border-radius arguments
border-radius arguments
.dialog
border-radius 5px 10px
to:
.dialog {
-webkit-border-radius: 5px 10px;
-moz-border-radius: 5px 10px;
border-radius: 5px 10px;
}
SLIDE:
add(a, b = a)
return a + b
button
padding: add(5px)
padding: add(5px, 10px)
to:
button {
padding: 10px;
padding: 15px;
}
SLIDE:
add(a, b = a)
return a + b
add(a, b = a)
a + b
add(a, b = a){ a + b }
add(a, b = a) {
return a + b;
}
SLIDE:
box(n, props = margin padding)
if margin in props
margin n
if padding in props
padding n
.dialog
box(5px)
.dialog
box(5px, margin)
to:
.dialog {
margin: 5px;
padding: 5px;
}
.dialog {
margin: 5px;
}
SLIDE:
prevent-reset = true
reset-table() {
border-collapse: collapse;
border-spacing: 0;
}
table
margin: 15px
unless prevent-reset
reset-table()
SLIDE:
box(n, props = margin padding)
margin n if margin in props
padding n if padding in props
SLIDE:
box(n, props = margin padding)
for prop in props
{prop} n
.dialog
box(5px)
.dialog
box(5px, foo bar baz)
to:
.dialog {
margin: 5px;
padding: 5px;
}
.dialog {
foo: 5px;
bar: 5px;
baz: 5px;
}
SLIDE:
box(n, props = margin padding)
{prop} n for prop in props
body
nums = 1 2 3
foo: n for n in nums if length(nums) > 2
to:
body {
foo: 1;
foo: 2;
foo: 3;
}
SLIDE:
button(text = #eee, background = #888)
// implementation ...
button
a.button,
input[type=submit]
button(white, black)
button(background: black, text: white)
button(background: black, white)
button(black, text: white)
p(button)
// => button(text, background)
SLIDE:
sum(nums...)
sum = 0
sum += n for n in nums
sum(1,2,3,4)
// => 10
SLIDE:
join(delim, vals...)
str = ''
for val, i in vals
if i
str += delim + val
else
str += val
join(', ', 1, 2, 3)
// => '1, 2, 3'
SLIDE:
vendor(prop, args)
-webkit-{prop} args
-moz-{prop} args
{prop} args
border-radius()
vendor('border-radius', arguments)
.dialog
border-radius 5px
to:
.dialog {
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
}
SLIDE:
opposite-position(pos)
return bottom if pos == top
return top if pos == bottom
return right if pos == left
return left if pos = right
error('Invalid position ' + pos)
opposite(positions)
for pos in positions
pos = opposite-position(pos)
ret = ret is defined ? ret pos : pos
opposite(top)
// => bottom
opposite(left)
// => right
opposite(top left)
// => bottom right
SLIDE:
reset()
if mixin == 'root'
// mixin some selectors
else if mixin
// mixin some properties
else
// return a value
SLIDE:
.page-number
fixed: top right
to:
.page-number {
position: fixed;
top: 0;
right: 0;
}
or
.page-number
absolute: top 5px right 5px
to:
.page-number {
absolute: fixed;
top: 5px;
right: 5px;
}
SLIDE:
fixed()
pos('fixed', arguments)
absolute()
pos('absolute', arguments)
pos(pos, args)
position: pos
if length(args) == 2
{args[0]}: 0
{args[1]}: 0
else if length(args) == 4
{args[0]}: args[1]
{args[2]}: args[3]
else
error('invalid arguments. ' + type + ': <pos> [n] <pos> [n];')
SLIDE:
[]
! ~ + -
is defined
** * / %
+ -
... ..
<= >= < >
in
== is != is not isnt
is a
&& and || or
?:
= ?= += -= *= /= %=
not
if unless
SLIDE:
size ?= 5px
size ?= 10px
size
// => 5px
size = 5px unless size is defined
size = 10px unless size is defined
size
// => 5px
SLIDE:
#fff is a 'color'
// => true
15px is a 'color'
// => false
'something' is a 'string'
// => true
SLIDE:
#eee + #f0e
// => #fef
#eee - 5
// => #e9e9e9
#eee - rgba(200,0,0,0.5)
// => rgba(38,238,238,0.5)
#eee - 50%
//=> #777
SLIDE:
dimensions = 50px 100px
dimensions[0]
// => 50px
dimensions[1]
// => 100px
SLIDE:
list = foo bar baz
list[1] = 'bar'
p(list)
// => foo 'bar' baz
list[1..4] = 1
p(list)
// => foo 1 1 1 1
SLIDE:
size is defined
// => false
size = 15px
size is defined
// => true
SLIDE:
nums = 1..5
// => 1 2 3 4 5
list = a b c d e f
list[0..2]
// => a b c
list[0...2]
// => a b
SLIDE:
props = foo bar baz
bar in props
// => true
rawr in props
// => false
SLIDE:
#fff / 2
// => #808080
'value: ' + 5px
// => 'number: 5px'
large-font = 30px
small-font = 10px
size = large
size + '-font'
// => 30px
SLIDE:
1s + 500ms
// => 1.5s
500ms + 1s
// => 1500ms
10cm - 1in
=> 7.46cm
SLIDE:
Over 45 built-in functions.
- color manipulation
- image dimensions
- utilities
- math
SLIDE:
red(#c00)
// => 204
alpha(#fff)
// => 1
alpha(rgba(0,0,0,0.3))
// => 0.3
SLIDE:
hue(hsla(50deg, 100%, 80%))
// => 50deg
saturation(hsla(50deg, 100%, 80%))
// => 100%
lightness(hsla(50deg, 100%, 80%))
// => 80%
SLIDE:
dark(black)
// => true
dark(#005716)
// => true
dark(white)
// => false
light(black)
// => false
light(white)
// => true
light(#00FF40)
// => true
SLIDE:
type(12)
// => 'unit'
typeof(12)
// => 'unit'
typeof(#fff)
// => 'rgba'
type-of(#fff)
// => 'rgba'
SLIDE:
abs(-5px)
// => 5px
ceil(5.5in)
// => 6in
floor(5.6px)
// => 5px
round(5.5px)
// => 6px
round(5.4px)
// => 5px
max(1, 5)
// => 5
even(6px)
// => true
sum(1 2 3)
// => 6
avg(1 2 3)
// => 2
SLIDE:
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'
SLIDE:
rgba(255,0,0,0.5)
// => rgba(255,0,0,0.5)
rgba(255,0,0,1)
// => #ff0000
rgba(#ffcc00, 0.5)
// rgba(255,204,0,0.5)
SLIDE:
lighten(#2c2c2c, 30)
// => #787878
lighten(#2c2c2c, 30%)
// => #393939
darken(#D62828, 30)
// => #551010
darken(#D62828, 30%)
// => #961c1c
SLIDE:
desaturate(#f00, 40%)
// => #c33
saturate(#c33, 40%)
// => #f00
SLIDE:
unquote('sans-serif')
// => sans-serif
unquote(sans-serif)
// => sans-serif
unquote('1px / 2px')
// => 1px / 2px
SLIDE:
s('bar()');
// => bar()
s('bar(%s)', 'baz');
// => bar("baz")
s('bar(%s)', baz);
// => bar(baz)
s('X-Crazy-Microsoft-Stuff(%s)', #ffcc00);
// => X-Crazy-Microsoft-Stuff(#fc0)
'foo(%s)' % bar
// => foo(bar)
'foo(%s, %s)' % (5 10)
// => foo(5, 10)
SLIDE:
op = '+'
operate(op, 15, 5)
// => 20
SLIDE:
length(1 2 3 4)
// => 4
length(1 2)
// => 2
length(1)
// => 1
length(())
// => 0
length()
// => 0
SLIDE:
warn('you shouldnt do that')
error('im broken!')
SLIDE:
opposite-position(right)
// => left
opposite-position(top left)
// => bottom right
opposite-position('top' 'left')
// => bottom right
SLIDE:
width(img)
return image-size(img)[0]
height(img)
return image-size(img)[1]
image-size('tux.png')
// => 405px 250px
image-size('tux.png')[0] == width('tux.png')
// => true
SLIDE:
linear-gradient(pos, from, to)
prop = current-property[0]
moz = '-moz-linear-gradient(%s, %s 0%, %s 100%)' % (pos from to)
add-property(prop, moz)
'linear-gradient(%s, %s 0%, %s 100%)' % (pos from to)
body
background: linear-gradient(bottom right, white, black)
body
background-image: linear-gradient(bottom right, white, black)
to:
body {
background: -moz-linear-gradient(bottom right, #fff 0%, #000 100%);
background: linear-gradient(bottom right, #fff 0%, #000 100%);
}
body {
background-image: -moz-linear-gradient(bottom right, #fff 0%, #000 100%);
background-image: linear-gradient(bottom right, #fff 0%, #000 100%);
}
SLIDE:
$ stylus -i
> 100 + 50%
=> 150
> list = one two three four five
=> one two three four five
> list[1..2]
=> (two three)
SLIDE:
var connect = require('connect')
, stylus = require('stylus')
, pub = __dirname + '/public'
connect(
stylus.middleware({ src: pub, compress: true }),
connect.static(pub)
).listen(3000);
SLIDE:
Usage: stylus [options] [command] [< in [> out]]
[file|dir ...]
Commands:
help <prop> Opens help info for <prop> in
your default browser. (osx only)
Options:
-i, --interactive Start interactive REPL
-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
-V, --version Display the version of stylus
-h, --help Display help information
SLIDE:
var stylus = require('stylus')
, nib = require('nib')
, fs = require('fs');
fs.readFile('test.styl', 'utf8', function(err, str){
stylus(str)
.set('filename', 'test.styl')
.include(nib.path)
.render(function(err, css){
console.log(css);
});
});
SLIDE:
$ npm install nib
- customizable components (buttons etc)
- transparent vendor functions (gradients etc)
- transparent vendor properties (border-radius, opacity, etc)
- custom properties (fixed, absolute, etc)
- various mixins (hide-text(), resets, etc)
SLIDE:
SLIDE:
@import 'nib/vendor'
button {
opacity: .5;
}
to:
button {
opacity: 0.5;
filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50);
}
SLIDE:
@import 'nib'
button {
border-radius: top 5px, bottom 10px;
}
to:
button {
-moz-border-radius-topleft: 5px;
-webkit-border-top-left-radius: 5px;
border-top-left-radius: 5px;
-moz-border-radius-topright: 5px;
-webkit-border-top-right-radius: 5px;
border-top-right-radius: 5px;
-moz-border-radius-bottomleft: 10px;
-webkit-border-bottom-left-radius: 10px;
border-bottom-left-radius: 10px;
-moz-border-radius-bottomright: 10px;
-webkit-border-bottom-right-radius: 10px;
border-bottom-right-radius: 10px;
}
SLIDE:
@import 'nib'
button {
border-radius: top left 5px, bottom right 10px;
}
to:
button {
-moz-border-radius-topleft: 5px;
-webkit-border-top-left-radius: 5px;
border-top-left-radius: 5px;
-moz-border-radius-bottomright: 10px;
-webkit-border-bottom-right-radius: 10px;
border-bottom-right-radius: 10px;
}
SLIDE:
@import 'nib'
#logo {
fixed: top left;
}
#feedback {
absolute: top 10px right 10px
}
to:
#logo {
position: fixed;
top: 0;
left: 0;
}
#feedback {
position: absolute;
top: 10px;
right: 10px;
}
SLIDE:
@import 'nib/gradients'
button {
background: linear-gradient(top, white, black);
}
to:
button {
background: -webkit-gradient(linear, left top, left bottom,
color-stop(0, #fff),
color-stop(1, #000));
background: -moz-linear-gradient(top, #fff 0%, #000 100%);
background: linear-gradient(top, #fff 0%, #000 100%);
}
SLIDE:
@import 'nib/gradients'
button {
background: linear-gradient(top, 50% red, green, blue);
}
to:
button {
background: -webkit-gradient(linear, left top,left bottom,
color-stop(0.5, #f00),
color-stop(0.33, #008000),
color-stop(1, #00f));
background: -moz-linear-gradient(top, #f00 50%, #008000 33.33%, #00f 100%);
background: linear-gradient(top, #f00 50%, #008000 33.33%, #00f 100%);
}
SLIDE: