Techorama 2014, by Jochen Vandendriessche and Gregory Van Looy
Freelance front-end developer - JS junkie
Freelance HTML & CSS architect - sucks @ JS
#kthxbye
/* no classes here, only element selectors */
body {}
p {}
a {}
ul {}
h1 {}
h2 {}
h3 {}
/* grid */
.col {}
.col--2 {}
.col--primary {}
/* layout specific: .layout-- prefix */
.layout--homepage .container {}
.layout--XXXX
classes are added to the html
tag
Biggest chunk of your CSS file
/* skip the prefix, it's too verbose */
.module-carousel {}
/* that's the way, uhu uhu */
.carousel {}
/* .is- prefix */
.is-active {}
.is-hidden {}
.is-collapsed {}
.is-expanded {}
for JavaScript = easier to debug
/* .js-is- prefix */
.js-is-active {}
.js-is-hidden {}
.js-is-collapsed {}
.js-is-expanded {}
Will you need this one?
.theme--culture .tag {}
.theme--x-mas blockquote:before {
content: 'hohoho';
}
.theme--
classes are added to the html
tag
in combination with Sass
| - sass
main.scss
_site-settings.scss
_mixins.scss
|- base
_base.scss
_normalize.scss
_defaults.scss
_webfonts.scss
...
|- layout
_layout.scss
_grid.scss
_sections.scss
...
|- modules
_modules.scss
_carousel.scss
_pagination.scss
...
|- state
_state.scss
...
|- theme
_theme.scss
_x-mas.scss
...
An interchangeable single-part of a larger system that can easily be re-used
(function(){
// self executing anonymous function
}());
there's no privacy
'use strict';
ToggleModule = (function() {
// private function
function _init() {
// collect all toggle objects and make them behave
}
// private function
function _show(args) {
// show stuff
}
// private function
function _hide(args) {
// hide stuff
}
// private _init is public available as init
return {
init: _init
};
}());
Encapsules how disparate modules interact with each other by acting as an intermediary
Allows modules to broadcast or listen to notifications without worrying about the system
'use strict';
ToggleModule = (function() {
// private function
function _init() {
// let's the mediator know we have to functions that listen
Mediator.subscribe('/toggle/show', _show);
Mediator.subscribe('/toggle/hide', _hide);
// collect all toggle objects and make them behave
}
// private function
function _show(args) {
// show stuff
}
// private function
function _hide(args) {
// hide stuff
}
// private _init is public available as init
return {
init: _init
};
}());
| - js
|- config
config.js
|- 3rdparty
jquery.min.js
...
|- modules
toggle.js
...
|- vendor
modernizr.js
webfont.js
...
main.js
main.toggle.js
Block - Element - Modifier
.block {}
.block__element {} /* note: double underscore */
.block--modifier {} /* note: double hyphen */
...
...
...
...
Carousel
- ...
- ...
- ...
- ...
/* Bad */
.pageHeader {}
.button--blue {}
/* Good */
.page-header {}
.button--primary {}
/* This is OK! */
.article__header--no-border {}
.teaser--large--primary {}
“BEM, so ugly it actually works!”
/* old skool */
article > header {}
/* BEM */
.article__header {}
/* old skool + Smacss theming */
.theme--x-mas article > header {}
/* BEM + SMACSS theming */
.theme--x-mas .article__header {}
Minified and gZipped
$('.my #awesome selector');
document.querySelectorAll('.my #awesome selector');
$(el).find(selector);
el.querySelectorAll(selector);
$(el).addClass(className);
el.className += ' ' + className;
if (el.classList) {
el.classList.add(className);
}else{
el.className += ' ' + className;
}
$(el).outerHeight()
el.offsetHeight
$(el).parent();
el.parentNode
$(el).remove();
el.parentNode.removeChild(el);
Like Qwery, Bonzo, Bean, Reqwest, etc...
$primary-color: #f90;
h1 {
color: $primary-color;
}
/* output */
h1 {
color: #f90;
}
/* Sass */
nav {
ul {
list-style: none;
margin: 0;
padding: 0;
overflow: hidden; /* clearfixer */
}
li {
float: left;
}
a {
display: block;
}
}
/* output */
nav ul {
list-style: none;
margin: 0;
padding: 0;
overflow: hidden; /* clearfixer */
}
nav li {
float: left;
}
nav a {
display: block;
}
_forms.scss
/* main.scss */
@import 'forms';
@mixin border-radius($radius) {
-webkit-border-radius: $radius;
-moz-border-radius: $radius;
border-radius: $radius;
}
.alert {
@include border-radius(4px);
}
/* Output */
.alert {
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
nav {
ul {
list-style: none;
margin: 0;
padding: 0;
}
}
/* extended version */
.unstyled-list {
list-style: none;
margin: 0;
padding: 0;
}
nav {
ul {
@extend .unstyled-list;
}
}
/* output */
.unstyled-list,
nav ul {
list-style: none;
margin: 0;
padding: 0;
}
standard operators : +
, -
, *
, /
and %
h1 {
margin-bottom: $base-spacing-unit*3;
}
.col--2 {
width: 360px / 960px * 100%; /* = 37.5% */
}
@for $i from 1 through 11 {
.col--#{$i} {
width: ((100%/12) * $i);
}
}
/* output */
.col--1 {
width: 8.3333333%;
}
.col--2 {
width: 16.6666667%;
}
...
.col--11 {
width: 91.6666667%;
}
a:hover {
color: lighten($link-color, 10%); /* more on color functions : http://jackiebalzer.com/color */
}
.col--2 {
width: floor(360px / 960px * 100%);
}
.overlay {
background-color: rgba(255,0,0,0.75) + rgba(0,255,0,0.75); /* output = rgba(255,255,0,0.75) */
}
More on Sass functions
.block {
&__element {}
&--modifier {}
}
/* output */
.block {}
.block__element {}
.block--modifier {}
In one word: automation. The less work you have to do when performing repetitive tasks like minification, compilation, unit testing, linting, etc, the easier your job becomes.
Grunt and Grunt plugins are installed and managed via npm, the Node.js package manager.
options: {
curly: true,
browser: true,
node: true,
camelcase: true,
eqeqeq: true,
eqnull: true,
indent: 2,
latedef: true,
newcap: true,
quotmark: 'single',
trailing: true,
undef: true,
unused: true,
strict: true,
globals: {
'bean': true,
'bonzo': true,
'qwery': true,
'Arbiter': true,
'moment': true,
'reqwest': true,
'App': false,
'FB': true,
},
reporter: require('jshint-stylish')
},
all: ['<%= package.jssrc %>/modules/*.js', '<%= package.jssrc %>/*.js', '<%= package.jssrc %>/test/spec/*.js']
options: {
compress: false,
separator: ''
},
dist: {
src: [
'<%= package.jssrc %>/3rdparty/*.js',
'<%= package.jssrc %>/main.js',
'<%= package.jssrc %>/modules/*.js',
'<%= package.jssrc %>/*.js'
],
dest: '<%= package.js %>/main.js'
}
options: {
mangle: true,
compress: true,
beautify: false ,
banner: '/*! <%= package.title || package.name %> - v<%= package.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %>\n' +
'<%= package.homepage ? "* " + package.homepage + "\\n" : "" %>' +
' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= package.author.name %>;' +
' Licensed <%= _.pluck(package.licenses, "type").join(", ") %> */\n'
},
dist: {
src: '<%= package.js %>/main.js',
dest: '<%= package.js %>/main.min.js'
}
// for production
dist: {
files: {
'<%= package.csssrc %>/main.min.css': '<%= package.sass %>/main.scss'
},
options: {
style : 'compressed'
}
},
// for development
dev: {
files: {
'<%= package.csssrc %>/main.css': '<%= package.sass %>/main.scss'
},
options: {
style : 'expanded',
lineNumbers: true,
trace: false
}
}
main.css
@import url('main-blessed1.css?z=1400852303781');
/* selector rule #4097 continues here */
.something {}
.something-else {}
...