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

259

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

La chose que j'essaie de résoudre a deux aspects. Tout d'abord, obtenir la fenêtre modale centrée verticalement, ce qui fonctionne comme prévu. La seconde consiste à faire défiler la fenêtre modale - en externe, de sorte que la fenêtre modale entière défile, pas le contenu qu'elle contient (c'est ainsi que vous pouvez avoir des listes déroulantes et d'autres éléments d'interface utilisateur qui peuvent s'étendre en dehors des limites du modal - comme un sélecteur de date personnalisé, etc.)

Cependant, lors de la combinaison du centrage vertical avec des barres de défilement, le haut du modal peut devenir inaccessible lorsqu'il commence à déborder. Dans l'exemple ci-dessus, vous pouvez redimensionner pour forcer le débordement, et ce faisant, il vous permet de faire défiler vers le 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 (actuel) Firefox, Safari, Chrome et Opera .. Il se comporte de manière intéressante correctement dans IE10 si vous commentez dans le CSS préfixé du vendeur IE10 - Je n'ai pas encore pris la peine de tester dans IE11, mais je suppose 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.

jejacks0n
la source

Réponses:

478

Le problème

Flexbox facilite le centrage.

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

Cependant, il y a un problème avec cette méthode lorsque l'élément flexible est plus grand que le conteneur flexible.

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

entrez la description de l'image ici

Pour un débordement horizontal, la section gauche devient inaccessible (ou la section droite, dans les langues RTL).

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

entrez la description de l'image ici

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


Solution n ° 1

Pour résoudre ce problème, utilisez les marges automatiques de Flexbox au lieu de justify-content.

Avec les automarges, 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'article flexible:

.flex-item {
    margin: auto;
}

entrez la description de l'image ici

Démo révisée


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

Ajoutez la safevaleur à votre règle d'alignement des mots clés, comme ceci:

justify-content: safe center

ou

align-self: safe center

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

4.4. Alignement overflow: la safeet unsafemots - clés et défilement des limites de sécurité

