Vincent Garreau
Co-Founder & Front-end developer livestorm.co
Workflows, outils et astuces pour un développement front-end avancé
Vendredi 12/05 | Workflow CSS + ES2015/17 Workflow JS + Modules et composants web |
Vendredi 19/05 | Frameworks JS + Introduction à Vue.js |
Fondamentaux CSS
Préprocesseurs CSS / Postprocesseurs CSS
Méthodologies CSS
Linters CSS
CSS : Trucs et astuces perso
Introduction à ES2015 jusqu'à ES2017
Package managers
Task runners / Introduction à Gulp
Introduction aux modules / composants
Systèmes de modules existants
Module bundlers / Introduction à Webpack
Linters JS
Présentation des frameworks JS existants
Introduction à Vue.js
Live coding :
Création d'un portfolio avec Vue.js + Webpack
Quelques notions basiques à maîtriser et à avoir en tête
Internal style 😱
Inline style 😰
External style 👍🏻
<style>.element { width: 200px; }</style>
<span style="width:200px"></span>
<link rel="stylesheet" href="style.css">
Terme en anglais : CSS specificity
Terme en français : Poids des sélecteurs
<span style="color: red"> // 1000
#element // 100
.element // 10
span // 1
#element > div > li:hover // 100 + 1 + 1 + 10
.element !important // S'applique en priorité
Style inline (HTML) |
IDs |
Classes, attributs, pseudo classes (:) |
Elements, pseudo elements (::) |
---|---|---|---|
1000 | 100 | 10 | 1 |
.button-push { padding: 10px; }
<button class="button-push">Push 1</button>
<button class="button-push">Push 2</button>
D'après les standards W3C
Un préprocesseur CSS contient une palette d'outils qui permet d'écrire un CSS plus maintenable
// CSS
.element {
width: 200px;
height: 80px;
font-size: 1.2em;
}
// Stylus ({}, : et ; sont chacun optionnel)
.element
width 200px
height 80px
font-size 1.2em
Léger et rapide à écrire
// CSS
.element > li { padding:10px; }
.element > li:hover { padding:20px; }
// Stylus
.element
> li
padding 10px
&:hover
padding 20px
Principe d'indentation (évitez plus de 3 niveaux)
// Sans préprocesseur
.element
width 20px
height 20px
margin-right 10px
// Avec préprocesseur
$element-size = 20px
.element
width $element-size
height $element-size
margin-right $element-size / 2 // Opération
// Création de la mixin
text-truncate(customWidth)
overflow hidden
text-overflow ellipsis
white-space nowrap
width customWidth
max-width 100%
// Appel de la mixin
.element
text-truncate(200px)
Permet de retourner et déclarer une série de propriétées
// Création de la fonction
add(a, b)
a + b
// Appel de la fonction
.element
width add(10px, 5px) // 15px
Fonctions utiles intégrées dans Stylus :
rgba, darken, lighten...
Même principe qu'une mixin, mais retourne une valeur
Opérateurs
Conditions
Itérations
@extend
@block
....
Un postprocesseur CSS est un outil qui permet d'effectuer
des tâches spécifiques sur un fichier CSS
PostCSS est un outil JavaScript qui permet d'effectuer des transformations d'un fichier CSS grâce à des plugins
Plugins PostCSS populaires :
autoprefixer : préfixe les propriétés
cssnext : permet d'écrire dès aujourd'hui du CSS4
Ensemble de conseils et de lignes de conduite
pour un CSS organisé et maintenable
Catégorisation / Structure
Convention de nommage
Avantage d'un préprocesseur CSS :
Pouvoir générer un fichier CSS
à partir de plusieurs fichiers
Remarque
Sans préprocesseur, il est possible d'importer plusieurs fichiers CSS avec la méthode @import, mais cela est lourd car sans préprocesseur aucun fichier n'est généré.
Sans préprocesseur, 1 import = 1 requête HTTP en plus.
7-1 Pattern
7 dossiers, 1 fichier
Détails sur sass-guidelin.es/#the-7-1-pattern
📁 base
📁 components
📁 layout
📁 pages
📁 themes
📁 abstracts
📁 vendors
main.scss
Permet d'éviter des cas problématiques comme écraser du style précédemment appliqué / mélanger des styles
Si plusieurs développeurs travaillent sur un même projet, appliquer une règle de nommage commune est plus facile à comprendre / lire et à maintenir
OOCSS
Object-Oriented CSS
SMACSS
Scalable and Modular Approach for CSS
BEM
Block Element Modifier
// block-name__element-name--modifier-name
<header class="app-header">
<nav class="app-header-nav">
<ul>
<li class="app-header-nav__item"></li>
<li class="app-header-nav__item app-header-nav__item--on"></li>
</ul>
</nav>
</header>
Outil pour garder un code CSS lisible, cohérent et harmonieux
Intégré via un plugin SlublimeText par exemple
et / ou
Intégré dans un script (tâche Grunt, Gulp, Webpack...)
// CSS2
.nav
.nav-item
display inline-block
vertical-align middle
// CSS3
.nav
display flex
align-items center
// Largeur responsive à gauche, fixe à droite
.wrapper
display flex
width 100%
.left // Largeur variable
width calc(100% - 300px)
.right // Largeur toujours égale à 300px
width 300px
// Largeur de 100px, padding inclus
.myElement
width 100px
padding 20px
box-sizing border-box
// border-box = padding inclus
// content-box (par défaut) = padding exclus
Classes vraiment utiles :
dropdown
modal
tooltip
// custom-bootstrap.styl (chargé après BS.)
.modal-header
border-radius .25rem .25rem 0 0
background $white-alabaster
text-align center
border-bottom 0
.form-control
border 1px solid $grey-alto
// var-colors.styl
$blue-picton = #36AAEA
// button.styl
.custom-button
background-color $blue-picton
$CouleurDominante-NomDeLaCouleur
Outil : Name That Color / Plugin Sublime
css-tricks.com/icon-fonts-vs-svg
Insertion du code de l'icône SVG directement dans le HTML
Insertion de l'icône SVG dans le HTML en utilisant les symboles
// On sélectione l'icône en ciblant l'id du symbole dans la balise "use"
<div class="svg-wrap">
<svg>
<use xlink:href="#icon-cross"></use>
</svg>
</div>
// On insère le fichier définition SVG dans le HTML (en haut, juste après l'ouverture du body)
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<symbol id="icon-cross" viewBox="0 0 32 32">
<title>cross</title>
<path fill="#222" class="path1" d="M15.392 13.984l12.32-12.32c0.384-0.384 0.384-0.992 0-1.376s-0.992-0.384-1.376 0l-12.32 12.32-12.352-12.32c-0.384-0.384-0.992-0.384-1.376 0s-0.384 0.992 0 1.376l12.32 12.32-12.32 12.352c-0.384 0.384-0.384 0.992 0 1.376s0.992 0.384 1.376 0l12.352-12.32 12.32 12.32c0.384 0.384 0.992 0.384 1.376 0s0.384-0.992 0-1.376l-12.32-12.352z"></path>
</symbol>
<symbol id="icon-arrow" viewBox="0 0 32 32">
<title>arrow</title>
<path fill="#666" class="path1" d="M0.29 8.875l0.18 0.21 13.6 15.65c0.46 0.53 1.15 0.86 1.92 0.86s1.46-0.34 1.92-0.86l13.82-15.88c0.17-0.25 0.27-0.55 0.27-0.87 0-0.87-0.74-1.58-1.66-1.58v0h-28.68c-0.92 0-1.66 0.71-1.66 1.58 0 0.33 0.11 0.64 0.29 0.89z"></path>
</symbol>
</defs>
</svg>
Le standard JavaScript
ECMAScript 2015 = 6e édition / ES6)
ECMAScript 2016 = 7e édition / ES7)
ECMAScript 2017 = 8e édition / ES8)
Règles de portées
var = portées des fonctions
let = portées de blocs (if, for...)
// Anciennement var (ES5)
for (var i = 0; i <= 10; i++) {
console.log(i)
}
console.log(i) // 11
// Avec let (ES6)
for (let i = 0; i <= 10; i++) {
console.log(i)
}
console.log(i) // undefined
var school = 'HETIC'
// Anciennement var (ES5)
if (school === 'HETIC') {
var director = 'M. Beaux'
}
console.log(director) // M. Beaux
// Avec let (ES6)
if (school === 'HETIC') {
let director = 'M. Beaux'
}
console.log(director) // undefined
let age = 21
const firstname = 'Marie'
const identity = {}
age = 22 // let donc OK
firstname = 'Elodie' // const donc FAIL
identity = { firstname: 'Marie' } // FAIL
identity.firstname = 'Marie' // OK
Règle d'utilisation
const = variable non modifiable*
let = variable modifiable
non modifiable* = non redéclarable
// ES5
function Example() {
var self = this // On "copie" this dans self
this.callbackClick = function() {
console.log('clicked')
}
$('button').on('click', function() { // Non fléchée
self.callbackClick() // this réfère à button
})
}
var example = new Example()
// ES6
function Example() {
// Syntaxe concise (si 1 seule instruction)
this.callbackClick = () => console.log('clicked')
$('button').on('click', () => { // Fléchée
this.callbackClick() // this réfère à Example
})
}
var example = new Example()
// ES5
var methods = {
login: function () {
console.log('login...')
}
}
// ES6
const methods = {
login() { // Notation raccourcie
console.log('login...')
}
}
name = 'HETIC'
level = 'Bac +5'
// ES5
var school = {
name: name,
level: level
}
// ES6
const school = {
name,
level
}
// On insère "..." devant l'objet itérable
const displayNames = (...people) => {
console.log(people) // ['Jean', 'Louis', 'Charles']
}
displayNames('Jean', 'Louis', 'Charles')
// Insertion dans un tableau (alternatif à "push")
const missingNb = [2, 3]
const nb = [1, ...missingNb, 4] // [1, 2, 3, 4]
year = '2020'
// ES5
var str = 'La P' + year + ' est au top'
// ES6 : Entre backticks (différents des quotes)
const str = `La P${year} est au top`
// La P2020 est au top
const setColor(value = '#FF0000') = () {
console.log(`Couleur : ${value}`)
}
setColor("#000000") // Couleur : #000000
setColor() // Couleur : #FF0000
str = 'Les cours de marketing en H2 sont intenses'
youtubers = ['DirtyBiology', 'E-Penser']
// ES5
str.indexOf('marketing') !== -1 // true
youtubers['E-Penser'] !== undefined // true
// ES6
str.includes('marketing') // true
youtubers.includes('E-Penser') // true
const getAvatar = (email) => {
return new Promise((resolve, reject) => {
$.ajax({
url: `https://www.gravatar.com/${email}.json`,
dataType: 'jsonp',
success(data) { resolve(data) },
error(data) { reject(data) }
})
})
}
getAvatar('08e83ed895943c88b5d11db6665ee8b4')
.then((response) => {
console.log('resolve data', response)
})
.catch((response) => {
console.log('reject data', response)
})
const ajax = (email) => {
return new Promise((resolve, reject) => {
$.ajax({
url: `https://www.gravatar.com/${email}.json`,
dataType: 'jsonp',
success(data) { resolve(data) },
error(data) { reject(data) }
})
})
}
const getAvatar = async function(email) {
const res = await ajax(email)
return res
}
getAvatar('08e83ed895943c88b5d11db6665ee8b4')
.then((response) => { console.log('resolve data', response) })
.catch((response) => { console.log('reject data', response) })
Gestion des librairies / plugins via un
gestionnaire de paquets
// package.json
{
"name": "my-portfolio-package",
"version": "1.0.0",
"dependencies": {
"jquery": "^2.2.3"
}
}
// Commande pour installer le package jquery par exemple :
npm install jquery --save
Installer Node.js (npm inclus) : nodejs.org
Rechercher un package npm : npmjs.com
Un outil pour automatiser certaines tâches :
compilation d'assets, etc.
// gulpfile.js
// Import du module gulp et gulp-stylus
var gulp = require('gulp')
var stylus = require('gulp-stylus')
// Création d'une tâche, nommée "stylus"
gulp.task('stylus', function() {
return gulp.src('./assets/css/main.styl')
.pipe(stylus())
.pipe(gulp.dest('./build/css'))
})
// 1. Aller à l'emplacement du projet dans le terminal
// 2. Lancer la tâche "stylus" en tapant la commande :
gulp stylus
C'est quoi ? Pourquoi ?
Consiste à utiliser une
approche modulaire de l'architecture d'un projet informatique
Concept appliqué au
Javascript
Plus large qu'un module :
Template HTML + Javascript + Style CSS
Différents systèmes pour créer des modules Javascript
AMD
CommonJS
ES2015 Modules
// operators.js
define([], function () {
return {
sum: function (a, b) {
return a + b
},
divide: function (a, b) {
return a / b
}
}
})
// app.js
define(["./operators.js"], function (operators) {
var test = operators.sum(10, 5) // 15
})
Asynchronous Module Definition
// operators.js
exports.sum = function (a, b) {
return a + b
}
exports.divide = function (a, b) {
return a / b
}
// app.js
var operators = require('./operators.js')
var test = operators.sum(10, 5) // 15
// operators.js
const myObject = {}
myObject.sum = (a, b) => {
return a + b
}
myObject.divide = (a, b) => {
return a / b
}
export default myObject
// app.js
import operators from './operators.js'
const test = operators.sum(10, 5) // 15
Un outil qui analyse les modules pour générer des assets
module.exports = {
// Points d'entrée
entry: './assets/js/main.js',
// Configuration de l'export
output: {
path: './build/js',
filename: "main.js"
},
// Configuration des loaders
module: {
rules: [
{ test: /\.css$/, loader: "style-loader!css-loader" },
]
},
// Configuration des plugins
plugins: []
}
Grafikart - Lien du tutoriel
Outil pour garder un code JS lisible, cohérent et harmonieux
SublimeLinter
github.com/SublimeLinter/SublimeLinter3
packagecontrol.io/packages/SublimeLinter
Plugin - SublimeLinter Eslint
github.com/roadhump/SublimeLinter-eslint
packagecontrol.io/packages/SublimeLinter-contrib-eslint
Configuration - Airbnb .eslintrc
github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb-base
Un outil tout en un pour créer une application maintenable
2010
2011
2011
2013
2009
2013
2014
Jeremy Ashkenas
Yehuda Katz
Meteor
Evan You
Facile à prendre en main
Développement rapide
Un écosystème flexible grâce aux différents plugins Vue
Mises à jour régulières
Communauté active
github.com/VincentGarreau/H2P2020
By Vincent Garreau
Workflows, outils et astuces pour un développement front-end avancé