Flexbox: 4 artículos por fila

260

Estoy usando un cuadro flexible para mostrar 8 elementos que cambiarán de tamaño dinámicamente con mi página. ¿Cómo lo obligo a dividir los elementos en dos filas? (4 por fila)?

Aquí hay un recorte relevante:

(O si prefiere jsfiddle - http://jsfiddle.net/vivmaha/oq6prk1p/2/ )

.parent-wrapper {
  height: 100%;
  width: 100%;
  border: 1px solid black;
}
.parent {
  display: flex;
  font-size: 0;
  flex-wrap: wrap;
  margin: -10px 0 0 -10px;
}
.child {
  display: inline-block;
  background: blue;
  margin: 10px 0 0 10px;
  flex-grow: 1;
  height: 100px;
}
<body>
  <div class="parent-wrapper">
    <div class="parent">
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
    </div>
  </div>
</body>

Vivek Maharajh
fuente
16
[Actualización] Esta pregunta se basó en un diseño pobre que no responde. Si te encuentras usando una de las respuestas a continuación, ten cuidado. En un buen diseño, tendría más elementos en pantallas más anchas y menos en pantallas más pequeñas. Forzar 4 elementos para todos los tamaños de pantalla solo se verá atractivo en un rango estrecho de anchos de pantalla.
Vivek Maharajh

Respuestas:

382

Tienes flex-wrap: wrapen el contenedor. Eso es bueno, porque anula el valor predeterminado, que es nowrap( fuente ). Esta es la razón por la cual los elementos no se ajustan para formar una cuadrícula en algunos casos .

En este caso, el problema principal está flex-grow: 1en los elementos flexibles.

La flex-growpropiedad en realidad no dimensiona elementos flexibles. Su tarea es distribuir espacio libre en el contenedor ( fuente ). Entonces, no importa cuán pequeño sea el tamaño de la pantalla, cada elemento recibirá una parte proporcional del espacio libre en la línea.

Más específicamente, hay ocho artículos flexibles en su contenedor. Con flex-grow: 1, cada uno recibe 1/8 del espacio libre en la línea. Dado que no hay contenido en sus elementos, pueden reducirse a un ancho cero y nunca se ajustarán.

La solución es definir un ancho en los artículos. Prueba esto:

.parent {
  display: flex;
  flex-wrap: wrap;
}

.child {
  flex: 1 0 21%; /* explanation below */
  margin: 5px;
  height: 100px;
  background-color: blue;
}
<div class="parent">
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
</div>

Con la flex-grow: 1definición flexabreviada, no es necesario flex-basisser del 25%, lo que en realidad daría como resultado tres elementos por fila debido a los márgenes.

Como flex-growconsumirá espacio libre en la fila, flex-basissolo necesita ser lo suficientemente grande como para forzar un ajuste. En este caso, con flex-basis: 21%, hay mucho espacio para los márgenes, pero nunca suficiente espacio para un quinto elemento.

Michael Benjamin
fuente
1
Me gusta esto porque funcionó para mí, pero "mucho espacio" me hace sentir un poco incómodo. ¿Hay alguna pequeña ventana o situación en la que esta "estimación" podría fallarme?
Jackson
1
¿Qué tipo de situación? En la mayoría de los diseños hay casos extremos que pueden crear problemas. Tales casos normalmente pasan por análisis de costo-beneficio porque nunca, o casi nunca, ocurren. Por ejemplo, en la solución anterior, si coloca márgenes muy grandes, el diseño puede romperse. Si eso es un problema, entonces debe publicarse en la pregunta. @Jackson
Michael Benjamin
2
“Si coloca márgenes muy grandes, el diseño puede romperse”. Ese es un ejemplo de un escenario que me gustaría evitar. No me importa lo práctico; entretener mi adoración por la perfección. ¿Hay alguna manera de ser más exacto?
Jackson
27
También puedes usarflex: 1 0 calc(25% - 10px);
MarkG
2
¡Gran respuesta! Una pequeña mejora que uso es en margin: 2%;lugar de un número de píxel fijo para evitar que los cuadros salten a una nueva línea en dispositivos pequeños / resoluciones. la fórmula general es (100 - (4 * box-width-percent)) / 8% para diferentes anchos de caja
thomaspsk
104

Agregue un ancho a los .childelementos. Personalmente, usaría porcentajes en el margin-leftsi desea tenerlo siempre 4 por fila.

MANIFESTACIÓN

.child {
    display: inline-block;
    background: blue;
    margin: 10px 0 0 2%;
    flex-grow: 1;
    height: 100px;
    width: calc(100% * (1/4) - 10px - 1px);
}
dowomenfart
fuente
Buena idea. Usé esta idea con ediciones menores. jsfiddle.net/vivmaha/oq6prk1p/6
Vivek Maharajh
1
Ah Esto en realidad no resuelve mi problema. Vea aquí un ejemplo: jsfiddle.net/vivmaha/oq6prk1p/7 . No tengo la libertad de usar porcentajes para mi margen. Deben ser de ancho fijo. Esto significa que el 23% mágico que elegimos no funcionará, ya que no tiene en cuenta el margen fijo.
Vivek Maharajh
3
¡Sí, calc lo resuelve! 'calc (100% * (1/4) - 10px - 1px)'. Ver jsfiddle.net/vivmaha/oq6prk1p/9
Vivek Maharajh
24
Entonces, ¿de qué sirve flex en esto, todavía?
veces el
¿Qué pasa con el diseño receptivo? No queremos poner un ancho fijo en el niño
velajack
40

Aquí hay otro apporach.

También puedes lograrlo de esta manera:

.parent{
  display: flex;
  flex-wrap: wrap;
}

.child{
  width: 25%;
  box-sizing: border-box;
}

Muestra: https://codepen.io/capynet/pen/WOPBBm

Y una muestra más completa: https://codepen.io/capynet/pen/JyYaba

Capy
fuente
1
¿Qué pasa si tengo menos de 4 hijos? No me gusta ese espacio vacío en blanco, el niño no responde ...
Vela el
La otra respuesta de Muddasir Abbas usa solo configuraciones flexibles, así que creo que es una solución más limpia.
Andrew Koster
17

Lo haría así usando márgenes negativos y cálculo para las canaletas:

.parent {
  display: flex;
  flex-wrap: wrap;
  margin-top: -10px;
  margin-left: -10px;
}

.child {
  width: calc(25% - 10px);
  margin-left: 10px;
  margin-top: 10px;
}

Demostración: https://jsfiddle.net/9j2rvom4/


Método alternativo de cuadrícula CSS:

.parent {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-column-gap: 10px;
  grid-row-gap: 10px;
}

Demostración: https://jsfiddle.net/jc2utfs3/

shanomurphy
fuente
14
<style type="text/css">
.parent{
    display: flex;
    flex-wrap: wrap;
}
.parent .child{
    flex: 1 1 25%;
}
</style>    
<div class="parent">
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
    </div>

Espero eso ayude. para más detalles puedes seguir este enlace

Muddasir Abbas
fuente
4

Creo que este ejemplo es más básico y más fácil de entender que @dowomenfart.

.child {
    display: inline-block;
    margin: 0 1em;
    flex-grow: 1;
    width: calc(25% - 2em);
}

Esto logra los mismos cálculos de ancho mientras se corta directamente a la carne. La matemática es mucho más fácil y emes el nuevo estándar debido a su escalabilidad y facilidad de uso móvil.

Joseph Cho
fuente
3
em no es realmente el nuevo estándar. Puede ser una molestia, y los diseñadores no diseñan con EM en mente.
Danny van Holten
2

.parent-wrapper {
	height: 100%;
	width: 100%;
	border: 1px solid black;
}
	.parent {
	display: flex;
	font-size: 0;
	flex-wrap: wrap;
	margin-right: -10px;
	margin-bottom: -10px;
}
	.child {
	background: blue;
	height: 100px;
	flex-grow: 1;
	flex-shrink: 0;
	flex-basis: calc(25% - 10px);
}
	.child:nth-child(even) {
	margin: 0 10px 10px 10px;
	background-color: lime;
}
	.child:nth-child(odd) {
	background-color: orange; 
}
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
	<style type="text/css">

	</style>
</head>
<body>
  <div class="parent-wrapper">
    <div class="parent">
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
      <div class="child"></div>
    </div>
  </div>
</body>
</html>

;)

