No CSS Flexbox, por que não existem propriedades "justify-items" e "justify-self"?

676

Considere o eixo principal e o eixo transversal de um contêiner flexível:

insira a descrição da imagem aqui                                                                                                                                                    Fonte: W3C

Para alinhar itens flexíveis ao longo do eixo principal, existe uma propriedade:

Para alinhar itens flexíveis ao longo do eixo transversal, existem três propriedades:

Na imagem acima, o eixo principal é horizontal e o eixo transversal é vertical. Essas são as direções padrão de um contêiner flexível.

No entanto, essas instruções podem ser facilmente trocadas com a flex-directionpropriedade.

/* main axis is horizontal, cross axis is vertical */
flex-direction: row;
flex-direction: row-reverse;

/* main axis is vertical, cross axis is horizontal */    
flex-direction: column;
flex-direction: column-reverse;

(O eixo transversal é sempre perpendicular ao eixo principal.)

Meu argumento ao descrever como os eixos funcionam é que não parece haver nada de especial em nenhuma das direções. Eixo principal, eixo transversal, ambos são iguais em termos de importância e flex-directionfacilitam a alternância.

Então, por que o eixo transversal obtém duas propriedades de alinhamento adicionais?

Por que align-contente são align-itemsconsolidados em uma propriedade para o eixo principal?

Por que o eixo principal não obtém uma justify-selfpropriedade?


Cenários em que essas propriedades seriam úteis:

  • colocando um item flexível no canto do contêiner flexível
    #box3 { align-self: flex-end; justify-self: flex-end; }

  • alinhando um grupo de itens flexíveis à direita ( justify-content: flex-end), mas com o primeiro item alinhado à esquerda ( justify-self: flex-start)

    Considere uma seção de cabeçalho com um grupo de itens de navegação e um logotipo. Com justify-selfo logotipo pode ser alinhado à esquerda, enquanto os itens de navegação ficam à direita, e tudo se ajusta suavemente ("flexiona") para diferentes tamanhos de tela.

  • em uma linha de três itens flexíveis, afixe ​​o item do meio ao centro do contêiner ( justify-content: center) e alinhe os itens adjacentes às bordas do contêiner ( justify-self: flex-starte justify-self: flex-end).

    Observe que os valores space-arounde space-betweena justify-contentpropriedade não manterão o item do meio centralizado sobre o contêiner se os itens adjacentes tiverem larguras diferentes.

Versão jsFiddle


No momento da redação deste documento, não há menção justify-selfou justify-itemsna especificação do flexbox .

No entanto, no Módulo de alinhamento de caixas CSS , que é a proposta inacabada do W3C de estabelecer um conjunto comum de propriedades de alinhamento para uso em todos os modelos de caixas, existe o seguinte:

insira a descrição da imagem aqui                                                                                                                                                    Fonte: W3C

Você notará isso justify-selfe justify-itemsestá sendo considerado ... mas não para o flexbox .


Terminarei reiterando a questão principal:

Por que não existem propriedades "justify-items" e "justify-self"?

Michael Benjamin
fonte
4
Como você esperaria justify-selftrabalhar para um item flexível? Suponha que você tenha os itens a, b, c, d com espaço extra para distribuir em torno deles, e o contêiner flex tenha justify-content: space-between, portanto eles acabam como | abcd |. O que significaria adicionar, por exemplo, justify-self: centerou 'justificar-se: flex-end', apenas ao item 'b' lá? Para onde você esperaria que fosse? (Eu vejo algumas demos em uma das respostas aqui, mas eu não vejo uma forma clara que ele iria trabalhar em geral.)
dholbert
(Como alternativa: suponha que temos justify-content: flex-start, para que os itens estão lotados no início como | abcd | O que você espera que ele faça, se você colocar. justify-self: [anything]Do item 'b' lá?)
dholbert
1
@ dholbert, você escreveu: Como você esperaria justify-selftrabalhar para um item flexível? Eu diria que não tão diferente do que as automargens já funcionam em itens flex. No seu segundo exemplo, o justify-self: flex-enditem d o moveria para a extremidade. Isso por si só seria um ótimo recurso, que as automargens já podem fazer. Postei uma resposta com uma demonstração.
Michael Benjamin
2
Estou principalmente vendo mais casos de uso aqui, e casos de uso são grandes - mas o pouco complicado é como encaixar isso na actual forma que justify-contente justify-selfsão especificados, para que casos com conflitos (como os cenários perguntei sobre) são definidos de forma clara e sensata. Como observei na minha resposta aqui, {justify|align}-selftrata-se de alinhar itens dentro de uma caixa maior, dimensionada independentemente do {justify|align}-selfvalor - e não existe essa caixa, no eixo principal, para alinhar um item flexível.
dholbert
1
RE "não é diferente das margens automáticas" - na verdade, eu estava perguntando sobre como você imagina justify-selfe justify-contentinterage, nos casos em que elas conflitam (como os cenários apresentados). As margens automáticas simplesmente não interagem justify-content- elas roubam todo o espaço da embalagem antes que você justify-contentpossa usá-lo. Portanto, as margens automáticas não são realmente um bom análogo de como isso funcionaria.
Dholbert

