Como especificar quebras de linha em um layout de caixa flexível de várias linhas?

236

Existe uma maneira de fazer uma quebra de linha no flexbox de várias linhas?

Por exemplo, para quebrar após cada terceiro item neste 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>

Gostar

.item:nth-child(3n){
  /* line-break: after; */    
}
Artem Svirskyi
fonte
1
Eu tive o mesmo problema ou muito semelhante; Eu queria quebrar cada quarto item, então apenas defina a largura de cada item flexível como 25vw (ou 25%). Portanto, no seu caso, para cada terceiro item, você usaria 33,3vw (ou 33,3%). Funcionou perfeitamente para o que eu queria. Pode ajudar alguém se estiver procurando um método mais simples.
Ben Clarke
Ben Clarke! Muito obrigado! Sua resposta é a única que funcionou. Você pode adicioná-lo como resposta. :-)
itmuckel
Relacionados: stackoverflow.com/q/4609279/405017
Phrogz

Respostas:

322

A solução mais simples e confiável é inserir itens flexíveis nos lugares certos. Se tiverem largura suficiente ( width: 100%), forçarão uma quebra de linha.

Mas isso é feio e não semântico. Em vez disso, poderíamos gerar pseudoelementos dentro do contêiner flex e usá order-los para movê-los para os lugares certos.

Mas há uma limitação: o contêiner flex pode ter apenas um ::beforee um ::afterpseudo-elemento. Isso significa que você só pode forçar duas quebras de linha.

Para resolver isso, você pode gerar os pseudoelementos dentro dos itens flex, em vez de no contêiner flex. Dessa forma, você não ficará limitado a 2. Mas esses pseudoelementos não serão itens flexíveis, portanto não poderão forçar quebras de linha.

Mas, felizmente, o CSS Display L3 introduziu display: contents(atualmente suportado apenas pelo Firefox 37):

O próprio elemento não gera caixas, mas seus filhos e pseudo-elementos ainda geram caixas normalmente. Para fins de geração e layout de caixas, o elemento deve ser tratado como se tivesse sido substituído por seus filhos e pseudo-elementos na árvore de documentos.

Assim, você pode aplicar display: contentsaos filhos do contêiner flex e envolver o conteúdo de cada um dentro de um invólucro adicional. Então, os itens flexíveis serão os invólucros adicionais e os pseudoelementos das crianças.

Alternativamente, de acordo com Fragmentar Flex Disposição e fragmentação CSS , Flexbox permite quebras forçado usando break-before, break-afterou os seus nomes alternativos CSS 2.1:

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

As quebras de linha forçadas no flexbox ainda não são amplamente suportadas, mas funcionam no Firefox.

Oriol
fonte
@ Oriol Sobre a primeira abordagem, por que você diz que é feia e não semântica? Apenas curioso.
nacho4d
18
@ nacho4d Porque o HTML não deve ser modificado para fins de estilo. E se você mudar de idéia e decidir que deseja 4 colunas em vez de 3, talvez precise modificar muito HTML. Compare com a break-aftersolução, que exigiria apenas a modificação de um seletor na folha de estilo.
Oriol
1
Eu precisava adicionar display: block;as classes .container ::beforee ::afterpseudo para fazer a solução número dois funcionar no IE. YMMV!
twined
1
@twined Isso é estranho, porque os itens flexíveis devem ser bloqueados automaticamente.
Oriol
2
Como a coisa de quebra de página foi aparentemente removida das especificações, é possível executar o segundo trecho na direção da coluna e não expandir a altura do contêiner? Não tive sorte e definir a base flexível como 100% / itens aumenta sua altura.
Lucent
42

Na minha perspectiva, é mais semântico usar <hr> elementos como quebras de linha entre itens flexíveis.

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

Testado no Chrome 66, Firefox 60 e Safari 11.

Petr Stepanov
fonte
7
É assim que eu também faço, funciona muito bem. Adicionando hr {base flexível: 100%; altura: 0; margem: 0; borda: 0; } torna a pausa perfeita.
Besworks 25/03/19
Eu gosto dessa abordagem. Nota: ao usar gap: 10px;a distância entre as linhas é realmente 20px. Para endereço, especificar uma lacuna fileira de metade desse tamanho: gap: 5px 10px;.
CuddleBunny
@Besworks: borderdeve ser definida para none, em vez de0
Mark
@mark, border:0;é tão válido quanto border:none;. Veja: stackoverflow.com/questions/2922909/…
Besworks
23

O @Oriol tem uma excelente resposta, infelizmente, a partir de outubro de 2017, também display:contentsnão page-break-afteré amplamente suportado, é melhor dizer que é sobre o Firefox que suporta isso, mas não os outros jogadores, eu criei o seguinte "hack", que considero melhor do que difícil codificação em uma pausa após cada terceiro elemento, porque isso tornará muito difícil tornar a página compatível com dispositivos móveis.

Como foi dito, é um truque e a desvantagem é que você precisa adicionar muitos elementos extras por nada, mas ele funciona e funciona em vários navegadores, mesmo no IE11 datado.

