Largura do fluido com DIVs igualmente espaçados

329

Eu tenho um DIV de largura de fluido.

Dentro deste eu tenho 4 DIVs todos os 300px x 250px ...

<div id="container">
   <div class="box1"> </div>
   <div class="box2"> </div>
   <div class="box3"> </div>
   <div class="box4"> </div>
</div>

O que eu quero que aconteça é a caixa 1 ser lançada à esquerda, a caixa 4 ser lançada à direita e as caixas 2 e 3 espaçadas igualmente entre elas. Quero que o espaçamento seja fluido também, para que o navegador fique menor, o espaço também fique menor.

insira a descrição da imagem aqui

Lee Price
fonte
2
Por que não fazer em display:inline-block;vez de flutuar?
ayyp
1
porque IE6 / IE7 suporta apenas inline-blockem inlineelementos
Lee Preço
Ok, não tinha certeza de quais navegadores você estava procurando.
ayyp
1
A solução mais próxima que consegui pensar foi agrupar cada div .box filho em outra div com 25% de largura. Em seguida, centralize a div .box filho no wrapper. As divs .box serão espaçadas uniformemente, mas as div esquerda e direita não estarão à direita na borda.
Paul Sham
5
Transformei a ideia de @Paul Sham em um JSFiddle .
Sparky

Respostas:

440

Veja: http://jsfiddle.net/thirtydot/EDp8R/

  • Isso funciona no IE6 + e em todos os navegadores modernos!
  • Reduzimos pela metade as dimensões solicitadas apenas para facilitar o trabalho.
  • text-align: justifycombinado com o .stretchque está lidando com o posicionamento.
  • display:inline-block; *display:inline; zoom:1correções inline-blockpara o IE6 / 7, veja aqui .
  • font-size: 0; line-height: 0 corrige um pequeno problema no IE6.

#container {
  border: 2px dashed #444;
  height: 125px;
  text-align: justify;
  -ms-text-justify: distribute-all-lines;
  text-justify: distribute-all-lines;
  /* just for demo */
  min-width: 612px;
}

.box1,
.box2,
.box3,
.box4 {
  width: 150px;
  height: 125px;
  vertical-align: top;
  display: inline-block;
  *display: inline;
  zoom: 1
}

.stretch {
  width: 100%;
  display: inline-block;
  font-size: 0;
  line-height: 0
}

.box1,
.box3 {
  background: #ccc
}

.box2,
.box4 {
  background: #0ff
}
<div id="container">
  <div class="box1"></div>
  <div class="box2"></div>
  <div class="box3"></div>
  <div class="box4"></div>
  <span class="stretch"></span>
</div>

O extra span( .stretch) pode ser substituído por :after.

Isso ainda funciona nos mesmos navegadores que a solução acima. :afternão funciona no IE6 / 7, mas eles estão usando de distribute-all-linesqualquer maneira, por isso não importa.

Veja: http://jsfiddle.net/thirtydot/EDp8R/3/

Há uma pequena desvantagem :after: para que a última linha funcione perfeitamente no Safari, você deve ter cuidado com o espaço em branco no HTML.

Especificamente, isso não funciona:

<div id="container">
    ..
    <div class="box3"></div>
    <div class="box4"></div>
</div>

E isso faz:

<div id="container">
    ..
    <div class="box3"></div>
    <div class="box4"></div></div>

Você pode usar isso para qualquer número arbitrário de filhos divsem adicionar uma boxNclasse a cada um, alterando

