La Cascade

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

CSS Flexbox et la dimension des boîtes

par Rachel Andrew, 10 décembre 2018, css, flexbox, article original paru le 17 septembre 2018 dans Smashing Magazine

Nous allons explorer le dimensionnement en Flexbox, qui est souvent un casse-tête : comment Flexbox décide-t-il de la taille de nos items ?


 NdT : Les articles précédents ont été traduits dans la Cascade :

Affichage initial des items flex

Si j’ai un ensemble d’items ayant des contenus de longueur variable et que je règle leur parent sur display: flex, ils s’afficheront sous forme de ligne et s’aligneront au début de cet axe. Dans l'exemple ci-dessous, mes trois items ont un contenu réduit et ils peuvent afficher ces contenus sous forme de ligne ininterrompue. Il y a un espace à la fin du conteneur flex que les items n'occupent pas car la valeur initiale de flex-grow est 0, c'est à dire pas d'expansion.

Les items flex ont suffisamment d'espace pour être alignés sur une seule ligne

Si j'ajoute du texte à ces éléments, ils finissent par remplir le conteneur et des retours à la ligne apparaissent. Les boîtes se voient attribuer un espace correspondant à la longueur de texte qu'elles contiennent — un item avec beaucoup de texte a plus d'espace. Du coup, on ne se retrouve pas avec une colonne maigrichonne contenant beaucoup de texte lorsque l’item suivant ne contient qu’un seul mot.

L'espace est réparti de façon à donner plus de place à un item de contenu plus long

Ce comportement vous paraîtra sans doute familier si vous avez déjà utilisé Flexbox, et peut-être vous êtes-vous déjà demandé comment le navigateur effectuait ces redimensionnements, d'autant que si vous comparez les navigateurs modernes, vous pouvez constater qu'ils font tous la même chose. La raison en est que des détails comme celui-ci sont définis dans la spécification même, afin de s'assurer que quel que soit le navigateur on sache toujours comment fonctionne ce calcul. Nous pouvons utiliser la spécification pour trouver cette information par nous-mêmes.

Spécification de dimensionnement CSS intrinsèque et extrinsèque

Lorsqu'on examine le dimensionnement dans la spécification Flexbox, on découvre assez vite qu'une grande partie des informations dont on a besoin se trouve dans une autre spécification — CSS Intrinsic et Extrinsic Sizing. En effet, les concepts de dimensionnement que nous utilisons ne sont pas propres à Flexbox, de la même manière que les propriétés d’alignement ne sont pas propres à Flexbox, comme nous l'avons vu dans l'article précédent. Cependant, pour savoir comment ces dimensionnement sont utilisées dans Flexbox, il faut revenir à la spécification Flexbox. Pour vous éviter d'avoir à faire des allers-retours dans les specs, je vais donc vous donner quelques définitions-clés, que je vais utiliser dans la suite de l’article.

Taille préférée

La taille préférée d'une boîte est la taille définie par une width ou une height, ou par les alias logiques inline-size et block-size pour ces propriétés. Lorsque vous utilisez :

.box {
    width: 500px;
}

ou l'alias logique inline-size :

.box {
    inline-size: 500px;
}

...vous déclarez que vous souhaitez que votre boîte ait une largeur de 500 pixels ou 500 pixels dans la direction inline.

min-content size

La taille minimale du contenu, min-content, est la plus petite taille possible pour une boîte sans créer d'overflow. Si votre boîte contient du texte, toutes les opportunités possibles de retour à la ligne (soft) seront utilisées.

max-content size

La taille maximale du contenu, max-content, est la plus grande taille que la boîte puisse prendre afin de contenir le contenu. Si la boîte contient du texte sans retour à la ligne, elle apparaîtra sous la forme d'une longue chaîne de caractères ininterrompue.

Taille principale d'un item flex

La taille principale d'un élément flexible est la taille qu'il a dans la dimension principale (main). Si vous travaillez dans une rangée — en français — alors la taille principale est sa largeur. Dans une colonne en français, la taille principale est sa hauteur.

Les items ont également une taille principale minimale et maximale définie par leur min-width ou leur min-height dans la dimension principale.

Comprendre la taille d'un élément flexible

Maintenant que certains termes sont définis, nous pouvons examiner la façon dont nos éléments flex sont dimensionnés. La valeur initiale des propriétés flex est la suivante:

  • flex-grow: 0
  • flex-shrink: 1
  • flex-basis: auto

Le calcul des dimensions part de flex-basis. Si nous donnons à flex-basis la valeur 0, et à flex-grow la valeur 1, alors nos boîtes n'ont pas de largeur initiale et par conséquent l'espace à l'intérieur du conteneur flex est partagé de manière égale.

Si par contre flex-basis a pour valeur auto et flex-grow: 1, alors l'espace disponible est distribué en prenant en compte la taille du contenu.

