Un style Web nouvelle génération

Découvrez certaines des fonctionnalités intéressantes du CSS moderne.

De nombreuses choses passionnantes se passent actuellement dans le CSS, et beaucoup d'entre elles sont déjà compatibles avec les navigateurs actuels. Notre conférence au CDS 2019, que vous pouvez regarder ci-dessous, aborde plusieurs fonctionnalités nouvelles et à venir qui, selon nous, devraient attirer votre attention.

Cet article se concentre sur les fonctionnalités que vous pouvez utiliser dès aujourd'hui. Veillez donc à regarder la conférence pour en savoir plus sur les fonctionnalités à venir, comme Houdini. Vous trouverez également des démonstrations de toutes les fonctionnalités que nous décrivons sur notre page CSS@CDS.

Sommaire

Accrochage au défilement

La fonctionnalité Ancrage au défilement vous permet de définir des points d'ancrage lorsque l'utilisateur fait défiler votre contenu verticalement, horizontalement ou les deux. Il offre une inertie et une décélération de défilement intégrées, et est compatible avec le toucher.

Cet exemple de code configure le défilement horizontal dans un élément <section> avec des points d'ancrage alignés sur le côté gauche des éléments <picture> enfants:

section {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
}

section > picture {
  scroll-snap-align: start;
}

