Chrome/Safari no llena el 100% de la altura del padre flexible

Resuelto Ricardo Castañeda asked hace 9 años • 5 respuestas

Quiero tener un menú vertical con una altura específica.

Cada hijo debe llenar la altura del padre y tener el texto alineado en el medio.

El número de hijos es aleatorio, por lo que tengo que trabajar con valores dinámicos.

Div .containercontiene un número aleatorio de hijos (.item ) que siempre deben llenar la altura del padre. Para lograr eso utilicé flexbox.

Para hacer enlaces con texto alineado al medio estoy usandodisplay: table-cell la técnica. Pero el uso de visualizadores de mesa requiere utilizar una altura del 100%.

Mi problema es que .item-inner { height: 100% }no funciona en webkit (Chrome).

  1. ¿Hay alguna solución para este problema?
  2. ¿O existe una técnica diferente para hacer que todos .itemllenen la altura del padre con texto alineado verticalmente al medio?

Ejemplo aquí jsFiddle, debe verse en Firefox y Chrome

.container {
  height: 20em;
  display: flex;
  flex-direction: column;
  border: 5px solid black
}
.item {
  flex: 1;
  border-bottom: 1px solid white;
}
.item-inner {
  height: 100%;
  width: 100%;
  display: table;
}
a {
  background: orange;
  display: table-cell;
  vertical-align: middle;
}
<div class="container">
  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>

  <div class="item">
    <div class="item-inner">
      <a>Button</a>
    </div>
  </div>
</div>
Expandir fragmento

Ricardo Castañeda avatar Nov 11 '15 01:11 Ricardo Castañeda
Aceptado

Solución

Utilice contenedores flexibles anidados.

Deshazte de las alturas porcentuales. Deshazte de las propiedades de la tabla. Deshacerse de vertical-align. Evite el posicionamiento absoluto. Simplemente quédese con flexbox hasta el final.

Aplicar display: flexal elemento flexible ( .item), convirtiéndolo en un contenedor flexible. Esto establece automáticamente align-items: stretch, lo que le dice al hijo ( .item-inner) que expanda la altura completa del padre.

Importante: elimine las alturas especificadas de los elementos flexibles para que este método funcione. Si un niño tiene una altura especificada (por ejemplo height: 100%), ignorará la align-items: stretchllegada del padre. Para que el stretchvalor predeterminado funcione, la altura del niño debe calcularse auto (explicación completa ).

Pruebe esto (sin cambios en HTML):

Mostrar fragmento de código

Demostración de jsFiddle


Explicación

Mi problema es que .item-inner { height: 100% }no funciona en webkit (Chrome).

No funciona porque estás usando el porcentaje de altura de una manera que no se ajusta a la implementación tradicional de la especificación.

10.5 Altura del contenido: la heightpropiedad

porcentaje
Especifica un porcentaje de altura. El porcentaje se calcula con respecto a la altura del bloque contenedor del cuadro generado. Si la altura del bloque contenedor no se especifica explícitamente y este elemento no está en una posición absoluta, el valor se calcula como auto.

auto
La altura depende de los valores de otras propiedades.

En otras palabras, para que el porcentaje de altura funcione en un hijo entrante, el padre debe tener una altura establecida.

En su código, el contenedor de nivel superior tiene una altura definida:.container { height: 20em; }

El contenedor del tercer nivel tiene una altura definida:.item-inner { height: 100%; }

Pero entre ellos, el contenedor del segundo nivel – .itemno tiene una altura definida. Webkit ve esto como un eslabón perdido.

.item-innerle dice a Chrome: dameheight: 100% . .itemChrome busca referencia en el padre ( ) y responde: ¿100% de qué? No veo nada (ignorando la flex: 1regla que hay). Como resultado, se aplica height: auto(alto del contenido), de acuerdo con la especificación.

Firefox, por otro lado, ahora acepta la altura flexible de los padres como referencia para el porcentaje de altura del niño. IE11 y Edge también aceptan alturas flexibles.

Además, Chrome aceptará flex-growcomo referencia principal adecuada si se usa junto conflex-basis (cualquier valor numérico funciona ( autono lo hará), incluido flex-basis: 0). Sin embargo, al momento de escribir este artículo, esta solución falla en Safari.

Mostrar fragmento de código


Cuatro soluciones

1. Especifique una altura en todos los elementos principales.

Una solución confiable para varios navegadores es especificar una altura en todos los elementos principales. Esto evita que falten enlaces, que los navegadores basados ​​en Webkit consideran una violación de la especificación.

Tenga en cuenta que min-heighty max-heightno son aceptables. Debe ser la heightpropiedad.

Más detalles aquí: Trabajar con la heightpropiedad CSS y valores porcentuales

2. Posicionamiento relativo y absoluto de CSS

Se aplica position: relativea los padres y position: absoluteal niño.

Dimensione el niño con height: 100%y width: 100%, o use las propiedades de desplazamiento: top: 0, right: 0, bottom: 0, left: 0.

Con el posicionamiento absoluto, la altura porcentual funciona sin una altura especificada en el padre.

3. Elimine los contenedores HTML innecesarios (recomendado)

¿ Se necesitan dos contenedores button? ¿Por qué no eliminar .itemo .item-innero ambos? Aunque buttonlos elementos a veces fallan como contenedores flexibles , pueden ser elementos flexibles. Considere convertir o buttonen un elemento secundario y eliminar el margen de beneficio gratuito..container.item

He aquí un ejemplo:

Mostrar fragmento de código

4. Contenedores flexibles anidados (recomendado)

Deshazte de las alturas porcentuales. Deshazte de las propiedades de la tabla. Deshacerse de vertical-align. Evite el posicionamiento absoluto. Simplemente quédese con flexbox hasta el final.

Aplicar display: flexal elemento flexible ( .item), convirtiéndolo en un contenedor flexible. Esto establece automáticamente align-items: stretch, lo que le dice al hijo ( .item-inner) que expanda la altura completa del padre.

Importante: elimine las alturas especificadas de los elementos flexibles para que este método funcione. Si un niño tiene una altura especificada (por ejemplo height: 100%), ignorará la align-items: stretchllegada del padre. Para que el stretchvalor predeterminado funcione, la altura del niño debe calcularse auto (explicación completa ).

Pruebe esto (sin cambios en HTML):

Mostrar fragmento de código

jsFiddle

Michael Benjamin avatar Nov 11 '2015 04:11 Michael Benjamin

Especificar un atributo flexible para el contenedor funcionó para mí:

.container {
    flex: 0 0 auto;
}

Esto asegura que la altura esté establecida y que tampoco crezca.

huseyin39 avatar Nov 05 '2019 21:11 huseyin39

Para Mobile Safari hay una solución para el navegador. necesitas agregar -webkit-box para dispositivos iOS.

Ex.

display: flex;
display: -webkit-box;
flex-direction: column;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-webkit-flex-direction: column;
align-items: stretch;

Si está utilizando align-items: stretch;la propiedad para el elemento principal, elimine la height : 100%del elemento secundario.

Nara avatar Nov 01 '2018 10:11 Nara