Lorsqu'il n'y a pas d'espace disponible, par exemple quand notre contenu ne tient pas sur une ligne unique, alors il n'y a pas d'espace à distribuer.

Il est donc important de bien comprendre auto si nous voulons savoir comment Flexbox détermine la taille des boîtes. La valeur d'auto sera notre point de départ.

Définir auto

Lorsque auto est la valeur d'une propriété CSS, il a une signification spécifique à ce contexte. Le CSS Working Group a passé beaucoup de temps à clarifier la signification de auto selon les contextes, comme l'explique cette présentation.

Nous pouvons trouver le sens de auto utilisé en tant que flex-basis dans la spécification. Les termes définis tout à l'heure devraient nous permettre d'analyser cette phrase:

Lorsque spécifié sur un item flex, le mot-clé auto va chercher la valeur de la propriété de taille principale pour l'utiliser comme flex-basis. Si cette valeur est elle-même auto, alors la valeur utilisée est content.

Autrement dit, si notre flex-basis est auto, Flexbox examine la propriété de taille principale définie. Par exemple, nous aurions une taille principale si nous avions donné une largeur à l’un au moins de nos articles flexibles. Dans l'exemple ci-dessous, les éléments ont tous une largeur de 110 px, cette taille est donc utilisée comme taille principale, car la valeur initiale de flex-basis est auto.

Cependant, notre exemple a des items sans width ce qui signifie que leur dimension principale est auto, et nous passons donc à la suite de la phrase "si cette valeur est elle-même auto, alors la valeur utilisée est content".

Nous devons maintenant regarder ce que dit la spec à propos du mot-clé content. Voici une autre valeur que nous pouvons utiliser pour notre flex-basis(dans les navigateurs compatibles), par exemple :

.item {
    flex: 1 1 content;
}

La spécification définit contentainsi :

Il indique un dimensionnement automatique basé sur le contenu du flex item. Typiquement, il est équivalent à la dimension max-content mais avec des ajustements permettant de traiter les ratios d'aspect, les contraintes de dimensionnement intrinsèque et les flux orthogonaux"

Dans notre exemple, avec des items flex contenant du texte, nous pouvons ignorer certains ajustements complexes et considérer content comme étant la dimension max-content.

Ceci explique pourquoi, lorsque nous avons peu de texte dans chaque item, nous n'avons pas de retour à la ligne. Les items flex sont dimensionnés automatiquement, Flexbox cherche leur dimension max-content, les items s'ajustent à cette taille dans leur conteneur, et le tour est joué.

L'histoire ne s'arrête pas là, lorsque nous ajoutons du contenu les boîtes ne restent pas à la dimension max-content. Sinon, elles sortiraient du conteneur avec un overflow. Une fois qu'il a rempli le container, le contenu retourne à la ligne et les items prennent des tailles différentes en fonction de leur contenu.

Résolution des tailles flexibles

À partir d'ici, la spécification devient raisonnablement complexe. Voici les prochaines étapes.

D'abord, ajouter la taille principale de tous les items et voir si elle est supérieure ou inférieure à l'espace disponible dans le container. Si la taille du conteneur est supérieure, nous passons à flex-grow puisque nous avons de l'espace pour nous étendre.

Dans ce premier cas, nos items ont de la place disponible pour s'étendre

Par contre, si la taille du conteneur est inférieure au total, nous nous tournons vers flex-shrink car nous devons nous serrer.

Dans le second cas, nos items sont trop grands et doivent être réduits pour s'adapter à la taille du conteneur

Il est possible de choisir une taille pour certains items, qui deviennent ainsi "inflexibles". Si nous utilisons flex-grow, cela inclurait tous les éléments qui ont flex-grow: 0. C'est le scénario que nous avons lorsque nos articles flexibles ont de la place dans le conteneur. La valeur initiale de flex-grow est 0, nos items deviennent donc aussi grands que leur largeur maximale et ne grandissent plus à partir de leur taille principale.

Si nous utilisons flex-shrink, cela inclura tous les éléments avec flex-shrink: 0. Nous pouvons voir ce qui se passe dans cette étape si nous donnons à notre ensemble d’items flex un facteur de flex-shrink de 0. Les éléments sont figés dans leur état max-content et ainsi ne peuvent pas s'organiser eux-mêmes de manière flexible pour tenir dans le conteneur.

Dans notre cas, avec leur valeurs initiales d'items flex, nos items peuvent se réduire. Nous continuons donc, et l'algorithme entre dans une boucle lui permettant de calculer l'espace à attribuer ou à réduire. Nous utilisons flex-shrinkpuisque la taille totale de nos items est supérieure à la taille du conteneur — nous devons donc réduire l'espace.

