Come specificare le interruzioni di riga in un layout flexbox multilinea?


236

C'è un modo per interrompere una linea nel flexbox su più linee?

Ad esempio per rompere dopo ogni 3 ° elemento in questo codice .

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

Piace

.item:nth-child(3n){
  /* line-break: after; */    
}

1
Ho avuto lo stesso problema o molto simile; Volevo rompere ogni quarto oggetto, quindi ho appena impostato la larghezza di ogni oggetto flessibile su 25vw (o 25%). Quindi, nel tuo caso, per ogni 3 ° articolo useresti 33.3vw (o 33.3%). Ha funzionato perfettamente per quello che volevo. Potrebbe aiutare qualcun altro se stanno cercando un metodo più semplice.
Ben Clarke,

Ben Clarke! Grazie mille! La tua risposta è l'unica che ha funzionato. Potresti considerare di aggiungerlo come risposta. :-)
itmuckel,

Risposte:


322

La soluzione più semplice e affidabile è l'inserimento di articoli flessibili nei punti giusti. Se sono abbastanza larghi ( width: 100%), forzeranno un'interruzione di linea.

Ma è brutto e non semantico. Invece, potremmo generare pseudo-elementi all'interno del contenitore flessibile e usarli orderper spostarli nei posti giusti.

Ma c'è un limite: il contenitore flessibile può avere solo uno ::beforee uno ::afterpseudo-elemento. Ciò significa che puoi forzare solo 2 interruzioni di riga.

Per risolverlo, è possibile generare gli pseudo-elementi all'interno degli oggetti flessibili anziché nel contenitore flessibile. In questo modo non sarai limitato a 2. Ma quegli pseudo-elementi non saranno oggetti flessibili, quindi non saranno in grado di forzare le interruzioni di linea.

Ma per fortuna, CSS Display L3 ha introdotto display: contents(attualmente supportato solo da Firefox 37):

L'elemento stesso non genera alcuna scatola, ma i suoi figli e pseudo-elementi generano comunque scatole normalmente. Ai fini della generazione e del layout della scatola, l'elemento deve essere trattato come se fosse stato sostituito con i suoi figli e pseudo-elementi nell'albero del documento.

Quindi puoi applicare display: contentsai bambini del contenitore flessibile e avvolgere il contenuto di ciascuno all'interno di un involucro aggiuntivo. Quindi, gli oggetti flessibili saranno quegli involucri aggiuntivi e gli pseudo-elementi dei bambini.

In alternativa, secondo frammentare Flex layout e frammentazione CSS , Flexbox permette pause forzata usando break-before, break-afteroi loro CSS 2.1 alias:

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

Le interruzioni di riga forzata in flexbox non sono ancora ampiamente supportate, ma funzionano su Firefox.


@Oriol A proposito del primo approccio, perché dici che è brutto e non semantico? Solo curioso.
nacho4d,

18
@ nacho4d Perché l'HTML non deve essere modificato ai fini dello stile. E se cambi idea e decidi di volere 4 colonne anziché 3, dovrai modificare forse un sacco di codice HTML. Confronta con la break-aftersoluzione, che richiederebbe solo la modifica di un selettore nel foglio di stile.
Oriol,

1
Avevo bisogno di aggiungere display: block;alle classi pseudo .container ::beforee ::afterper far funzionare la soluzione numero due in IE. YMMV!
attorcigliato il

1
@twined È strano, perché gli oggetti flessibili dovrebbero essere bloccati automaticamente.
Oriol,

2
Poiché la cosa di interruzione di pagina è stata apparentemente rimossa dalle specifiche, è possibile far funzionare il secondo snippet nella direzione della colonna e non far espandere l'altezza del suo contenitore? Non ho avuto fortuna e impostare la base flessibile al 100% / gli oggetti allunga la sua altezza.
Lucent,

42

Dal mio punto di vista, è più semantico utilizzare gli <hr> elementi come interruzioni di riga tra gli elementi flessibili.

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

