¿Cómo especificar saltos de línea en un diseño flexbox de varias líneas?

236

¿Hay alguna manera de hacer un salto de línea en flexbox de varias líneas?

Por ejemplo, para romper después de cada 3er elemento en este CodePen .

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  align-content: space-between;
  justify-content: space-between;
}
.item {
  width: 100px;
  height: 100px;
  background: gold;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px;
}
.item:nth-child(3n) {
  background: silver;
}
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>

Me gusta

.item:nth-child(3n){
  /* line-break: after; */    
}
Artem Svirskyi
fuente
1
Tuve el mismo problema o muy similar; Quería romper cada cuarto elemento, así que solo configuré el ancho de cada elemento flexible en 25vw (o 25%). Entonces, en su caso, por cada 3er artículo usaría 33.3vw (o 33.3%). Funcionó perfectamente para lo que quería. Podría ayudar a alguien más si está buscando un método más simple.
Ben Clarke
Ben Clarke! Muchas gracias! Tu respuesta es la única que funcionó. Podría considerar agregarlo como respuesta. :-)
itmuckel

Respuestas:

322

La solución más simple y confiable es insertar elementos flexibles en los lugares correctos. Si son lo suficientemente anchos ( width: 100%), forzarán un salto de línea.

Pero eso es feo y no semántico. En cambio, podríamos generar pseudoelementos dentro del contenedor flexible y usarlos orderpara moverlos a los lugares correctos.

Pero hay una limitación: el contenedor flexible solo puede tener un ::beforey un ::afterpseudo-elemento. Eso significa que solo puedes forzar 2 saltos de línea.

Para resolver eso, puede generar los pseudoelementos dentro de los elementos flexibles en lugar de en el contenedor flexible. De esta forma, no estará limitado a 2. Pero esos pseudoelementos no serán elementos flexibles, por lo que no podrán forzar saltos de línea.

Pero afortunadamente, se introdujo CSS Display L3display: contents (actualmente solo es compatible con Firefox 37):

El elemento en sí no genera ningún cuadro, pero sus elementos secundarios y pseudoelementos aún generan cuadros de forma normal. A los efectos de la generación y el diseño de la caja, el elemento debe tratarse como si hubiera sido reemplazado por sus elementos secundarios y pseudoelementos en el árbol de documentos.

Por lo tanto, puede aplicar display: contentsa los hijos del contenedor flexible y envolver el contenido de cada uno dentro de un contenedor adicional. Entonces, los elementos flexibles serán esos envoltorios adicionales y los pseudo-elementos de los niños.

Alternativamente, de acuerdo con Fragmenting Flex Layout y CSS Fragmentation , Flexbox permite interrupciones forzadas mediante el uso de break-before,break-after o sus alias CSS 2.1:

.item:nth-child(3n) {
  page-break-after: always; /* CSS 2.1 syntax */
  break-after: always; /* New syntax */
}

Los saltos de línea forzados en flexbox aún no son ampliamente compatibles, pero funciona en Firefox.

Oriol
fuente
@Oriol Sobre el primer enfoque, ¿por qué dices que es feo y no semántico? Sólo curioso.
nacho4d
18
@ nacho4d Porque el HTML no debe modificarse para propósitos de estilo. Y si cambia de opinión y decide que quiere 4 columnas en lugar de 3, necesitaría modificar tal vez mucho HTML. Compare con la break-aftersolución, que solo requeriría modificar un selector en la hoja de estilo.
Oriol
1
Necesitaba agregar display: block;a las .container ::beforey ::afterpseudo clases para hacer que la solución número dos funcione en IE. YMMV!
entrelazado el
1
@twined Eso es extraño, porque los elementos flexibles deben bloquearse automáticamente.
Oriol
2
Dado que el salto de página aparentemente se eliminó de la especificación, ¿es posible hacer que su segundo fragmento se ejecute en la dirección de la columna y no hacer que expanda la altura de su contenedor? No tuve suerte y establecer flex-base al 100% / artículos estira su altura.
Lucent
42

Desde mi perspectiva, es más semántico usar <hr> elementos como saltos de línea entre elementos flexibles.

.container {
  display: flex;
  flex-flow: wrap;
}