Respostas:

1248

Métodos para alinhar itens flexíveis ao longo do eixo principal

Como afirmado na pergunta:

Para alinhar itens flexíveis ao longo do eixo principal, existe uma propriedade: justify-content

Para artigos de flex de alinhamento ao longo do eixo transversal, existem três propriedades: align-content, align-itemsealign-self .

A pergunta então pergunta:

Por que não existem justify-itemse justify-selfpropriedades?

Uma resposta pode ser: porque eles não são necessários.

A especificação flexbox fornece dois métodos para alinhar itens flexíveis ao longo do eixo principal:

  1. A justify-contentpropriedade da palavra-chave e
  2. auto margens

justificar conteúdo

o justify-content propriedade alinha itens flexíveis ao longo do eixo principal do contêiner flexível.

É aplicado ao contêiner flexível, mas afeta apenas itens flexíveis.

Existem cinco opções de alinhamento:

  • flex-start ~ Os itens flexíveis são compactados no início da linha.

    insira a descrição da imagem aqui

  • flex-end ~ Os itens flexíveis são compactados no final da linha.

    insira a descrição da imagem aqui

  • center ~ Os itens flexíveis são compactados em direção ao centro da linha.

    insira a descrição da imagem aqui

  • space-between~ Os itens flexíveis são espaçados igualmente, com o primeiro item alinhado a uma borda do contêiner e o último item alinhado à borda oposta. As bordas usadas pelos primeiros e últimos itens depende flex-directione modo de escrita ( ltrou rtl).

    insira a descrição da imagem aqui

  • space-around~ O mesmo que space-betweencom espaços de meio tamanho nas duas extremidades.

    insira a descrição da imagem aqui


Margens automáticas

Com automargens , os itens flexíveis podem ser centralizados, espaçados ou agrupados em subgrupos.

Diferentemente justify-content, aplicado ao contêiner flexível, as automargens continuam nos itens flexíveis.

Eles trabalham consumindo todo o espaço livre na direção especificada.


Alinhar o grupo de itens flexíveis à direita, mas o primeiro item à esquerda

Cenário da pergunta:

  • alinhando um grupo de itens flexíveis à direita ( justify-content: flex-end), mas com o primeiro item alinhado à esquerda (justify-self: flex-start )

    Considere uma seção de cabeçalho com um grupo de itens de navegação e um logotipo. Com justify-selfo logotipo pode ser alinhado à esquerda, enquanto os itens de navegação ficam à direita, e tudo se ajusta suavemente ("flexiona") para diferentes tamanhos de tela.

insira a descrição da imagem aqui

insira a descrição da imagem aqui


Outros cenários úteis:

insira a descrição da imagem aqui

insira a descrição da imagem aqui

insira a descrição da imagem aqui


Coloque um item flexível no canto

Cenário da pergunta:

  • colocando um item flexível em um canto .box { align-self: flex-end; justify-self: flex-end; }

insira a descrição da imagem aqui


Centralize um item flexível na vertical e na horizontal

insira a descrição da imagem aqui

margin: autoé uma alternativa para justify-content: centere align-items: center.

Em vez deste código no contêiner flex:

.container {
    justify-content: center;
    align-items: center;
}

Você pode usar isso no item flexível:

.box56 {
    margin: auto;
}

Essa alternativa é útil ao centralizar um item flexível que transborda o contêiner .


Centralize um item flexível e centralize um segundo item flexível entre o primeiro e a borda

Um contêiner flexível alinha itens flexíveis distribuindo espaço livre.

Portanto, para criar equilíbrio igual , para que um item do meio possa ser centralizado no contêiner com um único item ao lado, um contrapeso deve ser introduzido.

Nos exemplos abaixo, os terceiros itens flexíveis invisíveis (casas 61 e 68) são introduzidos para equilibrar os itens "reais" (casas 63 e 66).

