web-dev-qa-db-fra.com

Pourquoi la largeur et la hauteur d'un élément flexible affectent-elles le rendu d'un élément flexible?

Une image dans un flexbox qui a un max-height le style semble s'afficher différemment selon que ses attributs height et width sont définis.

Celui avec les attributs, définis sur la largeur/hauteur réelle de l'image, est rendu avec son rapport d'aspect préservé, mais ceux sans les attributs respectent la max-height et apparaissent écrasés.

.flex-parent {
  display: flex;
  max-height: 10vh;
}
<div class="flex-parent">
  <img                          src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyed_tree_frog_edit2.jpg/320px-Red_eyed_tree_frog_edit2.jpg">
  <img width="320" height="240" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyed_tree_frog_edit2.jpg/320px-Red_eyed_tree_frog_edit2.jpg">
</div>

Voici comment cela apparaît dans Chrome 58 (et il apparaît de la même manière dans Firefox 54).

Different rendering of img in flexbox. Without width and height attributes, and with

Pourquoi rendent-ils différemment? Quelles sont les règles qui régissent ce comportement?

Ma compréhension (manifestement incorrecte) est que les attributs de hauteur et de largeur remplacent la hauteur et la largeur intrinsèques trouvées lors du chargement de l'image, et si les attributs de hauteur et de largeur sont égaux aux dimensions de l'image, il ne devrait pas y avoir de différence de rendu une fois l'image a chargé.

Le contexte crée une page avec des images réactives, où chaque image

  • peut avoir des dimensions originales uniques
  • ne provoque pas de refusion lorsqu'il est chargé, c'est-à-dire que l'espace correct est réservé lors du rendu initial (d'où l'utilisation d'attributs de hauteur et de largeur)
  • peut tenir tout sur l'écran à la fois (d'où moi jouer avec vh dans le CSS)

L'image de la grenouille provient de https://en.wikipedia.org/wiki/File:Red_eyed_tree_frog_edit2.jpg

37
Michal Charemza

Un paramètre initial d'un conteneur flexible est align-items: stretch .

Cela signifie que les éléments flexibles se développeront à travers axe transversal du conteneur.

Dans un conteneur de direction de ligne, comme dans la question, l'axe transversal est vertical.

Cela signifie que les articles (images, dans ce cas) couvriront toute la hauteur du conteneur.

Cependant, lorsqu'un élément flexible a une taille croisée définie, cela remplace la valeur par défaut stretch.

D'après les spécifications:

8.3. Alignement transversal: le align-items et align-self propriétés

Les éléments flexibles peuvent être alignés dans l'axe transversal de la ligne actuelle du conteneur flexible, comme justify-content mais dans la direction perpendiculaire.

stretch

Si la propriété de taille croisée de l'élément flexible est calculée sur auto et qu'aucune des marges de l'axe transversal n'est auto, l'élément flexible est étiré.

C'est le langage clé:

Si la propriété de taille croisée de l'élément flexible se calcule en auto

Et voici comment la spécification définit la "propriété de taille croisée":

La largeur ou la hauteur d'un élément flexible, quelle que soit sa dimension croisée, correspond à la taille de la croix de l'élément. La propriété cross size est celle de width ou height qui est dans la dimension croisée.

https://www.w3.org/TR/css-flexbox-1/#cross-size-property


Ainsi, votre code semble se jouer comme défini dans la spécification.

Voici ce que vous avez:

.flex-parent {
  display: flex;
  max-height: 10vh;
}
<div class="flex-parent">
  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyed_tree_frog_edit2.jpg/320px-Red_eyed_tree_frog_edit2.jpg">
  <img width="320" height="240" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyed_tree_frog_edit2.jpg/320px-Red_eyed_tree_frog_edit2.jpg">
</div>

La première image n'a pas de largeur définie (taille principale) ou de hauteur (taille croisée), ni en CSS ni en HTML. Par conséquent, sa taille croisée est calculée en auto.

Cette déclaration:

Si la propriété de taille croisée de l'élément flexible se calcule en auto

... est vrai, et align-items: stretch entre en vigueur.

L'image s'étend sur toute la hauteur du conteneur, qui est de 10 pixels.

La deuxième image a cependant un dimensionnement explicite. La taille croisée est définie dans le code HTML (height="240").

Maintenant, cette déclaration:

Si la propriété de taille croisée de l'élément flexible se calcule en auto

... est faux, et align-items: stretch est remplacé. L'attribut HTML height prévaut.