Testato su Chrome 66, Firefox 60 e Safari 11.


7
È così che lo faccio anche io, funziona alla grande. Aggiunta di h {base flessibile: 100%; altezza: 0; margine: 0; bordo: 0; } rende la pausa senza soluzione di continuità.
Besworks,

Mi piace questo approccio. Nota: quando si utilizza gap: 10px;la distanza tra le file è in realtà 20px. Per indirizzo, specificare un gap fila di metà dimensione: gap: 5px 10px;.
CuddleBunny

@Besworks: borderdovrebbe essere impostato su none, anziché0
Mark

@mark, border:0;è valido quanto border:none;. Vedi: stackoverflow.com/questions/2922909/...
Besworks

23

@Oriol ha una risposta eccellente, purtroppo a partire da ottobre 2017, nessuno dei display:contentsdue page-break-afterè ampiamente supportato, meglio detto che è su Firefox che supporta questo ma non gli altri giocatori, ho escogitato il seguente "hack" che considero migliore che difficile la codifica in una pausa dopo ogni 3 ° elemento, perché ciò renderà molto difficile rendere la pagina mobile friendly.

Come detto è un trucco e lo svantaggio è che devi aggiungere molti elementi extra per nulla, ma fa il trucco e funziona su più browser anche su IE11 datato.

L '"hack" è semplicemente aggiungere un ulteriore elemento dopo ogni div, che è impostato su display:nonee quindi utilizzato il CSS nth-childper decidere quale di questi dovrebbe essere effettivamente reso visibile forzando un freno di linea come questo:

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


2
Ho anche scoperto che i metodi "display: contents" e "page-break-after" non funzionano e ho fatto ricorso a questo "hack". Questo è stato segnalato come un bug di Chrome e contrassegnato come "WontFix" (vedi bugs.chromium.org/p/chromium/issues/detail?id=473481 ) con la spiegazione: "Secondo il gruppo di lavoro CSS, modo attuale di forzare un'interruzione di linea in una scatola flessibile con CSS ".
Martin_W,

È possibile salvare un tocco di disordine utilizzando il selettore .container>p. Quindi tutti quei <p></p>tag non avrebbero bisogno classdell'attributo. Non importante ovviamente. Solo il mio cervello pigro trova una piccola modifica salvaspazio per la tua soluzione intelligente. Naturalmente, si basa anche sul fatto che l'utente non abbia altri <p>tag come figli diretti del .containerdiv. Tecnicamente potresti fare lo stesso con tutti gli altri <div>bambini, ma è molto più probabile che tu abbia altri <div>s nel .containertuo rispetto a quello che sei <p>, quindi probabilmente non una mossa intelligente lì.
Steve,

13

Vuoi un break line semantico?

Quindi prendere in considerazione l'utilizzo <br>. W3Schools potrebbe suggerirti che BRè solo per scrivere poesie (la mia è in arrivo) ma puoi cambiare lo stile in modo che si comporti come un elemento di blocco con larghezza del 100% che spinga i tuoi contenuti alla riga successiva. Se "br" suggerisce un'interruzione, allora mi sembra più appropriato che usare hro un 100% dive rende l'html più leggibile.

Inserisci il punto in <br>cui hai bisogno di interruzioni di riga e modellalo in questo modo.

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

È possibile disabilitare <br>con le media query , impostando display:su blocko nonecome appropriato (ho incluso un esempio di questo ma ho lasciato commentato).

È possibile utilizzare order:per impostare l'ordine, se necessario.

E puoi metterne quanti ne vuoi, con classi o nomi diversi :-)

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


Non è necessario limitarsi a ciò che dice W3Schools:

inserisci qui la descrizione dell'immagine