O "hack" é simplesmente adicionar um elemento adicional após cada div, que é definido como display:nonee, em seguida, usado o css nth-childpara decidir qual deles deve ser realmente visível, forçando um freio de linha 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
fonte
2
Também descobri que os métodos "display: contents" e "page-break-after" não estão funcionando e recorri a esse "hack". Isso foi relatado como um bug do Chrome e marcado como "WontFix" (consulte bugs.chromium.org/p/chromium/issues/detail?id=473481 ) com a explicação: "Existe, de acordo com o CSS Working Group, não maneira atual de forçar uma quebra de linha em uma caixa flexível com CSS ".
Martin_W 4/0618
Você pode economizar um pouco de confusão usando o seletor .container>p. Então todas essas <p></p>tags não precisariam do classatributo. Não é importante, é claro. Apenas meu cérebro preguiçoso encontrando um pequeno ajuste na economia da sua solução inteligente. Obviamente, também depende do usuário não ter outras <p>tags como filhos diretos da .containerdiv. Tecnicamente, você poderia fazer o mesmo com todas as outras <div>crianças, mas é muito mais provável que você tenha outros <div>s do .containerque você <p>é, então provavelmente não é uma jogada inteligente para lá.
Steve Steve
13

Você quer uma quebra de linha semântica?

Então considere usar <br>. O W3Schools pode sugerir que você BRé apenas para escrever poemas (o meu será lançado em breve), mas você pode alterar o estilo para que se comporte como um elemento de bloco de 100% de largura que levará o seu conteúdo para a próxima linha. Se 'br' sugere uma pausa, parece-me mais apropriado do que usar hrou 100% dive torna o html mais legível.

Insira o local <br>onde você precisa quebras de linha e estilize-o assim.

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

Você pode desativar <br>com consultas de mídia , definindo display:a blockou noneconforme o caso (eu incluí um exemplo disso, mas deixou-o comentado).

Você também pode order:definir o pedido, se necessário.

E você pode colocar quantas quiser, com diferentes classes ou nomes :-)

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


Não há necessidade de se limitar ao que o W3Schools diz:

insira a descrição da imagem aqui

Simon_Weaver
fonte
Uma extensão da técnica é colocar <br class="2col">após cada segundo item, <br class="3col">após cada terceiro. Em seguida, aplique uma classe cols-2ao contêiner e crie css para ativar apenas as quebras de linha apropriadas para esse número de colunas. por exemplo. br { display: none; } .cols-2 br.2col { display: block; }
Simon_Weaver
Não, a brnão é para elementos de quebra de linha , é para texto : developer.mozilla.org/en-US/docs/Web/HTML/Element/br ... stackoverflow.com/questions/3937515/…
Ason
2
Vou mudar minha redação para não apresentar isso como uma solução perfeita, mas em alguns casos não vejo isso pior do que outras soluções div ou pseudo-elementos. Talvez eu escreva um poema sobre isso agora.
Simon_Weaver
Sim ... um poema seria legal, não se esqueça de postar um link para ele aqui :) ... Em relação a uma solução perfeita, existe um ( break-*mostrado na resposta aceita), embora, infelizmente, ainda não chegue a vários navegadores , portanto, o segundo melhor é usar um elemento que preencha nativamente a largura dos pais e forneça os irmãos próximos a uma linha de si mesmos, o que novamente é dado na resposta aceita. Portanto, usar qualquer outro elemento que não seja um bloco como um seria pior, semanticamente, como o br.
Ason
5
Lembre-se, você publica uma impressão do W3Schools, não do W3C, eles não estão conectados.
Edu Ruiz
7

Eu acho que a maneira tradicional é flexível e bastante fácil de entender:

Marcação

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

Crie o arquivo 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;
  }
}

Eu criei um exemplo (jsfiddle)

Tente redimensionar a janela em 400px, é responsivo !!

Moshe Quantz
fonte
Nesta solução, os elementos estão juntos, a idéia é ter um longo espaço em branco entre eles.
Juanma Menendez
2

Outra solução possível que não requer adição de nenhuma marcação extra é adicionar margem dinâmica para separar os elementos.

No caso do exemplo, isso pode ser feito com a ajuda de calc(), apenas adicionando margin-lefte margin-rightao elemento 3n + 2 (2, 5, 8)

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

Exemplo de snippet

.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 Menendez
fonte
1
Isso merece uma votação. Usar a combinação de flexibilidade e margem é uma maneira muito simples de suportar quebras de linha. Também funciona muito bem, calcconforme descrito nesta resposta.
31519 stwilz
Eu gosto mais disso, apenas margin-right: 1pxdo item, e fará com que o próximo item comece em uma nova linha.
arvil 4/09/19
0

Para perguntas futuras, também é possível fazer isso usando a floatpropriedade e limpando-a em cada 3 elementos.

Aqui está um exemplo que eu fiz.

.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
fonte
3
o problema aqui é o OP afirmou a solução tem de utilização flexbox ou display: flex;, nãodisplay: inline-block;
bafromca
1
você pode escrever como .cell:nth-child(3n + 1)vez
Si7ius
-1

Tentei várias respostas aqui e nenhuma delas funcionou. Ironicamente, o que funcionou foi a alternativa mais simples a uma que <br/>se poderia tentar:

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

ou você também pode fazer:

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

Coloque isso onde quiser uma nova linha. Parece funcionar mesmo com os adjacentes <span>, mas estou usando com os adjacentes <div>.

Andrew
fonte
2
Divs de 100% de largura são a primeira solução dada na resposta aceita.
TylerH 13/09/19
1
Verdade, mais ou menos. Eles são menosprezados por um motivo ruim (feio, sério?). Além disso, minha resposta tem 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>

você pode tentar agrupar os itens em um elemento dom como aqui. Com isso, você não precisa conhecer muitos CSS, apenas ter uma boa estrutura resolverá o problema.

Naseeruddin VN
fonte
1
Você pode tornar o contêiner normal display: blocke criar flexboxes para essas novas divisões de nível 2. Isso funciona para linhas. Substitua os divs por vãos ao usar o modo de coluna.
Jggunjer #