Le principe est le suivant :

  • Dans l'élément <section> parent,
    • overflow-x est défini sur auto pour permettre le défilement horizontal.
    • overscroll-behavior-x est défini sur contain pour empêcher le défilement des éléments parents lorsque l'utilisateur atteint les limites de la zone de défilement de l'élément <section>. (Ce n'est pas strictement nécessaire pour l'ancrage, mais c'est généralement une bonne idée.)
    • scroll-snap-type est défini sur x (pour l'ancrage horizontal) et mandatory (pour s'assurer que la fenêtre d'affichage s'ancre toujours au point d'ancrage le plus proche).
  • Sur les éléments enfants <picture>, scroll-snap-align est défini sur "start" (début), ce qui définit les points d'ancrage à gauche de chaque image (en supposant que direction soit défini sur ltr).

Voici une démonstration en direct:

Vous pouvez également regarder des démonstrations de l'ancrage du défilement vertical et de l'ancrage du défilement matriciel.

:focus-within

:focus-within résout un problème d'accessibilité de longue date: dans de nombreux cas, la sélection d'un élément enfant doit affecter la présentation d'un élément parent afin que l'UI soit accessible aux utilisateurs de technologies d'assistance.

Par exemple, si vous avez un menu déroulant contenant plusieurs éléments, le menu doit rester visible lorsque l'un des éléments est sélectionné. Sinon, le menu disparaît pour les utilisateurs de clavier.

:focus-within indique au navigateur d'appliquer un style lorsque le curseur est placé sur n'importe quel élément enfant d'un élément spécifié. Pour revenir à l'exemple de menu, en définissant :focus-within sur l'élément de menu, vous pouvez vous assurer qu'il reste visible lorsqu'un élément de menu est sélectionné:

.menu:focus-within {
  display: block;
  opacity: 1;
  visibility: visible;
}

Illustration montrant la différence de comportement entre &quot;focus&quot; et &quot;focus-within&quot;.

Essayez de faire défiler les éléments pouvant recevoir la sélection dans la démo ci-dessous. Vous remarquerez que les menus restent visibles lorsque vous sélectionnez les éléments de menu:

Requêtes multimédias niveau 5

Les nouvelles requêtes média nous offrent des moyens efficaces d'ajuster l'expérience utilisateur de nos applications en fonction des préférences de l'appareil. En fait, le navigateur sert de proxy pour les préférences système auxquelles nous pouvons répondre dans notre CSS à l'aide du groupe de requêtes média prefers-*:

Schéma illustrant les requêtes multimédias qui interprètent les préférences utilisateur au niveau du système.

Voici les nouvelles requêtes qui devraient particulièrement intéresser les développeurs:

Ces requêtes sont un énorme avantage pour l'accessibilité. Auparavant, nous n'avions aucun moyen de savoir, par exemple, qu'un utilisateur avait défini son système d'exploitation sur le mode contraste élevé. Si vous souhaitiez proposer un mode à contraste élevé pour une application Web qui restait fidèle à votre marque, vous deviez demander aux utilisateurs de le choisir dans l'interface utilisateur de votre application. Vous pouvez désormais détecter le paramètre de contraste élevé à partir de l'OS à l'aide de prefers-contrast.

L'une des implications intéressantes de ces requêtes multimédias est que nous pouvons concevoir plusieurs combinaisons de préférences utilisateur au niveau du système pour répondre à la grande variété de préférences et de besoins d'accessibilité des utilisateurs. Si un utilisateur souhaite utiliser le mode sombre à contraste élevé dans des environnements faiblement éclairés, vous pouvez le faire.

Il est important pour Adam que l'option "préfère une réduction du mouvement" ne soit pas implémentée comme "pas de mouvement". L'utilisateur indique qu'il préfère moins de mouvement, et non qu'il ne veut pas d'animation. Il affirme que les mouvements réduits ne signifient pas qu'il n'y a pas de mouvement. Voici un exemple qui utilise une animation de fondu enchaîné lorsque l'utilisateur préfère un mouvement réduit:

Propriétés logiques

Les propriétés logiques résolvent un problème qui a gagné en visibilité à mesure que de plus en plus de développeurs s'attaquent à l'internationalisation. De nombreuses propriétés de mise en page, comme margin et padding, supposent une langue qui se lit de haut en bas et de gauche à droite.

Schéma illustrant les propriétés de mise en page CSS traditionnelles.

Lorsque les développeurs concevaient des pages dans plusieurs langues avec différents modes d'écriture, ils devaient ajuster toutes ces propriétés individuellement sur plusieurs éléments, ce qui devenait rapidement un cauchemar en termes de maintenance.

Les propriétés logiques vous permettent de préserver l'intégrité de la mise en page entre les traductions et les modes d'écriture. Elles s'actualisent de manière dynamique en fonction de l'ordre sémantique du contenu plutôt que de son organisation spatiale. Avec les propriétés logiques, chaque élément possède deux dimensions:

  • La dimension bloc est perpendiculaire au flux de texte dans une ligne. (En anglais, block-size correspond à height.)
  • La dimension en ligne est parallèle au flux de texte sur une ligne. (En anglais, inline-size est identique à width.)

Ces noms de dimension s'appliquent à toutes les propriétés de mise en page logique. Par exemple, en anglais, block-start est identique à top, et inline-end est identique à right.

Schéma illustrant les nouvelles propriétés de mise en page logique CSS.

Avec des propriétés logiques, vous pouvez mettre à jour automatiquement votre mise en page pour d'autres langues en modifiant simplement les propriétés writing-mode et direction de votre page au lieu de mettre à jour des dizaines de propriétés de mise en page pour des éléments individuels.

Vous pouvez observer le fonctionnement des propriétés logiques dans la démonstration ci-dessous en définissant la propriété writing-mode de l'élément <body> sur des valeurs différentes:

position: sticky

Un élément avec position: sticky reste dans le flux de bloc jusqu'à ce qu'il commence à sortir de l'écran, puis il arrête le défilement avec le reste de la page et reste à la position spécifiée par la valeur top de l'élément. L'espace alloué à cet élément reste dans le flux, et l'élément y revient lorsque l'utilisateur fait défiler l'écran vers le haut.

Le positionnement persistant vous permet de créer de nombreux effets utiles qui nécessitaient auparavant JavaScript. Pour vous montrer quelques-unes des possibilités, nous avons créé plusieurs démonstrations. Chaque démonstration utilise essentiellement le même CSS et n'ajuste que légèrement la balise HTML pour créer chaque effet.

Pile persistante

Dans cette démonstration, tous les éléments persistants partagent le même conteneur. Cela signifie que chaque élément persistant glisse sur le précédent lorsque l'utilisateur fait défiler la page vers le bas. Les éléments persistants partagent la même position.

Diapositive persistante

Ici, les éléments persistants sont cousins. (c'est-à-dire que leurs parents sont des frères et sœurs). Lorsqu'un élément persistant atteint la limite inférieure de son conteneur, il se déplace vers le haut avec le conteneur, ce qui donne l'impression que les éléments persistants inférieurs poussent les éléments supérieurs vers le haut. En d'autres termes, ils semblent se disputer la position bloquée.

Desperado collant

Comme pour la diapositive persistante, les éléments persistants de cette démonstration sont des cousins. Cependant, ils ont été placés dans des conteneurs avec une mise en page en grille à deux colonnes.

backdrop-filter

La propriété backdrop-filter vous permet d'appliquer des effets graphiques à la zone derrière un élément plutôt qu'à l'élément lui-même. De nombreux effets sympas qui n'étaient auparavant réalisables qu'à l'aide de hacks CSS et JavaScript complexes peuvent désormais être obtenus avec une seule ligne de code CSS.

Par exemple, cette démonstration utilise backdrop-filter pour obtenir un floutage de type OS:

Nous avons déjà publié un excellent article sur backdrop-filter. Pour en savoir plus, consultez-le.

:is()

Bien que la pseudo-classe :is() date en réalité de plus de 10 ans, elle n'est pas aussi largement utilisée que nous le pensons. Il prend une liste de sélecteurs séparés par des virgules comme argument et correspond à tous les sélecteurs de cette liste. Cette flexibilité est incroyablement pratique et peut réduire considérablement la quantité de CSS que vous proposez.

Voici un exemple simple :

button.focus,
button:focus {
  
}

article > h1,
article > h2,
article > h3,
article > h4,
article > h5,
article > h6 {
  
}

/* selects the same elements as the code above */
button:is(.focus, :focus) {
  
}

article > :is(h1,h2,h3,h4,h5,h6) {
  
}

gap

La disposition en grille CSS utilise gap (anciennement grid-gap) depuis un certain temps. En spécifiant l'espacement interne d'un élément contenant plutôt que l'espacement autour des éléments enfants, gap résout de nombreux problèmes de mise en page courants. Par exemple, avec l'espacement, vous n'avez pas à vous soucier des marges des éléments enfants qui créent des espaces vides indésirables autour des bords d'un élément contenant:

Illustration montrant comment la propriété &quot;gap&quot; évite les espaces indésirables autour des bords d&#39;un élément de conteneur.

Bonne nouvelle: gap arrive sur Flexbox et offre les mêmes avantages d'espacement que la grille:

  • Il n'y a qu'une seule déclaration d'espacement au lieu de plusieurs.
  • Il n'est pas nécessaire d'établir des conventions pour votre projet concernant les éléments enfants qui doivent posséder l'espacement. C'est l'élément contenant qui possède l'espacement.
  • Le code est plus facile à comprendre que les anciennes stratégies, comme la hibou lobotomisé.

La vidéo suivante présente les avantages de l'utilisation d'une seule propriété gap pour deux éléments, l'un avec une mise en page en grille et l'autre avec une mise en page flexible:

Pour le moment, seul Firefox est compatible avec gap dans les mises en page flex. Essayez cette démonstration pour voir comment cela fonctionne:

CSS Houdini

Houdini est un ensemble d'API de bas niveau pour le moteur de rendu du navigateur. Il vous permet d'indiquer au navigateur comment interpréter le CSS personnalisé. En d'autres termes, il vous donne accès au modèle d'objet CSS, ce qui vous permet d'extend le CSS via JavaScript. Cela présente plusieurs avantages :

  • Il vous permet de créer des fonctionnalités CSS personnalisées beaucoup plus facilement.
  • Il est plus facile de séparer les problèmes de rendu de la logique de l'application.
  • Il est plus performant que le polyfillage CSS que nous effectuons actuellement avec JavaScript, car le navigateur n'a plus besoin d'analyser les scripts ni d'effectuer un deuxième cycle de rendu. Le code Houdini est analysé lors du premier cycle de rendu.

Illustration montrant le fonctionnement de Houdini par rapport aux polyfills JavaScript traditionnels.

Houdini est un nom générique pour plusieurs API. Pour en savoir plus à leur sujet et leur état actuel, accédez à la page Is Houdini Ready Yet? (Est-ce que Houdini est prêt pour l'instant ?) Lors de notre discussion, nous avons abordé l'API Properties and Values, l'API Paint et le Worklet d'animation, car ce sont actuellement les plus compatibles. Nous pourrions facilement consacrer un article complet à chacune de ces API intéressantes, mais pour l'instant, regardez notre conférence pour obtenir un aperçu et quelques démonstrations intéressantes qui vous donneront une idée de ce que vous pouvez faire avec les API.

Dépassement

Nous voulions aborder d'autres sujets, mais nous n'avons pas eu le temps de les traiter en profondeur. Nous les avons donc abordés en quelques mots.⚡ Si vous ne connaissez pas encore certaines de ces fonctionnalités, n'oubliez pas de regarder la dernière partie de la discussion.

  • size: propriété qui vous permet de définir la hauteur et la largeur en même temps
  • aspect-ratio: propriété qui définit un format pour les éléments qui n'en ont pas intrinsèquement.
  • min(), max() et clamp(): fonctions qui vous permettent de définir des contraintes numériques sur n'importe quelle propriété CSS, et pas seulement sur la largeur et la hauteur
  • list-style-type : propriété existante, mais qui acceptera bientôt une plus grande variété de valeurs, y compris les emoji et les SVG
  • display: outer inner: la propriété display acceptera bientôt deux paramètres, ce qui vous permettra de spécifier explicitement ses mises en page externe et interne plutôt que d'utiliser des mots clés composés tels que inline-flex.
  • Régions CSS: elles vous permettent de remplir une zone non rectangulaire spécifiée qui peut entrer et sortir du contenu.
  • Modules CSS: JavaScript peut demander un module CSS et récupérer un objet enrichi sur lequel il est facile d'effectuer des opérations.