Compléments sur CSS

Alexandre Niveau
GREYC — Université de Caen

Hacks CSS

Aux débuts de CSS : certaines propriétés implémentées différemment par Netscape et IE, notamment le modèle de boîte
  • Netscape et Opera suivaient le standard, width = largeur du contenu
  • Pour IE, width = largeur de la boîte entière

Pour supporter tous les navigateurs, la seule solution était d'utiliser des hacks CSS, c'est-à-dire d'exploiter des bugs d'implémentation pour que tel navigateur ignore telle propriété (e.g., le fameux box model hack)

D'autre part, la compétition fait que chaque navigateur implémente des fonctionnalités spécifiques ⇒ peut entraîner des problèmes de standardisation ensuite

Préfixes constructeur

Pour éviter ce genre de problème, le W3C demande que les navigateurs utilisent des préfixes pour leurs implémentations de fonctionnalités CSS non standard

Le principe général : les propriétés et mots-clefs commençant par un trait d'union sont réservés pour l'expérimentation

Chaque moteur de rendu a son propre préfixe :
  • -webkit- pour WebKit (Safari ; Chrome et Opera avant 2013)
  • -moz- pour Gecko (Firefox)
  • -ms- pour Trident (Internet Explorer)
  • -o- pour Presto (Opera avant 2012)

Principe de la standardisation CSS

Les navigateurs utilisent leur préfixe pour
  • expérimenter leurs propres fonctionnalités
  • implémenter les fonctionnalités des autres
  • implémenter les versions préliminaires des standards

Lorsqu'une spécification est suffisamment mature (statut candidate recommendation), les navigateurs sont censés supporter les propriétés sans préfixe, et progressivement arrêter de supporter les versions avec préfixe

Le principe des préfixes est de faciliter le test à grande échelle des nouvelles spécs, et de permettre à ceux qui le désirent de les utiliser, mais seulement à leurs risques et périls (puisqu'il n'y a aucune garantie que la syntaxe ne changera pas)

Ce qui se passe en pratique

  • Les navigateurs font de la pub pour leurs fonctionnalités non standardisées
  • Les gens commencent à les utiliser
  • Les autres navigateurs doivent les implémenter aussi
  • Au final, nombreuses propriétés avec la même syntaxe mais des préfixes différents
Un exemple classique de la fin des années 2000 (les préfixes sont inutiles pour cette propriété de nos jours !) :
.box {
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    -o-border-radius: 5px;
    border-radius: 5px;
}

Quand on se rend compte que la syntaxe doit changer avant qu'une propriété n'arrive en CR, il faut de toute façon la rendre incompatible avec la précédente, sous peine de casser les sites utilisant l'ancienne syntaxe préfixée

Encore plus de problèmes

Processus de normalisation très lent ⇒ les développeurs prennent l'habitude d'utiliser des préfixes et oublient leur aspect expérimental

problèmes quand la syntaxe change, surtout que…

  • …Peu de développeurs nettoient leurs préfixes !
  • Nombreux préfixes inutiles, mais surtout, nombreux préfixes manquants
  • Certains sites ne fonctionnent correctement que sous WebKit
  • Retour aux browser wars des années 90 ?

Le début de la fin : en 2012, Opera, Mozilla et Microsoft ont commencé à envisager de reconnaître le préfixe -webkit-

Au final

On rencontre à peu près les mêmes problèmes que s'il n'y avait pas de préfixes…

… sauf qu'il y en a d'autres en plus…