.container hr {
  width: 100%;
}
<div class="container">
  <div>1</div>
  <div>2</div>
  <hr>
  <div>3</div>
  <div>2</div>
  ...
</div>

Probado en Chrome 66, Firefox 60 y Safari 11.

Petr Stepanov
fuente
77
Así es como yo también lo hago, funciona muy bien. Agregar hr {base flexible: 100%; altura: 0; margen: 0; borde: 0; } hace que el descanso sea perfecto.
Besworks
Me gusta este enfoque. Nota: cuando se usa gap: 10px;la distancia entre filas es en realidad 20px. Para la dirección, especifique un hueco fila de la mitad de ese tamaño: gap: 5px 10px;.
CuddleBunny
@Besworks: borderdebe establecerse en none, en lugar de0
Mark
@mark, border:0;es tan válido como border:none;. Ver: stackoverflow.com/questions/2922909/…
Besworks el
23

@Oriol tiene una excelente respuesta, lamentablemente a partir de octubre de 2017, ninguno display:contents, ningunopage-break-after es ampliamente compatible, mejor dicho, se trata de Firefox que admite esto, pero no de los otros jugadores, se me ocurrió el siguiente "truco" que considero mejor que difícil codificar en un descanso después de cada tercer elemento, porque eso hará que sea muy difícil hacer que la página sea amigable para dispositivos móviles.

Como se dijo, es un truco y el inconveniente es que debe agregar una gran cantidad de elementos adicionales para nada, pero funciona y funciona en varios navegadores incluso en el IE11 con fecha.

El "truco" es simplemente agregar un elemento adicional después de cada div, que se establece en display:noney luego usa el CSS nth-childpara decidir cuál de estos debe hacerse visible forzando un freno de línea como este:

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
}
.item {
  width: 100px;
  background: gold;
  height: 100px;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px
}
.item:nth-child(3n-1) {
  background: silver;
}
.breaker {display:none;}
.breaker:nth-child(3n) {
  display:block;
  width:100%;
  height:0;
 }
<div class="container">
  <div class="item">1</div><p class=breaker></p>
  <div class="item">2</div><p class=breaker></p>
  <div class="item">3</div><p class=breaker></p>
  <div class="item">4</div><p class=breaker></p>
  <div class="item">5</div><p class=breaker></p>
  <div class="item">6</div><p class=breaker></p>
  <div class="item">7</div><p class=breaker></p>
  <div class="item">8</div><p class=breaker></p>
  <div class="item">9</div><p class=breaker></p>
  <div class="item">10</div><p class=breaker></p>
</div>

Emil Borconi
fuente
2
También descubrí que los métodos "display: contenido" y "salto de página después" no funcionan, y recurrí a este "hack". Esto se informó como un error de Chrome y se marcó como "WontFix" (consulte bugs.chromium.org/p/chromium/issues/detail?id=473481 ) con la explicación: "Según el Grupo de trabajo de CSS, no hay forma actual de forzar un salto de línea en un cuadro flexible con CSS ".
Martin_W
Puede guardar un toque de desorden utilizando el selector .container>p. Entonces todas esas <p></p>etiquetas no necesitarían el classatributo. No es importante, por supuesto. Solo mi cerebro perezoso encuentra un pequeño y ahorrador espacio para su solución inteligente. Por supuesto, también se basa en que el usuario no tenga otras <p>etiquetas como hijos directos del .containerdiv. Técnicamente, podrías hacer lo mismo con todos los demás <div>niños, pero es mucho más probable que tengas otros <div>s en .containertu vida <p>, así que probablemente no sea un movimiento inteligente allí.
Steve
13

¿Quieres un salto de línea semántico?

Entonces considere usar <br>. W3Schools puede sugerirle que BRes solo para escribir poemas (el mío vendrá pronto) pero puede cambiar el estilo para que se comporte como un elemento de bloque de 100% de ancho que empujará su contenido a la siguiente línea. Si 'br' sugiere un descanso, entonces me parece más apropiado que usar hro un 100%div y hace que el html sea más legible.

Inserte el lugar <br>donde necesita los saltos de línea y asígnele un estilo como este.

 // Use `>` to avoid styling `<br>` inside your boxes 
 .container > br 
 {
    width: 100%;
    content: '';
 }

