No se puede desplazar a la parte superior del elemento flexible que está desbordando el contenedor


259

Entonces, al intentar hacer un modo útil usando flexbox, encontré lo que parece ser un problema del navegador y me pregunto si hay una solución o solución conocida, o ideas sobre cómo resolverlo.

Lo que estoy tratando de resolver tiene dos aspectos. Primero, obtener la ventana modal centrada verticalmente, que funciona como se esperaba. El segundo es hacer que la ventana modal se desplace, externamente, de modo que toda la ventana modal se desplace, no el contenido dentro de ella (esto es para que pueda tener menús desplegables y otros elementos de la interfaz de usuario que puedan extenderse fuera de los límites del modal) como un selector de fecha personalizado, etc.)

Sin embargo, al combinar el centrado vertical con las barras de desplazamiento, la parte superior del modal puede volverse inaccesible a medida que comienza a desbordarse. En el ejemplo anterior, puede cambiar el tamaño para forzar el desbordamiento, y al hacerlo le permite desplazarse hacia la parte inferior del modal, pero no hacia la parte superior (el primer párrafo se corta).

Aquí está el enlace al código de ejemplo (altamente simplificado)

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
}

Esto afecta (actual) a Firefox, Safari, Chrome y Opera. Curiosamente se comporta correctamente en IE10 si comenta en el CSS prefijado del vendedor de IE10. Todavía no me molesté en probar en IE11, pero supongo que el comportamiento coincide con el de IE10 .

Cualquier idea sería buena. Los enlaces a problemas conocidos o el razonamiento detrás de este comportamiento también serían útiles.

Respuestas:


478

El problema

Flexbox hace que el centrado sea muy fácil.

Simplemente aplicando align-items: centery justify-content: centeral contenedor flexible, sus elementos flexibles estarán centrados vertical y horizontalmente.

Sin embargo, hay un problema con este método cuando el elemento flexible es más grande que el contenedor flexible.

Como se señaló en la pregunta, cuando el elemento flexible desborda el contenedor, la parte superior se vuelve inaccesible.

ingrese la descripción de la imagen aquí

Para el desbordamiento horizontal, la sección izquierda se vuelve inaccesible (o la sección derecha, en lenguajes RTL).

Aquí hay un ejemplo con un contenedor LTR que tiene justify-content: centery tres elementos flexibles:

ingrese la descripción de la imagen aquí

Consulte la parte inferior de esta respuesta para obtener una explicación de este comportamiento.


Solución n. ° 1

Para solucionar este problema, use los márgenes automáticos de flexbox , en lugar de justify-content.

Con los automárgenes, un elemento flexible que se desborda puede centrarse vertical y horizontalmente sin perder el acceso a ninguna parte del mismo.

Entonces, en lugar de este código en el contenedor flexible:

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

Use este código en el elemento flexible:

.flex-item {
    margin: auto;
}

ingrese la descripción de la imagen aquí

Demo revisada


Solución # 2 (aún no implementada en la mayoría de los navegadores)

Agregue el safevalor a su regla de alineación de palabras clave, así:

justify-content: safe center

o

align-self: safe center

De la especificación del módulo de alineación de caja CSS :

4.4. Desbordamiento Orientación: el safey unsafepalabras clave y los límites de seguridad de desplazamiento

Cuando el [elemento flexible] es más grande que el [contenedor flexible], se desbordará. Algunos modos de alineación, si se cumplen en esta situación, pueden causar pérdida de datos: por ejemplo, si los contenidos de una barra lateral están centrados, cuando se desbordan, pueden enviar parte de sus cuadros más allá del borde inicial de la ventana gráfica, que no se puede desplazar a .

Para controlar esta situación, se puede especificar explícitamente un modo de alineación de desbordamiento . Unsafela alineación respeta el modo de alineación especificado en situaciones de desbordamiento, incluso si causa pérdida de datos, mientras que la safealineación cambia el modo de alineación en situaciones de desbordamiento en un intento de evitar la pérdida de datos.

El comportamiento predeterminado es contener el asunto de alineación dentro del área desplazable, aunque al momento de escribir esta característica de seguridad aún no está implementada.

safe

Si el tamaño del [elemento flexible] desborda el [contenedor flexible], el [elemento flexible] se alinea como si el modo de alineación fuera [ flex-start].

unsafe

Independientemente de los tamaños relativos de [elemento flexible] y [contenedor flexible], se respeta el valor de alineación dado.

Nota: El módulo de alineación de cajas se utiliza en varios modelos de diseño de cajas, no solo en flex. Entonces, en el extracto de especificaciones anterior, los términos entre paréntesis en realidad dicen "sujeto de alineación", "contenedor de alineación" y " start". Usé términos específicos de flex para mantener el foco en este problema en particular.


Explicación para la limitación de desplazamiento de MDN:

Consideraciones de artículos flexibles

Las propiedades de alineación de Flexbox hacen un centrado "verdadero", a diferencia de otros métodos de centrado en CSS. Esto significa que los elementos flexibles permanecerán centrados, incluso si desbordan el contenedor flexible.

Sin embargo, esto a veces puede ser problemático si se desbordan más allá del borde superior de la página o del borde izquierdo, ya que no puede desplazarse a esa área, ¡incluso si hay contenido allí!

En una versión futura, las propiedades de alineación se ampliarán para tener también una opción "segura".

Por ahora, si esto es una preocupación, puede utilizar márgenes para lograr el centrado, ya que responderán de una manera "segura" y dejarán de centrarse si se desbordan.

En lugar de usar las align-propiedades, simplemente ponga automárgenes en los elementos flexibles que desea centrar.