… et que ça rend l'écriture du CSS plus compliquée:
.box {
    background: #1e5799; /* Old browsers */
    background: -moz-linear-gradient(top,  #1e5799 0%, #2989d8 50%, #207cca 51%, #7db9e8 100%); /* FF3.6+ */
    background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#1e5799), color-stop(50%,#2989d8), color-stop(51%,#207cca), color-stop(100%,#7db9e8)); /* Chrome,Safari4+ */
    background: -webkit-linear-gradient(top,  #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* Chrome10+,Safari5.1+ */
    background: -o-linear-gradient(top,  #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* Opera 11.10+ */
    background: -ms-linear-gradient(top,  #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* IE10+ */
    background: linear-gradient(to bottom,  #1e5799 0%,#2989d8 50%,#207cca 51%,#7db9e8 100%); /* W3C */
}
(source)

Vers une solution

La leçon sur laquelle tout le monde s'accorde : les fonctionnalités expérimentales ne doivent pas être utilisables en prod

Depuis 2012, (source) Firefox ne rend plus les nouvelles fonctionnalités accessibles par défaut

Il faut modifier la configuration pour pouvoir les essayer (et elles n'utilisent pas de préfixe)

On peut toujours tester les fonctionnalités expérimentales, mais pas les utiliser sur un vrai site

Les moteurs Blink (créé en 2013, utilisé par Chrome et Opera) et EdgeHTML (créé en 2015 pour Microsoft Edge) fonctionnent de la même façon, et n'ont même pas de préfixe attribué

L'avenir des préfixes

En outre, les navigateurs et le W3C sont d'accord pour que les nouvelles fonctionnalités soient livrées sans préfixe lorsque les spécs semblent suffisamment interopérables, sans attendre des tests formels.

Avantages de la nouvelle approche :
  • possibilité de vraiment changer la syntaxe avant la livraison
  • les fabricants de navigateurs ont intérêt à standardiser au plus vite
  • plus simple pour les personnes qui utilisent CSS

Les préfixes sont donc a priori voués à disparaître… mais en attendant, nombre sont encore nécessaires.

Une solution : Autoprefixer

Autoprefixer est un post-processeur de CSS : il prend un fichier CSS normal et génère du CSS avec les bons préfixes

Il contient la base de données de caniuse.com, et sait donc quels préfixes sont vraiment utiles

Il gère aussi les différences de syntaxe (gradients, flexbox)

Le principe est de passer les CSS à Autoprefixer avant chaque déploiement (facilement automatisable)

Avantages :
  • On n'écrit que du CSS « standard »
  • Si Autoprefixer est à jour, notre CSS sera à jour
  • On ne se préoccupe pas de quels préfixes sont nécessaires, et des différences de syntaxe : tout ce qui est supportable sera supporté, tout ce qui est inutile n'apparaîtra pas

Un tutoriel (CSS-Tricks)

Règle @supports

Remplacement des hacks CSS pour tester si une fonctionnalité est implémentée

Permet de faire des feature query ; fonctionne comme une media query
@supports (display: flex) {
  .conteneur { display: flex; }
}

@supports not (display: flex) {
  .conteneur div { float: left; }
}

@supports (column-width: 20rem) and (column-span: all) {
  div { column-width: 20rem; }
  div h2 { column-span: all; }
}

Supportée par tous les navigateurs récents ; les autres ignorent la règle

complètement utilisable en prod, à condition de ne pas compter pour l'instant sur @supports not pour les fallbacks (regarder l'exemple au-dessus : que se passe-t-il pour un navigateur qui supporte flexbox mais pas @supports ?)

Modernizr

En attendant que @supports soit supportée partout, Modernizr est une librairie JavaScript pour détecter les fonctionnalités (CSS, mais aussi HTML et JavaScript) implémentées par le navigateur

Elle ajoute des classes à l'élément html pour indiquer les fonctionnalités supportées.

Exemple, on veut utiliser un gradient pour notre classe glossy :
.no-js .glossy,
.no-cssgradients .glossy {
  /* Modernizr indique que le navigateur
   * n'implémente pas les gradients
   * (ou n'exécute pas le JavaScript) */
  background: url("images/glossybutton.png");
}

.cssgradients .glossy {
  /* Modernizr indique que le navigateur comprend les gradients */
  background-image: linear-gradient(top, #555, #333);
}

Il permet aussi facilement de charger des polyfills JavaScript pour implémenter les fonctionnalités manquantes

Fondamental pour obtenir relativement facilement un résultat identique partout — mais ne dispense pas de faire attention à l'accessibilité et aux clients sans JavaScript !

CSS resets

Le principe de CSS est de modifier le style par défaut du HTML

Mais les navigateurs ont des styles par défaut différents, et les internautes peuvent les avoir modifiés

Idée des CSS resets : partir d'un CSS unifié, en particulier avec la plupart des marges et paddings à 0

Exemple : premier CSS reset, par Eric Meyer. Il en existe d'autres.
/* http://meyerweb.com/eric/tools/css/reset/ 
 *    v2.0 | 20110126
 *       License: none (public domain)
 */

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed, 
figure, figcaption, footer, header, hgroup, 
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
    margin: 0;
    padding: 0;
    border: 0;
    font-size: 100%;
    font: inherit;
    vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, 
footer, header, hgroup, menu, nav, section {
    display: block;
}
body {
    line-height: 1;
}
ol, ul {
    list-style: none;
}
blockquote, q {
    quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
    content: '';
    content: none;
}
table {
    border-collapse: collapse;
    border-spacing: 0;
}

L'idée est d'adapter son CSS reset à ses préférences. On peut ainsi repartir d'un style de base bien connu, sans surprise.

Normalize.css

Le projet normalize.css est une alternative aux CSS resets

Au lieu d'effacer les styles par défaut des navigateurs, les conserve mais les rend cohérents

une page avec pour seule feuille de style normalize.css s'affichera de la même façon sur tous les navigateurs

Corrige quelques bugs et incohérences par rapport aux spécs

Code modulaire, très clair et lisible (notamment pratique dans les outils de développement du navigateur)

Pas de JavaScript, simplement une feuille de style

Vivement conseillé !

(Une alternative : sanitize.css reprend les mêmes principes, mais inclut aussi des décisions plus pragmatiques bien que non standard (ex. : box-sizing:border-box et background-repeat:no-repeat par défaut pour tous les éléments)

Limites de la syntaxe CSS

Pour diverses raisons, la syntaxe CSS est très limitée

il y manque des choses basiques auquel toute personne qui programme un peu est habituée : variables, fonctions/macros, imbrication du code…

Une solution est d'utiliser un pré-processeur de CSS :
  • on écrit les feuilles de style dans un langage plus puissant que CSS
  • avant chaque déploiement, on génère les fichiers CSS correspondants
  • le client ne voit que le CSS au final, mais le code réellement « manipulé » est plus simple, clair et facile à maintenir

Les pré-processeurs les plus utilisés sont SASS et LESS

La syntaxe SASS, appelée SCSS, est assez élégante et est une extension de CSS (càd que tout CSS valide est aussi du SCSS valide)

Voir ce guide pour débuter

BEM, OOCSS, Atomic CSS, etc.

TODO: dire des trucs. BEM: c'est bien justifié. Un article : https://medium.com/@jackappleby/does-bem-work-945c523116c Principes : https://en.bem.info/methodology/quick-start/ Justifications : https://en.bem.info/methodology/solved-problems/

Frameworks CSS

En CSS, on se retrouve souvent à réécrire le même genre de code : les designs changent superficiellement, mais la plupart des éléments restent fondamentalement les mêmes

On finit souvent par avoir un ou plusieurs projets-types dont on repart pour tout nouveau travail

Certain·e·s s'efforcent de rendre ces « modèles » les plus généraux et simples à utiliser possibles, et les diffusent. On parle de frameworks CSS

Il y en a de nombreux, plus ou moins complets et lourds ; les plus connus et utilisés sont Bootstrap et Foundation. Parmi les plus récents on peut citer Semantic UI

Autre exemple : Skeleton, qui est beaucoup plus léger (presque plutôt un reset qu'un framework)

Exemple de fonctionnalités pouvant être gérées par un framework :
  • système de grille responsive
  • typographie
  • choix de styles de base cohérents
  • styles de formulaires
  • icônes…

Veille technologique

Il y a encore de nombreuses choses dans le CSS que ce cours n'a pas mentionnées ou à peine survolées

Les navigateurs implémentent sans cesse de nouvelles propriétés, un exemple récent est le blending d'images en CSS (ne fonctionne que sous les versions récentes de Chrome, Firefox et Opera)

Le développement front-end nécessite de se tenir au courant
  • pas forcément des toutes dernières nouveautés…
  • … mais de ce qui devient utilisable en prod
  • et de l'évolution des pratiques de la communauté (code, techniques…) : ce qui était une bonne idée en 2010 ne l'est plus forcément de nos jours !

il faut faire un minimum de veille technologique

Liste de flux RSS sur le dév front-end avec de bonnes ressources (en anglais…) qu'il est intéressant de suivre (pas mise à jour depuis longtemps, mais la section « Must Read » est toujours valide et déjà suffisante). Même chose, plus récent, et carrément exhaustif (mais format moins agréable à lire « à l'œil nu »)

Ne pas se laisser déborder

La veille technologique est importante, néanmoins
  • Les pratiques, les outils et les frameworks à la mode évoluent très rapidement, et il n'est pas évident de s'y retrouver
  • garder en tête qu'il n'est pas nécessaire de tout connaître. Tous ces aspects ajoutent une énorme complexité, qui n'est rentable que sur des projets de très grande ampleur.
  • en développement logiciel, la complexité est un ennemi. On a toujours tendance à faire plus compliqué que nécessaire, car paradoxalement c'est souvent plus facile sur le moment — mais la difficulté de maintenance s'en retrouve augmentée exponentiellement.
  • Le principe de base à suivre : Keep It Simple, Stupid