Flexbox: 4 itens por linha

260

Estou usando uma caixa flexível para exibir 8 itens que serão redimensionados dinamicamente com minha página. Como forçá-lo a dividir os itens em duas linhas? (4 por linha)?

Aqui está um trecho relevante:

(Ou se você preferir 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
fonte
16
[Update] Esta questão foi baseada em um design pobre que não responde. Se você estiver usando uma das respostas abaixo, tenha cuidado. Em um bom design, você teria mais itens em telas maiores e menos em telas menores. Forçar 4 itens para todos os tamanhos de tela parecerá atraente apenas em uma faixa estreita de larguras de tela.
Vivek Maharajh

Respostas:

381

Você entrou flex-wrap: wrapno recipiente. Isso é bom, porque substitui o valor padrão, que é nowrap( origem ). É por isso que os itens não são agrupados para formar uma grade em alguns casos .

Nesse caso, o principal problema está flex-grow: 1nos itens flexíveis.

Na flex-growverdade, a propriedade não dimensiona itens flexíveis. Sua tarefa é distribuir espaço livre no contêiner ( origem ). Portanto, não importa o tamanho da tela, cada item receberá uma parte proporcional do espaço livre na linha.

Mais especificamente, existem oito itens flexíveis no seu contêiner. Com flex-grow: 1, cada um recebe 1/8 do espaço livre na linha. Como não há conteúdo em seus itens, eles podem diminuir para largura zero e nunca serão quebrados.

A solução é definir uma largura nos itens. Tente o seguinte:

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

Com flex-grow: 1definido na flexabreviação, não há necessidade de flex-basis25%, o que resultaria em três itens por linha devido às margens.

Como flex-growconsumirá espaço livre na linha, flex-basissó precisa ser grande o suficiente para impor uma quebra automática. Nesse caso, com flex-basis: 21%, há muito espaço para as margens, mas nunca espaço suficiente para um quinto item.

Michael Benjamin
fonte
1
Gosto disso porque funcionou para mim, mas "muito espaço" me deixa um pouco desconfortável. Existe alguma pequena janela ou situação em que essa "estimativa" pode me falhar?
1013 Jackson
1
Que tipo de situação? Na maioria dos layouts, existem casos extremos que podem criar problemas. Esses casos normalmente passam por análises de custo-benefício porque nunca, ou quase nunca, ocorrem. Por exemplo, na solução acima, se você colocar margens muito grandes, o layout poderá ser interrompido. Se isso é um problema, ele deve ser publicado na pergunta. @Jackson
Michael Benjamin
2
“Se você colocar margens muito grandes, o layout poderá quebrar” Esse é um exemplo de cenário que eu gostaria de evitar. Eu não me importo com praticidade; entretenha minha adoração pela perfeição. Existe alguma maneira de ser mais exato?
22416 Jackson
27
Você também pode usarflex: 1 0 calc(25% - 10px);
MarkG
2
Ótima resposta! Uma pequena melhoria que utilizo é em margin: 2%;vez de um número fixo de pixels para impedir que as caixas pulem para uma nova linha em pequenos dispositivos / resoluções. a fórmula geral é (100 - (4 * box-width-percent)) / 8% para diferentes larguras de caixa
thomaspsk
104

Adicione uma largura aos .childelementos. Eu, pessoalmente, usaria porcentagens no margin-leftse você quiser tê-lo sempre 4 por linha.

DEMO

.child {
    display: inline-block;
    background: blue;
    margin: 10px 0 0 2%;
    flex-grow: 1;
    height: 100px;
    width: calc(100% * (1/4) - 10px - 1px);
}
dowomenfart
fonte
Boa ideia. Eu usei essa ideia com edições menores. jsfiddle.net/vivmaha/oq6prk1p/6
Vivek Maharajh,
1
Ah Na verdade, isso não resolve o meu problema. Veja aqui um exemplo: jsfiddle.net/vivmaha/oq6prk1p/7 . Não tenho a liberdade de usar porcentagens para minha margem. Eles devem ter uma largura fixa. Isso significa que os 23% mágicos que escolhemos não funcionarão, pois não levam em conta a margem fixa.
Vivek Maharajh 9/04/2015
3
Sim, o calc resolve! «calc (100% * (1/4) - 10 px - 1 px)». Veja jsfiddle.net/vivmaha/oq6prk1p/9
Vivek Maharajh
24
Então, qual é a utilidade do flex nisso?
twicejr
E o design responsivo? Nós não queremos colocar uma largura fixa na criança
candlejack
40

Aqui está outra abordagem.

Você também pode fazer isso desta maneira:

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

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

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

E uma amostra mais completa: https://codepen.io/capynet/pen/JyYaba

Capy
fonte
1
E se eu tiver menos de quatro filhos? Eu não gosto que o espaço vazio em branco, a criança não são sensíveis ...
candlejack
A outra resposta de Muddasir Abbas usa apenas configurações flexíveis, então acho que é uma solução mais limpa.
Andrew Koster
17

Eu faria assim usando margens negativas e calc para as calhas:

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

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

Demonstração: https://jsfiddle.net/9j2rvom4/


Método alternativo de grade CSS:

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

Demonstração: https://jsfiddle.net/jc2utfs3/

shanomurphy
fonte
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 que ajude. para mais detalhes, você pode seguir este link

Muddasir Abbas
fonte
4

Acredito que este exemplo é mais barebones e mais fácil de entender do que @dowomenfart.

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

Isso realiza os mesmos cálculos de largura enquanto corta diretamente para a carne. A matemática é muito mais fácil e emé o novo padrão devido à sua escalabilidade e facilidade de uso.

Joseph Cho
fonte
3
em realmente não é o novo padrão. Pode ser um pé no saco, e os designers não projetam com os EMs em 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
fonte
1
Se você puder adicionar algum contexto sobre por que isso responde à pergunta do OP, em vez de apenas postar o código.
d219 31/03/19
se você adicionar justify-content: space-evenly;ao incentivo, ele se alinhará bem e você não precisará fazer isso calcna criança. Obrigado pelo exemplo, no entanto!
precisa
0

Invólucro flexível + margem negativa

Por que flexionar vs. display: inline-block?

Por que margem negativa?

Você usa SCSS ou CSS-in-JS para os casos extremos (ou seja, primeiro elemento da coluna) ou define uma margem padrão e se livra da margem externa posteriormente.

Implementação

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

Aqui está outra maneira sem 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!

É tudo o que há para isso. Você pode gostar das dimensões para obter tamanhos mais estéticos, mas essa é a ideia.

wle8300
fonte
6
Não testei isso, mas a sintaxe do CSS está incorreta (os valores do CSS não são citados e as declarações devem terminar em ponto-e-vírgula), portanto, definitivamente não funcionará na sua forma atual.
Nick F