flex-grow no dimensiona los elementos flex como se esperaba
Parece que el contenido dentro de un div flex afecta su tamaño calculado con respecto a la propiedad flex-grow
. Estoy haciendo algo mal?
En el violín proporcionado a continuación, verá un teclado numérico. Todas las filas contienen 3 números excepto la fila inferior. Esa fila debe tener el ' 0 ' ser el ancho de 2 números, por lo tanto flex-grow: 2
y el ':' (dos puntos) ser el tamaño de 1 número, por lo tanto flex-grow: 1
.
¿Me estoy perdiendo algo aquí?
El lado derecho del ' 0 ' debe estar alineado con el 8, 5, y 2 por encima de él. Es un poco raro.
.numbers {
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex-direction: row;
flex-grow: 1;
justify-content: space-between;
}
.button {
display: flex;
flex-grow: 1;
justify-content: center;
align-items: center;
margin: 5px;
border-radius: 5px;
border: 1px solid gray;
background: rgba(255, 255, 255, 0.2);
cursor: pointer;
}
.button#number0 {
flex-grow: 2;
}
.button#colon {
flex-grow: 1;
}
<div class="numbers">
<div class="row">
<div class="button number" id="number1">1</div>
<div class="button number" id="number2">2</div>
<div class="button number" id="number3">3</div>
</div>
<div class="row">
<div class="button number" id="number4">4</div>
<div class="button number" id="number5">5</div>
<div class="button number" id="number6">6</div>
</div>
<div class="row">
<div class="button number" id="number7">7</div>
<div class="button number" id="number8">8</div>
<div class="button number" id="number9">9</div>
</div>
<div class="row">
<div class="button number" id="number0">0</div>
<div class="button" id="colon">:</div>
</div>
</div>
5 answers
Parece que el contenido dentro de un div flex afecta su tamaño calculado con respecto a la propiedad
flex-grow
. Estoy haciendo algo mal?
El origen del problema no es el contenido dentro del elemento flex.
En el violín proporcionado a continuación, verá un teclado numérico. Todas las filas contienen 3 números excepto la fila inferior. Esa fila debe tener el ' 0 ' ser el ancho de 2 números, por lo tanto
flex-grow: 2
y el ':' ser el tamaño de 1 número, por lo tantoflex-grow: 1
. Soy yo falta algo aquí?
Sí. Su interpretación de la propiedad flex-grow
es incorrecta. flex-grow
no está destinado a definir el tamaño de un elemento flexible. Su trabajo es distribuir el espacio libre en el contenedor flex entre los elementos flex.
Al aplicar flex-grow: 1
a un grupo de elementos flexibles, les estás diciendo que distribuyan el espacio libre uniformemente entre ellos. Esta es la razón por la que, en su demostración, las filas uno, dos y tres tienen elementos flexibles del mismo tamaño.
Cuando solicitas flex-grow: 2
, estás decirle al elemento flexible que consuma el doble de espacio libre que los elementos con flex-grow: 1
. Esto no significa necesariamente que el artículo flex sea el doble del tamaño.
También, en su caso, incluso si flex-grow: 2
significaba el doble del tamaño, ¿cómo sabría incluir ese segundo margen de 10px de las filas anteriores a su cálculo de ancho (que sería necesario para lograr la alineación que desea)?
La razón por la que la alineación está desactivada en la fila cuatro es porque solo tiene una margen de 10px.
Notará que si elimina la regla de margen obtendrá la alineación deseada.
.numbers {
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex-direction: row;
flex-grow: 1;
justify-content: space-between;
}
.button {
display: flex;
flex-grow: 1;
justify-content: center;
align-items: center;
/* margin: 5px; */
border-radius: 5px;
border: 1px solid gray;
background: rgba(255, 255, 255, 0.2);
cursor: pointer;
}
.button#number0 {
flex-grow: 2;
}
.button#colon {
flex-grow: 1;
}
<div class="numbers">
<div class="row">
<div class="button number" id="number1">1</div>
<div class="button number" id="number2">2</div>
<div class="button number" id="number3">3</div>
</div>
<div class="row">
<div class="button number" id="number4">4</div>
<div class="button number" id="number5">5</div>
<div class="button number" id="number6">6</div>
</div>
<div class="row">
<div class="button number" id="number7">7</div>
<div class="button number" id="number8">8</div>
<div class="button number" id="number9">9</div>
</div>
<div class="row">
<div class="button number" id="number0">0</div>
<div class="button" id="colon">:</div>
</div>
</div>
Entonces, ¿qué pasa en la fila cuatro a ese segundo margen de 10px?
Es absorbido por los dos elementos flex.
Así es como
flex-grow
distribuye el espacio extra en la fila cuatro:
- Flex item left (con contenido "0") tiene
flex-grow: 2
. (.button#number0
en el código.)- Elemento flexible la derecha (con el contenido ":") tiene
flex-grow: 1
. (.button#colon
en el código.)- El segundo margen entre elementos, que aparece solo en filas con tres elementos flexibles, es de 10px de ancho. (El código dice 5px alrededor de cada elemento, pero en CSS márgenes horizontales nunca collapse . Además, en flexbox, no hay márgenes collapse .)
- La suma total de los valores
flex-grow
es tres. Dividamos 10px por 3. Ahora sabemos que la proporción de 1 es 3.33 px.- Por lo tanto, flex item left obtiene 6.66 px del espacio extra, y flex item right obtiene 3.33 px.
- Digamos que flex item left tenía
flex-grow: 3
en su lugar. Luego, el elemento flex izquierdo obtendría 7.5 px, y el elemento flex derecho obtendría 2.5 px.
La última parte de tu pregunta dice: {[31]]}
El lado derecho del '0' debe estar alineado con el 8, 5 y 2 por encima de él. Es un poco raro.
Debido a que flex-grow
no está directamente involucrado en el dimensionamiento de los artículos flex, necesitará otro método.
Intenta flex-basis
en su lugar. Esto parece funcionar:
.button { flex-basis: 33.33%; }
#number0 { flex-basis: calc(66.67% + 10px); }
.numbers {
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex-direction: row;
flex-grow: 1;
justify-content: space-between;
}
.button {
display: flex;
flex-basis: 33.33%;
justify-content: center;
align-items: center;
margin: 5px;
border-radius: 5px;
border: 1px solid gray;
background: rgba(255, 255, 255, 0.2);
cursor: pointer;
}
#number0 {
flex-basis: calc(66.67% + 10px);
}
<div class="numbers">
<div class="row">
<div class="button number" id="number1">1</div>
<div class="button number" id="number2">2</div>
<div class="button number" id="number3">3</div>
</div>
<div class="row">
<div class="button number" id="number4">4</div>
<div class="button number" id="number5">5</div>
<div class="button number" id="number6">6</div>
</div>
<div class="row">
<div class="button number" id="number7">7</div>
<div class="button number" id="number8">8</div>
<div class="button number" id="number9">9</div>
</div>
<div class="row">
<div class="button number" id="number0">0</div>
<div class="button" id="colon">:</div>
</div>
</div>
UPDATE
En respuesta a la retroalimentación en los comentarios, he hecho un ajuste al código anterior. Al agregar box-sizing: border-box
, se corrige una desalineación de 1-2px.
.button { flex-basis: 33.33%; box-sizing: border-box }
#number0 { flex-basis: calc(66.67% + 10px); }
.numbers {
display: flex;
flex-direction: column;
}
.row {
display: flex;
flex-direction: row;
flex-grow: 1;
justify-content: space-between;
}
.button {
display: flex;
flex-basis: 33.33%;
justify-content: center;
align-items: center;
margin: 5px;
border-radius: 5px;
border: 1px solid gray;
background: rgba(255, 255, 255, 0.2);
cursor: pointer;
box-sizing: border-box;
}
#number0 {
flex-basis: calc(66.67% + 10px);
}
<div class="numbers">
<div class="row">
<div class="button number" id="number1">1</div>
<div class="button number" id="number2">2</div>
<div class="button number" id="number3">3</div>
</div>
<div class="row">
<div class="button number" id="number4">4</div>
<div class="button number" id="number5">5</div>
<div class="button number" id="number6">6</div>
</div>
<div class="row">
<div class="button number" id="number7">7</div>
<div class="button number" id="number8">8</div>
<div class="button number" id="number9">9</div>
</div>
<div class="row">
<div class="button number" id="number0">0</div>
<div class="button" id="colon">:</div>
</div>
</div>
JSFIDDLE
Referencias:
-
flex-grow
definición ~ MDN -
flex-basis
definición ~ MDN - 7.2 Componentes de la flexibilidad ~ W3C
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-18 21:10:34
Actualizar 3:
Descubrí otra manera de deshacerme de la desalineación.
Esta versión, junto con la actualización 2:nd, funciona con el html original intacto, y está utilizando pseudo elementos para crear los botones, efectos de botón hover/click incluidos.
flex
solo versión
.row {
width: 60%;
margin: auto;
display: flex;
}
.button {
flex: 0 0 33.3%;
text-align: center;
position: relative;
padding: 10px 5px;
box-sizing: border-box;
pointer-events: none;
}
.button#number0 {
flex: 0 0 66.6%;
}
.button:before,
.button:after {
content: " ";
border-radius: 5px;
border: 1px solid gray;
cursor: pointer;
position: absolute;
left: 5px;
top: 5px;
right: 5px;
bottom: 5px;
pointer-events: auto;
}
.button:before {
background: rgba(255, 255, 255, 0.9);
z-index: -1
}
.button:hover:before {
background: rgba(0, 0, 0, 0.1);
}
.button:hover:after {
border: 2px solid red;
}
.button:active:before {
background: rgba(255, 0, 0, 0.5);
}
<div class="numbers">
<div class="row">
<div class="button number" id="number1">1</div>
<div class="button number" id="number2">2</div>
<div class="button number" id="number3">3</div>
</div>
<div class="row">
<div class="button number" id="number4">4</div>
<div class="button number" id="number5">5</div>
<div class="button number" id="number6">6</div>
</div>
<div class="row">
<div class="button number" id="number7">7</div>
<div class="button number" id="number8">8</div>
<div class="button number" id="number9">9</div>
</div>
<div class="row">
<div class="button number" id="number0">0</div>
<div class="button" id="colon">:</div>
</div>
</div>
flex
versión con una alternativa display: table
para navegadores que no soporta el nuevo flexbox modelo.
.row {
display: table; /* remove for flex only */
width: 60%;
margin: auto;
display: flex;
}
.button {
display:table-cell; /* remove for flex only */
width: 33.3%; /* remove for flex only */
flex: 0 0 33.3%;
text-align: center;
position: relative;
padding: 10px 5px;
box-sizing: border-box;
pointer-events: none;
}
.button#number0 {
width: 66.6%; /* remove for flex only */
flex: 0 0 66.6%;
}
.button:before,
.button:after {
content: " ";
border-radius: 5px;
border: 1px solid gray;
cursor: pointer;
position: absolute;
left: 5px;
top: 5px;
right: 5px;
bottom: 5px;
pointer-events: auto;
}
.button:before {
background: rgba(255, 255, 255, 0.9);
z-index: -1
}
.button:hover:before {
background: rgba(0, 0, 0, 0.1);
}
.button:hover:after {
border: 2px solid red;
}
.button:active:before {
background: rgba(255, 0, 0, 0.5);
}
<div class="numbers">
<div class="row">
<div class="button number" id="number1">1</div>
<div class="button number" id="number2">2</div>
<div class="button number" id="number3">3</div>
</div>
<div class="row">
<div class="button number" id="number4">4</div>
<div class="button number" id="number5">5</div>
<div class="button number" id="number6">6</div>
</div>
<div class="row">
<div class="button number" id="number7">7</div>
<div class="button number" id="number8">8</div>
<div class="button number" id="number9">9</div>
</div>
<div class="row">
<div class="button number" id="number0">0</div>
<div class="button" id="colon">:</div>
</div>
</div>
Actualizar 2:
Además de la respuesta de Michael_B, que por cierto tiene una muy buena explicación, está aquí una versión actualizada, que en realidad da la alineación deseada sin el, en este caso, 1-2 px apagado.
Aquí hay una muestra fiddle , y una imagen , de las versiones mía y Michael_B, donde el borde se ha aumentado un poco para que sea más fácil ver el desalineación.
Todo se reduce a cómo flexbox calcula los tamaños cuando border
/padding
está presente, que puede leer más en este post, donde box-sizing: border-box
necesita ser configurado junto con algunos ajustes más, que se comenta en el código.
Aquí está mi violín y fragmento
.row {
display: flex;
width: calc(100% - 30px); /* 30px = the sum of the buttons margin: 5px
to avoid horizontal scroll */
}
.button {
display: flex;
flex-basis: 33.33%;
flex-shrink: 0; /* we need flex-grow/shrink to be 1/0 to make
it calculate the size properly */
box-sizing: border-box; /* to take out the borders when calculate the
flex shrink/grow factor */
justify-content: center;
align-items: center;
margin: 5px;
border-radius: 5px;
border: 1px solid gray;
background: rgba(0, 0, 0, 0.1);
cursor: pointer;
}
#number0 {
flex-basis: calc(66.66% + 10px);
}
<div class="numbers">
<div class="row">
<div class="button number" id="number1">1</div>
<div class="button number" id="number2">2</div>
<div class="button number" id="number3">3</div>
</div>
<div class="row">
<div class="button number" id="number4">4</div>
<div class="button number" id="number5">5</div>
<div class="button number" id="number6">6</div>
</div>
<div class="row">
<div class="button number" id="number7">7</div>
<div class="button number" id="number8">8</div>
<div class="button number" id="number9">9</div>
</div>
<div class="row">
<div class="button number" id="number0">0</div>
<div class="button" id="colon">:</div>
</div>
</div>
Actualizar:
flex
solo versión, con un cambio menor de la estructura html existente, usando pseudo elementos.
.row {
display: flex;
}
.button {
flex: 0 0 33.3%;
}
.button:after {
content: attr(data-nr);
display: block;
border-radius: 5px;
border: 1px solid gray;
background: rgba(255, 255, 255, 0.9);
text-align: center;
padding: 3px;
margin: 5px;
cursor: pointer;
}
.button#number0 {
flex: 0 0 66.6%;
}
<div class="numbers">
<div class="row">
<div class="button number" id="number1" data-nr="1"></div>
<div class="button number" id="number2" data-nr="2"></div>
<div class="button number" id="number3" data-nr="3"></div>
</div>
<div class="row">
<div class="button number" id="number4" data-nr="4"></div>
<div class="button number" id="number5" data-nr="5"></div>
<div class="button number" id="number6" data-nr="6"></div>
</div>
<div class="row">
<div class="button number" id="number7" data-nr="7"></div>
<div class="button number" id="number8" data-nr="8"></div>
<div class="button number" id="number9" data-nr="9"></div>
</div>
<div class="row">
<div class="button number" id="number0" data-nr="0"></div>
<div class="button" id="colon" data-nr=":"></div>
</div>
</div>
flex
versión, con un cambio menor de la estructura html existente, usando pseudo elementos, y tiene una alternativa display: table
para navegadores que no soporta el nuevo modelo flexbox (como IE8/9).
.row {
display: table;
width: 100%;
}
.button {
display: table-cell;
width: 33.3%;
padding: 5px;
}
.button:after {
content: attr(data-nr);
display: block;
border-radius: 5px;
border: 1px solid gray;
background: rgba(255, 255, 255, 0.9);
text-align: center;
padding: 3px;
cursor: pointer;
}
.button#number0 {
width: 66.6%;
}
@supports (display: flex) {
.row {
display: flex;
}
.button {
display: block;
width: auto;
flex: 0 0 33.3%;
padding: 0;
}
.button#number0 {
flex: 0 0 66.6%;
}
.button:after {
margin: 5px;
}
}
<div class="numbers">
<div class="row">
<div class="button number" id="number1" data-nr="1"></div>
<div class="button number" id="number2" data-nr="2"></div>
<div class="button number" id="number3" data-nr="3"></div>
</div>
<div class="row">
<div class="button number" id="number4" data-nr="4"></div>
<div class="button number" id="number5" data-nr="5"></div>
<div class="button number" id="number6" data-nr="6"></div>
</div>
<div class="row">
<div class="button number" id="number7" data-nr="7"></div>
<div class="button number" id="number8" data-nr="8"></div>
<div class="button number" id="number9" data-nr="9"></div>
</div>
<div class="row">
<div class="button number" id="number0" data-nr="0"></div>
<div class="button" id="colon" data-nr=":"></div>
</div>
</div>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:09:56
Creo que todo lo que Michael_B dijo es correcto. Solo las soluciones son un poco incómodas. Personalmente no me gusta Calc. Simplemente no se siente bien.
El problema que tienes es más general. Pones demasiadas responsabilidades en un elemento. En este caso es la clase .button
. Flex y margen con flex-grow es demasiada responsabilidad. Trata de romper eso. Significa más elementos DOM, pero te ahorra mucho dolor.
.numbers {
display: flex;
flex-direction: column;
max-width: 200px;
margin: 0 auto;
}
.row {
display: flex;
flex-direction: row;
flex-grow: 1;
justify-content: space-between;
}
.row > .box {
display: flex;
flex-basis: 33.3333%;
justify-content: center;
align-items: center;
}
.row > .box.box-2 {
flex-basis: 66.6667%;
}
.button {
border-radius: 5px;
border: 1px solid gray;
background: rgba(255, 255, 255, 0.2);
cursor: pointer;
width: auto;
text-align: center;
margin: 5px;
width: 100%;
}
<div class="numbers">
<div class="row">
<div class="box"><div class="button number" id="number1">1</div></div>
<div class="box"><div class="button number" id="number2">2</div></div>
<div class="box"><div class="button number" id="number3">3</div></div>
</div>
<div class="row">
<div class="box"><div class="button number" id="number4">4</div></div>
<div class="box"><div class="button number" id="number5">5</div></div>
<div class="box"><div class="button number" id="number6">6</div></div>
</div>
<div class="row">
<div class="box"><div class="button number" id="number7">7</div></div>
<div class="box"><div class="button number" id="number8">8</div></div>
<div class="box"><div class="button number" id="number9">9</div></div>
</div>
<div class="row">
<div class="box box-2"><div class="button number" id="number0">0</div></div>
<div class="box"><div class="button" id="colon">:</div></div>
</div>
</div>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-13 11:16:31
Flexbox no responde bien a los márgenes, en mi opinión.
El mejor enfoque / solución que prefiero es asegurarme de que todos los hijos flex tengan márgenes 0, establecer el contenedor flex en justify-content: space-between;
y luego dar a los hijos un ancho total inferior al 100%. El resto será su margen.
En otras palabras, si desea dos elementos por fila, establezca cada uno en un 49% de ancho y tendrá un 2% de espacio entre ellos. Tres elementos, cada uno con un 32% de ancho y tendrás un 2% entre ellos. En la calculadora por ejemplo, la celda 0
debe tener un 66% de ancho y el resto un 32%.
Editar: Tenga en cuenta que debido a las razones (es decir, que content-box
es terrible), si alguno de sus hijos tienen fronteras, necesitará usar box-sizing: border-box
para que mi sugerencia funcione correctamente.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-22 05:44:01
Es importante utilizar la abreviatura para dar cabida a la compatibilidad entre navegadores:
.row {
display: flex;
flex-direction: row; /* <-- this is the default so unnecessary to state */
flex-grow: 1;
justify-content: space-between;
}
.button {
display: flex;
/* flex-grow: 1; replace with shorthand */
flex:1 0 100%; /* probably making the "width: 100%;" unnecessary */
justify-content: center;
}
.button#number0 {
/* flex-grow: 2; replace with shorthand */
flex:2 0 100%;
}
.button#colon {
/* flex-grow: 1; replace with shorthand */
flex:1 0 100%;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-21 07:10:01