insira a descrição da imagem aqui

insira a descrição da imagem aqui

Obviamente, esse método não é ótimo em termos de semântica.

Como alternativa, você pode usar um pseudoelemento em vez de um elemento DOM real. Ou você pode usar o posicionamento absoluto. Todos os três métodos são abordados aqui: Itens flexíveis de alinhamento central e inferior

NOTA: Os exemplos acima funcionarão apenas - em termos de verdadeira centralização - quando os itens mais externos tiverem altura / largura iguais. Quando os itens flexíveis tiverem comprimentos diferentes, consulte o próximo exemplo.


Centralizar um item flexível quando itens adjacentes variarem de tamanho

Cenário da pergunta:

  • em uma linha de três itens flexíveis, afixe ​​o item do meio ao centro do contêiner ( justify-content: center) e alinhe os itens adjacentes às bordas do contêiner ( justify-self: flex-starte justify-self: flex-end).

    Observe que os valores space-arounde space-betweena justify-contentpropriedade não manterão o item do meio centralizado em relação ao contêiner se os itens adjacentes tiverem larguras diferentes ( consulte a demonstração ).

Conforme observado, a menos que todos os itens flexíveis tenham largura ou altura iguais (dependendo flex-direction), o item do meio não poderá ser verdadeiramente centralizado. Esse problema justifica uma justify-selfpropriedade (projetada para lidar com a tarefa, é claro).

Aqui estão dois métodos para resolver esse problema:

Solução 1: posicionamento absoluto

A especificação flexbox permite o posicionamento absoluto de itens flex . Isso permite que o item do meio seja perfeitamente centralizado, independentemente do tamanho de seus irmãos.

Lembre-se de que, como todos os elementos absolutamente posicionados, os itens são removidos do fluxo de documentos . Isso significa que eles não ocupam espaço no contêiner e podem se sobrepor aos irmãos.

Nos exemplos abaixo, o item do meio é centralizado com posicionamento absoluto e os itens externos permanecem em fluxo. Mas o mesmo layout pode ser obtido de maneira inversa: centralize o item do meio justify-content: centere posicione absolutamente os itens externos.

insira a descrição da imagem aqui

Solução 2: recipientes flexíveis aninhados (sem posicionamento absoluto)

.container {
  display: flex;
}
.box {
  flex: 1;
  display: flex;
  justify-content: center;
}
.box71 > span { margin-right: auto; }
.box73 > span { margin-left: auto;  }

/* non-essential */
.box {
  align-items: center;
  border: 1px solid #ccc;
  background-color: lightgreen;
  height: 40px;
}
<div class="container">
  <div class="box box71"><span>71 short</span></div>
  <div class="box box72"><span>72 centered</span></div>
  <div class="box box73"><span>73 loooooooooooooooong</span></div>
</div>

Veja como funciona:

  • A div de nível superior (.container ) de é um contêiner flexível.
  • Cada div ( .box) filho agora é um item flexível.
  • Cada .boxitem é fornecido flex: 1para distribuir o espaço do contêiner igualmente.
  • Agora os itens estão consumindo todo o espaço da linha e têm a mesma largura.
  • Faça de cada item um contêiner flexível (aninhado) e adicione justify-content: center .
  • Agora cada span elemento é um item flexível centralizado.
  • Use automargens flexíveis para deslocar os botões externos para spana esquerda e direita.

Você também pode renunciar justify-contente usarauto margens exclusivamente.

Mas justify-contentpode funcionar aqui porque as automargens sempre têm prioridade. Das especificações:

8.1 Alinhando com auto margens

Antes do alinhamento via justify-contente align-self, qualquer espaço livre positivo é distribuído para as margens automáticas nessa dimensão.


justify-content: space-same (conceito)

Voltando a justify-contentum minuto, aqui está uma idéia para mais uma opção.

  • space-same~ Um híbrido de space-betweene space-around. Os itens flexíveis são espaçados uniformemente (como space-between), exceto que, em vez de espaços de meio tamanho nas duas extremidades (como space-around), há espaços em tamanho total nas duas extremidades.

Esse layout pode ser alcançado com ::beforee ::afterpseudoelementos no contêiner flex.

insira a descrição da imagem aqui

(crédito: @oriol para o código e @crl para o rótulo)

ATUALIZAÇÃO: Os navegadores começaram a implementar space-evenly, o que faz o acima. Consulte esta publicação para obter detalhes: Espaço igual entre itens flexíveis


PLAYGROUND (inclui código para todos os exemplos acima)

