"[-prefix-free is] fantastic, top-notch work! Thank you for creating and sharing it." - Eric Meyer
Grâce à -prefix-free, seules les propriétés standards suffisent. Pas étonnant que tous les Code Playgrounds se sont rués pour nous proposer cette librairie devenue incontournable. Prenons par exemple le pen suivant proposé par amos.
See the Pen cblAm by Julien Sobczak (@julien-sobczak) on CodePen.
Aucun préfixe -moz
ou -webkit
, un code simple d’autant plus grâce à l’utilisation
de Sass. Derrière le rideau, -prefix-free ajoute les propriétés
préfixées mais seulement si nécessaire. Comment opère cette magie ? C’est ce que nous allons découvrir.
-prefix-free nous est offert par Lea Verou et est disponible sur Github. Le code présenté dans cet article a été simplifié pour des raisons évidentes et n’a pas pour vocation à être utilisé en dehors de ce contexte d’apprentissage. Cet article est basé sur la dernière version du code au moment de la publication de cet article.
Un premier exemple
Si on inspecte le source dans notre navigateur Firefox 3.6, on constate quelques différences :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- demo.html (résultat avec Firefox 3.6) -->
<!doctype html>
<html class="-moz-">
<head>
<meta charset="utf-8">
<title>Démo PrefixFree</title>
<style media="" data-href="demo.css">
h1 {
background: orange;
-moz-border-radius: 10px;
}
</style>
</head>
<body>
<h1>Hello World!</h1>
<script src="http://cssdeck.com/assets/js/prefixfree.min.js"></script>
</body>
</html>
- 8
- Notre feuille de style a disparu et a été remplacée par une feuille de style inline.
- 8
- Le contenu est identique à une exception près : l'utilisation du préfixe
-moz
pour la propriété non supportéeborder-radius
.
C’est parti !
-prefix-free ajoute 2 variables globales (StyleFix
et PrefixFree
), reflet d’une librairie
divisée en deux parties bien distinctes :
- StyleFix est un framework qui permet d’appliquer des corrections à du CSS.
- PrefixFree repose dessus et enregistre un correcteur qui vient remplacer les propriétés CSS non supportés par les équivalents des navigateurs.
Note : Nous allons continuer sur notre exemple du border-radius
.
Cette propriété est disponible (avec préfixe) depuis
la version 2 de Firefox.
Les exemples qui suivent ont été testés avec la version Firefox 3.6.
StyleFix : corrigeons nos CSS !
StyleFix applique une série de corrections apportées par ce qu’on va appeler des fixers. Un fixer est simplement une fonction qui respecte la signature suivante :
où :
css
est une chaine de caractères contenant le code CSS à corriger.raw
qui vaut false lorsque le CSS est directement présent sur une balise HTML.element
qui correspond à l’élement associé au code (la baliselink
,style
ou la balise HTML avec un attributstyle
).
La fonction retourne le CSS modifié.
L’enregistrement des fixers se fait grâce à la fonction register
.
Les fixers sont ensuite déclenchés pour chaque élément contenant du code CSS grâce à la fonction fix
:
Rien d’insurmontable jusqu’à présent.
Intéressons nous maintenant à ce qui se passe au chargement de la page. Une fois le DOM chargé, StyleFix
recherche les balises link
, style
et celles ayant un attribut style
. Ici,
nous nous intéresserons uniquement aux balises style
mais le principe reste le même pour les autres
balises.
Zoom sur querySelectorAll
La petite subtilité de ce code provient de la méthode
querySelectorAll
qui retourne un object NodeList
.
Cet object propose une propriété length
et peut être itérer avec un for
, de quoi nous
laisser croire qu’on peut utiliser la méthode
forEach
.
Mais non. Il ne s’agit pas d’un tableau, d’où la subtilité décrite plus en détail dans
la documentation de l’objet.
Nous en avons fini avec l’objet StyleFix
. Voici le résultat final :
Avant de passer à la suite, voici un bref exemple d’utilisation de la librairie qui convertit les feuilles de style sur une seule ligne :
PrefixFree, les choses sérieuses commencent !
En prenant quelques raccourcis, on arrive à une première version opérationnelle :
1
2
3
4
5
6
7
8
9
10
11
StyleFix.register(function(css, raw, element) {
var prefix = '-moz-', // TODO
properties = ['border-radius']; // TODO
for (var i = 0; i < properties.length; i++) {
var regex = RegExp(properties[i], 'gi');
css = css.replace(regex, prefix + properties[i]);
}
return css;
});
- 2
- On se concentre unique sur notre Firefox 3.6 pour le moment.
- 3
- On considère uniquement la propriété
border-radius
. - 6
- On recherche chaque propriété à remplacer pour la remplacer par son équivalent préfixé.
On retrouve logiquement StyleFix qui nous sert à enregistrer un fixer. Ce fixer, pour chaque propriété non supportée, remplace par la propriété équivalente. L’expression régulière permet de faire un remplacement global, la méthode replace ne remplaçant que la première occurrence (un flag peut être défini en 3ème argument mais n’est pas supporté par le moteur V8).
Pour que le code fonctionne sur d’autres exemples, deux points restent à élucider :
- Comment connaître le préfixe du navigateur de l’utilisateur ?
- Comment identifier les propriétés à remplacer ?
Commençons par répondre à la première question.
Plusieurs solutions sont envisageables. On pourrait utiliser Modernizr
mais -prefix-free utilise une solution toute simple qui consiste à créer un élément dans le DOM et inspecter son
attribut style
représenté en JavaScript par l’objet CSSStyleDeclaration
.
Cet objet contient les valeurs de toutes les propriétés CSS supportées par le navigateur. On va se contenter de
mémoriser la liste des propriétés qui commencent par -
(synomyme d’extension) afin d’extraire le
préfixe et de répondre par la même occasion à la deuxième question.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var prefix = undefined,
properties = [],
dummy = document.createElement('div').style;
for (var property in dummy) {
property = deCamelCase(property);
if (property.charAt(0) === '-') {
properties.push(property);
prefix = prefix || property.split('-')[1];
}
}
self.prefix = '-' + prefix + '-';
- 6
-
Cette ligne est nécessaire pour retrouver le nom de la propriété telle que nous la connaissons en CSS. En
effet, côté JavaScript les propriétés CSS sont définies comme des propriétés de l’objet
CSSStyleDeclaration
et se conforment à la définition du langage (caractère - interdit dans un identifiant).
Deux fonctions utilitaires sont définies qui permettent de passer d’une notation à l’autre :
Si on revient à l’exemple précédent, nous étions arriver à un tableau contenant les propriétés avec préfixe
supportées par notre navigateur. Il nous un cas reste à gérer : les navigateurs évoluent et tôt ou tard les
propriétés standard deviennent supportées (ex : Firefox >= 4 supporte à la fois -moz-border-radius
et
border-radius
). Inutile dans ces cas d’effectuer les remplacements.
Notre version de PrefixFree est désormais complète :
Terminé !
Cela termine la découverte de -prefix-free. Moins de 100 lignes auront été nécessaires pour proposer une première version. L’exemple complet est disponible ici.
A vous de forker
-
Supporter les balises
link
et attributstyle
. Indice : récupérer le contenu des feuilles de style externes en AJAX. Quelles sont les limites ? -
Les changements CSS après chargement de la page (en JavaScript) ne sont pas supportés. Indice : écouter les
événements
DOMAttrModified
etDOMNodeInserted
(voir pluginprefixfree.dynamic-dom.js
). -
Supporter les
@rules
commekeyframe
. Indice : utiliser des expressions régulières plus poussées en reprenant le même principe.
A Retenir
- StyleFix/PrefixFree : un bon exemple de Divide-and-Conquer !
querySelectorAll
ne retourne pas un objetArray
maisNodeList
.- L'objet
CSSStyleDeclaration
permet de connaître les propriétés supportées par un navigateur.