.box1, .box2, .box3, .box4 { ...

para

#container > div { ...

Isso seleciona qualquer div que seja o primeiro filho da #containerdiv e nenhuma outra abaixo dela. Para generalizar as cores de segundo plano, você pode usar o seletor de ordem n de CSS3 , embora ele seja suportado apenas no IE9 + e em outros navegadores modernos:

.box1, .box3 { ...

torna-se:

#container > div:nth-child(odd) { ...

Veja aqui um exemplo do jsfiddle.

trinta dias
fonte
123
Levei 3h para descobrir que você deveria ter espaços entre as caixas no html. "Justificar" estende espaços entre os elementos e, se o seu conteúdo for, <div/><div/><div/>ele não funcionará. Você precisa ter <div/> <div/> <div/>.
venimus
5
só queria observar isso :) porque é difícil notar se você trabalha com um conteúdo gerado (que é o caso comum). Eu estava pensando em usar justifypara esse caso, mas obrigado por fornecer uma solução funcional. poupou-me muitos experimentos (apesar da depuração de 3h: D). Além disso, eu poderia acrescentar uma nota que se você quiser a sua última linha a ser alinhado à esquerda, você deve adicionar algumas caixas invisíveis extras (para completar a linha)
venimus
4
@venimus: Eu escrevi outra resposta usando esta técnica: stackoverflow.com/questions/10548417/… . O que você fez para se livrar da altura extra causada pela adição de caixas invisíveis?
thirtydot
11
Alguém pode explicar por que o .stretch é necessário?
Atp
6
@HartleySan: O .stretch/ :afteré necessário porque (normalmente) com texto justificado, a última linha não é justificada . Aqui, queremos que a última linha seja justificada, daí a necessidade :after. Quanto à sua segunda pergunta, explorei isso há algum tempo em uma resposta anterior . Nessa resposta, era necessário JavaScript. Se você precisa oferecer suporte a navegadores mais antigos (IE8), acredito que precisa de JavaScript.
thirtydot
140

A maneira mais fácil de fazer isso agora é com um flexbox:

http://css-tricks.com/snippets/css/a-guide-to-flexbox/

O CSS é simplesmente:

#container {
    display: flex;
    justify-content: space-between;
}

demo: http://jsfiddle.net/QPrk3/