Michael Benjamin
fonte
1
A resposta acima tampas o principal eixo , justify-contente automargens. Para o outro lado da moeda - o eixo transversal , align-items, align-selfe align-content- veja este post: stackoverflow.com/q/42613359/3597276
Michael Benjamin
4
@ MarkW, você está defendendo a justify-selfpropriedade ... as automargens são úteis, mas justify-self: centerseriam ideais. A maneira de resolver o problema que você apresentou seria criar itens duplicados invisíveis no lado oposto. Veja minha resposta aqui: stackoverflow.com/q/38948102/3597276
Michael Benjamin
5
Seu space-sameconceito é real agora. É chamado space-evenly, mas ele só é suportado pelo Firefox no momento: developer.mozilla.org/en-US/docs/Web/CSS/justify-content
benface
1
@ Benface, Sim, você está certo. Obrigado por apontar isso. Eu tenho realmente escrevendo sobre space-evenlyem outras respostas: stackoverflow.com/q/45134400/3597276
Michael Benjamin
1
De fato, space-evenly era suportado no Chrome 57-60, mas apenas para o layout de grade. Foi um bug que foi corrigido e, desde o Chrome 61, ele também é compatível com o Flexbox. Além disso, não é o caminho a imitá-lo sem pseudo-elementos: .item { margin-right: auto } .item:first-child { margin-left: auto }.
Ilya Streltsyn
154

Sei que isso não é uma resposta, mas gostaria de contribuir com esse assunto para o que vale a pena. Seria ótimo se eles pudessem liberar o justify-selfflexbox para torná-lo realmente flexível.

É minha convicção que, quando houver vários itens no eixo, a maneira mais lógica de justify-selfse comportar é alinhar-se aos vizinhos (ou arestas) mais próximos, conforme demonstrado abaixo.

Eu realmente espero que o W3C tome conhecimento disso e pelo menos o considere. =)

insira a descrição da imagem aqui

Dessa forma, você pode ter um item realmente centralizado, independentemente do tamanho da caixa esquerda e direita. Quando uma das caixas atinge o ponto da caixa central, simplesmente a empurra até que não haja mais espaço para distribuir.

insira a descrição da imagem aqui

A facilidade de criar layouts impressionantes é interminável, dê uma olhada neste exemplo "complexo".

insira a descrição da imagem aqui

Marca
fonte
12
@ Mark isso é incrível! Obrigado por reservar um tempo para redigir isso. Espero que você não se importe, mas eu o enviei aqui: discourse.wicg.io/t/flexbox-justify-self-property/1146
Zaqx 15/15
1
@Zaqx claro, quanto mais exposição, melhor. Sério, espero que eles encontrem uma maneira de tornar essa realidade, adorariam sujar minhas mãos nisso.
Mark
1
Olá Mark, @Zaqx, publiquei uma resposta que pode abranger alguns dos casos de uso mencionados nesta resposta. Eu descobri que muito ainda pode ser feito no eixo principal sem precisar justify-selfe justify-items.
Michael Benjamin
3
@Michael_B Que bom que você está aprendendo mais sobre o flexbox e apreciamos o tempo gasto para formatar suas anotações em uma resposta. Margem: auto é realmente legal (embora você encontre os navegadores que implementaram as versões de 2009 e 2012 da especificação flexbox não possuem recurso equivalente, o que reduz drasticamente a capacidade de usá-lo em um site de produção). No entanto, mesmo em navegadores que suportam margin: auto, o principal caso de uso aqui de um item centrado em relação ao seu contêiner enquanto o espaço existe ainda é impossível sem uma propriedade de justificativa ou similar.
Zaqx
1
@Zaqx, obrigado pelo feedback. E sim, eu concordo com você, as automargens não são um substituto completo justify-self. Tomei o cuidado de redigir meu comentário anterior dizendo que as automargens cobrirão alguns dos casos de uso . Como você observou, ele não pode centralizar um item no local quando itens adjacentes são de tamanhos diferentes. No entanto, fornece mais opções para alinhar itens flexíveis. Quando comecei a aprender sobre o flexbox, pensei que justify-contentitens espaçadores invisíveis eram a única maneira.
22715 Michael Michael Benjamin
20

Isso foi solicitado na lista de estilos www, e Tab Atkins (editor de especificações) forneceu uma resposta explicando o porquê . Vou elaborar um pouco aqui.

