La Cascade

Un peu de tout sur CSS, HTML, SVG et JS,traduit du web anglophone
Rechercher

Approfondir la propriété display : la génération de boîtes

par Rachel Andrew, 6 mars 2020, css, flexbox, cssgrid, article original paru le 1er mai 2019 dans Smashing Magazine

Rachel Andrew examine les valeurs qui contrôlent la génération des boîtes, au cas où vous ne voudriez pas générer de boîte du tout.


Cet article est le second d'une courte série d'articles sur la propriété display en CSS, le premier parle des deux valeurs de display. La spécification de display est très importante à comprendre car elle sous-tend toutes les différentes méthodes de mise en page dont nous disposons.

Même si de nombreuses valeurs de display ont leur propre spécification, beaucoup de termes et idées sont détaillés dans display. Par conséquent, la compréhension de cette spécification vous aide à comprendre les spécifications détaillant essentiellement les valeurs de display. Dans cet article, je vais examiner les valeurs de génération de boîtes de display — none et contents.

Tout est une boîte

En CSS, tout génère des boîtes. Fondamentalement, une page Web est un ensemble de boîtes, block et inline. On le voit très bien si on ouvre DevTools dans notre navigateur préféré et qu'on commence à sélectionner des éléments sur la page. On voit les boîtes qui composent la page, et comment leurs marges, paddings et bordures sont appliqués.

An image of a simple layout with an unordered list highlighted in browser DevTools
J'ai mis en évidence l'élément 'ul' à l'aide de Firefox DevTools afin de pouvoir inspecter les différentes parties de la boîte. (Grand aperçu)

Contrôler la génération de boîtes

Les valeurs none et contents de display déterminent si les boîtes doivent apparaître ou pas. Si vous avez des éléments dans votre balisage dont vous ne voulez pas qu'ils génèrent une boîte en CSS, vous devez d'une manière ou d'une autre supprimer la génération de la boîte. Vous pouvez faire deux choses :

  • Empêcher la génération d'une boîte et de tous ses enfants.
  • Empêcher la génération d'une boîte mais afficher quand même les enfants.

Nous allons examiner chacun de ces scénarios à tour de rôle.

display: none

La valeur none de display est la façon dont nous empêchons la génération d'une boîte et de tous les enfants de cette boîte. Elle agit comme si l'élément n'existait pas du tout. Elle est donc utile dans les situations où vous avez l'intention de cacher complètement ce contenu, peut-être parce qu'il sera révélé plus tard après l'activation d'un lien.

Voici un exemple avec un paragraphe, une liste non ordonnée et un autre paragraphe, vous pouvez voir que les éléments s'affichent dans un flux normal. L'ul a un background et une bordure appliqués, ainsi qu'un peu de padding.

voir Smashing Box Generation: example de rachelandrew dans CodePen

Si j'ajoute display: none à l'ul, il disparaît de l'affichage visuel, emportant avec lui ses enfants ainsi que le background et la bordure.

Si vous utilisez display: none, le contenu est caché à tous les utilisateurs du site Web. Y compris les utilisateurs de lecteurs d'écran. Par conséquent, vous ne devez l'utiliser que si votre intention est que la boîte et tout ce qu'elle contient soit complètement caché à tous.

Il existe des situations où vous souhaitez ajouter des informations supplémentaires pour les utilisateurs de technologies d'assistance, comme les lecteurs d'écran, mais les cacher pour les autres utilisateurs ; dans ce cas, vous devez utiliser une technique différente. D'excellentes suggestions sont faites par Scott O 'Hara dans son article "Inclusivement caché".

