web-dev-qa-db-fra.com

Impossible de faire défiler vers le haut de l'élément flex qui déborde le conteneur

Donc, en essayant de créer un modal utile en utilisant flexbox, j'ai trouvé ce qui semblait être un problème de navigateur et je me demandais s'il existait un correctif connu ou une solution de contournement - ou des idées sur la façon de le résoudre.

La chose que je tente de résoudre a deux aspects. Commencez par centrer la fenêtre modale verticalement, ce qui fonctionne comme prévu. La seconde consiste à faire défiler la fenêtre modale - en externe, de sorte que toute la fenêtre modale défile, et non son contenu (vous pouvez ainsi avoir des listes déroulantes et d'autres éléments d'interface utilisateur pouvant s'étendre en dehors des limites du modal - comme un sélecteur de date personnalisé, etc.)

Cependant, en combinant le centrage vertical avec les barres de défilement, le haut du modal peut devenir inaccessible au moment où il commence à déborder. Dans l'exemple ci-dessus, vous pouvez redimensionner pour forcer le débordement, ce qui vous permet de faire défiler l'écran jusqu'en bas du modal, mais pas vers le haut (le premier paragraphe est coupé).

Voici le lien vers l'exemple de code (hautement simplifié)

https://jsfiddle.net/dh9k18k0/2/

.modal-container {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background: rgba(0, 0, 0, 0.5);
  overflow-x: auto;
}
.modal-container .modal-window {
  display: -ms-flexbox;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  // Optional support to confirm scroll behavior makes sense in IE10
  //-ms-flex-direction: column;
  //-ms-flex-align: center;
  //-ms-flex-pack: center;
  height: 100%;
}
.modal-container .modal-window .modal-content {
  border: 1px solid #ccc;
  border-radius: 4px;
  background: #fff;
  width: 100%;
  max-width: 500px;
  padding: 10px
}

Cela affecte (en cours) Firefox, Safari, Chrome et Opera .. Il est intéressant de se comporter correctement dans IE10 si vous commentez dans le préfixe de vendeur IE10 - Je n'ai pas encore essayé de tester dans IE11, mais supposons que le comportement correspond à celui d'IE10 .

Toutes les idées seraient bonnes. Des liens vers des problèmes connus ou un raisonnement derrière ce comportement seraient également utiles.

155
jejacks0n

Le problème

Flexbox facilite le centrage.

En appliquant simplement align-items: center et justify-content: center au conteneur flexible, vos articles flexibles seront centrés verticalement et horizontalement.

Cependant, cette méthode pose problème lorsque l'élément flex est plus grand que le conteneur flex.

Comme indiqué dans la question, lorsque l'élément flexible déborde du conteneur, le haut devient inaccessible.

enter image description here

Pour les débordements horizontaux, la partie gauche devient inaccessible (ou la partie droite, dans les langues RTL).

Voici un exemple avec un conteneur LTR ayant justify-content: center et trois éléments flex:

enter image description here

Voir le bas de cette réponse pour une explication de ce comportement.


Solution n ° 1

Pour résoudre ce problème, utilisez _/flexbox auto marges au lieu de justify-content.

Avec les marges auto, un élément flexible débordant peut être centré verticalement et horizontalement sans perdre l’accès à aucune partie de celui-ci.

Donc, au lieu de ce code sur le conteneur flex:

#flex-container {
    align-items: center;
    justify-content: center;
}

Utilisez ce code sur l'élément flex:

.flex-item {
    margin: auto;
}

enter image description here

Démo révisée


Solution n ° 2 (pas encore implémentée dans la plupart des navigateurs)

Ajoutez la valeur safe à votre règle d'alignement des mots clés, comme suit:

justify-content: safe center

ou

align-self: safe center

À partir de la spécification du module d'alignement de la boîte CSS }:

4.4. Alignement de débordement: les mots clés safe et unsafe et Scroll safety Limits

Lorsque l'élément [flex] est plus grand que le [conteneur flex], il le sera débordement. Certains modes d'alignement, s'ils sont respectés dans cette situation, peuvent provoquer une perte de données: par exemple, si le contenu d'une barre latérale est centré, quand ils débordent ils peuvent envoyer une partie de leurs boîtes passé Edge de démarrage de la fenêtre, dans laquelle vous ne pouvez pas faire défiler.

