Vous êtes-vous déjà demandé la quantité de travail que le CSS effectue ? Vous modifiez un seul attribut, et soudainement, l'intégralité de votre site Web s'affiche dans une mise en page différente. C'est un peu magique. Jusqu'à présent, la communauté des développeurs Web n'a pu qu'observer et observer cette magie. Et si nous voulions créer notre propre magie ? Et si nous voulions devenir le magicien ?
Découvrez Houdini !
Le groupe de travail Houdini est composé d'ingénieurs de Mozilla, Apple, Opera, Microsoft, HP, Intel et Google qui travaillent ensemble pour présenter certaines parties du moteur CSS aux développeurs Web. Le groupe de travail travaille sur une collection de projets dans le but de les faire accepter par le W3C pour qu'ils deviennent des normes Web. Ils se sont fixés quelques objectifs généraux, les ont transformés en ébauches de spécifications, qui ont à leur tour donné naissance à un ensemble d'ébauches de spécifications de niveau inférieur.
C'est généralement l'ensemble de ces versions qui est désigné par le terme "Houdini". Au moment de la rédaction de cet article, la liste des brouillons est incomplète et certains d'entre eux ne sont que des espaces réservés.
Spécifications
Worklets (spécification)
Les Worklets en eux-mêmes ne sont pas vraiment utiles. Il s'agit d'un concept introduit pour rendre possibles de nombreuses versions ultérieures. Si vous avez pensé aux Web Workers lorsque vous avez lu "worklet", vous n'avez pas tort. Ils présentent de nombreux chevauchements conceptuels. Pourquoi créer un nouveau concept alors que nous avons déjà des travailleurs ?
L'objectif de Houdini est d'exposer de nouvelles API pour permettre aux développeurs Web de connecter leur propre code au moteur CSS et aux systèmes environnants. Il n'est probablement pas irréaliste de supposer que certains de ces fragments de code devront être exécutés à chaque frame. Certains d'entre eux doivent le faire par définition. Mention de la spécification Web Worker:
Cela signifie que les nœuds de travail Web ne sont pas adaptés à ce que Houdini prévoit de faire. C'est pourquoi les worklets ont été inventés. Les worklets utilisent des classes ES2015 pour définir un ensemble de méthodes, dont les signatures sont prédéfinies par le type du worklet. Ils sont légers et de courte durée.
API CSS Paint (spécification)
L'API Paint est activée par défaut dans Chrome 65. Lisez l'introduction détaillée.
Worklet de composition
L'API décrite ici est obsolète. Le worklet de composition a été repensé et est désormais proposé sous le nom de "Worklet d'animation". En savoir plus sur l'itération actuelle de l'API
Même si la spécification du Worklet du compositeur a été déplacée vers WICG et fera l'objet d'itérations, c'est celle qui m'intéresse le plus. Certaines opérations sont sous-traitées à la carte graphique de votre ordinateur par le moteur CSS, bien que cela dépende à la fois de votre carte graphique et de votre appareil en général.
Un navigateur prend généralement l'arborescence DOM et, en fonction de critères spécifiques, décide d'attribuer une couche à certaines branches et sous-arbres. Ces sous-arbres se peignent dessus (peut-être en utilisant un travaillet de peinture à l'avenir). Enfin, toutes ces couches individuelles, maintenant peintes, sont empilées et positionnées les unes sur les autres, en respectant les indices Z, les transformations 3D, etc., pour obtenir l'image finale visible à l'écran. Ce processus est appelé composition et est exécuté par le moteur de composition.
L'avantage du processus de composition est que vous n'avez pas besoin de faire repeindre tous les éléments lorsque la page défile un peu. À la place, vous pouvez réutiliser les calques du frame précédent et simplement réexécuter le compositeur avec la position de défilement mise à jour. Cela permet d'accélérer les choses. Cela nous permet d'atteindre 60 FPS.
Comme son nom l'indique, le worklet de composition vous permet de vous connecter au moteur de composition et d'influencer la façon dont la couche d'un élément, qui a déjà été peinte, est positionnée et superposée aux autres couches.
Pour être un peu plus précis, vous pouvez indiquer au navigateur que vous souhaitez vous associer au processus de composition pour un certain nœud DOM et demander l'accès à certains attributs tels que la position de défilement, transform
ou opacity
. Cela force cet élément à être placé sur son propre calque et à chaque frame, votre code est appelé. Vous pouvez déplacer votre calque en manipulant la transformation des calques et en modifiant ses attributs (comme opacity
), ce qui vous permet de faire des choses sophistiquées à 60 FPS.
Voici une implémentation complète du défilement en parallaxe, à l'aide du worklet du compositeur.
// main.js
window.compositorWorklet.import('worklet.js')
.then(function() {
var animator = new CompositorAnimator('parallax');
animator.postMessage([
new CompositorProxy($('.scroller'), ['scrollTop']),
new CompositorProxy($('.parallax'), ['transform']),
]);
});
// worklet.js
registerCompositorAnimator('parallax', class {
tick(timestamp) {
var t = self.parallax.transform;
t.m42 = -0.1 * self.scroller.scrollTop;
self.parallax.transform = t;
}
onmessage(e) {
self.scroller = e.data[0];
self.parallax = e.data[1];
};
});
Robert Flack a écrit un polyfill pour le worklet de composition afin que vous puissiez l'essayer, bien entendu avec un impact sur les performances beaucoup plus important.
Worklet de mise en page (spec)
La première ébauche de spécifications réelles a été proposée. L'implémentation est encore loin.
Encore une fois, les spécifications sont pratiquement vides, mais le concept est intéressant: écrivez votre propre mise en page ! Le Worklet de mise en page est censé vous permettre d'utiliser display: layout('myLayout')
et d'exécuter votre code JavaScript pour organiser les enfants d'un nœud dans la zone du nœud.
Bien entendu, exécuter une implémentation JavaScript complète de la mise en page flex-box
du CSS est plus lent que d'exécuter une implémentation native équivalente, mais il est facile d'imaginer un scénario où les raccourcis peuvent entraîner un gain de performances. Imaginez un site Web composé uniquement de cartes, comme Windows 10 ou une mise en page de style maçonnerie. Le positionnement absolu et fixe n'est pas utilisé, pas plus que z-index
. Les éléments ne se chevauchent jamais et ne comportent aucun type de bordure ni de débordement. La possibilité de sauter toutes ces vérifications lors de la redisposition peut entraîner un gain de performances.
registerLayout('random-layout', class {
static get inputProperties() {
return [];
}
static get childrenInputProperties() {
return [];
}
layout(children, constraintSpace, styleMap) {
const width = constraintSpace.width;
const height = constraintSpace.height;
for (let child of children) {
const x = Math.random()*width;
const y = Math.random()*height;
const constraintSubSpace = new ConstraintSpace();
constraintSubSpace.width = width-x;
constraintSubSpace.height = height-y;
const childFragment = child.doLayout(constraintSubSpace);
childFragment.x = x;
childFragment.y = y;
}
return {
minContent: 0,
maxContent: 0,
width: width,
height: height,
fragments: [],
unPositionedChildren: [],
breakToken: null
};
}
});
Code CSSOM saisi (spec)
Le code CSSOM typé (CSS Object Model ou Cascading Style Sheets Object Model) permet de résoudre un problème que nous avons probablement rencontré tous et que nous venons d'apprendre à résoudre. Je vais vous montrer avec une ligne de code JavaScript:
$('#someDiv').style.height = getRandomInt() + 'px';
Nous effectuons des calculs, en convertissant un nombre en chaîne pour ajouter une unité afin que le navigateur analyse cette chaîne et la convertisse à nouveau en nombre pour le moteur CSS. Ce comportement est encore plus affaibli lorsque vous manipulez des transformations avec JavaScript. Plus maintenant ! Le CSS va bientôt commencer à saisir du texte.
Ce projet est l'un des plus aboutis, et un polyfill est déjà en cours de développement. (Clause de non-responsabilité: l'utilisation du polyfill ajoutera évidemment encore plus de frais de calcul. L'objectif est de montrer à quel point l'API est pratique.)
Au lieu de chaînes, vous allez travailler sur le StylePropertyMap
d'un élément, où chaque attribut CSS a sa propre clé et son type de valeur correspondant. Les attributs tels que width
ont LengthValue
comme type de valeur. Un LengthValue
est un dictionnaire de toutes les unités CSS telles que em
, rem
, px
, percent
, etc. Définir height: calc(5px + 5%)
génère un LengthValue{px: 5, percent: 5}
. Certaines propriétés telles que box-sizing
n'acceptent que certains mots clés et ont donc un type de valeur KeywordValue
. La validité de ces attributs peut ensuite être vérifiée au moment de l'exécution.
<div style="width: 200px;" id="div1"></div>
<div style="width: 300px;" id="div2"></div>
<div id="div3"></div>
<div style="margin-left: calc(5em + 50%);" id="div4"></div>
var w1 = $('#div1').styleMap.get('width');
var w2 = $('#div2').styleMap.get('width');
$('#div3').styleMap.set('background-size',
[new SimpleLength(200, 'px'), w1.add(w2)])
$('#div4')).styleMap.get('margin-left')
// => {em: 5, percent: 50}
Propriétés et valeurs
Connaissez-vous les propriétés personnalisées CSS (ou leur alias non officiel "variables CSS") ? Voici les mêmes, mais avec des types. Jusqu'à présent, les variables ne pouvaient avoir que des valeurs de chaîne et utilisaient une approche de recherche et de remplacement simple. Cette ébauche vous permettrait non seulement de spécifier un type pour vos variables, mais aussi de définir une valeur par défaut et d'influencer le comportement d'héritage à l'aide d'une API JavaScript. Techniquement, cela permettrait également d'animer les propriétés personnalisées avec des transitions et des animations CSS standards, ce qui est également à l'étude.
["--scale-x", "--scale-y"].forEach(function(name) {
document.registerProperty({
name: name,
syntax: "<number>",
inherits: false,
initialValue: "1"
});
});
Métriques de police
Les métriques de police sont exactement ce à quoi elles ressemblent. Qu'est-ce que le cadre de délimitation (ou les cadres de délimitation) lorsque j'affiche la chaîne X avec une police Y de taille Z ? Que se passe-t-il si j'utilise des annotations Ruby ? Cette fonctionnalité a été très demandée, et Houdini devrait enfin la proposer.
Et ce n'est pas tout !
La liste des ébauches de Houdini contient encore plus de spécifications, mais leur avenir est plutôt incertain et elles ne sont guère plus que des espaces réservés pour les idées. Les exemples incluent les comportements de dépassement personnalisés, l'API d'extension de syntaxe CSS, l'extension du comportement de défilement natif et des éléments similaires ambitieux, qui permettent tous des éléments qui n'étaient pas possibles sur la plate-forme Web auparavant.
Démonstrations
J'ai rendu le code de la démonstration Open Source (démonstration en direct à l'aide d'un polyfill).