Se puede desactivar <br>con preguntas de los medios , mediante el establecimiento display:de blockonone en su caso (he incluido un ejemplo de esto, pero lo dejó comentada).

Puedes usar order: para establecer el orden si es necesario también.

Y puedes poner tantos como quieras, con diferentes clases o nombres :-)

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  justify-content: space-between;
}
.item {
  width: 100px;
  background: gold;
  height: 100px;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px
}

.container > br
{
  width: 100%;
  content: '';
}

// .linebreak1 
// { 
//    display: none;
// }

// @media (min-width: 768px) 
// {
//    .linebreak1
//    {
//       display: block;
//    }
// }
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <br class="linebreak1"/>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>


No es necesario limitarse a lo que dice W3Schools:

ingrese la descripción de la imagen aquí

Simon_Weaver
fuente
Una extensión de la técnica es colocar <br class="2col">después de cada segundo elemento, <br class="3col">después de cada tercero. Luego aplique una clase cols-2al contenedor y cree css para habilitar solo los saltos de línea apropiados para ese número de columnas. p.ej. br { display: none; } .cols-2 br.2col { display: block; }
Simon_Weaver
No, a brno es para elementos de salto de línea , es para texto : developer.mozilla.org/en-US/docs/Web/HTML/Element/br ... stackoverflow.com/questions/3937515/…
Ason
2
Cambiaré mi redacción para no presentar esto como una solución perfecta, pero en algunos casos no veo esto peor que otras soluciones de div o pseudoelementos. Tal vez iré a escribir un poema sobre eso ahora.
Simon_Weaver
Sí ... un poema sería bueno, no olvides publicar un enlace aquí :) ... En cuanto a una solución perfecta, hay una (que se break-*muestra en la respuesta aceptada) aunque desafortunadamente aún no ha llegado a los navegadores cruzados , por lo que la segunda mejor opción es utilizar un elemento que llene de forma nativa el ancho de su elemento primario y empuje a los siguientes hermanos a una fila de sí mismos, que nuevamente se da en la respuesta aceptada. Por lo tanto, usar cualquier otro elemento que no sea un bloque como uno sería peor, semánticamente, como el br.
Ason
55
Recuerde, usted publica una impresión de W3Schools, no W3C, no están conectados.
Edu Ruiz
7

Creo que la forma tradicional es flexible y bastante fácil de entender:

Margen

<div class="flex-grid">
    <div class="col-4">.col-4</div>
    <div class="col-4">.col-4</div>
    <div class="col-4">.col-4</div>

    <div class="col-4">.col-4</div>
    <div class="col-4">.col-4</div>
    <div class="col-4">.col-4</div>

    <div class="col-3">.col-3</div>
    <div class="col-9">.col-9</div>

    <div class="col-6">.col-6</div>
    <div class="col-6">.col-6</div>
</div>

Crear archivo grid.css :

.flex-grid {
  display: flex;
  flex-flow: wrap;
}

.col-1 {flex: 0 0 8.3333%}
.col-2 {flex: 0 0 16.6666%}
.col-3 {flex: 0 0 25%}
.col-4 {flex: 0 0 33.3333%}
.col-5 {flex: 0 0 41.6666%}
.col-6 {flex: 0 0 50%}
.col-7 {flex: 0 0 58.3333%}
.col-8 {flex: 0 0 66.6666%}
.col-9 {flex: 0 0 75%}
.col-10 {flex: 0 0 83.3333%}
.col-11 {flex: 0 0 91.6666%}
.col-12 {flex: 0 0 100%}

