Bonnes pratiques CSS (et SCSS) en production
- L’encodage des fichiers et des bases de données doit se faire en UTF-8 (sans BOM).
- Les indentations se font à l’aide de deux espaces et sous forme de tabulations. Pour assurer une cohérence inter-projets, utiliser la convention EditorConfig.
- Le code CSS produit doit être propre, optimisé et (autant que faire se peut) valide selon les normes (http://jigsaw.w3.org/css-validator/).
- La feuille de style CSS est de préférence unique et minifiée et appelée à l'aide d'un élément
<link>
dans la section<head>
. Pas de@import
dans un fichier CSS. - Privilégier tant que possible les syntaxes via propriétés raccourcies :
margin
,padding
,font
,border
,background
,border-radius
- Utiliser toujours le même type de guillemets. De préférence des doubles guillemets, exemple :
content: ""
; - Utiliser toujours des guillemets pour les valeurs dans les sélecteurs, exemple :
input[type="checkbox"]
- Éviter de spécifier les unités pour les valeurs nulles ainsi que pour les hauteurs de lignes, exemple :
margin: 0; line-height: 1.5
.
Repérer systématiquement les « objets CSS », c'est-à-dire des « patterns visuels » qui se répètent, afin de définir ainsi des classes réutilisables, des styles de base et des variantes.
- Privilégier au maximum l'usage de classes plutôt que d'écrire des sélecteurs basés sur le type des éléments ou leur
id
CSS with only class names - Séparer la structure de l’apparence (une règle CSS ne doit pas comporter à la fois
padding
etbackground
par exemple) - Séparer le conteneur du contenu (un composant ne doit jamais être ciblé par un sélecteur qui tient compte de son parent)
- Utiliser au maximum le pattern objet "media" : http://codepen.io/raphaelgoetter/pen/KMWWwj?editors=1100
- Utiliser au maximum le pattern objet "autogrid" : http://codepen.io/raphaelgoetter/pen/KMgBJd?editors=1100
Documentation : http://www.nicoespeon.com/fr/2013/05/plongee-au-coeur-de-oocss/
Un "reset" CSS permettant d’harmoniser les styles par défaut des navigateurs est systématiquement appliqué en début de projet.
Normalize.css est recommandé. Il s’agit d’un célèbre reset CSS employé par Twitter, Github, Bootstrap, Guardian, KNACSS, etc.
Documentation : http://necolas.github.io/normalize.css/
Les propriétés CSS sont - sauf exception - rédigées ligne par ligne dans chacun des blocs.
Un espace sépare le nom de la propriété de sa valeur, après les :
.
Un espace sépare le sélecteur du bloc avant la première accolade {
.
selecteur {
color: pink;
background: tomato;
}
Les déclarations au sein d’une règle CSS sont ordonnées de façon à faire apparaître les propriétés importantes en tête de liste.
Voici dans quel ordre nous déclarons nos propriétés :
- Contenu généré : les propriétés afférentes au contenu créé via :after et :before (
content
,counter
,quotes
). - Propriété display : tout ce qui affecte le rendu par défaut de l’élément (
none
,block
,inline
,inline-block
,flex
,grid
, …). - Positionnement : tout ce qui détermine la position de l’élément (
position
,float
,top
,right
,bottom
,left
,vertical-align
,z-index
,clear
). - Modèle de boîte : tout ce qui influe sur les dimensions de l’élément (
width
,height
,min-width
,min-height
,max-width
,max-height
,margin
,padding
,border
,overflow
). - Transformations et transitions : propriétés et valeurs CSS 3 (
transform
,transition
,animation
). - Typographie : tout ce qui détermine les caractéristiques de la police de caractères (
font
,text-align
,text-decoration
,letter-spacing
,text-indent
,line-height
,text-transform
,white-space
,word-wrap
). Décoration : les propriétés purement ornementales (background
,color
,list-style
,outline
).
Exemple :
selecteur {
display: inline-block;
position: relative;
top: -1em;
z-index: 1337;
max-width: 50%;
margin: 1em;
padding: 0;
overflow: hidden;
text-align: right;
font: bold 1.5em/1.3 arial, verdana, sans-serif;
background: rgba(0,0,0,.5);
}
Note : l’outil "CSScomb" permet de réordonner automatiquement les déclarations CSS. Il peut être utilisé sous forme de plugin (Atom, Brackets, Sublime text) ou intégré à un Workflow sous forme de tâche Gulp ou Grunt : http://csscomb.com/
Certaines propriétés CSS nécessitent d’être préfixées de la manière suivante (et dans cet ordre) :
Exemple :
-webkit-propriété
-moz-propriété
-ms-propriété
propriété
Note : l’outil "Autoprefixer" permet de préfixer automatiquement les propriétés CSS. Il peut être utilisé sous forme de plugin (Atom, Brackets, Sublime text) ou intégré à un Workflow sous forme de tâche Gulp ou Grunt : https://autoprefixer.github.io/
Les "hacks" sont des détournements de propriétés ou valeurs, permettant de tirer profit d’une faille des parseurs CSS des navigateurs.
En priorité, il est recommandé de privilégier d’autres méthodes que les hacks, car ceux-ci sont aléatoires et non pérennes.
En dernier ressort, employer la ressource Browserhacks.
Usage de mots-clés informatifs au sein de commentaires importants sont appréciés, sous la forme :
@TODO
→ point à finir / corriger avant de livrer@BUGFIX
→ explication d’une correction de bug@NOTE
→ note importante à partager@AUTHOR
→ auteur du document@TESTED
→ navigateurs / environnements testés@TOPROD
→ note à l’intention de la version de production
Le choix des sélecteurs CSS doit se faire en priorité pour leur pertinence et leur maintenabilité.
Ainsi, il est indiqué de pouvoir cibler n’importe quel élément indépendamment de son contexte : si l’élément doit être déplacé de son contexte, tel un module ou un composant, les styles devraient toujours s’appliquer.
De manière générale :
- Il est préférable de cibler les éléments à l’aide de leur classe HTML qui pourrait être utilisée dans n’importe quel contexte, par exemple
.title-primary
, - Les sélecteurs #id doivent être évités en CSS car trop spécifiques dans le calcul du poids. Si un id doit être ciblé, préférer un sélecteur d’attribut, par exemple
[id=header]
, - Les sélecteurs en cascade ou hyper-structurel doivent être évités de manière générale (ex:
ul.header li .info
ouh1 + p + p
), - La règle
!important
doit être éradiquée si possible du fait de son poids extrêmement important (certaines parties des styles peuvent toutefois exceptionnellement employer à juste titre!important
).
Opter pour des tailles de polices fluides (de préférence en rem
), éviter les tailles de police de taille fixe (px
ou pt
) car inaccessible aux personnes nécessitant d’agrandir les contenus textuels.
Non :
body {
font-size: 14px;
}
Oui :
html {
font-size: 62.5%;
}
body {
font-size: 1.4rem;
}
Opter pour le modèle de boîte CSS3 (box-sizing: border-box
) en début de la feuille de style.
* {
box-sizing: border-box;
}
ou bien :
html {
box-sizing: border-box;
}
* {
box-sizing: inherit;
}
Documentation : https://blog.goetter.fr/2012/07/27/box-sizing-et-pourquoi-pas/
Éviter de sortir les éléments du flux (float
, position
) sans nécessité.
Non :
div {
position: absolute;
right: 0;
}
Oui :
div {
margin-left: auto;
}
Documentation : https://github.com/bendc/frontend-guidelines#flow
Positionner les éléments en choisissant de préférence parmi ces méthodes, dans l’ordre :
display: block
|inline;
display: flex
|inline-flex;
display: inline-block
|table-cell;
float: left
|right;
position: relative
|absolute
|sticky
|fixed;
Règles permettant de faciliter la relecture de code CSS existant.
Écrire des syntaxes compréhensibles par des êtres humains et des collègues.
Non :
li + li {
visibility: hidden;
}
Oui :
li:not(:first-child) {
visibility: hidden;
}
Selon la complexité du projet, il peut être utile de préfixer les classes par « namespace » pour les regrouper et les distinguer aisément.
Exemple de Namespace (préfixe par "fonction") :
.o-container, .o-mod, .o-grid-container {
/* objects : éléments génériques multitâches */
}
.c-button, .c-nav, .c-lightbox {
/* components : éléments concrets */
}
.is-opened, .is-hidden, .has-* {
/* state : désigne un état ou une condition */
}
.js-menu, .js-is-hidden {
/* comportement : éléments liés à JavaScript */
}
Autre exemple de Namespace (préfixe par nom du framework) :
.kn-container, .kn-mod, .kn-grid {
...
}
Documentation : http://csswizardry.com/2015/03/more-transparent-ui-code-with-namespaces/
Définir des plages d’empilement (z-index) et s’y tenir, afin d’éviter les chevauchements indésirables.
Par exemple :
0000–1999
: Elements and Components2000–2999
: Element and Component Drop Downs3000–3999
: Secondary Navigation4000–4999
: Header / Footer5000–5999
: Primary Navigation6000–6999
: Full Screen Features7000–7999
: Special Cases8000–8999
: Modals / Dialog Windows9000–9999
: Notifications
Documentation : https://medium.com/@davidjpfeiffer/z-index-organization-in-css-5913fd4c25c9#.49lr5zmrs
Règles permettant de faciliter la maintenance de code CSS existant.
Éviter de surcharger un sélecteur, car cela lui ajoute du poids inutilement.
Non :
ul.nav li a.navlink {
…
}
Oui :
.navlink {
…
}
Non :
input[type="submit"] {
…
}
Oui :
[type="submit"] {
…
}
Documentation : http://cssspecificity.com/
Éviter d’utiliser le sélecteur d’id
, son poids est trop important et difficile à maintenir, éviter également le bazooka !important
Non :
#nav a {
…
}
Oui :
[id="nav"] a {
…
}
Oui :
.nav a {
…
}
Documentation : http://maintainablecss.com/chapters/ids/
Éviter les sélecteurs associés à la structure HTML, un élément doit pouvoir être ciblé quel que soit son conteneur ou son emplacement dans le DOM.
Non :
div > h1 + p {
…
}
Oui :
.intro {
…
}
Non :
#navigation h2, #sidebar h2 {
…
}
Oui :
.h2-like {
…
}
Non :
.sidebar .button {
…
}
Oui :
.button-primary {
…
}
Documentation : https://github.com/bendc/frontend-guidelines#selectors
Toujours séparer la structure de l’apparence dans les sélecteurs pour faciliter la factorisation.
Au sein d’une seule règle CSS ne doivent jamais cohabiter des propriétés décoratives et des propriétés de boîte ou de positionnement.
Non :
.button {
display: inline-block;
padding: 1em;
background: blue;
color: white;
}
Oui :
.button {
display: inline-block;
}
.button-large {
padding: 1em;
}
.button-primary {
background: blue;
color: white;
}
Éviter d’écraser une règle par une autre.
Non :
li {
visibility: hidden;
}
li:first-child {
visibility: visible;
}
Oui :
li + li {
visibility: hidden;
}
Oui :
li:not(:first-child) {
visibility: hidden;
}
Documentation : https://github.com/bendc/frontend-guidelines#overriding
Règles permettant de faciliter la performance (vitesse d’affichage) des pages web.
Les fichiers CSS doivent être rassemblés en un seul afin d’éviter les requêtes multiples.
Non :
<link rel="stylesheet" href="css/knacss.css">
<link rel="stylesheet" href="css/modal.css">
<link rel="stylesheet" href="css/carousel.css">
<link rel="stylesheet" href="css/styles.css">
Oui :
<link rel="stylesheet" href="css/styles.css">
Les fichiers CSS doivent être minifiés pour économiser du poids de chargement.
Non :
<link rel="stylesheet" href="css/styles.css">
Oui :
<link rel="stylesheet" href="css/styles.min.css">
Préférer les propriétés raccourcies.
Non :
div {
top: 50%;
margin-top: -10px;
flex-grow: 1;
flex-basis: 0;
padding-top: 5px;
padding-right: 10px;
padding-bottom: 20px;
padding-left: 10px;
}
Oui :
div {
top: calc(50% - 10px);
flex: 1 0 auto;
padding: 5px 10px 20px;
}
Documentation : https://github.com/bendc/frontend-guidelines#brevity-1
L’unité est inutile si la valeur est nulle. Ne pas donner d’unité à line-height
.
Non :
div {
margin: 0px;
font-size: 0.9rem;
line-height: 2em;
border: none;
}
Oui :
div {
margin: 0;
font-size: .9rem;
line-height: 2;
border: 0;
}
Documentation : https://github.com/bendc/frontend-guidelines#units
- Toujours préciser quelle(s) propriété(s) doit être animée dans transition ou animation
- Éviter d’animer des propriétés autres que transform ou opacity ou filter (ou alors ajouter la
propriété
will-change
et/ou le hack detranslateZ()
.) Source : https://tzi.github.io/presentation-CSS-perfs/
Non :
div {
margin-left: 100px;
transition: .5s;
}
Oui :
div {
transform: translateX(100px);
transition: transform .5s;
}
Oui (variante) :
div {
margin-left: 100px;
will-change: margin-left;
transition: margin-left .5s;
}
Documentation : https://csstriggers.com/
N’imposez pas de chargements aux anciens navigateurs (IE8). Privilégiez .woff2
.
Pour le détail, voir la partie "medias / polices"
Utiliser des pré-processeurs (Sass, LESS, Stylus) pour éviter les répétitions de code.
Concerne principalement :
- les couleurs de texte
- les couleurs de fond
- les tailles de police
- les breakpoints des Media Queries en Responsive
Non :
li {
color: red;
}
div {
color: #F00;
}
p {
color: #FF0000;
}
p {
color: #FF0001;
}
Oui :
// déclaration de variable Sass
$color: #F00;
// application de la variable
li {
color: $color;
}
div {
color: $color;
}
p {
color: $color;
}
Documentation : http://sass-lang.com/
Pour éviter les intervalles qui se chevauchent, ou des Media Queries trop variés, la convention pour définir la valeur d’un Breakpoint est systématiquement :
- (min-width: $breakpoint)** **
- (max-width: ($breakpoint - 1))
Exemple avec les variables de Breakpoints suivantes :
$tiny: 480px;
$small: 576px;
$medium: 768px;
$large: 992px;
$extra-large: 1200px;
Non :
@media (min-width: 767px) {...}
@media (max-width: 768px) {...}
@media (min-width: $small - 1) {...}
@media (min-width: $small) and (max-width: $large) {...}
Oui :
@media (min-width: 768px) {...}
@media (max-width: 767px) {...}
@media (min-width: $small) {...}
@media (min-width: $small) and (max-width: ($large - 1)) {...}
- Automatiser la gestion des préfixes à l’aide de Autoprefixer, ne pas le faire à la main
- Ne pas utiliser un mixin Sass/LESS pour cette tâche.
Non (mixin Sass) :
div {
transform: scale(2);
-webkit-transform: scale(2);
-moz-transform: scale(2);
-ms-transform: scale(2);
transition: 1s;
-webkit-transition: 1s;
-moz-transition: 1s;
-ms-transition: 1s;
}
Oui (Autoprefixer) :
div {
-webkit-transform: scale(2);
transform: scale(2);
transition: 1s;
}
Documentation : https://autoprefixer.github.io/
Éviter tant que possible les imbrications de plus d'un niveau en Sass.
Non :
.foo {
.bar {
&:hover {
color: red;
}
}
}
Résultat :
.foo .bar:hover {
color: red;
}
Oui (pas de nesting) :
.foo {
&-bar {
color: red;
}
}
Résultat :
.foo-bar {
color: red;
}
Documentation : http://sass-guidelin.es/#syntax--formatting
Autant que possible, privilégier le chargement de polices légères et respectueuses des performances, indiquées notamment sur Google Web Fonts. Limiter le nombre de ces polices à 2, voire 3 grand maximum.
Alsacréations partage une collection de fontes adaptées et optimisées pour le web : https://github.com/alsacreations/webfonts
Il est conseillé de récupérer les fontes sur ce repo Github si cela est possible.
Le format WOFF2 (Web Open Font Format 2) est privilégié dans tous les cas de figure, pour sa compatibilité et sa légèreté. En second lieu, utiliser WOFF.
Ces formats seront mentionnés en priorité dans la déclaration @font-face
avant les autres formats (TTF, OTF, SVG). Voir Optimiser le rendu des police @font-face
Voici un exemple de chargement de police conseillé (IE9 minimum) :
@font-face {
font-family: 'kiwi';
src: url('kiwi.woff2') format('woff2'),
url('kiwi.woff') format('woff');
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: 'kiwi';
src: url('kiwi-bold.woff2') format('woff2'),
url('kiwi-bold.woff') format('woff');
font-weight: bold;
font-style: normal;
}
BONUS : utiliser la directive <link rel="preload">
pour charger les fontes de manière asynchrone.
Compatibilité : http://caniuse.com/#feat=link-rel-preload
Ressource : https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf
Le remplissage par du contenu temporaire peut faire appel à Lorem Ipsum.
- Pour le texte :
- Pour les images :