Pour contrôler cette situation, un mode d'alignement débordement peut être explicitement spécifié. Unsafe alignement honore le spécifié mode d’alignement en cas de débordement, même s’il entraîne une perte de données, while safe alignement change le mode d’alignement par débordement situations afin d’éviter la perte de données.

Le comportement par défaut consiste à contenir le sujet de l'alignement dans le fichier Zone de défilement, bien qu’au moment de l’écriture, cette fonction de sécurité est Pas encore implémenté.

safe

Si la taille de l'élément [flex] dépasse du [conteneur flex], le fichier [flex item] est aligné à la place comme si le mode d'alignement était [flex-start]. 

unsafe

Quelles que soient les tailles relatives de [élément flex] et de [flex conteneur], la valeur d'alignement donnée est honorée.

Remarque: le module d'alignement de boîtes est destiné à être utilisé dans plusieurs modèles de présentation de boîtes, et pas seulement dans Flex. Ainsi, dans l'extrait de spécification ci-dessus, les termes entre parenthèses indiquent en fait "sujet de l'alignement", "conteneur d'alignement" et "start". J'ai utilisé des termes spécifiques à la flexion pour rester concentré sur ce problème particulier.


Explication de la limitation de défilement à partir de MDN:

Item Flex Considérations

Les propriétés d'alignement de Flexbox font un "vrai" centrage, contrairement à d'autres méthodes de centrage en CSS. Cela signifie que les éléments flexibles resteront centré, même s’ils débordent du conteneur flexible.

Cependant, cela peut parfois être problématique s’ils dépassent le haut Bord de la page, ou bord gauche [...], comme vous ne pouvez pas faire défiler jusqu'à cette zone, même s'il y a du contenu!

Dans une prochaine version, les propriétés d'alignement seront étendues pour avoir une option "sûre" aussi.

Pour l'instant, si cela vous pose problème, vous pouvez utiliser des marges pour atteindre centré, car ils réagiront de manière "sûre" et cesseront de centrer si ils débordent. 

Au lieu d'utiliser les propriétés align-, mettez simplement les marges auto sur les éléments flexibles que vous souhaitez centrer.

Au lieu des propriétés justify-, mettez les marges automatiques à l'extérieur bords des premier et dernier articles flexibles du conteneur flex.

Les marges auto "fléchiront" et assumeront l’espace restant, centrer les éléments flexibles lorsqu'il reste de l'espace et basculer à l'alignement normal quand pas.

Toutefois, si vous essayez de remplacer justify-content par centrage basé sur la marge dans une boîte flexible multi-lignes, vous êtes probablement hors de chance, car vous devez mettre les marges sur le premier et le dernier item flex sur chaque ligne. À moins que vous ne puissiez prédire à l’avance quels articles seront Si vous vous retrouvez sur quelle ligne, vous ne pouvez pas utiliser de manière fiable le centrage basé sur la marge l'axe principal pour remplacer la propriété justify-content.

291
Michael_B

Eh bien, comme le veut la loi de Murphy, la lecture que j'ai faite après avoir posté cette question a donné quelques résultats - pas complètement résolus, mais néanmoins utiles.

Je me suis un peu amusé avec min-height avant de poster, mais je n’étais pas conscient des contraintes de dimensionnement intrinsèques qui sont relativement nouvelles dans la spécification.

http://caniuse.com/#feat=intrinsic-width

L'ajout d'un min-height: min-content à la zone de flexbox résout le problème dans Chrome. De plus, les préfixes des vendeurs corrigent Opera et Safari, même si Firefox n'est pas résolu.

min-height: -moz-min-content; // not implemented
min-height: -webkit-min-content // works for opera and safari
min-height: min-content // works for chrome

Toujours à la recherche d'idées sur Firefox et d'autres solutions potentielles.

18
jejacks0n

J'ai réussi à retirer ceci avec seulement 3 conteneurs. L'astuce consiste à séparer le conteneur flexbox du conteneur qui contrôle le défilement. Enfin, mettez tout dans un conteneur racine pour tout centrer. Voici les styles essentiels pour créer l'effet:

CSS:

.root {
  display: flex;
  justify-content: center;
  align-items: center;
}

.scroll-container {
  margin: auto;
  max-height: 100%;
  overflow: auto;
}

