guia end align html css css3 flexbox

html - end - flex-grow no dimensiona los elementos flex como se esperaba



flex-shrink (5)

Parece que el contenido dentro de un div flexible afecta su tamaño calculado con respecto a la propiedad flex-grow . ¿Estoy haciendo algo mal?

En el violín que se proporciona 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'' como el ancho de 2 números, por lo tanto, flex-grow: 2 y el '':'' (dos puntos) debe ser del tamaño de 1 número, por lo tanto, flex-grow: 1 .

¿Me estoy perdiendo de algo?

El lado derecho del ''0'' debe estar alineado con el 8, 5 y 2 sobre él. Está un poco apagado.

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

https://jsfiddle.net/0r4hemdu/


Análisis corto

El problema es que las filas 1-3 tienen dos márgenes horizontales y la fila 4 solo tiene uno.

Con márgenes horizontales de 10 px cada uno, la fila 4 tiene 10 px más espacio libre que las otras filas. Esto elimina la alineación de las columnas.

Debido flex-grow aplica solo al espacio libre y está fuertemente influenciado por el contenido y los márgenes, no es la forma más segura de dimensionar elementos flexibles.

Prueba flex-basis lugar. Agregue esto a su código:

.button { flex-basis: 33.33%; } #number0 { flex-basis: calc(66.67% + 10px); } * { box-sizing: border-box; }

.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); } * { box-sizing: border-box; }

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

Análisis extendido

Tu escribiste:

Parece que el contenido dentro de un div flexible afecta su tamaño calculado con respecto a la propiedad flex-grow ¿Estoy haciendo algo mal?

La fuente de su problema no es el contenido dentro del elemento flexible.

Tu escribiste:

En el violín que se proporciona 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 tanto, flex-grow: 1 . ¿Me estoy perdiendo de algo?

Si. Su interpretación de la propiedad flex-grow es incorrecta. flex-grow no está destinado a definir el tamaño de un elemento flex. Su trabajo es distribuir espacio libre en el contenedor flexible entre los artículos.

Al aplicar flex-grow: 1 a un grupo de elementos flex, les está diciendo que distribuyan el espacio libre de manera uniforme entre ellos. Por eso, en su demostración, las filas 1, 2 y 3 tienen elementos flexibles de igual tamaño.

Cuando aplica flex-grow: 2 , le está diciendo al elemento flex que consuma el doble de espacio libre que los elementos con flex-grow: 1 .

Pero, ¿dónde influye el segundo margen de 10 píxeles de las filas anteriores en el diseño de la fila 4?

La razón por la cual la alineación está desactivada en la fila 4 es que la fila 4 tiene un margen menos que las otras filas, lo que significa que la fila 4 tiene 10px más espacio libre que las otras filas.

Notarás que si eliminas la regla de margen obtienes 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é sucede en la fila cuatro a ese segundo margen de 10 píxeles?

Se absorbe por los dos elementos flexibles.

Así es como flex-grow distribuye el espacio extra en la fila cuatro:

  • El elemento flexible restante (con contenido "0") tiene flex-grow: 2 . ( .button#number0 en su código.)
  • El elemento de la derecha (con el contenido ":") tiene flex-grow: 1 . ( .button#colon en su código).
  • El segundo margen entre elementos, que aparece solo en filas con tres elementos flexibles, tiene 10 píxeles de ancho. (El código dice 5px alrededor de cada elemento, pero en CSS los márgenes horizontales nunca colapsan . Además, en flexbox, no se colapsa ningún margen ).
  • La suma total de los valores de flex-grow es tres. Entonces, dividamos 10 px por 3. Ahora sabemos que la proporción de 1 es 3.33 px.
  • Por lo tanto, el elemento flexible a la izquierda obtiene 6.66px del espacio extra, y el elemento flexible a la derecha obtiene 3.33px.
  • Digamos que el elemento flexible restante tenía flex-grow: 3 lugar. Luego, el elemento flexible a la izquierda obtendría 7.5px, y el elemento flexible a la derecha obtendría 2.5px.

La última parte de tu pregunta dice:

El lado derecho del ''0'' debe estar alineado con el 8, 5 y 2 sobre él. Está un poco apagado.

Debido flex-grow aplica solo al espacio libre y está fuertemente influenciado por el contenido y los márgenes, no es la forma más segura de dimensionar elementos flexibles.

Prueba flex-basis lugar. Agregue esto a su código:

.button { flex-basis: 33.33%; } #number0 { flex-basis: calc(66.67% + 10px); } * { box-sizing: border-box; }

.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); } * { box-sizing: border-box; }

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

Referencias

EXTRA: SOLUCIÓN GRID CSS

Con el advenimiento de CSS Grid, el código para todo este diseño se puede simplificar enormemente.

.numbers { display: grid; grid-template-columns: repeat(auto-fill, minmax(26%, 1fr)); grid-gap: 10px; } #number0 { grid-column: span 2; } /* non-essential decorative styles */ .button { display: flex; justify-content: center; align-items: center; border-radius: 5px; border: 1px solid gray; }

<div class="numbers"> <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 class="button number" id="number4">4</div> <div class="button number" id="number5">5</div> <div class="button number" id="number6">6</div> <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 class="button number" id="number0">0</div> <div class="button" id="colon">:</div> </div>


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 and Margin con flex-grow es demasiada responsabilidad. Intenta romper eso aparte. 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>


Es importante utilizar la taquigrafía para acomodar la compatibilidad con varios 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%; }


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 niños flexibles tengan márgenes 0, configure el contenedor flexible para justify-content: space-between; , y luego dé a los niños un ancho total inferior al 100%. El resto será su margen.

En otras palabras, si desea dos elementos por fila, defina cada uno al 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 el ejemplo de la calculadora, la celda 0 debe tener un 66% de ancho y el resto un 32%.

Editar: Tenga en cuenta que debido a razones (es decir, que content-box es terrible), si alguno de sus hijos tiene bordes, deberá usar box-sizing: border-box para que mi sugerencia funcione correctamente.

https://jsfiddle.net/r3L1mtbe/2/


Actualización 3:

Descubrí otra forma 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, incluidos los efectos de desplazamiento / clic del botón.

versión solo flex

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

versión flex con display: table respaldo para navegadores que no admite el nuevo modelo flexbox.

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

Actualización 2:

Además de la respuesta de Michael_B, que por cierto tiene una muy buena explicación, aquí hay una versión actualizada, que realmente proporciona la alineación deseada sin, en este caso, 1-2 px apagado.

Aquí hay una muestra de violín y una imagen de las versiones mías y Michael_B, donde el borde se ha aumentado un poco para que sea más fácil ver la desalineación.

Todo se reduce a cómo flexbox calcula los tamaños cuando está presente el border / padding , sobre el que puede leer más en esta publicación, donde se debe configurar el box-sizing: border-box junto con algunos ajustes más, que se comentan 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:

versión solo flex , con un cambio menor de la estructura html existente, utilizando 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>

versión flex , con un cambio menor de la estructura html existente, que utiliza pseudo elementos, y tiene una display: table respaldo de display: table para navegadores que no admite 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>