No entanto , atualmente isso é suportado apenas por navegadores relativamente recentes ( http://caniuse.com/flexbox ). Além disso, as especificações para o layout do flexbox foram alteradas algumas vezes, portanto, é possível cobrir mais navegadores incluindo uma sintaxe mais antiga:

http://css-tricks.com/old-flexbox-and-new-flexbox/

http://css-tricks.com/using-flexbox/

Ben Jackson
fonte
1
Obrigado por isso, tão fácil, eu o apliquei em quatro listas espaçadas mesmo em um rodapé fixo na parte inferior de uma página. Trabalhou um tratamento em FF28.0, Chrome 34.0.1847.116 me IE11.
user1063287
1
O Flexbox não é a ferramenta mais suportada na Web e não supera a abordagem clássica de margem e preenchimento.
TheBlackBenzKid 28/08
Para todos que procuram justificar várias divs com widht não definido: use flex-wrap com a opção display: flex. Ele envolverá divs com largura dinâmica.
Kamil Budziewski 26/10
20

Se css3 for uma opção, isso pode ser feito usando a calc()função css .

Caso 1: justificando caixas em uma única linha ( FIDDLE )

A marcação é simples - um monte de divs com algum elemento container.

CSS fica assim:

div
{
    height: 100px;
    float: left;
    background:pink;
    width: 50px;
    margin-right: calc((100% - 300px) / 5 - 1px); 
}
div:last-child
{
    margin-right:0;
}

onde -1px para corrigir um erro de calc / arredondamento do IE9 + - veja aqui

Caso 2: justificando caixas em várias linhas ( FIDDLE )

Aqui, além da calc()função, media queriessão necessários.

A idéia básica é configurar uma consulta de mídia para cada #columns estados, onde então uso calc () para calcular a margem direita de cada um dos elementos (exceto os da última coluna).

Parece muito trabalho, mas se você estiver usando LESS ou SASS, isso pode ser feito facilmente

(Ainda pode ser feito com css regular, mas você terá que fazer todos os cálculos manualmente e, se alterar a largura da caixa - precisará resolver tudo novamente)

Abaixo está um exemplo usando LESS: (Você pode copiar / colar este código aqui para brincar com ele, [é também o código que eu usei para gerar o violino mencionado acima])

@min-margin: 15px;
@div-width: 150px;

@3divs: (@div-width * 3);
@4divs: (@div-width * 4);
@5divs: (@div-width * 5);
@6divs: (@div-width * 6);
@7divs: (@div-width * 7);

@3divs-width: (@3divs + @min-margin * 2);
@4divs-width: (@4divs + @min-margin * 3);
@5divs-width: (@5divs + @min-margin * 4);
@6divs-width: (@6divs + @min-margin * 5);
@7divs-width: (@7divs + @min-margin * 6);


*{margin:0;padding:0;}

.container
{
    overflow: auto;
    display: block;
    min-width: @3divs-width;
}
.container > div
{
    margin-bottom: 20px;
    width: @div-width;
    height: 100px;
    background: blue;
    float:left;
    color: #fff;
    text-align: center;
}

@media (max-width: @3divs-width) {
    .container > div {  
        margin-right: @min-margin;
    }
    .container > div:nth-child(3n) {  
        margin-right: 0;
    }
}

@media (min-width: @3divs-width) and (max-width: @4divs-width) {
    .container > div {  
        margin-right: ~"calc((100% - @{3divs})/2 - 1px)";
    }
    .container > div:nth-child(3n) {  
        margin-right: 0;
    }
}

@media (min-width: @4divs-width) and (max-width: @5divs-width) {
    .container > div {  
        margin-right: ~"calc((100% - @{4divs})/3 - 1px)";
    }
    .container > div:nth-child(4n) {  
        margin-right: 0;
    }
}

@media (min-width: @5divs-width) and (max-width: @6divs-width) {
    .container > div {  
        margin-right: ~"calc((100% - @{5divs})/4 - 1px)";
    }
    .container > div:nth-child(5n) {  
        margin-right: 0;
    }
}

@media (min-width: @6divs-width){
    .container > div {  
        margin-right: ~"calc((100% - @{6divs})/5 - 1px)";
    }
    .container > div:nth-child(6n) {  
        margin-right: 0;
    }
}

Então, basicamente, você primeiro precisa decidir a largura da caixa e a margem mínima que deseja entre as caixas.

Com isso, você pode descobrir quanto espaço precisa para cada estado.

Em seguida, use calc () para calcular a margem direita e enésimo filho para remover a margem direita das caixas na coluna final.

A vantagem desta resposta sobre a resposta aceita text-align:justifyé que, quando você tem mais de uma linha de caixas - as caixas na linha final não são "justificadas", por exemplo: Se houver duas caixas na linha final - I não queira que a primeira caixa fique à esquerda e a próxima à direita - mas que as caixas se sigam em ordem.

Sobre o suporte ao navegador : Isso funcionará no IE9 +, Firefox, Chrome, Safari6.0 + - (veja aqui para mais detalhes) No entanto, notei que no IE9 + há um pouco de falha entre os estados de consulta de mídia. [se alguém souber como consertar isso, eu realmente gostaria de saber :)] <- CORRIGIDO AQUI

Danield
fonte
13

Outras postagens mencionaram flexbox , mas se mais de uma linha de itens for necessária , a space-betweenpropriedade da flexbox falhará (consulte o final da postagem)

Até o momento, a única solução limpa para isso é com o

Módulo de layout de grade CSS ( demo do Codepen )

Basicamente, o código relevante necessário se resume a isso:

ul {
  display: grid; /* (1) */
  grid-template-columns: repeat(auto-fit, 120px); /* (2) */
  grid-gap: 1rem; /* (3) */
  justify-content: space-between; /* (4) */
  align-content: flex-start; /* (5) */
}

1) Faça do elemento container um container grid

2) Defina a grade com uma quantidade 'automática' de colunas - conforme necessário. Isso é feito para layouts responsivos. A largura de cada coluna será 120 px. (Observe o uso de auto-fit(como oposto a auto-fill) que (para um layout de 1 linha) reduz as faixas vazias para 0 - permitindo que os itens se expandam para ocupar o espaço restante. (Confira esta demonstração para ver do que estou falando) )).

3) Defina as lacunas / calhas para as linhas e colunas da grade - aqui, como deseja um layout de 'espaço entre elas' - a lacuna será realmente uma lacuna mínima, pois aumentará conforme necessário.

