CR React Paris 2025 : "I can't believe it's not JavaScript!"

Les 20 et 21 mars 2025 s’est tenue la conférence React Paris, à laquelle nous avons eu la chance de pouvoir assister. Plusieurs talks nous ont marqués et nous avons choisi de vous les partager à travers différents articles.

Dans celui-ci, nous parlerons de la conférence “I can’t believe it’s not JavaScript”, de Jemima Abu, développeuse front-end. Elle nous montre via quatre exemples comment développer des fonctionnalités poussées à l’aide de HTML et de CSS, sans recourir à l’ancienne solution en JavaScript.

Le code présenté ici a l’avantage de prendre en compte l’accessibilité et d’être compatible pour la majorité avec tous les navigateurs web !

Enfin, un tableau récapitulatif est disponible à la fin de cet article !

Theme Switcher

Le “theme switcher” consiste en un bouton “switch”, permettant de basculer entre le mode clair et le mode sombre du site. Il s’agit sous le capot d’une case à cocher, qui active le deuxième, le premier l’étant par défaut.

'empty'

Pour chacun, des couleurs spécifiques vont s’appliquer au texte, aux boutons et autres éléments du site, de manière uniforme. On pourra ainsi avoir du texte blanc sur un fond noir en mode clair, et inversement en mode sombre.

Avant en JavaScript

La méthode consistait à détecter lorsque la case à cocher est activée, pour ajouter une classe CSS “dark” à la balise <body>, soit la balise positionnée la plus haute dans le DOM.

Ainsi, si l’on définit des variables CSS pour le texte ou la couleur de fond par défaut, celles-ci seront facilement surchargées en passant à l’autre thème.

Voici le code CSS :

body {
  background-color: var(--bg-color);
  color: var(--text-color);
 
  --bg-color: #fff;
  --text-color: #000;
 }

body.dark {
  --bg-color: #333;
  --text-color: #fff;
}

Voir le Theme Switcher version JavaScript sur CodePen

Désormais en CSS

On utilise ici la pseudo-classe CSS “:has”, qui applique des styles à une balise si celle-ci contient un élément spécifique. Ici, on va détecter si la balise <body> contient notre case à cocher à l’état activée, pour appliquer les couleurs du mode “sombre”.

body:has(#theme-switcher:checked) {
  --bg-color: #333;
  --text-color: #fff;
}

Cette méthode fonctionne sur tous les navigateurs, cependant elle ne permet pas de garder en mémoire (localStorage) le choix de l’utilisateur.

Voir le Theme Switcher version CSS sur CodePen

Accordéons

Un accordéon sert à afficher une grande quantité d’informations dans un espace réduit, grâce à un système de “plier / replier”. Pour cela, il se constitue de deux éléments : un bouton pour déplier ou replier un bloc de contenu, et celui-ci.

Dans les exemples suivants, nous retrouvons plusieurs accordéons ensemble, chacun correspondant à une thématique d’une foire à questions.

Avant en JavaScript

Ici, lorsqu’on ouvre un accordéon dans un groupe, celui qui est déjà ouvert se referme automatiquement, afin de gagner de la place sur l’écran.

'empty'

De même, des éléments visuels indiquent l'ouverture ou non d’un accordéon. Pour les rendre accessibles aux personnes non voyantes et malvoyantes, qui ont recours au lecteur d’écran, des attributs ARIA sont ajoutés au code HTML. Ainsi, l’attribut “aria-expanded”, présent sur les boutons, permet de savoir si le contenu lié à ces derniers est ouvert ou fermé.

Voici le code HTML :

<div class="accordion-item">
    	<button class="accordion-trigger" id="accordion-trigger-1" aria-expanded="false" aria-controls="accordion-content-1">
      		<span class="accordion-title">Comment marche un accordéon ?</span>
      		<span class="accordion-icon">+</span>
    	</button>
    	<div class="accordion-content" id="accordion-content-1">
      		<p>Il affiche le contenu replié en fonction de l’action de l’utilisateur.</p>
    	</div>
  </div>

Voir les accordéons version JavaScript sur CodePen

Désormais en HTML

La version HTML repose sur les élément suivants :

  • La balise <details>, pour créer nativement un accordéon ;
  • La balise <summary>, pour renseigner le texte du bouton contrôlant son ouverture ;
  • Enfin, l’attribut HTML “name”, présent sur toutes les balises <details>, permet de fermer automatiquement un accordéon lorsqu’un autre est ouvert.

Cette version a les avantages suivants :

  • Elle est nativement accessible et ne nécessite pas l’ajout d’attributs ARIA ;
  • Elle ne requiert pas de développement JavaScript pour afficher le contenu au clic sur le bouton correspondant et gérer la fermeture automatique ;
  • Des styles spécifiques en CSS peuvent être appliqués à la balise <details> à l’état ouvert, grâce au pseudo-sélecteur “open”.