En lugar de las justify-propiedades, coloque márgenes automáticos en los bordes exteriores del primer y último elemento flexible en el contenedor flexible.

Los automárgenes se "flexionarán" y asumirán el espacio sobrante, centrando los elementos flexibles cuando haya espacio sobrante y cambiando a alineación normal cuando no lo sea.

Sin embargo, si está intentando reemplazar justify-contentcon un centrado basado en márgenes en una caja flexible de varias líneas, probablemente no tenga suerte, ya que necesita colocar los márgenes en el primer y último elemento flexible en cada línea. A menos que pueda predecir con anticipación qué elementos terminarán en qué línea, no puede utilizar de manera confiable el centrado basado en márgenes en el eje principal para reemplazar la justify-contentpropiedad.


44
Sí, esa es una mejor solución, y gracias por proporcionarnos información valiosa adicional.
jejacks0n

1
Cabe señalar que no funciona en IE11. El fondo se cortará.
Daniel

2
@Daniel, acabo de probar el código en IE11. Nada es inaccesible. De hecho, el problema descrito en la pregunta ni siquiera existe en IE11. Puede estar refiriéndose al desbordamiento de texto que ocurre solo en IE11. Esa es otra cuestión para otra pregunta.
Michael Benjamin

11
Para solucionar el problema en IE11: agregue align-items: flex-startal contenedor flexible y guarde margin: autopara el elemento flexible.
Eugene Fidelin

2
Esto no funciona para mí cuando utilizo flex-direction: column;
Stefan

22

Bueno, como diría la Ley de Murphy, la lectura que hice después de publicar esta pregunta resultó en algunos resultados, no completamente resueltos, pero de alguna manera útiles.

Jugué un poco con la altura mínima un poco antes de publicar, pero no estaba al tanto de las restricciones de tamaño intrínsecas que son bastante nuevas para la especificación.

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

Agregar un min-height: min-contentárea de Flexbox resuelve el problema en Chrome, y con los prefijos de los proveedores también se corrige Opera y Safari, aunque Firefox sigue sin resolverse.

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

Todavía estoy buscando ideas en Firefox y otras posibles soluciones.


Solo quería decir que ya funciona para mí en Firefox. Entonces la solución con min-content fue perfecta.
pudgereyem

@pudgereyem Supongo que lo implementaron entonces. La otra solución con margin: autodeja flex-basisde funcionar para mí, mientras que esta respuesta resolvió ambos problemas.
Martin Dawson

Una solución brillante de hecho. No me importa Edge o IE, ¡así que esto funciona perfectamente para mí!
Ohgodwhy

18

Logré lograr esto con solo 3 contenedores. El truco consiste en separar el contenedor flexbox del contenedor que controla el desplazamiento. Por último, coloque todo en un contenedor raíz para centrarlo todo. Estos son los estilos esenciales para crear el efecto:

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>

He creado una demostración aquí: https://jsfiddle.net/r5jxtgba/14/


Gracias por los consejos de un contenedor de desplazamiento, busqué desde hace dos días para arreglar mi contenido de desplazamiento de *****.
artSx

recuerda, no le des flex: 1 1 autoa la scroll-container. Estaba haciendo esto con la costumbre y me metí en un problema.
AmirHossein

1
Jsfiddle muestra que no funciona cuando agrega más contenido dentro del contenedor.
bplittle

4

Creo que encontré una solución. Funciona con mucho texto y un poco de texto . No necesita especificar el ancho de nada, y debería funcionar en 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>


Esta es la mejor solución para navegadores heredados. ¡Muchas gracias!
Daniel

55
Wow, eso es un montón de envolturas.
Nathan Arthur

1
Wow, he pasado horas tratando de lograr esto. (Todos los demás métodos fallan en Chrome móvil cuando agrega animaciones. Esto no lo hace) ¡Muchas gracias!
falsePockets

1

Según MDN, el safevalor ahora se puede proporcionar a propiedades como align-itemsy justify-content. Se describe de la siguiente manera:

Si el tamaño del elemento desborda el contenedor de alineación, el elemento se alineará como si lo fuera el modo de alineación start.

Entonces, podría usarse de la siguiente manera.

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

Sin embargo, no está claro cuánto soporte de navegador tiene, no pude encontrar ningún ejemplo de su uso, y yo también he tenido algunos problemas. Mencionándolo aquí para llamar más la atención.


7 de junio de 2018 y aún no se implementa en Chrome.
AmirHossein

De acuerdo con las páginas (actuales) de MDN, "seguro" y "inseguro" siguen siendo solo para Firefox en este momento (bueno, Safari y la mayoría de los navegadores móviles tienen soporte desconocido; lo jugaría seguro y asumiría que no hay soporte).
JaMiT

MDN informa que es compatible con Firefox, pero cuando lo probé en Firefox, no pareció funcionar. jsbin.com/pimoqof/1/edit?html,css,output
Oliver Joseph Ash

Junio ​​de 2020 y no en la mayoría de los navegadores, según caniuse
den232 hace

0

También logré hacerlo usando un contenedor extra

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;
}

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

cambiar los valores de ancho / alto de contenido y ver


0

2 Método Flex de contenedor con tabla de respaldo probada IE8-9, flex funciona en IE10,11. Editar: editado para garantizar el centrado vertical cuando el contenido es mínimo, se agregó soporte heredado.

El problema se debe a que la altura se hereda del tamaño de la ventana gráfica, lo que hace que los niños se desborden, como respondió Michael. https://stackoverflow.com/a/33455342/3500688

algo más simple y use flex para mantener el diseño dentro del contenedor emergente (contenido):

#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>

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.