preproCeSSor
by Corinne Krych / @corinnekrych
and Olivier Audard / @_dhar
Brand new CSS language?
Nope ...
CSS preprocessors take code written in preprocessed language and then convert that code into POCSS
- Plain Old CSS - in case you're puzzled
There are a variety of CSS preprocessors, the main contenders being Less, SASS and Stylus...
80% of SASS, LESS and Stylus is the same
Syntactically Awesome Style Sheets
mature
the oldest, full of libraries available
strong community
latest addition Scut (thanks Matthieu for tweeting)
based on ruby
does it matter?
Remember 80% implement the same features
For code snippet we use SASS unless stated.
How to stay DRY using CSS
Take the following snippet of CSS:
.module img {
width: 6em;
padding: 5px;
}
.module p {
color: #7514e1;
text-align: center;
font-size: 0.9em;
}
.module:hover img, .module:active img {
border: 5px #f23eea solid;
padding: 0;
border-radius: 4px;
}
.module.ios h3 {
color: #214067;
}
.module.android h3 {
color: #718927;
}
.module.web h3 {
color: #be420c;
}
.module.hybrid h3 {
color: #60625e;
}
I don't want to keep writing module again and again. It's tedious and repetitive!
Much concise:
.module
img
width: 6em
padding: 5px
p
color: #7514e1
text-align: center
font-size: 0.9em
&:hover img, &:active img
border: 5px #f23ee solid
padding: 0
border-radius: 4px
&.ios h3
color: #214067
&.android h3
color: #718927
&.web h3
color: #be420c
&.hybrid h3
color: #60625e
Nesting is a common pattern within CSS preprocessors.
Prepocessors take this and compile it down to CSS for you.
JUST the same syntax fo Less and Stylus
2 syntaxes: sassy scss (.scss) or sass syntax (.sass)
For stylus, 2 syntaxes supported, Less uses "sassy" syntax
Quite often in CSS we stick to a color palette
The whole point is to reuse colors.
h1 {
font-size: 2em;
text-color: #669eb2;
}
h2 {
font-size: 1.75em;
text-color: #e25027;
}
h3 {
font-size: 1.25em;
text-color: #669eb2;
}
h4 {
font-size: 1em;
margin-top: 3em;
text-color: #e25027;
}
copy/paste is my only option...
CSS Preprocessors let you define variables!
/* Variables to hold our base colour, size */
$gear-color: #669eb2
$aero-color: #e25027
$reference-size: 1em
h1
font-size: $reference-size + 1em
text-color: $gear-color
h2
font-size: $reference-size + 0.75em
text-color: $aero-color
h3
font-size: $reference-size + 0.25em
text-color: $gear-color
h4
font-size: $reference_size
margin-top: 3em
text-color:$aero_gear;
SASS syntax
In Sass, $reference_size same as $reference-size
Small differences in syntax for Less and Stylus
Operation on variables
Changing colours made easy youpi!
Maybe not to abuse...
I would work with a CSS preprocessor
Annoyed by CSS full of vendor prefixes?
.foo {
background: #87e0fd;
background: -moz-linear-gradient(top, #87e0fd 0%, #05abe0 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#87e0fd), color-stop(100%,#05abe0));
background: -webkit-linear-gradient(top, #87e0fd 0%,#05abe0 100%);
background: -o-linear-gradient(top, #87e0fd 0%,#05abe0 100%);
background: -ms-linear-gradient(top, #87e0fd 0%,#05abe0 100%);
background: linear-gradient(to bottom, #87e0fd 0%,#05abe0 100%);
}
Can be fixed using mixin
Annoyed by CSS full of vendor prefixes?
.foo {
background-color: #87e0fd;
@include background-image(
linear-gradient(
top,
#87e0fd 0%,
#05abe0 100%
)
);
}
Less redundancy
Use a mixin built into the Compass framework
Perfect use case for preprocessor usage
Really ???
Prefixes to add support for new CSS features
Android: -webkit- Chrome: -webkit- Firefox: -moz- Internet Explorer: -ms- iOS: -webkit- Opera: -o- Safari: -webkit-
By nature, they are temporary
Don't assume properties are named the same
use a generic mixin to generate them, won't work
Use well maintained libraries like Compass or Bourbon
Even better...
postprocessor to fix prefixes ;)
like Autoprefixer is kept up to date with can I use database
For example: vertical align text
to be applied several times on different context
with different variant
build your own toolkit
or reuse toolkit like SCUT
@mixin vertically-center ($child: ".vcentered") {
display: table;
& > #{$child} {
display: table-cell;
vertical-align: middle;
}
}
Avoid repetition
use parameter, here with default value
Organize code
Reuse code
Going further with CSS features
Include block with @content
Loop with @for
Use mixin with @include
@media queries block scatters styles rules
p {
max-width: 960px;
}
.feature {
max-width: 960px;
}
..... Lots of other CSS rules here
/* AeroGear custom styles for Tablets, break point: 848px */
@media only screen and (max-width: 848px) {
p {
max-width: 720px;
}
.feature {
max-width: 720px;
}
}
What if, we could keep the logic at one place
p
max-width: 960px;
@media only screen and (max-width: 656px)
max-width: 720px;
.feature
max-width: 960px;
@media only screen and (max-width: 656px)
max-width: 720px;
}
All CSS on HTML element are grouped in a same place
but I repeat @media WAIT...
anymore
Parametrized break point!
$break-phone:656px
$break-tablet:848px
@mixin respond-to($media-size)
@if $media-size == phone
@media only screen and (max-width: $break-phone)
@content
@else if $media-size == tablet
@media only screen and (min-width:$break-phone + 1) and (max-width: $break-tablet - 1)
@content
@else if $media-size == desktop
@media only screen and (min-width: $break-tablet)
@content
p
@include respond-to(desktop)
max-width: 960px
@include respond-to(tablet)
max-width: 720px
Is it difficult to use?
Install
> gem install sass
Convert existing CSS
> sass-convert --from css --to sass -R css
Compile
> sass --watch sass:css
Install
> npm install -g less
Compile
> lessc styles.less
Dev mode
// include JS
// include less file
// To enable watch, append ‘#!watch’
NOT for production
Install
> npm install stylus
Convert existing CSS
> stylus --css css/main.css stylus/main.styl
lost my comments and my fonts :(
some error when back to CSS :(
Compile
> stylus css
no watch
Reverse engineer my CSS into Sass
Start with color variables, progressively use mixin for code reusability
Investigate built-in libraries
Build my own CSS toolbox
CSS for clean and fast web apps
also exist in light color
desktop and mobile version
took him 2 hours work tbh :P
reusability at its best
Existing button-bar
and button-list
@import and @extend
@import topcoat-button
@import button-bar
.topcoat-button-list {
@extend .button-bar
}
/* Custom behavior to display in list*/
.topcoat-button-list__item {
width: auto;
border-radius: 0;
}
/* Custom behavior for top element */
.topcoat-button-list > .topcoat-button-list__item:first-child {
border-top-left-radius: var-border-radius;
border-top-right-radius: var-border-radius;
}
/* Custom behavior for bottom element */
.topcoat-button-list > .topcoat-button-list__item:last-child {
border-bottom-left-radius: var-border-radius;
border-bottom-right-radius: var-border-radius;
}
.topcoat-button-list__item > input {
@extend .button-bar__item > input
}
.topcoat-button-list__item:first-child > .topcoat-button-list__button,
.topcoat-button-list__item:first-child > .topcoat-button-list__button--large {
border-bottom: none;
}
.topcoat-button-list__item:last-child > .topcoat-button-list__button,
.topcoat-button-list__item:last-child > .topcoat-button-list__button--large {
border-top: none;
}
.topcoat-button-list__button {
@extend .topcoat-button;
border-radius: inherit;
}
/* Custom behavior to size to longest text button */
.topcoat-button-list__button,
.topcoat-button-list__button--large {
width:100%;
}
.topcoat-button-list__button:active,
.topcoat-button-list__button--large:active,
:checked + .topcoat-button-list__button {
@extend .topcoat-button:active
}
.topcoat-button-list__button:disabled {
@extend .topcoat-button:disabled
}
.topcoat-button-list__button:hover {
@extend .topcoat-button:hover
}
.topcoat-button-list__button:focus,
.topcoat-button-list__button--large:focus {
@extend .topcoat-button:focus
z-index: 1;
}
.topcoat-button-list__button--large {
@extend .topcoat-button--large
border-radius: inherit;
}
.topcoat-button-list__button--large:disabled {
@extend .topcoat-button:disabled
}
.topcoat-button-list__button--large:hover {
@extend .topcoat-button:hover
}
That's all?
Fabrice, you're such a lazybutt
grunt task to generate CSS
4 combinaisons light vc dark, desktop vs mobile
grunt task to generate great doc, awesome demo
grunt task to run unit test!
that's work, man
Object Oriented CSS
/*
* Base reset components
* Use the naming convention:
* {component}-{name}__{subcomponent}--{modifier}
*
*/
/* Component */
.button-group
/* Component Modifier */
.button-group--large
/* Subcomponent */
.button-group__button
/* Subcomponent Modifier */
.button-group__button--cta
/*
* Themed components
* Use the naming convention:
* {theme}-{component}-{name}__{subcomponent}--{modifier}
*/
/* Component */
.topcoat-button-group
/* Component Modifier */
.topcoat-button-group--large
/* Subcomponent */
.topcoat-button-group__button
/* Subcomponent Modifier */
.topcoat-button-group__button--cta
follow the convention
You're not just hacking CSS, you design and code reusable CSS