Voici le code HTML :

<!-- Premier accordéon –>
<details class="accordion-item" name="accordion">
    	<summary class="accordion-trigger">
      		<span class="accordion-title">Titre 1</span>
      		<span class="accordion-icon" aria-hidden="true">+</span>
    	</summary>
    	<div class="accordion-content">
      		<!-- Contenu 1 –>
    	</div>
</details>

<!-- Deuxième accordéon –>
<details class="accordion-item" name="accordion">
    	<summary class="accordion-trigger">
      		<span class="accordion-title">Titre 2</span>
      		<span class="accordion-icon" aria-hidden="true">+</span>
    	</summary>
    	<div class="accordion-content">
      		<!-- Contenu 2 –>
    	</div>
</details>

Et le code CSS :

.accordion-item[open] .accordion-icon {
  transform: rotate(45deg);
}

Voir les accordéons natifs en HTML sur CodePen

Et du CSS en plus pour les animations

'empty'

Comment animer l’accordéon, lorsqu’il passe de l’état “plié”, soit avec une hauteur à 0 pixels, à l’état “déplié”, avec une certaine hauteur ?

Historiquement, que l’animation soit faite en JavaScript ou en CSS, il faut préciser la hauteur finale du contenu à l’état déplié, pour qu’elle fonctionne. Or, la hauteur changeant selon la quantité d’éléments à afficher, elle doit souvent être calculée dynamiquement en JavaScript.

Jemina nous fait découvrir deux propriétés CSS pour pallier ce problème :

  1. La fonction “calc-size(auto)”, qui calcule automatiquement la hauteur d’un élément. Celle-ci est encore au stade expérimental et n’est compatible pour le moment qu’avec Chrome et Edge.
  2. La mixin “@starting-style”, qui définit des styles par défaut pour les animations. Elle est utilisable sur tous les navigateurs.

Voici le code CSS :

.accordion-content {
  height: 0;
  overflow: hidden;
  transition: height 0.5s;
}

.accordion-item[open] .accordion-content {
  height: auto;
  height: calc-size(auto);
 
  @starting-style {
	height: 0;
  }
}

Voir les accordéons animés en CSS sur CodePen

Modale

Une “modale”, aussi appelée “boîte de dialogue”, est une fenêtre qui apparaît au-dessus de la page Web, devant le seul contenu avec lequel il est possible d’interagir.

Avant en JavaScript

'empty'

On a ici une modale classique, contenant du texte et un bouton de fermeture, dont l’ouverture est déclenchée par un autre bouton.

Au niveau du code HTML, on retrouve une balise <section> avec les attributs suivants pour l’accessibilité :

  • role="dialog", surchargeant la sémantique et indiquant au lecteur d’écran qu’il s’agit d’une boîte de dialogue ;
  • aria-labelledby="modal-title", faisant référence à son titre pour lui donner un nom.

Note : on retrouve dans le code de Jemina un attribut aria-hidden=”true” en plus sur la balise. Celui-ci est inutile ici car un “display : none” est appliqué en CSS, le rendant invisible aux lecteurs d’écran.

Encore une fois, cette version nécessite l’ajout d’attributs ARIA au code HTML pour être accessible. De même, les comportements claviers attendus, comme fermer la modale avec la touche Echap, ou, tabuler uniquement à l’intérieur de la modale, doivent être gérés en JavaScript.

Voir la modale en JavaScript sur CodePen

Désormais en HTML et CSS

'empty'

Cette version repose sur trois éléments :

  1. Une boîte de dialogue modale native ;
  2. Un bouton d’ouverture situé sur la page Web ;
  3. Un bouton de fermeture à l’intérieur de la modale.

Pour faire le lien entre les trois, on utilise à l’API "Popover", qui met à disposition pour ce faire des attributs HTML spécifiques.

Sur la balise <div> de la modale :

  • popover : la balise doit s’afficher comme une “pop-up” ;
  • id="modal" : id de la modale qui sera nécessaire pour les boutons de contrôle.

Sur le bouton d’ouverture :

Enfin, sur le bouton de fermeture :

  • popovertarget="modal" : fait référence à l’id de la modale ;
  • popovertargetaction="hide" : ce bouton cache la modale.

Voici le code HTML :

<button class="modal-btn" popovertarget="modal" popovertargetaction="show">Ouvrir la modale</button>

<div popover role="dialog" aria-labelledby="modal-title" class="modal" id="modal">
  <div class="modal-content">
	<button popovertarget="modal" popovertargetaction="hide" class="modal-close">Fermer la modale</button>
	<h2 id="modal-title">Hello, React Miami! </h2>
	<p>Quibusdam nulla velit dolores sed neque facere ut, tenetur fuga itaque?</p>
  </div>