Un'estensione della tecnica è quella di inserire <br class="2col">ogni secondo elemento, <br class="3col">dopo ogni terzo. Quindi applicare una classe cols-2al contenitore e creare CSS per abilitare solo le interruzioni di riga appropriate per quel numero di colonne. per esempio. br { display: none; } .cols-2 br.2col { display: block; }
Simon_Weaver,

No, a brnon è per gli elementi di interruzione di riga , è per il testo : developer.mozilla.org/en-US/docs/Web/HTML/Element/br ... stackoverflow.com/questions/3937515/…
Ason

2
Cambierò il mio testo per non presentarlo come una soluzione perfetta, ma in alcuni casi non lo vedo come peggiore di altre soluzioni div o pseudo-elementi. Forse ora vado a scrivere una poesia al riguardo.
Simon_Weaver il

Sì ... una poesia sarebbe piacevole, non dimenticare di pubblicare un link qui :) ... Per quanto riguarda una soluzione perfetta, ce n'è una ( break-*mostrata nella risposta accettata) anche se sfortunatamente non ha ancora raggiunto i browser incrociati , quindi il secondo migliore è usare un elemento che riempia nativamente la larghezza dei suoi genitori e spinga i fratelli successivi su una fila di se stessi, che è data ancora nella risposta accettata. Quindi usando qualsiasi altro elemento diverso da un blocco come uno sarebbe peggio, semanticamente, come il br.
Ason,

5
Ricorda, pubblichi una stampa di W3Schools, non W3C, non sono collegati.
Edu Ruiz,

7

Penso che il modo tradizionale sia flessibile e abbastanza facile da capire:

markup

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

Creare il file 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;
  }
}

Ho creato un esempio (jsfiddle)

Prova a ridimensionare la finestra sotto 400px, è reattivo !!


In questa soluzione gli elementi sono uniti, l'idea è di avere un lungo spazio vuoto tra di loro.
Juanma Menendez,

2

Un'altra possibile soluzione che non richiede l'aggiunta di alcun markup aggiuntivo è l'aggiunta di un margine dinamico per separare gli elementi.

Nel caso dell'esempio, questo può essere fatto con l'aiuto di calc(), semplicemente aggiungendo margin-lefte margin-rightall'elemento 3n + 2 (2, 5, 8)

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

Esempio di frammento

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


1
Questo merita un voto. L'uso della combinazione di flessibilità e margine è un modo davvero semplice per supportare le interruzioni di linea. Funziona anche molto bene calccome indicato in questa risposta.
stwilz,

Mi piace di più, solo margin-right: 1pxl'oggetto, e farà iniziare l'elemento successivo in una nuova riga.
incudine

0

Per domande future, è anche possibile farlo utilizzando float proprietà e cancellandola in ogni 3 elementi.

Ecco un esempio che ho fatto.

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


3
il problema qui è che l'OP ha dichiarato che la soluzione deve usare flexbox o display: flex;nodisplay: inline-block;
bafromca,

1
puoi scrivere come .cell:nth-child(3n + 1)invece
Si7ius

-1

Ho provato diverse risposte qui, e nessuna di queste ha funzionato. Ironia della sorte, ciò che ha funzionato riguardava l'alternativa più semplice a una che <br/>si potesse tentare:

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

oppure potresti anche fare:

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

Posizionalo ovunque tu voglia una nuova linea. Sembra funzionare anche con quelli adiacenti <span>, ma lo sto usando con quelli adiacenti <div>.


2
I div al 100% di larghezza sono la prima soluzione data nella risposta accettata.
TylerH,

1
Vero, un po '. Sono guardati in basso per una ragione scadente (brutta, davvero?). Inoltre, la mia risposta ha 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>

potresti provare a avvolgere gli oggetti in un elemento dom come qui. con questo non devi sapere un sacco di CSS solo avere una buona struttura risolverà il problema.


1
Puoi rendere normale il container display: blocke rendere quei nuovi flexbox div di livello 2. Questo funziona per le file. Sostituisci i div con span quando usi la modalità colonna.
jiggunjer,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.