Le facteur flex-shrink est multiplié par la taille de base interne, ici c'est la taille max-content. Cela donne une valeur avec laquelle réduire l'espace. Si les éléments retirent de l'espace uniquement en fonction du facteur de flex-shrink, les éléments de petite taille risquent en principe de disparaître car tout leur espace a été supprimé, tandis que l'élément le plus volumineux peut encore être réduit.

Dans cette boucle, il existe une étape supplémentaire pour rechercher les éléments qui deviendraient plus petits ou plus grands que leur taille principale cible. Dans ce cas, l'élément cesse de croître ou de se réduire. Encore une fois, ceci permet d'éviter que certains objets ne deviennent minuscules ou énormes par rapport au reste des objets.

Tout cela a été simplifié du point de vue des spécifications, car je n'ai pas examiné certains des scénarios les plus limites. Vous pouvez vous en passer si vous souhaitez laisser Flexbox agir à votre place ou si vous ne recherchez pas la perfection au pixel près. Garder à l'esprit les deux mécanismes suivants vous aidera dans la plupart des cas :

  • Si vous êtes en mode grow depuis auto, alors flex-basis sera traitée comme n'importe quelle largeur ou hauteur de l'item ou comme son max-content. L'espace sera ensuite attribué en fonction du facteur flex-grow en utilisant cette dimension comme point de départ.
  • Si vous êtes en mode shrink depuis auto, alors flex-basis sera traitée comme n'importe quelle largeur ou hauteur de l'item ou comme son max-content. L'espace sera alors rétréci ou supprimé en fonction de la taille de flex-basis multipliée par le facteur flex-shrink et donc proportionnellement à la taille max-content des items.

Contrôler grow et shrink

J'ai passé la plus grande partie de cet article à décrire ce que fait Flexbox lorsqu'il se débrouille tout seul. Vous pouvez bien sûr exercer un meilleur contrôle sur vos items flexibles en utilisant les propriétés flex. J'espère qu'elles vous paraîtront maintenant plus prévisibles grâce à une bonne compréhension de ce qui se passe en coulisses.

Si vous définissez votre propre flex-basis ou si vous attribuez à l'élément lui-même une taille ensuite utilisée comme flex-basis, vous reprenez le contrôle de l'algorithme, en indiquant à Flexbox que vous souhaitez augmenter ou réduire cette taille. Vous pouvez désactiver complètement la croissance ou la réduction en réglant flex-grow ou flex-shrink sur 0.

Un dernier point sur cette question du contrôle : lorsque vous sentez monter le désir de mieux contrôler les éléments flexibles, prenez un moment pour vérifier que vous utilisez la bonne méthode de layout : si vous essayez d’aligner des éléments flexibles en deux dimensions, vous feriez sans doute mieux de choisir Grid Layout.

Débogage des problèmes liés à la taille

Si vos items flex atteignent une dimension inattendue, c'est généralement dû au fait que votre flex-basis est auto et que quelque chose donne à votre item une largeur, qui est ensuite utilisée comme flex-basis. L'inspection de l'élément dans DevTools peut aider à identifier la provenance de la dimension. Vous pouvez également essayer de définir une flex-basis de 0, ce qui obligera Flexbox à traiter l'élément comme s'il avait une largeur nulle. Même si vous n'obtenez pas un résultat souhaité, cela vous aidera à identifier la valeur de flex-basis utilisée, laquelle est peut-être la cause de vos problèmes de dimensionnement.

Espaces ou gouttières flex

Une fonctionnalité très demandée de Flexbox serait la possibilité de spécifier des espaces ou des gouttières entre les éléments flex comme on peut le faire avec CSS Grid Layout. Cette fonctionnalité est spécifiée pour Flexbox dans le cadre de Box Alignment et la première mise en œuvre du navigateur est en route. Pour Firefox ça devrait sortir avec Firefox 63. L'exemple suivant peut être visualisé dans Firefox Nightly.

L'image vue dans Firefox 63

Comme pour Grid Layout, la taille de la gouttière est prise en compte avant que l'espace ne soit distribué aux items flex.

On récapitule

Dans cet article, j’ai essayé d’expliquer en détail comment Flexbox définit la taille des éléments flexibles. Cela peut sembler un peu théorique, cependant, prendre un peu de temps pour comprendre le fonctionnement de cette solution peut vous faire gagner un temps considérable lors de l’utilisation de Flexbox dans vos layouts. Je trouve très utile de revenir au fait que, par défaut, Flexbox essaie de vous donner la présentation la plus judicieuse d’un ensemble d'items de tailles variables. Si un élément a plus de contenu, il dispose de plus d'espace. Si votre design et vous n'êtes pas d'accord avec ce que Flexbox estime préférable, vous pouvez reprendre le contrôle en définissant votre propre flex-basis.

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 17 septembre 2018 dans Smashing Magazine
Traduit avec l'aimable autorisation de Smashing Magazine et de Rachel Andrew.
Copyright Smashing Magazine © 2018