</div>

Ensuite, du côté du CSS, nous avons :

  • Le pseudo-élément “:backdrop”, pour styliser l’arrière-plan de la modale ;
  • La pseudo-classe “:popover-open”, pour styliser la modale à l’état “ouvert” (on anime l’ouverture grâce à la mixin “@starting-style” ici également).

Les deux fonctionnent avec tous les navigateurs.

Voici le code CSS :

.modal:popover-open {
  opacity: 1;
  transform: scale(1);
}

@starting-style {
  .modal:popover-open {
	opacity: 0;
	transform: scale(0);
  }
}

.modal:backdrop {
  width: 100%;
  height: 100%;
  position: absolute;
  background-color: rgba(0, 0, 0, 0.5);
  left: 0;
}

Pour conclure, cette solution fonctionne avec tous les navigateurs et intègre des comportements clavier et souris attendus pour l’accessibilité, à savoir :

  • Fermer la modale en cliquant en dehors ;
  • Fermer la modale via la touche Echap ;
  • Redonner le focus au bouton d’ouverture si la fermeture se fait au clavier.

Il faut néanmoins noter qu’un comportement a été omis : lorsque la modale est ouverte, donner le focus au bouton de fermeture, soit le premier élément interactif dedans.

Note : Il existe également la balise <dialog> pour créer une boîte de dialogue native. A la place des attributs HTML vus plus haut, celle-ci utilise des événements JavaScript pour gérer l’ouverture et la fermeture de la modale. Enfin, elle intègre aussi le pseudo-élément CSS “:backdrop”, ainsi que la pseudo-classe “:open” au lieu de “:popover-oven” vu précédemment.

Voir la modale en HTML et CSS sur CodePen

Animations au scroll

'empty'

Il s’agit ici de déclencher une animation selon le niveau de scroll sur la page. Jusqu’à alors, on avait recourt à des librairies JavaScript dédiées ou du JavaScript natif, qui pouvaient poser des soucis de performance et alourdir le poids des pages.

Aujourd’hui, il est possible de réaliser cela en CSS grâce à l’API “Scroll-driven animations”, compatible avec Chrome et Edge pour le moment.

Celle-ci fournit plusieurs propriétés CSS qui, appliquées à un élément, permettent d’animer celui-ci lorsqu’on le parcourt au scroll.

Voici le code HTML :

<section class="scroll-container">
  <div class="scroll-element fade-in"><!-- Le bloc animé –></div>
  <div class="scroll-caption">
	<p>Cet élément apparaît en fondu.</p>
  </div>
</section>

Et le code CSS :

@keyframes fade-in { /* On crée ici l’animation “fade-in” qui sera appliquée à l’élément */
  0% {
	opacity: 0;
  }
  100% {
	opacity: 1;
  }
}

.fade-in {
	view-timeline-name: --fade-in-timeline; /* Nom de référence pour la “timeline” */
	view-timeline-axis: block; /* Se baser sur le scroll vertical */

	animation-name: fade-in; /* Fait référence à l’animation créée plus haut */
	animation-timeline: --fade-in-timeline; /* Fait référence à la “timeline” définie plus haut */
	animation-range: entry 25% cover 50%; /* L’animation commence lorsqu’on a scrollé 25% de l’élément, et finit lorsqu’on atteint 50% de celui-ci. */
}

Pour en apprendre davantage sur les propriétés CSS existantes et les possibilités offertes par l’API, il existe le site "Scroll-driven Animations” dédié et exhaustif.

Voir l'animation en CSS sur CodePen

Tableau récapitulatif

Composant

Ancienne solution en JavaScript

Solution en HTML

Solution en CSS

Theme Switcher

Bouton “switch” permettant de basculer entre les deux thèmes



Pseudo-classe CSS “:has”, qui détecte si

Accordéon

Bouton ouvrant / fermant une zone de contenu

- Balises <details> et <summary>
- Avec du CSS pour animer l’affichage : fonction “calc-size(auto)”, disponible sur Chrome et Edge à date, et mixin “@starting-style”



Modale

Balise avec un attribut role=dialog, rendue interactive

API “Popover"



Animation au scroll

Librairie JavaScript ou JavaScript natif



API “Scroll-driven animations”, compatible avec Chrome et Edge à date

Conclusion

Via ces différents exemples, Jemima Abu nous prouve ainsi que le HTML et le CSS ont suffisamment progressé aujourd’hui, pour pouvoir intégrer des composants dynamiques sans passer par du JavaScript !

Les deux langages ne cessent d’évoluer au fil du temps, aussi une veille régulière vous évitera de réinventer la roue, avec des développements longs et inutiles sur vos projets !

Enfin, vous pouvez retrouver la conférence sur Youtube, traduite en plusieurs langues !