[class*="col-"] {
  margin: 0 0 10px 0;

  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

@media (max-width: 400px) {
  .flex-grid {
    display: block;
  }
}

He creado un ejemplo (jsfiddle)

Intenta cambiar el tamaño de la ventana por debajo de 400 px, ¡responde!

Moshe Quantz
fuente
En esta solución, los elementos están juntos, la idea es tener un largo espacio en blanco entre ellos.
Juanma Menéndez
2

Otra posible solución que no requiere agregar ningún marcado adicional es agregar un margen dinámico para separar los elementos.

En el caso del ejemplo, esto se puede hacer con la ayuda de calc(), simplemente agregando margin-lefty margin-rightal elemento 3n + 2 (2, 5, 8)

.item:nth-child(3n+2) {
  background: silver;
  margin: 10px calc(50% - 175px);
}

Ejemplo de fragmento

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  align-content: space-between;
  justify-content: space-between;
}
.item {
  width: 100px;
  height: 100px;
  background: gold;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px;
}
.item:nth-child(3n+2) {
  background: silver;
  margin: 10px calc(50% - 175px);
}
<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
  <div class="item">4</div>
  <div class="item">5</div>
  <div class="item">6</div>
  <div class="item">7</div>
  <div class="item">8</div>
  <div class="item">9</div>
  <div class="item">10</div>
</div>

Juanma Menéndez
fuente
1
Esto merece un voto. El uso de la combinación de flexión y margen es una forma realmente simple de soportar saltos de línea. También funciona muy bien calccomo se describe en esta respuesta.
stwilz
Me gusta más, solo margin-right: 1pxel artículo, y hará que el siguiente artículo comience en una nueva fila.
arvil
0

Para futuras preguntas, también es posible hacerlo utilizando float propiedad y borrándola en cada 3 elementos.

Aquí hay un ejemplo que hice.

.grid {
  display: inline-block;
}

.cell {
  display: inline-block;
  position: relative;
  float: left;
  margin: 8px;
  width: 48px;
  height: 48px;
  background-color: #bdbdbd;
  font-family: 'Helvetica', 'Arial', sans-serif;
  font-size: 14px;
  font-weight: 400;
  line-height: 20px;
  text-indent: 4px;
  color: #fff;
}

.cell:nth-child(3n) + .cell {
  clear: both;
}
<div class="grid">
  <div class="cell">1</div>
  <div class="cell">2</div>
  <div class="cell">3</div>
  <div class="cell">4</div>
  <div class="cell">5</div>
  <div class="cell">6</div>
  <div class="cell">7</div>
  <div class="cell">8</div>
  <div class="cell">9</div>
  <div class="cell">10</div>
</div>

Gabriel
fuente
3
El problema aquí es el OP se indica la solución tiene que FlexBox uso o display: flex;nodisplay: inline-block;
bafromca
1
puede escribir como en su .cell:nth-child(3n + 1)lugar
Si7ius
-1

Intenté varias respuestas aquí, y ninguna de ellas funcionó. Irónicamente, lo que funcionó fue la alternativa más simple a la que <br/>uno podría intentar:

<div style="flex-basis: 100%;"></div>

o también podrías hacer:

<div style="width: 100%;"></div>

Coloca eso donde quieras una nueva línea. Parece funcionar incluso con los adyacentes <span>, pero lo estoy usando con los adyacentes <div>.

Andrés
fuente
2
Los divs de 100% de ancho son la primera solución dada en la respuesta aceptada.
TylerH
1
Es cierto, más o menos. Son menospreciados por una mala razón (¿feo, en serio?). Además, mi respuesta sí flex-basis.
Andrew
-4

.container {
  background: tomato;
  display: flex;
  flex-flow: row wrap;
  align-content: space-between;
  justify-content: space-between;
}

.item {
  width: 100px;
  height: 100px;
  background: gold;
  border: 1px solid black;
  font-size: 30px;
  line-height: 100px;
  text-align: center;
  margin: 10px;
}
<div class="container">
  <div>
    <div class="item">1</div>
    <div class="item">2</div>
    <div class="item">3</div>
  </div>
  <div>
    <div class="item">4</div>
    <div class="item">5</div>
    <div class="item">6</div>
  </div>
  <div>
    <div class="item">7</div>
    <div class="item">8</div>
    <div class="item">9</div>
  </div>
  <div class="item">10</div>
</div>

podría intentar envolver los elementos en un elemento dom como aquí. con esto no tienes que saber mucho css, solo tener una buena estructura resolverá el problema.

Naseeruddin VN
fuente
1
Puede hacer que el contenedor sea normal display: blocky hacer esos nuevos flexboxes divs de nivel 2. Esto funciona para filas. Reemplace los divs con vanos cuando use el modo columna.
jiggunjer