Chrome/Safari no llena el 100% de la altura del padre flexible
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 .container
contiene 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).
- ¿Hay alguna solución para este problema?
- ¿O existe una técnica diferente para hacer que todos
.item
llenen 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>
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: flex
al 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: stretch
llegada del padre. Para que el stretch
valor 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
height
propiedadporcentaje
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 comoauto
.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 – .item
– no tiene una altura definida. Webkit ve esto como un eslabón perdido.
.item-inner
le dice a Chrome: dameheight: 100%
. .item
Chrome busca referencia en el padre ( ) y responde: ¿100% de qué? No veo nada (ignorando la flex: 1
regla 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-grow
como referencia principal adecuada si se usa junto conflex-basis
(cualquier valor numérico funciona ( auto
no 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-height
y max-height
no son aceptables. Debe ser la height
propiedad.
Más detalles aquí: Trabajar con la height
propiedad CSS y valores porcentuales
2. Posicionamiento relativo y absoluto de CSS
Se aplica position: relative
a los padres y position: absolute
al 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 .item
o .item-inner
o ambos? Aunque button
los elementos a veces fallan como contenedores flexibles , pueden ser elementos flexibles. Considere convertir o button
en 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: flex
al 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: stretch
llegada del padre. Para que el stretch
valor 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
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.
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.