.flex-container {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

HTML:

<div class="root">
  <div class="scroll-container">
    <div class="flex-container">
      <p>Lorem ipsum dolor sit amet.</p>
    </div>
  </div>
</div>

J'ai créé une démo ici: https://jsfiddle.net/r5jxtgba/14/

12
colinbr96

Je pense avoir trouvé une solution. Cela fonctionne avec beaucoup de texte et un petit texte . Vous n'avez pas besoin de spécifier la largeur de quoi que ce soit, et cela devrait fonctionner dans IE8.

.wrap1 {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background: rgba(0, 0, 0, 0.5);
  overflow-y: auto;
}
.wrap2 {
  display: table;
  width: 100%;
  height: 100%;
  text-align: center;
}
.wrap3 {
  vertical-align: middle;
  display: table-cell;
}
.wrap4 {
  margin: 10px;
}
.dialog {
  text-align: left;
  background-color: white;
  padding: 5px;
  border-radius: 3px;
  margin: auto;
  display: inline-block;
  box-shadow: 2px 2px 4px rgba(0, 0, 0, .5);
}
<div class="wrap1">
  <div class="wrap2">
    <div class="wrap3">
      <div class="wrap4">
        <div class="dialog">
          <p>Lorem ipsum dolor sit amet.</p>
        </div>
      </div>
    </div>
  </div>
</div>

4
mpen

Selon MDN, la valeur safe peut maintenant être fournie à des propriétés telles que align-items et justify-content . Il est décrit comme suit:

Si la taille de l'élément dépasse le conteneur d'alignement, l'élément est aligné comme si le mode d'alignement était start.

Donc, il pourrait être utilisé comme suit.

.rule
{
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: safe center;
}

Cependant, on ne sait pas combien de navigateur il a, je n'ai trouvé aucun exemple d'utilisation, et j'ai eu quelques problèmes avec lui-même. En le mentionnant ici pour attirer davantage l'attention.

1
Chris Talman

J'ai aussi réussi à le faire en utilisant un conteneur supplémentaire

HTML

<div class="modal-container">
  <div class="modal">
    <div class="content-container">
       <div class="content">
         <p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
        </div>
      </div>
  </div>  
</div>

CSS

.modal-container {
  display: flex;
  justify-content: center;
  align-items: center;
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  background-color: black;
}

.modal {
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #aaa;
  height: 80%;
  width: 90%;
}

.content-container {
  background-color: blue;
  max-height: 100%;
  overflow: auto;
  padding:0;
}

.content {
  display: flex;
  background-color: red;
  padding: 5px;
  width: 900px;
  height: 300px;
}

dans jsfiddle> https://jsfiddle.net/Nash171/cpf4weq5/

changez .content _ valeurs de largeur/hauteur et voyez

0
Nadeesh Peiris

2 La méthode Container Flex avec table de repli testée IE8-9, flex fonctionne dans IE10,11. Éditer: Édité pour assurer un centrage vertical lorsque le contenu est minimal, ajout du support hérité.

Le problème provient de la hauteur héritée de la taille de la fenêtre, ce qui provoque un débordement d'enfants, comme l'a répondu Michael. https://stackoverflow.com/a/33455342/3500688

quelque chose de plus simple et utilisez flex pour maintenir la mise en page dans le conteneur contextuel (contenu):

#popup {
position: fixed;
top: 0;
left: 0;
right: 0;
min-height: 100vh;
background-color: rgba(0,0,0,.25);
margin: auto;
overflow: auto;
height: 100%;
bottom: 0;
display: flex;
align-items: flex-start;
box-sizing:border-box;
padding:2em 20px;
}
.container {
background-color: #fff;
margin: auto;
border: 1px solid #ccc;
border-radius: 4px;
background: #fff;
/* width: 100%; */
max-width: 500px;
padding: 10px;
    /* display: flex; */
    /* flex-wrap: wrap; */
}
                <!--[if lt IE 10]>
<style>
          #popup {
                        display: table;
                        width:100%;
                }
                .iewrapper {
                        display: table-cell;
                        vertical-align: middle;
                }
        </style>
        <![endif]-->
<div id="popup">
        <!--[if lt IE 10]>
<div class="iewrapper">
<![endif]-->
    <div class="container">
        <p class="p3">Test</p>
    <p class="p3">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
    <p class="p3">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
    </div>
        <!--[if lt IE 10]>
<div class="iewrapper">
<![endif]-->
</div>
0
Silverandrew