Deux notes sur la deuxième image:

  1. L'image ignore le max-height limite sur le conteneur car un paramètre initial en CSS est overflow: visible .
  2. Les attributs HTML width et height correspondent à leurs propriétés CSS respectives. Par conséquent, height="240" remplace le height: auto défaut. Voir ci-dessous pour les références de spécifications. *

Il y a deux autres problèmes à prendre en compte lors du rendu d'images dans un conteneur flexible.

  1. Taille minimale par défaut des éléments flexibles. Ce paramètre empêche les éléments flexibles de rétrécir en dessous de la taille de leur contenu. Lisez cet article pour plus de détails:

  2. Comportement variable parmi les principaux navigateurs. Firefox, Chrome, Safari, Edge et IE11 ne rendent pas toujours les images en tant qu'éléments flex de la même manière. Lisez cet article pour plus de détails:


Compte tenu de tous les facteurs ci-dessus, voici ma solution suggérée:

.flex-parent {
  display: flex;
  max-height: 50vh; /* adjusted for demo */
}

.flex-parent {
  min-width: 0;
}

img {
  width: 100%;
  height: auto;
}
<div class="flex-parent">
  <div>
    <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyed_tree_frog_edit2.jpg/320px-Red_eyed_tree_frog_edit2.jpg">
  </div>
  <div>
    <img width="320" height="240" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyed_tree_frog_edit2.jpg/320px-Red_eyed_tree_frog_edit2.jpg">
  </div>
</div>

* Les attributs HTML width et height correspondent à leurs propriétés CSS respectives. Par conséquent, lorsqu'ils sont spécifiés, ils remplacent les valeurs par défaut CSS. De la spécification HTML5:

10.4.3 Attributs pour le contenu et les images intégrés

Les attributs width et height sur applet, embed, iframe, object ou video éléments, et input éléments avec un attribut type dans l'état du bouton Image et qui soit représente une image, soit que l'utilisateur attend éventuellement représentera une image, mapper aux propriétés de dimension width et height sur l'élément respectivement.

10.2 La feuille de style de l'agent utilisateur CSS et les conseils de présentation

Lorsque le texte ci-dessous indique qu'un attribut sur un élément correspond à la propriété de dimension (ou aux propriétés), cela signifie que si l'élément a un ensemble d'attributs, et l'analyse de la valeur de cet attribut à l'aide de règles pour l'analyse des valeurs de dimension ne génère pas d'erreur, alors l'agent utilisateur devrait utiliser la dimension analysée comme valeur pour un indice de présentation = pour les propriétés, avec la valeur donnée en longueur de pixel si la dimension était un entier et avec la valeur donnée en pourcentage si la dimension était un pourcentage.

35
Michael_B

J'ai essayé de lire les spécifications w3c flexbox et je suis tombé sur this . Il dit que

Pour chaque dimension, si cette dimension de la zone de contenu du conteneur flexible est une taille définie, utilisez-la; si cette dimension du conteneur flexible est dimensionnée sous une contrainte de contenu min ou max, l'espace disponible dans cette dimension est cette contrainte.

Sinon, soustrayez la marge, la bordure et le rembourrage du conteneur flexible de l'espace disponible pour le conteneur flexible dans cette dimension et utilisez cette valeur qui pourrait donner une valeur infinie.

J'espère que cela t'aides.

3
Eggineer

Ici, vous avez écrit max-height: 10vh, vh ne prend en charge aucun navigateur, à l'exception du tout dernier iOS 6. Cela vaut pour toutes les unités de longueur liées à la fenêtre. utilisez d'autres valeurs au lieu de Vh, cela fonctionnera bien. Veuillez lire ce blog https://css-tricks.com/the-lengths-of-css/ .

.flex-parent {
  display: flex;
  max-height:  max-content;
}
<div class="flex-parent">
  <img                          src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyed_tree_frog_edit2.jpg/320px-Red_eyed_tree_frog_edit2.jpg">
  <img width="320" height="240" src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/be/Red_eyed_tree_frog_edit2.jpg/320px-Red_eyed_tree_frog_edit2.jpg">
</div>
2
Pradeep Kumar Das

Le problème est où vous définissez max-height. La propriété css max-height n'est pas héritée par défaut. Votre déclaration CSS crée une div qui correspond à 10% de la hauteur de la fenêtre. L'image sans aucune dimension définie a été réduite en fonction de ses dimensions parentes. L'image sur laquelle vous définissez les dimensions implicites sera toujours ces dimensions. Selon la taille du div, il peut déborder. Si vous mettez la propriété max-height sur la première image, elle devrait être redimensionnée en gardant le même rapport hauteur/largeur.

0
Philip Tinney