Les dernières ressources publiées sur Alsacreations.com
LearnLayout est un mini-site d'apprentissage dédié au positionnement en CSS.
Parfaitement adapté aux débutants (display, modèle de boîte, float, position, inline-block), le tutoriel n'exclut pas les intégrateurs chevronnés puisqu'il aborde des sujets avancés tels que clearfix, box-sizing, media queries, multicolonnes, flexbox et les frameworks CSS.
Les navigateurs rivalisent d'ingéniosité pour diminuer le temps de chargement des pages, ou du moins le faire ressentir à l'utilisateur. Quelques tentatives de pré-chargement automatique furent réalisées dans le passé, sans toutefois rencontrer un succès immédiat. En effet, effectuer une requête nécessite de "deviner" par avance quelles pages seront les plus pertinentes à pré-charger, avec plus ou moins de justesse et de risques :
Désormais, des moteurs de navigateurs courants tels que Firefox, Internet Explorer 9/10/11+ et Chrome peuvent exploiter les directives de la balise <link>
et de l'attribut rel
(relation) avec certains mots-clés pour pré-charger des URLs précises, que ce soit du code HTML, CSS, JavaScript, images, etc.
Ces techniques sont à utiliser avec une extrême précaution. Mal employées, elles peuvent vous causer plus de tort que de bien et gêner vos utilisateurs (voir les différents cas évoqués précédemment).
Une relation prefetch
va déclencher le pré-chargement du fichier mentionné par le lien (attribut href
), afin de le placer en cache.
Cette instruction figure dans la spécification côté WhatWG (Links) et W3C (HTML5 Links). Elle est supportée par Mozilla Firefox, Chrome et IE9+.
<link rel="prefetch" href="http://www.mondomaine.com/autre_page.html">
<link rel="prefetch" href="http://www.mondomaine.com/autre_feuille_de_styles.css">
On ne peut pas spécifier d'adresse globale de répertoire, de caractère joker (*), de fichier à télécharger/enregistrer, ou d'autre protocole que http/https. Ne passons pas à côté des choses simples.
Il faut se servir de cette directive avec parcimonie pour ne pas pénaliser la bande passante du visiteur (qui est peut-être sur du bas-débit/mobile) et du serveur. De toute manière, les navigateurs imposent des limites ; par exemple Internet Explorer 11 ne tolère que 10 ressources pré-chargées.
Lorsque la navigation logique de l'utilisateur a toutes les chances d'aboutir sur un lien précis, par exemple :
Comment distinguer une requête envoyée au serveur pour un pré-chargement d'une consultation réelle ? Le navigateur peut le signaler avec un en-tête HTTP supplémentaire. Par exemple Firefox envoie X-moz: prefetch
, qui pourra se retrouver avec PHP dans $_SERVER['HTTP_X_MOZ']
mais ceci peut évoluer au cours du temps et n'est pas standardisé.
Tous les bons outils de développement (Firebug, F12, etc) pourront afficher les requêtes partant vers le serveur.
La spécification précise également que l'on peut placer cette relation avec les éléments <link>
, <a>
et <area>
.
Dans ce cas, le pré-chargement sera en réalité une requête DNS menée par anticipation, pour résoudre un nom de domaine en adresse IP, sans attendre de le rencontrer dans le code source de la page ou d'une page suivante. Ces requêtes peuvent parfois nécessiter quelques dizaines de millisecondes, et il y en a d'autant plus qu'un document fait appel à des ressources issues de domaines variés.
Note : Cette instruction n'est pas encore standardisée. Elle est reconnue par Mozilla Firefox, Google Chrome et IE10+.
<link rel="dns-prefetch" href="http://www.autredomaine.com/">
Ou sans protocole :
<link rel="dns-prefetch" href="//www.autredomaine.com/">
Si l'on sait par avance que www.mondomaine.com
fera ultérieurement appel à des pages, images, CSS, JavaScript de www.autredomaine.com
, ou de cdn.mondomaine.com
, il pourra être utile de tenter de prédire ce comportement et de gagner du temps sur les requêtes DNS qui seront nécessaires pour convertir ces différents domaines ou sous-domaines en adresses IP (entre 50 et 250 ms généralement).
Certains navigateurs - notamment Chrome - utilisent aussi cette fonctionnalité sans vous demander votre avis et sans déclaration explicite dans un code HTML ; par exemple selon l'historique de l'utilisateur (les 10 derniers domaines visités avant fermeture) et/ou par diviniation de ce qu'il va taper dans la barre d'adresse. Pour voir quelques statistiques DNS sur ce moteur, consultez la page chrome://dns/
Le pré-rendu de document va passer la main au moteur d'interprétation pour mettre en cache (mémoire) par avance une page afin de l'afficher quasiment instantanément si le visiteur y accède en ayant déjà un "rendu graphique".
Note : Cette instruction n'est pas encore standardisée. Elle est reconnue par Google Chrome et IE11+.
<link rel="prerender" href="http://www.mondomaine.com/autre_page.html">
Dans ce cas de figure, l'API PageVisibility pourra être utile pour se renseigner sur l'état précis du rendu de la page avec la propriété document.visibilityState
(alors égale à prerender
). On peut ajouter dans la valeur de l'attribut rel
le mot-clé prefetch
pour les navigateurs le supportant mais pas encore prerender.
Pour citer un exemple, Internet Explorer 11+ ne pré-calcule qu'une page à la fois. Il agit aussi intelligemment en n'exécutant cette instruction que si le document y faisant appel est au premier plan (onglet actif) et visible. La page de destination est effacée de la mémoire, entre autres :
On retrouve ces conditions du côté de Google Chrome, qui y ajoutera aussi une annulation en cas de :
Ce navigateur permet d'examiner l'activité du pre-rendering via la page interne chrome://net-internals/#prerender
. Il n'y a (a priori) pas d'en-tête HTTP spécifique envoyé donc pas de possibilité de distinguer un prerender d'une requête classique.
Un petit site de test a été mis au point sur http://prerender-test.appspot.com/ pour détecter l'activation (ou non) de cette fonctionnalité.
Il faut retenir qu'on peut aussi injecter ce type de balise avec JavaScript, de préférence dans la section <head>
, c'est alors la dernière présente qui prendra le pas sur les autres.
Alsacréations est fier de vous annoncer la naissance de Schnaps.it, notre nouvel outil de génération de code HTML / CSS !
Combinaison de plusieurs outils existants (KNACSS, Schnapsum et Squelettor), Schnaps.it offre une palette de fonctionnalités lorsque vous débutez un nouveau projet web :
Le générateur de gabarits permet d'affiner certains réglages visuels des différents éléments (largeur, marges internes, marges externes, alignement de texte, etc.).
Une fois vos réglages effectués, il ne vous reste plus qu'à récupérer l'ensemble des fichiers en un clic !
Un grand merci à Laetitia Bonanni, stagiaire dans l'agence Alsacréations pour ce joli travail réalisé tant du point de vue graphique que technique !
Comme le dit fort à propos Wikipédia : L'accélération matérielle consiste à confier une fonction spécifique effectuée par le processeur à un circuit intégré dédié qui effectuera cette fonction de façon plus efficace.
Dans le monde du Web cette possibilité concernera généralement les animations, et reposera sur la présence de deux éléments essentiels :
Certaines propriétés CSS affectent directement ou indirectement la taille de la boîte d'un élément : width
, height
, mais aussi margin
, padding
, border
, top
, right
, bottom
, left
, etc.
Lorsque l'on modifie l'une de ces valeurs via CSS, le navigateur se voit contraint de recalculer la boîte ainsi que celles qui l'entourent et de "repeindre" la page (repaint).
Ce comportement est généralement insignifiant… sauf en cas de transition ou d'animation CSS : le navigateur, via le processeur, doit alors recalculer tous les éléments à chaque étape-clé de la transition !
La conséquence de cet effort du processeur se traduit par des effets de ralentissements et des saccades qui peuvent devenir très gênantes sur des périphériques de faible puissance, et en particulier sur des tablettes et smartphones.
Lors de vos animations CSS, pensez dans un premier temps à éviter les propriétés de "boîte" (citées précédemment) et remplacez-les avantageusement par des équivalents beaucoup plus performants (mais parfois moins compatibles) telles que les transformations : translations, rotations, déformations.
Et quand ce n'est pas possible,… il sera alors grand temps d'activer l'accélération matérielle via CSS, et le gain en fluidité sera immédiat et perceptible !
Appliquer une transformation CSS force un élément à s'afficher dans un "calque" indépendant du reste des éléments, permettant alors au navigateur de le traiter différemment.
L'une des possibilités offertes est alors de basculer tous les traitements et calculs de cet élément du côté de la carte graphique (GPU), et non plus du processeur (CPU). Bref,
Une transformation CSS "classique" (translate
, rotate
, skew
, scale
, matrix
) ne suffit pas à activer l'accélération matérielle, il est nécessaire que cette transformation passe via l'axe de la pronfondeur (axe Z). En clair, il faut opérer une transformation 3D.
Voici une liste de déclarations CSS 3D permettant d'activer l'accélération matérielle sans altérer l'affichage ou la position de l'élément :
transform: translateZ(0);
transform: translate3d(0,0,0);
perspective: 1000; backface-visibility: hidden;
Les propriétés de transformations 3D sont plutôt bien supportées par les navigateurs, mais dans tous les cas, n'oubliez pas d'ajouter les préfixes constructeurs de rigueur (-webkit-
, -moz-
, -ms-
, -o-
) nécessaires tant que la spécification W3C du module des transformations 3D n'est pas finalisée.
Notez également que certains filtres CSS (CSS3 filters, actuellement à l'état de brouillon), WebGL, la vidéo et l'élément HTML5 <canvas>
contribuent également à l'activation de la carte graphique.
Certains navigateurs permettent d'afficher les informations de la carte graphique et notamment si l'accélération est possible. Par exemple dans Firefox, la commande est about:support
, et dans Chrome la syntaxe est chrome://gpu
:
Pour mieux comprendre la mise en pratique de l'accélération matérielle, je vous propose un court exemple concret. Le but est de faire apparaître un menu de navigation en transition lors d'un événement :
nav {
transform: translate3d(-100%,0,0); /* activation de l'AM */
transition: transform .4s;
}
nav.open {
transform: translate3d(0,0,0);
}
Variante (plus compatible si les transformations 3D ne sont pas supportées) :
nav {
position: absolute;
left: -100%;
transform: translate3d(0,0,0); /* activation de l'AM */
transition: left .4s;
}
nav.open {
left: 0;
}
Les snippets de navigation responsive sur la page goetter.fr/nav activent tant que faire se peut l'accélération matérielle. Je vous invite à les décortiquer et vous les approprier.
Les filtres CSS, actuellement en brouillon dans les spécifications, offrent de nouvelles possibilités graphiques fort intéressantes : flou, noir et blanc, sépia, contraste, luminosité, etc.
Cependant, à l'instar des animations, certains filtres CSS tels que blur
(flou) posent des problèmes de lenteur sur mobiles.
Dans ce cas, activer l'accélération matérielle vous sera également d'une grande utilité.
Le lissage des polices laisse souvent à désirer sur Chrome Windows, je ne vous l'apprends sans doute pas. Sachez que dans ce domaine aussi l'activation de l'accélération matérielle peut faire des miracles.
Prenez deux caractères agrandis et tournés. Dans le premier cas, opérez une rotation simple à l'aide d'une transformation classique. Dans le second cas, ajoutez une transformation CSS 3D afin de solliciter la carte graphique. Vous serez bluffés par le résultat (à voir sur CodePen) :
span {
display: inline-block;
-webkit-transform: rotate(60deg);
}
span+span {
-webkit-transform: rotate(60deg) translate3d(0,0,0);
}
Activer l'accélération matérielle favorise la fluidité des animations CSS, mais provoque également d'autres effets bénéfiques pour les périphériques dont le processeur est parfois à la traîne.
Sachez en profiter sans toutefois en abuser : les cartes graphiques de nos anciens mobiles ne sont pas non plus des foudres de guerre et pourraient facilement pâtir d'un excès de zèle dans vos choix d'activation matérielle.
Deux attributs HTML permettent de modifier le comportement des balises <script>
et plus particulièrement pour le chargement des ressources JavaScript :
Ils sont souvent confondus avec pourtant des conséquences différentes. À l'heure où les performances sont surveillées de plus en plus près par les robots d'indexation, et les temps de chargement scrutés pour le confort des utilisateurs, leur usage est le bienvenu.
Ces attributs sont reconnus par tous les navigateurs modernes actuels : Firefox 3.6+, Chrome, Safari, à partir d'Internet Explorer 10 et bientôt Opera. Y compris dans les versions mobiles. Si un moteur ne comprend pas l'un ou l'autre, ceci ne se révélera pas bloquant pour l'interprétation du document, les performances resteront simplement "non optimisées".
Le but de ces deux attributs, décrits en détails ci-après, est principalement de charger et lancer l'interprétation de code JavaScript sans bloquer le rendu HTML (son affichage à l'écran). Ils ne concernent en général que des interprétations de codes situés dans des fichiers externes (lorsque l'attribut src
est utilisé) et viennent assouplir la pratique communément admise de placer - dans la mesure du possible - les balises <script>
à la fin du document juste avant la fermeture de </body>
.
Cette dernière recommandation provient d'un comportement que les navigateurs ne peuvent éviter : par défaut (et pour simplifier), toute balise <script>
rencontrée met en attente le moteur HTML/CSS car le navigateur ne sait pas si le code JavaScript va contenir des instructions spécifiques à exécuter immédiatement qui pourront avoir une conséquence importante sur... le code HTML/CSS lui-même, notamment avec la fonction document.write()
. Il va donc falloir effectuer des requêtes HTTP vers le serveur pour chaque fichier JavaScript externe, attendre les réponses, recueillir le code et l'exécuter. Ces actions prennent souvent plusieurs dizaines de millisecondes. Avec plusieurs éléments <script>
comme on le voit souvent dans le code source des pages et applications web, le ralentissement du chargement en est multiplié d'autant.
Pour examiner les cas de figure pouvant se présenter, partons d'une page-type dans laquelle se situent des balises <script>
dans l'en-tête, le corps et la fin du document. L'une d'entre elles fait appel à un fichier script-lent.js
qui comme son nom l'indique met volontairement un peu plus d'une seconde à être délivré par le serveur.
<!doctype html>
<html>
<head>
<title>Test JS</title>
<script>if(typeof console!='undefined') console.time('Timing');</script>
<script src="script-lent.js"></script>
</head>
<body>
<p>Script dans <head> et avant </body></p>
<script>if(typeof console!='undefined') console.debug('Affichage du body HTML');</script>
<script src="script.js"></script>
<script src="script2.js"></script>
<script>if(typeof console!='undefined') console.timeEnd('Timing');</script>
</body>
</html>
Dans ce cas de figure, nous observons le comportement suivant :
Du côté réseau :
Verdict
DOMContentLoaded
)<script>
Antérieur à la vague HTML5, l'attribut defer
existait déjà dans les "anciennes" versions d'Internet Explorer. Il signifie que le navigateur peut charger le(s) script(s) en parallèle, sans stopper le rendu de la page HTML. Contrairement à async
, l'ordre d'exécution des scripts est préservé, en fonction de leur apparition dans le code source HTML. Il est par ailleurs reporté à la fin du parsing du DOM (avant l'événement DOMContentLoaded
). De nos jours, cet attribut présente moins d'intérêt car les navigateurs disposent par défaut de techniques internes pour télécharger les ressources en parallèle sans nécessairement attendre les autres.
<script src="code.js" defer></script>
Reprenons le premier code en ajoutant l'attribut defer.
<!doctype html>
<html>
<head>
<title>Test JS</title>
<script>if(typeof console!='undefined') console.time('Timing');</script>
<script src="script-lent.js" defer></script>
</head>
<body>
<p>Script dans <head> et avant </body></p>
<script>if(typeof console!='undefined') console.debug('Affichage du body HTML');</script>
<script src="script.js" defer></script>
<script src="script2.js" defer></script>
<script>if(typeof console!='undefined') console.timeEnd('Timing');</script>
</body>
</html>
Dans ce cas de figure, nous observons le comportement suivant :
Côté réseau :
Verdict :
<script>
dans le code source.defer
, il prend donc place avant leur interprétation.
Nouveau venu dans HTML5, async
signifie que le script pourra être exécuté de façon asynchrone, dès qu'il sera disponible (téléchargé). Cela signifie aussi que le navigateur n'attendra pas de suivre un ordre particulier si plusieurs balises <script>
sont présentes, et ne bloquera pas le chargement du reste des ressources, notamment la page HTML. L'exécution aura lieu avant l'événement load
lancé sur window
et ne sera valable que pour les scripts externes au document, c'est-à-dire ceux dont l'attribut src
mentionne l'adresse.
<script src="code.js" async></script>
Ce comportement est bien pratique pour gagner en temps de chargement, il faut cependant l'utiliser avec prudence : si l'ordre n'est pas respecté, un fichier exécuté de façon asynchrone ne pourra attendre le chargement d'un précédent, par exemple s'il en utilise des fonctions voire un framework. Il ne faudra pas non plus compter appeler document.write()
pour écrire dans le document HTML puisqu'il sera impossible de savoir à quel moment les actions seront déclenchées.
En résumé, n'écrivez pas ça :
<!-- Attention le code ci-dessous est un contre-exemple, ne PAS utiliser -->
<script src="jquery.js" async></script>
<script src="autre_script_utilisant_jquery.js" async></script>
Reprenons le premier test en ajoutant l'attribut.
<!doctype html>
<html>
<head>
<title>Test JS</title>
<script>if(typeof console!='undefined') console.time('Timing');</script>
<script src="script-lent.js" async></script>
</head>
<body>
<p>Script dans <head> et avant </body></p>
<script>if(typeof console!='undefined') console.debug('Affichage du body HTML');</script>
<script src="script.js" async></script>
<script src="script2.js" async></script>
<script>if(typeof console!='undefined') console.timeEnd('Timing');</script>
</body>
</html>
Dans ce cas de figure, nous observons le comportement suivant :
Côté réseau :
Verdict
DOMContentLoaded
)<script>
Selon la nature des scripts à exécuter, les deux attributs peuvent être utilisés ensemble.
En général, les scripts créés dynamiquement (c'est-à-dire par des instructions JavaScript elles-mêmes et non par des balises <script>
), se voient automatiquement affublés de l'attribut/comportement async
puisqu'il ne sont pas liés à un ordre logique déclaré dans le DOM.
Deux attributs HTML permettent de modifier le comportement des balises <script>
et plus particulièrement pour le chargement des ressources JavaScript :
Ils sont souvent confondus avec pourtant des conséquences différentes. À l'heure où les performances sont surveillées de plus en plus près par les robots d'indexation, et les temps de chargement scrutés pour le confort des utilisateurs, leur usage est le bienvenu.
Ces attributs sont reconnus par tous les navigateurs modernes actuels : Firefox 3.6+, Chrome, Safari, à partir d'Internet Explorer 10 et bientôt Opera. Y compris dans les versions mobiles. Si un moteur ne comprend pas l'un ou l'autre, ceci ne se révélera pas bloquant pour l'interprétation du document, les performances resteront simplement "non optimisées".
Le but de ces deux attributs, décrits en détails ci-après, est principalement de charger et lancer l'interprétation de code JavaScript sans bloquer le rendu HTML (son affichage à l'écran). Ils ne concernent en général que des interprétations de codes situés dans des fichiers externes (lorsque l'attribut src
est utilisé) et viennent assouplir la pratique communément admise de placer - dans la mesure du possible - les balises <script>
à la fin du document juste avant la fermeture de </body>
.
Cette dernière recommandation provient d'un comportement que les navigateurs ne peuvent éviter : par défaut (et pour simplifier), toute balise <script>
rencontrée met en attente le moteur HTML/CSS car le navigateur ne sait pas si le code JavaScript va contenir des instructions spécifiques à exécuter immédiatement qui pourront avoir une conséquence importante sur... le code HTML/CSS lui-même, notamment avec la fonction document.write()
. Il va donc falloir effectuer des requêtes HTTP vers le serveur pour chaque fichier JavaScript externe, attendre les réponses, recueillir le code et l'exécuter. Ces actions prennent souvent plusieurs dizaines de millisecondes. Avec plusieurs éléments <script>
comme on le voit souvent dans le code source des pages et applications web, le ralentissement du chargement en est multiplié d'autant.
Pour examiner les cas de figure pouvant se présenter, partons d'une page-type dans laquelle se situent des balises <script>
dans l'en-tête, le corps et la fin du document. L'une d'entre elles fait appel à un fichier script-lent.js
qui comme son nom l'indique met volontairement un peu plus d'une seconde à être délivré par le serveur.
<!doctype html>
<html>
<head>
<title>Test JS</title>
<script>if(typeof console!='undefined') console.time('Timing');</script>
<script src="script-lent.js"></script>
</head>
<body>
<p>Script dans <head> et avant </body></p>
<script>if(typeof console!='undefined') console.debug('Affichage du body HTML');</script>
<script src="script.js"></script>
<script src="script2.js"></script>
<script>if(typeof console!='undefined') console.timeEnd('Timing');</script>
</body>
</html>
Dans ce cas de figure, nous observons le comportement suivant :
Du côté réseau :
Verdict
DOMContentLoaded
)<script>
Antérieur à la vague HTML5, l'attribut defer
existait déjà dans les "anciennes" versions d'Internet Explorer. Il signifie que le navigateur peut charger le(s) script(s) en parallèle, sans stopper le rendu de la page HTML. Contrairement à async
, l'ordre d'exécution des scripts est préservé, en fonction de leur apparition dans le code source HTML. Il est par ailleurs reporté à la fin du parsing du DOM (avant l'événement DOMContentLoaded
). De nos jours, cet attribut présente moins d'intérêt car les navigateurs disposent par défaut de techniques internes pour télécharger les ressources en parallèle sans nécessairement attendre les autres.
<script src="code.js" defer></script>
Reprenons le premier code en ajoutant l'attribut defer.
<!doctype html>
<html>
<head>
<title>Test JS</title>
<script>if(typeof console!='undefined') console.time('Timing');</script>
<script src="script-lent.js" defer></script>
</head>
<body>
<p>Script dans <head> et avant </body></p>
<script>if(typeof console!='undefined') console.debug('Affichage du body HTML');</script>
<script src="script.js" defer></script>
<script src="script2.js" defer></script>
<script>if(typeof console!='undefined') console.timeEnd('Timing');</script>
</body>
</html>
Dans ce cas de figure, nous observons le comportement suivant :
Côté réseau :
Verdict :
<script>
dans le code source.defer
, il prend donc place avant leur interprétation.
Nouveau venu dans HTML5, async
signifie que le script pourra être exécuté de façon asynchrone, dès qu'il sera disponible (téléchargé). Cela signifie aussi que le navigateur n'attendra pas de suivre un ordre particulier si plusieurs balises <script>
sont présentes, et ne bloquera pas le chargement du reste des ressources, notamment la page HTML. L'exécution aura lieu avant l'événement load
lancé sur window
et ne sera valable que pour les scripts externes au document, c'est-à-dire ceux dont l'attribut src
mentionne l'adresse.
<script src="code.js" async></script>
Ce comportement est bien pratique pour gagner en temps de chargement, il faut cependant l'utiliser avec prudence : si l'ordre n'est pas respecté, un fichier exécuté de façon asynchrone ne pourra attendre le chargement d'un précédent, par exemple s'il en utilise des fonctions voire un framework. Il ne faudra pas non plus compter appeler document.write()
pour écrire dans le document HTML puisqu'il sera impossible de savoir à quel moment les actions seront déclenchées.
En résumé, n'écrivez pas ça :
<!-- Attention le code ci-dessous est un contre-exemple, ne PAS utiliser -->
<script src="jquery.js" async></script>
<script src="autre_script_utilisant_jquery.js" async></script>
Reprenons le premier test en ajoutant l'attribut.
<!doctype html>
<html>
<head>
<title>Test JS</title>
<script>if(typeof console!='undefined') console.time('Timing');</script>
<script src="script-lent.js" async></script>
</head>
<body>
<p>Script dans <head> et avant </body></p>
<script>if(typeof console!='undefined') console.debug('Affichage du body HTML');</script>
<script src="script.js" async></script>
<script src="script2.js" async></script>
<script>if(typeof console!='undefined') console.timeEnd('Timing');</script>
</body>
</html>
Dans ce cas de figure, nous observons le comportement suivant :
Côté réseau :
Verdict
DOMContentLoaded
)<script>
Selon la nature des scripts à exécuter, les deux attributs peuvent être utilisés ensemble.
En général, les scripts créés dynamiquement (c'est-à-dire par des instructions JavaScript elles-mêmes et non par des balises <script>
), se voient automatiquement affublés de l'attribut/comportement async
puisqu'il ne sont pas liés à un ordre logique déclaré dans le DOM.