4) e 5) - Similar ao flexbox.

body {
  margin: 0;
}
ul {
  display: grid;
  grid-template-columns: repeat(auto-fit, 120px);
  grid-gap: 1rem;
  justify-content: space-between;
  align-content: flex-start;
  
  /* boring properties: */
  list-style: none;
  width: 90vw;
  height: 90vh;
  margin: 2vh auto;
  border: 5px solid green;
  padding: 0;
  overflow: auto;
}
li {
  background: tomato;
  height: 120px;
}
<ul>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
  <li></li>
</ul>

Demonstração Codepen (Redimensione para ver o efeito)


Suporte do navegador - Caniuse

Atualmente suportado pelo Chrome (Blink), Firefox, Safari e Edge! ... com suporte parcial do IE (veja este post de Rachel Andrew)


NB:

A space-betweenpropriedade do Flexbox funciona muito bem para uma linha de itens, mas quando aplicada a um contêiner flexível que envolve seus itens - (com flex-wrap: wrap) - falha, porque você não tem controle sobre o alinhamento da última linha de itens; a última linha sempre será justificada (geralmente não é o que você deseja)

Para demonstrar:

Codepen (redimensione para ver do que estou falando)


Leitura adicional em grades CSS:

Danield
fonte
1
Resposta muito subestimada. Essa foi a maneira mais simples e eficaz de alcançar o que eu queria fazer. Obrigado.
Barnaby Mercer
1
Essa foi a menor quantidade de CSS (e nenhum JS!) Que produziu exatamente o comportamento que eu estava procurando, com alguns ajustes no tamanho e no espaço.
EKW
1
Eu tenho procurado por isso por um tempo e finalmente encontrei! Obrigado @Danield
nareeboy
2

Isso funcionou para mim com 5 imagens em tamanhos diferentes.

  1. Criar uma div de contêiner
  2. Uma lista não ordenada para as imagens
  3. No css, o desordenado deve ser exibido verticalmente e sem marcadores
  4. Justificar o conteúdo da div do contêiner

Isso funciona por causa do justify-content: space-between, e está em uma lista, exibido horizontalmente.

Em CSS

 #container {
            display: flex;
            justify-content: space-between;
 }
    #container ul li{ display:inline; list-style-type:none;
}

Em html

<div id="container"> 
  <ul>  
        <li><img src="box1.png"><li>
        <li><img src="box2.png"><li>
        <li><img src="box3.png"><li>
        <li><img src="box4.png"><li>
        <li><img src="box5.png"><li>
    </ul>
</div>
Sebastián Brun Valiente
fonte
Embora esse código possa funcionar, uma boa resposta inclui uma explicação de como funciona e por que é uma boa solução.
Blackwood
É importante notar que flexbox não (ou apenas parcialmente) é suportado pelo IE caniuse.com/#feat=flexbox
David Salamon
isso é responsivo?
stackdave
1

em jQueryque você pode direcionar o Pai diretamente.

Isso é útil se você não sabe exatamente quantas crianças serão adicionadas dinamicamente ou se você não consegue descobrir seu número.

var tWidth=0;

$('.children').each(function(i,e){
tWidth += $(e).width();

///Example: If the Children have a padding-left of 10px;..
//You could do instead:
tWidth += ($(e).width()+10);

})
$('#parent').css('width',tWidth);

Isso permitirá que parentcresça horizontalmente à medida que childrensão adicionados.

NOTA: Isso pressupõe que o '.children'têm widthe HeightSet

Espero que ajude.

ErickBest
fonte
1

Se você souber o número de elementos por "linha" e a largura do contêiner, poderá usar um seletor para adicionar uma margem aos elementos necessários para causar uma aparência justificada.

Eu tinha linhas de três divs que eu queria justificadas, então usei o:

.tile:nth-child(3n+2) { margin: 0 10px }

isso permite que a div central em cada linha tenha uma margem que força a primeira e a terceira div às bordas externas do contêiner

Também é bom para outras coisas, como bordas de cores de fundo etc.

Dave Robertson
fonte