Mateus Manosso Barszcz
fuente
1
Si puede, agregue algún contexto sobre por qué esto responde a la pregunta de OP en lugar de solo publicar código.
d219
si agrega justify-content: space-evenly;al prent, entonces se alinean muy bien y no tiene que hacer lo mismo calccon el niño. Gracias por el ejemplo, sin embargo!
Mattijs
0

Flex wrap + margen negativo

¿Por qué la flexión frente display: inline-block?

¿Por qué margen negativo?

O usa SCSS o CSS-in-JS para los casos de borde (es decir, el primer elemento en la columna), o establece un margen predeterminado y luego elimina el margen exterior.

Implementación

https://codepen.io/zurfyx/pen/BaBWpja

<div class="outerContainer">
    <div class="container">
        <div class="elementContainer">
            <div class="element">
            </div>
        </div>
        ...
    </div>
</div>
:root {
  --columns: 2;
  --betweenColumns: 20px; /* This value is doubled when no margin collapsing */
}

.outerContainer {
    overflow: hidden; /* Hide the negative margin */
}

.container {
    background-color: grey;
    display: flex;
    flex-wrap: wrap;
    margin: calc(-1 * var(--betweenColumns));
}

.elementContainer {
    display: flex; /* To prevent margin collapsing */
    width: calc(1/var(--columns) * 100% - 2 * var(--betweenColumns));
    margin: var(--betweenColumns);
}

.element {
    display: flex;
    border: 1px solid red;
    background-color: yellow;
    width: 100%;
    height: 42px;
}
zurfyx
fuente
-12

Aquí hay otra forma sin usar calc().

// 4 PER ROW
// 100 divided by 4 is 25. Let's use 21% for width, and the remainder 4% for left & right margins...
.child {
  margin: 0 2% 0 2%;
  width: 21%;
}

// 3 PER ROW
// 100 divided by 3 is 33.3333... Let's use 30% for width, and remaining 3.3333% for sides (hint: 3.3333 / 2 = 1.66666)
.child {
  margin: 0 1.66666% 0 1.66666%;
  width: 30%;
}

// and so on!

Eso es todo al respecto. Puede obtener fantasía con las dimensiones para obtener tamaños más estéticos, pero esta es la idea.

wle8300
fuente
66
No he probado esto, pero la sintaxis de CSS es incorrecta (los valores de CSS no se citan y las declaraciones deben terminar en punto y coma), por lo que definitivamente no funcionará en su forma actual.
Nick F