Lorsque [l'élément flexible] est plus grand que le [conteneur flexible], il débordera. Certains modes d'alignement, s'ils sont respectés dans cette situation, peuvent entraîner une perte de données: par exemple, si le contenu d'une barre latérale est centré, lorsqu'il déborde, il peut envoyer une partie de ses boîtes au-delà du bord de départ de la fenêtre, qui ne peut pas être défilée jusqu'à .

Pour contrôler cette situation, un mode d' alignement de débordement peut être spécifié explicitement. Unsafel'alignement respecte le mode d'alignement spécifié dans les situations de débordement, même s'il entraîne une perte de données, tandis que l' safealignement modifie le mode d'alignement dans les situations de débordement afin d'éviter la perte de données.

Le comportement par défaut consiste à contenir le sujet d'alignement dans la zone de défilement, bien qu'au moment de l'écriture, cette fonction de sécurité ne soit pas encore implémentée.

safe

Si la taille de [l'élément flexible] déborde du [conteneur flexible], [l'élément flexible] est plutôt aligné comme si le mode d'alignement était [ flex-start].

unsafe

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

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


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

Considérations sur les éléments flexibles

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

Cependant, cela peut parfois poser problème s'ils dépassent le bord supérieur de la page ou le bord gauche, [...] car vous ne pouvez pas faire défiler jusqu'à cette zone, même s'il y a du contenu!

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

Pour l'instant, si cela vous inquiète, vous pouvez plutôt utiliser des marges pour réaliser le centrage, car elles répondront de manière "sûre" et cesseront de centrer si elles débordent.

Au lieu d'utiliser les align-propriétés, placez simplement des automarges sur les éléments flexibles que vous souhaitez centrer.

Au lieu des justify-propriétés, placez des marges automatiques sur les bords extérieurs des premier et dernier éléments flexibles dans le conteneur flexible.

Les automarges "fléchiront" et occuperont l'espace restant, en centrant les éléments flexibles lorsqu'il y a de l'espace restant et en passant à l'alignement normal dans le cas contraire.

Cependant, si vous essayez de remplacer justify-contentpar un centrage basé sur les marges dans une boîte flexible multi-lignes, vous n'avez probablement pas de chance, car vous devez mettre les marges sur le premier et le dernier élément flexible sur chaque ligne. À moins que vous ne puissiez prédire à l'avance quels éléments se retrouveront sur quelle ligne, vous ne pouvez pas utiliser de manière fiable le centrage basé sur les marges dans l'axe principal pour remplacer la justify-contentpropriété.

Michael Benjamin
la source
4
Oui, c'est une meilleure solution, et merci d'avoir fourni des informations précieuses supplémentaires.
jejacks0n
1
Il convient de noter que cela ne fonctionne pas dans IE11. L'arrière-plan sera coupé.
Daniel
2
@Daniel, je viens de tester le code dans IE11. Rien n'est inaccessible. En fait, le problème décrit dans la question n'existe même pas dans IE11. Vous faites peut-être référence au débordement de texte qui se produit uniquement dans IE11. C'est une autre question pour une autre question.
Michael Benjamin
11
Pour résoudre le problème dans IE11: ajoutez align-items: flex-startau conteneur flex et conservez margin: autopour l'élément flex.
Eugene Fidelin
2
Cela ne fonctionne pas pour moi lorsque j'utilise flex-direction: column;
Stefan
22

Eh bien, comme le prévoit 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 quelque peu utiles néanmoins.

J'ai joué avec min-height un peu avant de poster, mais je n'étais pas au courant des contraintes de dimensionnement intrinsèques qui sont assez nouvelles pour la spécification.

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

L'ajout d'un min-height: min-contentà la zone flexbox résout le problème dans Chrome, et avec les préfixes des fournisseurs, il corrige également Opera et Safari, bien que Firefox ne soit toujours 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.

jejacks0n
la source
Je voulais juste dire que cela fonctionne déjà pour moi dans Firefox. La solution avec min-content était donc parfaite.
pudgereyem
@pudgereyem Je suppose qu'ils l'ont ensuite implémenté. L'autre solution avec des margin: autoarrêts flex-basisde travailler pour moi alors que cette réponse a résolu les deux problèmes.
Martin Dawson
Une solution brillante en effet. Je ne me soucie pas d'Edge ou d'IE, donc cela fonctionne parfaitement pour moi!
Ohgodwhy
18

J'ai réussi à retirer cela 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/

colinbr96
la source
merci pour des conseils sur les conteneurs de défilement, j'ai cherché depuis deux jours pour corriger mon contenu de défilement ***** !!!
artSx
rappelez-vous, ne donnez pas flex: 1 1 autoau scroll-container. Je faisais ça avec habitude et j'ai eu des problèmes.
AmirHossein
1
Le jsfiddle montre que cela ne fonctionne pas lorsque vous ajoutez plus de contenu à l'intérieur du conteneur.
bplittle
4

Je pense avoir trouvé une solution. Cela fonctionne avec beaucoup de texte et un peu de 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>

mpen
la source
Il s'agit de la meilleure solution pour les navigateurs hérités. Merci beaucoup!
Daniel
5
Wow, c'est beaucoup de tours.
Nathan Arthur
1
Wow, j'ai passé des heures à essayer d'y parvenir. (Toutes les autres méthodes échouent dans Chrome mobile lorsque vous ajoutez des animations. Ce n'est pas le cas) Merci beaucoup!
falsePockets
1

Selon MDN, la safevaleur peut désormais être fournie à des propriétés comme align-itemset justify-content. Il est décrit comme suit:

Si la taille de l'élément déborde du conteneur d'alignement, l'élément est plutôt aligné comme si le mode d'alignement l'était start.

Ainsi, il pourrait être utilisé comme suit.

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

Cependant, le support du navigateur n'est pas clair, je n'ai trouvé aucun exemple de son utilisation et j'ai eu quelques problèmes avec lui-même. Le mentionner ici pour attirer davantage l'attention sur lui.

Chris Talman
la source
7 juin 2018 et toujours pas implémenté en chrome.
AmirHossein
Selon les pages MDN (actuelles), "sûr" et "dangereux" ne sont encore que Firefox à ce stade (enfin, Safari et la plupart des navigateurs mobiles ont un support inconnu - je le jouerais en toute sécurité et n'assumerais aucun support).
JaMiT
MDN signale le support de Firefox, mais quand je l'ai testé dans Firefox, cela ne semblait pas fonctionner. jsbin.com/pimoqof/1/edit?html,css,output
Oliver Joseph Ash
Juin 2020 et pas dans la plupart des navigateurs, selon Caniuse
Den232
0

J'ai également 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/

changer les valeurs de largeur / hauteur de contenu et voir

Nadeesh Peiris
la source
0

2 Méthode Flex du conteneur avec table de secours testée IE8-9, flex fonctionne dans IE10,11. Modifier: modifié pour assurer un centrage vertical en cas de contenu minimal, ajout de la prise en charge héritée.

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

quelque chose de plus simple et d'utiliser flex pour maintenir la mise en page dans le conteneur popup (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>

Silverandrew
la source