Para começar, vamos assumir inicialmente que nosso contêiner flex é uma linha ( flex-wrap: nowrap). Nesse caso, há claramente uma diferença de alinhamento entre o eixo principal e o eixo transversal - há vários itens empilhados no eixo principal, mas apenas um item empilhado no eixo transversal. Portanto, faz sentido ter um "auto-alinhamento" personalizável por item no eixo cruzado (já que cada item é alinhado separadamente, por si só), enquanto não faz sentido no eixo principal (pois lá, o itens são alinhados coletivamente).

Para caixa flexível de várias linhas, a mesma lógica se aplica a cada "linha flexível". Em uma determinada linha, os itens são alinhados individualmente no eixo transversal (já que há apenas um item por linha, no eixo transversal), versus coletivamente no eixo principal.


Aqui está outra maneira de expressar isso: então, todas as propriedades *-selfe *-contentsão sobre como distribuir espaço extra em torno das coisas. Mas a principal diferença é que as *-selfversões são para casos em que há apenas uma coisa nesse eixo , e as *-contentversões são para quando há potencialmente muitas coisas nesse eixo . Os cenários de uma coisa versus muitas coisas são tipos diferentes de problemas e, portanto, eles têm tipos diferentes de opções disponíveis - por exemplo, os valores space-around/ space-betweenfazem sentido para *-content, mas não para *-self.

SO: No eixo principal de uma caixa flexível, há muitas coisas para distribuir espaço. Portanto, uma *-contentpropriedade faz sentido lá, mas não uma *-selfpropriedade.

Por outro lado, no eixo transversal, temos *-selfuma *-contentpropriedade e uma . Um determina como distribuiremos o espaço em torno das muitas linhas flexíveis ( align-content), enquanto o outro ( align-self) determina como distribuir o espaço em torno dos itens individuais flexíveis no eixo transversal, dentro de uma determinada linha flexível.

(Estou ignorando *-itemspropriedades aqui, pois elas simplesmente estabelecem padrões para *-self.)

dholbert
fonte
1
Entendo como um justify-selfproblema pode ser em um eixo com vários itens em oposição a um item. No entanto, eu realmente espero que eles estudem mais, em uma situação de vários itens, como se justify-selfcomportaria, porque há algumas situações em que isso pode ser realmente útil. Por exemplo ( stackoverflow.com/questions/32378953/… ).
Mark
Boa descoberta nessa lista de endereços. Tentando enrolar minha cabeça, como ainda vejo boas possibilidades de casos de uso justify-self.
Michael Benjamin
Adicionei um pouco mais de esclarecimento, explicando como *-selfé o caso de casos em que só temos uma coisa a alinhar, enquanto que os *-contentcasos em que temos muitas coisas a alinhar. Isso torna um pouco mais claro?
precisa saber é o seguinte
Sim, é mais claro. Agradeço a explicação. Mas parece que tudo se resume a uma simples preferência dos autores das especificações, não a uma necessidade específica baseada na lógica. Na lista de correspondência que você referenciou : As propriedades * -self só funcionam se o filho estiver sozinho nesse eixo. Por quê? Parece não haver necessidade disso. É uma decisão arbitrária. Uma preferência. De fato, as automargens, também parte da especificação, permitem o alinhamento * com vários itens na linha. Não há razão clara para que as propriedades da palavra-chave também não possam.
Michael Benjamin
1

Sei que isso não usa o flexbox, mas, para o simples caso de uso de três itens (um à esquerda, um no centro e outro à direita), isso pode ser feito facilmente usando display: grido pai, grid-area: 1/1/1/1;os filhos e o justify-selfposicionamento dessas crianças.

<div style="border: 1px solid red; display: grid; width: 100px; height: 25px;">
  <div style="border: 1px solid blue; width: 25px; grid-area: 1/1/1/1; justify-self: left;"></div>
  <div style="border: 1px solid blue; width: 25px; grid-area: 1/1/1/1; justify-self: center;"></div>
  <div style="border: 1px solid blue; width: 25px; grid-area: 1/1/1/1; justify-self: right;"></div>
</div>

Venryx
fonte
Obrigado pela resposta, mas realmente não aborda a questão. Além disso, há uma maneira mais simples de realizar o seu layout: jsfiddle.net/fga89m2o
Michael Benjamin
0

Acabei de encontrar minha própria solução para esse problema, ou pelo menos meu problema.
Eu estava usando em justify-content: space-aroundvez de justify-content: space-between;.

Dessa forma, os elementos finais permanecerão na parte superior e inferior e você poderá ter margens personalizadas, se desejar.

Leif Messinger LOAF
fonte