Abaixo estão cinco opções para alcançar esse layout:
- Posicionamento CSS
- Flexbox com elemento DOM invisível
- Flexbox com pseudo-elemento invisível
- Flexbox com
flex: 1
- Layout de Grade CSS
Método # 1: Propriedades de posicionamento CSS
Aplique position: relative
no recipiente flexível.
Aplique position: absolute
ao item D.
Agora este item está absolutamente posicionado dentro do contêiner flexível.
Mais especificamente, o item D é removido do fluxo de documentos, mas permanece dentro dos limites do ancestral posicionado mais próximo .
Use as propriedades de deslocamento CSS top
e right
para mover esse elemento para a posição.
li:last-child {
position: absolute;
top: 0;
right: 0;
background: #ddd;
}
ul {
position: relative;
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
p {
text-align: center;
margin-top: 0;
}
span {
background-color: aqua;
}
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>true center</span></p>
Uma ressalva para esse método é que alguns navegadores podem não remover completamente um item flexível absolutamente posicionado do fluxo normal. Isso altera o alinhamento de maneira inesperada e não padrão. Mais detalhes: O item flexível absolutamente posicionado não é removido do fluxo normal no IE11
Método 2: Margens automáticas flexíveis e item flexível invisível (elemento DOM)
Com uma combinação de auto
margens e um novo item flexível invisível, o layout pode ser alcançado.
O novo item flexível é idêntico ao item D e é colocado na extremidade oposta (a borda esquerda).
Mais especificamente, como o alinhamento flexível é baseado na distribuição de espaço livre, o novo item é um contrapeso necessário para manter as três caixas do meio centralizadas horizontalmente. O novo item deve ter a mesma largura que o item D existente, ou as caixas do meio não serão centralizadas com precisão.
O novo item é removido da visualização com visibility: hidden
.
Em resumo:
- Crie uma duplicata do
D
elemento.
- Coloque-o no início da lista.
- Uso flectir
auto
margens para manter A
, B
e C
centrado, com ambos os D
elementos de criar equilíbrio igual a partir de ambas as extremidades.
- Aplicar
visibility: hidden
à duplicataD
li:first-child {
margin-right: auto;
visibility: hidden;
}
li:last-child {
margin-left: auto;
background: #ddd;
}
ul {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
p { text-align: center; margin-top: 0; }
span { background-color: aqua; }
<ul>
<li>D</li><!-- new; invisible spacer item -->
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>true center</span></p>
Método # 3: Margens automáticas flexíveis e item flexível invisível (pseudoelemento)
Esse método é semelhante ao nº 2, exceto que é mais limpo semanticamente e a largura de D
deve ser conhecida.
- Crie um pseudoelemento com a mesma largura que
D
.
- Coloque-o no início do recipiente com
::before
.
- Use
auto
margens flexíveis para manter A
, B
e C
perfeitamente centralizado, com o pseudo e os D
elementos criando um equilíbrio igual entre as duas extremidades.
ul::before {
content:"D";
margin: 1px auto 1px 1px;
visibility: hidden;
padding: 5px;
background: #ddd;
}
li:last-child {
margin-left: auto;
background: #ddd;
}
ul {
padding: 0;
margin: 0;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
li {
display: flex;
margin: 1px;
padding: 5px;
background: #aaa;
}
p { text-align: center; margin-top: 0; }
span { background-color: aqua; }
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>true center</span></p>
Método 4: Adicionar flex: 1
aos itens esquerdo e direito
Começando pelo método nº 2 ou nº 3 acima, em vez de se preocupar com a mesma largura dos itens esquerdo e direito para manter o equilíbrio, basta fornecer cada um flex: 1
. Isso forçará os dois a consumir o espaço disponível, centralizando o item do meio.
Você pode adicionar display: flex
itens individuais para alinhar seu conteúdo.
NOTA sobre o uso deste método com min-height
: Atualmente no Chrome, Firefox, Edge e possivelmente em outros navegadores, a regra abreviada seflex: 1
divide em:
flex-grow: 1
flex-shrink: 1
flex-basis: 0%
Essa unidade de porcentagem (%) ativada flex-basis
faz com que esse método quebre quando min-height
é usado no contêiner. Isso ocorre porque, como regra geral, as alturas de porcentagem nos filhos exigem uma height
configuração explícita de propriedade no pai.
Essa é uma regra antiga de CSS que remonta a 1998 ( CSS Nível 2 ), que ainda está em vigor em muitos navegadores, em algum grau ou outro. Para detalhes completos, veja aqui e aqui .
Aqui está uma ilustração do problema postado nos comentários do usuário2651804 :
#flex-container {
display: flex;
flex-direction: column;
background: teal;
width: 150px;
min-height: 80vh;
justify-content: space-between;
}
#flex-container>div {
background: orange;
margin: 5px;
}
#flex-container>div:first-child {
flex: 1;
}
#flex-container::after {
content: "";
flex: 1;
}
<div id="flex-container">
<div>very long annoying text that will add on top of the height of its parent</div>
<div>center</div>
</div>
A solução é não usar a unidade percentual. Tente px
ou simplesmente nada (o que a especificação realmente recomenda , apesar do fato de que pelo menos alguns dos principais navegadores acrescentaram uma unidade de porcentagem por qualquer motivo).
#flex-container {
display: flex;
flex-direction: column;
background: teal;
width: 150px;
min-height: 80vh;
justify-content: space-between;
}
#flex-container > div {
background: orange;
margin: 5px;
}
/* OVERRIDE THE BROWSER SETTING IN THE FLEX PROPERTY */
#flex-container > div:first-child {
flex: 1;
flex-basis: 0;
}
#flex-container::after {
content: "";
flex: 1;
flex-basis: 0;
}
/* OR... JUST SET THE LONG-HAND PROPERTIES INDIVIDUALLY
#flex-container > div:first-child {
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
#flex-container::after {
content: "";
flex-grow: 1;
flex-shrink: 1;
flex-basis: 0;
}
*/
<div id="flex-container">
<div>very long annoying text that will add on top of the height of its parent</div>
<div>center</div>
</div>
Método # 5: Layout da Grade CSS
Esse pode ser o método mais limpo e eficiente. Não há necessidade de posicionamento absoluto, elementos falsos ou outros truques.
Basta criar uma grade com várias colunas. Posicione seus itens nas colunas central e final. Basicamente, basta deixar a primeira coluna vazia.
ul {
display: grid;
grid-template-columns: 1fr repeat(3, auto) 1fr;
grid-column-gap: 5px;
justify-items: center;
}
li:nth-child(1) { grid-column-start: 2; }
li:nth-child(4) { margin-left: auto; }
/* for demo only */
ul { padding: 0; margin: 0; list-style: none; }
li { padding: 5px; background: #aaa; }
p { text-align: center; }
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
</ul>
<p><span>| true center |</span></p>