L'utilisation de display: none est donc assez simple. Utilisez-la dans une situation où vous voulez qu'une boîte et son contenu disparaissent de l'affichage, de l'arbre des boîtes et de l'arbre d'accessibilité (comme si elle n'avait jamais été là).

display: contents

Pour le deuxième scénario, nous devons examiner une valeur beaucoup plus récente de display. La valeur display: contents supprime la boîte à laquelle elle est appliquée de l'arbre des boîtes, de la même manière que display: none, mais laisse les enfants en place. Ça entraîne un comportement bien utile pour ce que nous pouvons faire ensuite dans notre mise en page. Prenons un exemple simple et explorons-le plus avant.

J'utilise le même exemple que précédemment, mais cette fois, j'ai utilisé display: contents sur le ul. Les éléments de la liste sont maintenant visibles, mais ils n'ont pas d'arrière-plan ni de bordures et se comportent comme si l'on avait ajouté des éléments li à la page sans aucun ul.

La raison pour laquelle il peut être utile de supprimer une boîte tout en gardant les enfants tient à la façon dont les autres valeurs d'affichage se comportent. Lorsque nous modifions la valeur de display, nous le faisons sur une boîte et les enfants directs de cette boîte, comme je l'ai décrit dans le dernier article. Si j'ajoute display: flex aux règles CSS d'un élément, cet élément devient une boîte de niveau bloc, et les enfants directs deviennent des éléments flex. Les enfants de ces éléments flex reviennent au flux normal (ils ne font pas partie de la mise en page flex).

Vous pouvez voir ce comportement dans l'exemple suivant. Ici, j'ai un élément conteneur, configuré comme display: flex, il a quatre enfants directs, trois éléments div et un ul. L'ul comporte deux éléments liste. Les enfants directs participent tous à la mise en page flex et s'affichent comme des éléments flex. Les éléments de liste ne sont pas des enfants directs et s'affichent donc comme des éléments de liste à l'intérieur de la boîte de l'ul.

Si nous reprenons cet exemple et ajoutons display: contents à l'ul, la boîte est retirée de l'affichage visuel et les enfants participent maintenant à la mise en page flex. Vous pouvez voir qu'ils ne deviennent pas des enfants directs. Ils ne sont pas sélectionnés par le sélecteur universel d'enfant direct (.wrapper > *) comme le sont les éléments div et ul, et ils conservent l'arrière-plan qui leur a été donné. Tout ce qui s'est passé, c'est que la boîte de l'élément ul qui le contient a été supprimée, tout le reste continue normalement.

Ça a des implications potentiellement très utiles si nous considérons les éléments du HTML qui sont importants pour l'accessibilité et les données sémantiques, mais qui génèrent une boîte supplémentaire pouvant nous empêcher de mettre en page le contenu avec flex ou grid.

Ceci n'est pas un reset CSS

Vous avez peut-être remarqué que l'un des effets secondaires de l'utilisation de display: contents est la suppression de la marge et du padding de l'élément. C'est dû au fait qu'elles sont liées à la boîte, qui fait partie du modèle de boîte CSS. Ça pourrait vous amener à penser que display: contents est un bon moyen de se débarrasser rapidement du padding et de la marge d'un élément.

C'est une utilisation qu'Adrian Roselli a repérée dans la nature ; il s'est suffisamment inquiété pour rédiger un billet détaillé expliquant les problèmes que cela pose — "display : contents is not a CSS reset". Certains des problèmes qu'il soulève sont dus à un malheureux problème d'accessibilité dans les navigateurs actuellement dotés de display: contents, dont nous parlerons plus loin. Cependant, même une fois ces problèmes résolus, supprimer un élément de l'arbre des boîtes juste pour se débarrasser de la marge et du padding est quelque peu... extrême.

Entre autres choses, ça serait problématique pour la maintenance future du site, un futur développeur pourrait se demander pourquoi il ne peut apparemment pas appliquer quoi que ce soit à cette mystérieuse boîte — oubliant le fait qu'elle a été supprimée ! Si vous avez besoin que margin et padding soient à 0, faites une faveur à votre moi futur et réglez-les à 0 de la manière traditionnelle. Réservez l'utilisation de display: contents pour les cas particuliers où vous voulez vraiment supprimer la boîte.

Il convient également de noter la différence entre display: contents et CSS Grid Layout subgrid. Alors que display: contents supprime complètement la boîte, le background et la bordure de l'affichage, faire d'un élément de grille une sous-grille maintiendrait le style de la boîte sur cet élément et transmettrait simplement le dimensionnement de la piste de façon à ce que les éléments imbriqués puissent utiliser la même grille. Pour en savoir plus, consultez mon article "Grille CSS niveau 2 : voici la sous-grille".

Problèmes d'accessibilité et display: contents

Un problème sérieux rend actuellement display: contents inutile pour la chose-même pour laquelle il serait le plus utile. Les cas évidents d'utilisation de display: contents sont ceux où des boîtes supplémentaires sont nécessaires pour ajouter des balises qui rendent votre contenu plus facilement compréhensible par ceux qui utilisent des lecteurs d'écran ou d'autres dispositifs d'assistance.

L'élément ul de notre liste dans le premier CodePen display: contents en est un parfait exemple. Vous pourriez obtenir le même résultat visuel en aplatissant le balisage et en n'utilisant pas de liste du tout. Toutefois, si le contenu est sémantiquement une liste, qu'il est mieux compris et lu par un lecteur d'écran comme une liste, il doit être balisé comme tel.

Si vous souhaitez ensuite que les éléments enfants fassent partie d'une mise en page flex ou grid, comme si la boîte de l'ul n'existait pas, vous devriez pouvoir utiliser display: contents pour faire disparaître magiquement la boîte et la rendre ainsi — tout en laissant la sémantique en place. La spécification indique que cela devrait être le cas,

La propriété display n'a aucun effet sur la sémantique d'un élément : celle-ci est définie par le langage du document et n'est pas affectée par CSS. À l'exception de la valeur none, qui affecte également la sortie sonore/parlée et l'interactivité d'un élément et de ses descendants, la propriété display n'affecte que la mise en page visuelle : son but est de laisser aux concepteurs la liberté de modifier le comportement de mise en page d'un élément sans affecter la sémantique sous-jacente du document.

2. Box Layout Modes: the display property

Comme nous l'avons déjà vu, la valeur none masque l'élément aux lecteurs d'écran, cependant, les autres valeurs de display sont toujours là pour nous permettre de changer la façon dont les choses s'affichent visuellement. Elles ne doivent pas toucher à la sémantique du document.

C'est pourquoi beaucoup d'entre nous ont été surpris de constater que display: contents supprimait en fait l'élément de l'arbre d'accessibilité dans les deux navigateurs (Chrome et Firefox) qui l'avaient mis en œuvre. Cela changeait donc la sémantique du document, de sorte qu'un lecteur d'écran ne savait pas qu'une liste était une liste une fois que l'ul avait été supprimé à l'aide de display: contents. Il s'agit d'un bogue de navigateur — et d'un bogue sérieux.

L'an dernier, Hidde de Vries a évoqué ce problème dans son billet "More Accessible Markup with display:contents" et a utilement soulevé des problèmes auprès des différents navigateurs afin de les sensibiliser et de les amener à travailler sur une correction. Firefox a partiellement corrigé le problème, bien que des problèmes subsistent avec certains éléments tels que le bouton. Le problème fait l'objet d'un travail actif dans Chrome. Il existe également un problème pour WebKit.

Jusqu'à ce que ces problèmes soient résolus et que les versions des navigateurs qui présentaient le problème ne soient plus utilisées, vous devez être très prudent lorsque vous utilisez display: contents sur tout ce qui véhicule des informations sémantiques et doit être exposé à la technologie d'assistance. Comme le déclare Adrian Roselli,

Pour l'instant, n'utilisez display : contents que si vous avez l'intention de tester avec une technologie d'assistance et que vous pouvez confirmer que les résultats fonctionnent pour les utilisateurs.
— Adrian Roselli

Il existe des endroits où vous pouvez utiliser display: contents en toute sécurité sans cette préoccupation. Par exemple, si vous devez ajouter des balises supplémentaires pour créer des solutions de repli pour votre grille de mises en page flexibles dans les anciens navigateurs. Les navigateurs qui prennent en charge display: contents prennent également en charge grid et flexbox. Vous pouvez donc utiliser display: contents sans ajouter d'éléments div redondants. Dans l'exemple ci-dessous, j'ai créé une grille basée sur float, avec des wrappers de rangées.
J'utilise ensuite display: contents pour supprimer les wrappers de rangées et permettre à tous les éléments de devenir des grid items et donc de faire partie de la mise en page grid. Cela pourrait vous donner un outil supplémentaire lors de la création de solutions de repli pour des mises en page avancées. En effet, si vous devez ajouter des balises supplémentaires, vous pouvez les supprimer avec display: contents lors de la création de votre grille ou de votre mise en page flexible. Je pense que cette utilisation ne devrait pas poser de problème — mais si quelqu'un dispose de meilleures informations que moi en matière d'accessibilité et peut signaler un problème, qu'il le fasse dans les commentaires.

Pour conclure

Cet article s'est penché sur les valeurs de génération de boîtes de la propriété display. J'espère que vous comprenez mieux maintenant le comportement différent de display: none — qui supprime complètement une boîte et tous ses enfants, et de display: contents qui supprime uniquement la boîte elle-même. Vous devriez également comprendre les problèmes potentiels liés à l'utilisation de ces méthodes en matière d'accessibilité.

Autres ressources externes

Articles de Rachel Andrew traduits dans La Cascade

Voir la page de Rachel Andrew et la liste de ses articles dans La Cascade.
Article original paru le 1er mai 2019 dans Smashing Magazine
Traduit avec l'aimable autorisation de Smashing Magazine et de Rachel Andrew.
Copyright Smashing Magazine © 2019