Solución
Use contenedores flexibles anidados.
Deshágase de las alturas porcentuales. Deshágase de las propiedades de la tabla. Deshacerse de vertical-align
. Evitar el posicionamiento absoluto. Solo quédate con flexbox hasta el final.
Aplique display: flex
al elemento flexible ( .item
), convirtiéndolo en un contenedor flexible. Esto se establece automáticamente align-items: stretch
, lo que le dice al niño ( .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 (p height: 100%
. Ej. ), Ignorará la align-items: stretch
llegada del padre. Para que el stretch
valor predeterminado funcione, la altura del niño debe calcular auto
(explicación completa ).
Pruebe esto (sin cambios en HTML):
.container {
display: flex;
flex-direction: column;
height: 20em;
border: 5px solid black
}
.item {
display: flex; /* new; nested flex container */
flex: 1;
border-bottom: 1px solid white;
}
.item-inner {
display: flex; /* new; nested flex container */
flex: 1; /* new */
/* height: 100%; <-- remove; unnecessary */
/* width: 100%; <-- remove; unnecessary */
/* display: table; <-- remove; unnecessary */
}
a {
display: flex; /* new; nested flex container */
flex: 1; /* new */
align-items: center; /* new; vertically center text */
background: orange;
/* display: table-cell; <-- remove; unnecessary */
/* vertical-align: middle; <-- remove; unnecessary */
}
<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>
jsFiddle demo
Explicación
Mi problema es que .item-inner { height: 100% }
no funciona en webkit (Chrome).
No funciona porque está utilizando 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
propiedad
porcentaje
Especifica un porcentaje de altura. El porcentaje se calcula con respecto a la altura del bloque que contiene la caja generada. 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 en auto
.
auto
La altura depende de los valores de otras propiedades.
En otras palabras, para que la altura porcentual funcione en un elemento secundario en flujo, el elemento primario debe tener una altura establecida.
En su código, el contenedor de nivel superior tiene una altura definida: .container { height: 20em; }
El contenedor de tercer nivel tiene una altura definida: .item-inner { height: 100%; }
Pero entre ellos, el contenedor de segundo nivel .item
- no tiene una altura definida. Webkit lo ve como un eslabón perdido.
.item-inner
le está diciendo a Chrome: dameheight: 100%
. Chrome mira al padre ( .item
) como referencia y responde: ¿ 100% de qué? No veo nada (ignorando la flex: 1
regla que está allí). Como resultado, se aplica height: auto
(altura de contenido), de acuerdo con la especificación.
Firefox, por otro lado, ahora acepta la altura flexible de un padre como referencia para la altura porcentual 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
). Al escribir estas líneas, sin embargo, esta solución falla en Safari.
#outer {
display: flex;
flex-direction: column;
height: 300px;
background-color: white;
border: 1px solid red;
}
#middle {
flex-grow: 1;
flex-basis: 1px;
background-color: yellow;
}
#inner {
height: 100%;
background-color: lightgreen;
}
<div id="outer">
<div id="middle">
<div id="inner">
INNER
</div>
</div>
</div>
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 la falta de 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 los valores de porcentaje
2. Posicionamiento relativo y absoluto de CSS
Aplicar position: relative
a los padres y position: absolute
al niño.
Tamaño del niño con height: 100%
y width: 100%
, o utilizar las propiedades de desplazamiento: top: 0
, right: 0
, bottom: 0
, left: 0
.
Con posicionamiento absoluto, la altura porcentual funciona sin una altura especificada en el padre.
3. Eliminar contenedores HTML innecesarios (recomendado)
¿Hay necesidad de dos contenedores alrededor button
? ¿Por qué no eliminar .item
o .item-inner
, o ambos? Aunque los button
elementos a veces fallan como contenedores flexibles , pueden ser elementos flexibles. Considere crear button
un hijo de .container
o .item
y eliminar el marcado gratuito.
Aquí hay un ejemplo:
.container {
height: 20em;
display: flex;
flex-direction: column;
border: 5px solid black
}
a {
flex: 1;
background: orange;
border-bottom: 1px solid white;
display: flex; /* nested flex container (for aligning text) */
align-items: center; /* center text vertically */
justify-content: center; /* center text horizontally */
}
<div class="container">
<a>Button</a>
<a>Button</a>
<a>Button</a>
</div>
4. Contenedores flexibles anidados (recomendado)
Deshágase de las alturas porcentuales. Deshágase de las propiedades de la tabla. Deshacerse de vertical-align
. Evitar el posicionamiento absoluto. Solo quédate con flexbox hasta el final.
Aplique display: flex
al elemento flexible ( .item
), convirtiéndolo en un contenedor flexible. Esto se establece automáticamente align-items: stretch
, lo que le dice al niño ( .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 (p height: 100%
. Ej. ), Ignorará la align-items: stretch
llegada del padre. Para que el stretch
valor predeterminado funcione, la altura del niño debe calcular auto
(explicación completa ).
Pruebe esto (sin cambios en HTML):
.container {
display: flex;
flex-direction: column;
height: 20em;
border: 5px solid black
}
.item {
display: flex; /* new; nested flex container */
flex: 1;
border-bottom: 1px solid white;
}
.item-inner {
display: flex; /* new; nested flex container */
flex: 1; /* new */
/* height: 100%; <-- remove; unnecessary */
/* width: 100%; <-- remove; unnecessary */
/* display: table; <-- remove; unnecessary */
}
a {
display: flex; /* new; nested flex container */
flex: 1; /* new */
align-items: center; /* new; vertically center text */
background: orange;
/* display: table-cell; <-- remove; unnecessary */
/* vertical-align: middle; <-- remove; unnecessary */
}
<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>