web frontend development: tools and good practices to (re)organize the chaos
DESCRIPTION
After my first attempt to "organize the chaos" (2012) in the structure of a front-end project, Stefano Verna (@steffoz) and I, have tried to bring together a number of tools and conventions to deal with front-end development in a way that could be understandable and maintainable, over the time, by a whole team. This presentation has been performed, for the first time, during the Ruby-Day-2014 in Venice, Italy. Here the video of the speech (italian): https://www.youtube.com/watch?v=fUJOJY_yVXg&index=6&list=PL5ImBN21eKvbQ6kH6WCAqj1QqgusGsiO0TRANSCRIPT
FRONTEND (re)organize the chaos
FRONTEND (re)organize the chaos
Matteo Papadopoulos@spleenteo
@steffozStefano Verna
www.cantierecreativo.net
Asset Pipelinea.k.a. Sprockets
“The new pipeline makes assets a first class citizen in the
Rails stack.”
Asset Pipeline
Asset Pipeline
gem 'jquery-rails'!
//= require 'jquery'
Asset Pipeline
2011Rails 3.1
Asset Pipeline
2012
Asset Pipeline
BowerFrontend package manager
Asset Pipeline
+17.000packages
Asset Pipeline
$ npm install -g bower$ bower init
Asset Pipeline
{ "name": "my-project", "dependencies": { "jquery-ui": "~1.11.1", "jquery": "~2.1.1" }}
$ cat bower.json
Asset Pipeline
$ tree bower_components -L 1
./bower_components"## jquery$## jquery-ui
Asset Pipeline
So we need two package managers?
Asset Pipeline
Rails AssetsFrictionless proxy between Bundler and Bower
Asset Pipeline
source 'https://rubygems.org'source 'https://rails-assets.org'!
gem 'rails-assets-jquery-ui'
Asset Pipeline
Bundler Rails Assets Bower
do you have rails-assets-jquery-ui?
do you have jquery-ui?
sure thing, take it!
here's the gem!
Asset Pipeline
win-winthat was easy.
Compass“A SASS Framework”
Asset Pipeline
Compass
vendor prefixes typography vertical rhythm grid reset helper functions image-related features
Asset Pipeline
Compass
Asset Pipeline
monolithic approach
Compass soooo slow
Asset Pipeline
Compass php syndrome
Asset Pipeline
Compass
Asset Pipeline
box-shadow: 10px 10px 5px red;
Compass
Asset Pipeline
+box-shadow(red 10px 10px 5px)
box-shadow: 10px 10px 5px red;
Compass
vendor prefixes typography vertical rhythm grid reset helper functions image-related features
Asset Pipeline
Compassvendor prefixes image-related features
Asset Pipeline
Compass unix-like approach
Asset Pipeline
Asset Pipeline
vendor prefixes
Asset Pipeline
100% Sass mixin library
Asset Pipeline
CSS post-processorAutoprefixer
gem 'autoprefixer-rails'
Asset Pipeline
a { display: flex;}
> 1%last 2 versionsFirefox ESROpera 12.1
a { display: -webkit-box; display: -webkit-flex; display: -moz-box; display: -ms-flexbox; display: flex}
Compassvendor prefixes image-related features
Asset Pipeline
Asset Pipeline
image-related features
sprites webfont high DPI images support lossless image compression …
Asset Pipeline
task management tools
Asset Pipeline
GRUNT GULP BROCCOLI
Asset Pipeline
+3400tasks
mostly frontend-related
Asset Pipeline
$ npm install -g grunt-cli
Asset Pipeline
$ cat package.json{ "name": "my-project", "dependencies": { "grunt": "~1.11.1", "grunt-bemo": "~2.1.1", ... }}$ npm install
Asset Pipeline
# Gruntfile.js!module.exports = function(grunt) { grunt.loadNpmTasks('grunt-bemo');! grunt.initConfig({ bemo: { webfonts: { src: "app/assets/fonts/svg", fontDest: "app/assets/fonts", sassDest: "app/assets/stylesheets/_icon-glyphs.css.scss" }, sprites: { src: "app/assets/images/sprites", imageDest: "app/assets/images/sprites-{{density}}.png", sassDest: "app/assets/stylesheets/_sprites.css.scss" } } });};
Asset Pipeline
$ grunt bemo!
Running "bemo-sprites" task...!
Running "bemo-webfonts" task...
Asset Pipeline
JS/Coffee code linter JS/Coffee code style checker Live reload SVG/PNG/JPG optimizer Inline assets Unused CSS removal ...
Asset Pipeline
RecapUse Bower packages, not gems Rails Assets Replace Compass Bourbon/Autoprefixer Grunt/Gulp/Broccoli
Writing Sass
Writing Sass
$ rails generate controller books create app/controllers/books_controller.rb invoke erb create app/views/books invoke helper create app/helpers/books_helper.rb invoke assets invoke coffee create app/assets/javascripts/books.js.coffee invoke scss create app/assets/stylesheets/books.css.scss
Rails conventions
OOCSSObject-oriented CSS
Writing Sass
Organize the chaos v1 2012 - http://goo.gl/6ZRJm4
OOCSS
A CSS “object” is a repeating visual pattern, that can be abstracted into an independent snippet of HTML, CSS, and possibly JavaScript. That object can then be reused throughout a site.
Writing Sass
Writing Sass
Writing Sass
media object
Writing Sass
.media display: table width: 100%!.media .img, .media .body display: table-cell vertical-align: top!.media .img padding-right: 10px
<div class="media">! <div class="img"> <img src="..." /> </div>! <div class="body"> ... </div>!</div>
Writing Sass
No margins, no positioning, 100% width
.media display: table width: 100%!.media .img, .media .body display: table-cell vertical-align: top!.media .img padding-right: 10px
Writing Sass
Location indipendenceLet the context choose your positioning
Be fluid: always expand to take the full width of the container
Writing Sass
Just class selectors?
.media display: table width: 100%!.media .img, .media .body display: table-cell vertical-align: top!.media .img padding-right: 10px
Writing Sass
ID selectorsLimit reuse within the same page
Tag selectorsForce a semantic Carpet bombing
.media display: table width: 100%!.media .img, .media .body display: table-cell vertical-align: top!.media .img padding-right: 10px
Writing Sass
Wait, what about descendent selectors?
Writing Sass
Descendent selectorsCarpet bombing (again) Potential name clashing
Writing Sass
Descendent selectorsDo not use them.
Writing Sass
.media display: table width: 100%!
.media .img, .media .body display: table-cell vertical-align: top!
.media__img padding-right: 10px
Writing Sass
.media display: table width: 100%!
.media__img, .media__body display: table-cell vertical-align: top!
.media__img padding-right: 10px
BEM
Writing Sass
Block • Element • Modifier
Writing Sass
.media display: table width: 100%!
.media__img, .media__body display: table-cell vertical-align: top!
.media__img padding-right: 10px
Block (CSS object)
Block element
Writing Sass
Block (CSS object).nav-bar.nav-bar__logo Block element
Writing Sass
Block (CSS object).nav-bar.nav-bar__logo Block element
.nav-bar--primary Modifier
Writing Sass
.media // ....!.media--rev direction: rtl text-align: left! .media__img padding-right: 0px padding-left: 10px
<div class="media media--rev">! <div class="media__img"> <img src="..." /> </div>! <div class="media__body"> ... </div>!</div>
Writing Sass
.nav-bar--primary__logo--dark
Writing Sass
But it's verbose and ugly and...!CSS has limited character set. Deal with it.
Writing Sass
Remember the pros!No more name clashing !
No more overrides !
Trivial to understand and maintain your codebase
Structure
Writing Sass
Writing Sass
."## application.css.sass"## _base.css.sass"## _font-faces.css.sass"## blocks% "## _button.css.sass% "## _media.css.sass% $## ..."## functions% $## ..."## mixins% $## ...$## variables $## ...
Root file
Writing Sass
."## application.css.sass"## _base.css.sass"## _font-faces.css.sass"## blocks% "## _button.css.sass% "## _media.css.sass% $## ..."## functions% $## ..."## mixins% $## ...$## variables $## ...
// Silent code@import 'functions/**/*'@import 'variables/**/*'@import 'bourbon'@import 'mixins/**/*'!// Font faces@import 'font-faces'!// Base@import 'normalize-scss'@import 'base'!// Blocks@import 'blocks/**/*'
Writing Sass
// Silent code@import 'functions/**/*'@import 'variables/**/*'@import 'bourbon'@import 'mixins/**/*'!// Font faces@import 'font-faces'!// Base@import 'normalize-scss'@import 'base'!// Blocks@import 'blocks/**/*'
gem "sass-globbing"
."## application.css.sass"## _base.css.sass"## _font-faces.css.sass"## blocks% "## _button.css.sass% "## _media.css.sass% $## ..."## formats% "## _align.css.sass% "## _font-size.css.sass% $## ..."## functions% $## ..."## mixins% $## ...$## variables
Writing Sass
."## application.css.sass"## _base.css.sass"## _font-faces.css.sass"## blocks% "## _button.css.sass% "## _media.css.sass% $## ..."## functions% $## ..."## mixins% $## ...$## variables $## ...
// Silent code@import 'functions/**/*'@import 'variables/**/*'@import 'bourbon'@import 'mixins/**/*'!// Font faces@import 'font-faces'!// Base@import 'normalize-scss'@import 'base'!// Blocks@import 'blocks/**/*'
."## application.css.sass"## _base.css.sass"## _font-faces.css.sass"## blocks% "## _button.css.sass% "## _media.css.sass% $## ..."## functions% $## ..."## mixins% $## ...$## variables $## ...
// Silent code@import 'functions/**/*'@import 'variables/**/*'@import 'bourbon'@import 'mixins/**/*'!// Font faces@import 'font-faces'!// Base@import 'normalize-scss'@import 'base'!// Formats@import 'formats/**/*'!// Blocks@import 'blocks/**/*'
Writing Sass
Configuration functions
mixins
// Silent code@import 'functions/**/*'@import 'variables/**/*'@import 'bourbon'@import 'mixins/**/*'!// Font faces@import 'font-faces'!// Base@import 'normalize-scss'@import 'base'!// Formats@import 'formats/**/*'!// Blocks@import 'blocks/**/*'
Writing Sass
."## application.css.sass"## _base.css.sass"## _font-faces.css.sass"## blocks% "## _button.css.sass% "## _media.css.sass% $## ..."## functions% $## ..."## mixins% $## ...$## variables $## ...
Default styling, Basefile
Writing Sass
html, body!a!ul, ol, blockquote!li!h1, h2, h3, h4, h5, h6, hgroup, ul, ol, dd, p, figure, pre, table, fieldset, hr, form!input, textarea!input[type="submit"], button
// Silent code@import 'functions/**/*'@import 'variables/**/*'@import 'bourbon'@import 'mixins/**/*'!// Font faces@import 'font-faces'!// Base@import 'normalize-scss'@import 'base'!// Blocks@import 'blocks/**/*'
Writing Sass
."## application.css.sass"## _base.css.sass"## _font-faces.css.sass"## blocks% "## _button.css.sass% "## _media.css.sass% $## ..."## functions% $## ..."## mixins% $## ...$## variables $## ... 99% of the
code is here!
Writing Sass
one block per file
group blocks into subdirectories
Asset Pipeline
RecapRails per-controller modularity is not scalable OCCSS is a better solution BEM How to structure our Rails stylesheets directory
BEMO
Writing Sass
Asset Pipeline
Bemohttp://github.com/stefanoverna/bemo
Project starter/Scaffolder Common BEM blocks library Grunt tasks for retina-ready sprites and web fonts
THANKS! question time
Matteo Papadopoulos@spleenteo
@steffozStefano Verna