Pare de chutar e aprenda como funciona a position: absolute

Marco Bruno
CollabCode
Published in
11 min readMay 4, 2018
Versão em vídeo do post pra quem não quiser ler ;-)

Essa foi a propriedade que eu mais utilizei no meu primeiro ano como Desenvolvedor FrontEnd. Até hoje me lembro do dia que fiz o código de uma landing page para o dia das mães na Locaweb e depois de uma semana trabalhando nela eu entreguei. Nessa época por algum motivo eu não tinha mais ninguém no mesmo time que eu como dev FrontEnd, mas logo a 4 fileiras a minha frente habitava um dev com um bom coração feliz, que me fez jogar fora todo o trabalho de uma semana que estava cheio de position: absolute. Em apenas uma noite fizemos a landing page juntos usando direito todas as propriedades de posicionamento do CSS, como: display: inline; display: block; display: inline-block; float: left | right; postion: static | relative.

Hoje graças ao William Bruno que foi o dev com o bom coração feliz, eu consigo passar todo meu conhecimento nas aulas da Caelum de FrontEnd, obrigado man. ;-)

Antes de entender o nosso desafio vamos ver o HTML e CSS base que utilizaremos:

HTML (index.html)

<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<title>Exemplo de como funciona a postion: absolute</title><link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/position.css">
</head>
<body>
<div class="elementExample elementExample_first">
Apenas uma div
</div>
<div class="elementExample elementExample_second">
Apenas outra div
</div>
<div class="elementExample elementExample_last">
<div class="elementExample-internal">Interna</div>
</div>
</body>
</html>

CSS (position.css)

.elementExample {
width: 200px;
height: 200px;
line-height: 200px;
color: #FFF;
text-transform: uppercase;
text-align: center;
cursor: pointer;
}
.elementExample_first {
background-color: #6c5ce7;
}
.elementExample_second {
background-color: #00b894;
}
.elementExample_last {
background-color: #d63031;
}
.elementExample-internal {
width: 100px;
height: 100px;
line-height: 100px;
background-color: #00cec9;
}

CSS (reset.css)

* {
margin: 0;
padding: 0;
border: 0;
}
body {
background-color: #b2bec3;
font-family: "Open Sans", sans-serif;
}
ul, ol, li {
list-style: none;
}

Por favor abra o arquivo index.html no seu browser (navegador) e você verá o seguinte resultado:

Nosso layout inicial

Agora que já temos o nosso layout inicial, podemos falar do nosso objetivo até o final do post. Vamos deixar a última div que é a vermelha alinhada totalmente a esquerda e no topo da página, além disso o elemento que está dentro dela tem que ficar centralizado. Nossa segunda div que é a verde escuro, ficará centralizada em relação à tela, tanto no sentido vertical quanto horizontal. Por último deixamos a nossa primeira div que é a roxa, totalmente no lado direito do browser e no topo. Conforme a imagem a seguir:

Nosso objetivo até o final do post :-)

Vamos começar a implementar nosso objetivo pela nossa primeira div, a roxa. Primeiro tentando deslocar ela para o lado direito da tela. Para isso precisamos voltar no nosso arquivo position.css e adicionar a propriedade position com o valor absolute no seletor .elementExample_first:

postion.css

.elementExample {
width: 200px;
height: 200px;
line-height: 200px;
color: #FFF;
text-transform: uppercase;
text-align: center;
cursor: pointer;
}
.elementExample_first {
position: absolute; /* adicionamos essa linha */
background-color: #6c5ce7;
}
.elementExample_second {
background-color: #00b894;
}
.elementExample_last {
background-color: #d63031;
}
.elementExample-internal {
width: 100px;
height: 100px;
line-height: 100px;
background-color: #00cec9;
}

Indo até o browser e atualizando ele, você verá o seguinte resultado visual:

Resultado visual com apenas a propriedade postion:absolute na primeira div

Agora temos a nossa primeira div e a terceira na tela, mas parece que a nossa segunda div sumiu. :-(

Isso está acontecendo porque toda vez que utilizamos a propriedade position com o valor absolute, esse valor cria de imediato um novo contexto para a div e este contexto fica a frente do contexto do browser, além disso, é liberado o espaço que a primeira div ocupava no contexto do browser. Por causa desse último comportamento do absolute que não estamos conseguindo ver a nossa segunda div, portanto podemos concluir que a segunda div está abaixo da nossa primeira div. Para vermos se isso é verdade, vamos voltar para o nosso arquivo position.css e adicionar em nossa primeira div a propriedade opacity com o valor 0 que deixará ela totalmente transparente.

position.css

.elementExample {
width: 200px;
height: 200px;
line-height: 200px;
color: #FFF;
text-transform: uppercase;
text-align: center;
cursor: pointer;
}
.elementExample_first {
position: absolute;
opacity: 0; /* adicionamos essa linha */
background-color: #6c5ce7;
}
.elementExample_second {
background-color: #00b894;
}
.elementExample_last {
background-color: #d63031;
}
.elementExample-internal {
width: 100px;
height: 100px;
line-height: 100px;
background-color: #00cec9;
}

Voltando no browser e atualizando ele, você verá que a nossa segunda div está de fato atrás da primeira div (que neste momento está transparente):

Resultado no browser após adicionarmos a propriedade opacity: 0 na primeira div

Para mover a nossa primeira div para o lado direito do browser só precisamos adicionar a propriedade right com o valor 0. Ah! não podemos nos esquecer de remover a propriedade opacity. Vamos até o arquivo position.css para fazer essas alterações:

position.css

.elementExample {
width: 200px;
height: 200px;
line-height: 200px;
color: #FFF;
text-transform: uppercase;
text-align: center;
cursor: pointer;
}
.elementExample_first {
position: absolute;
right: 0; /* adicionamos essa linha e removemos a propriedade opacity*/
background-color: #6c5ce7;
}
.elementExample_second {
background-color: #00b894;
}
.elementExample_last {
background-color: #d63031;
}
.elementExample-internal {
width: 100px;
height: 100px;
line-height: 100px;
background-color: #00cec9;
}

Salvando o arquivo e voltando para o nosso browser (lembre-se de atualizar) podemos ver que conseguimos implementar a primeira parte do nosso objetivo:

Nossa primeira div com position: absolute e right: 0

Não temos só a propriedade right temos um total de quatro propriedades que podemos utilizar junto com a propriedade position, uma vez que o valor dela não é o padrão static. As quatro propriedades são: right, bottom, left e top.

Quando utilizamos apropriedade right: 0; em conjunto com a propriedade position: absolute; na nossa primeira div ela foi para o ponto 0 do lado direito do browser. Então podemos concluir que a referência é o browser uma vez que estamos utilizando o valor absolute para a nossa propriedade position. Fora algumas linhas a seguir que temos apenas uma exceção. ;-)

Agora vamos fazer o código que deixará a segunda div centralizada no browser tanto no sentido horizontal (eixo x) quando no sentido vertical (eixo y). Como acabamos de ver, se quisermos alinhar um elemento em relação ao browser podemos utilizar a propriedade position com a valor absolute, portanto vamos ao nosso arquivo position.css para adicionar no seletor de classe .elementExample_second o valor absolute pra propriedade position:

position.css

.elementExample {
width: 200px;
height: 200px;
line-height: 200px;
color: #FFF;
text-transform: uppercase;
text-align: center;
cursor: pointer;
}
.elementExample_first {
position: absolute;
right: 0;
background-color: #6c5ce7;
}
.elementExample_second {
position: absolute; /* adicionando essa linha */
background-color: #00b894;
}
.elementExample_last {
background-color: #d63031;
}
.elementExample-internal {
width: 100px;
height: 100px;
line-height: 100px;
background-color: #00cec9;
}

Indo até o browser e atualizando ele podemos ver um comportamento de criar um novo contexto a frente do contexto padrão do browser acontecendo novamente:

Resultado no browser com o segundo elemento com a propriedade postion: absolute

A primeira coisa que quero fazer junto com você, é centralizar o elemento no sentido horizontal (eixo x). Para isso podemos utilizar a propriedade left com o valor 50%, essa porcentagem pega como referência a largura do browser, por exemplo se o eu browser tiver com a largura de 1000px o 50% será a mesma coisa que 500px, mas como a porcentagem é uma unidade de medida relativa não vamos precisar se preocupar caso alargura do browser seja alterada pelo usuário.

Bora ir no nosso arquivo position.css no seletor .elementExample_second e adicionar nele a left: 50%;:

position.css

.elementExample {
width: 200px;
height: 200px;
line-height: 200px;
color: #FFF;
text-transform: uppercase;
text-align: center;
cursor: pointer;
}
.elementExample_first {
position: absolute;
right: 0;
background-color: #6c5ce7;
}
.elementExample_second {
position: absolute;
left: 50%; /* adicionando essa linha */
background-color: #00b894;
}
.elementExample_last {
background-color: #d63031;
}
.elementExample-internal {
width: 100px;
height: 100px;
line-height: 100px;
background-color: #00cec9;
}

Atualizando o browser teremos o seguinte resultado visual:

Resultado no browser com a propriedade position: absolute e left: 50% na primeira div

Eita! Não ficou centralizada a nossa div como o esperado. Na verdade o que está centralizado é o lado esquerdo do elemento porque o position: absolute; utiliza como referência o lado esquerdo da div não o centro dela uma vez que utilizamos a propriedade left, se mudarmos para a propriedade right a referência se torna o lado direito da div.

O que precisamos fazer para que a div fique de fato centralizada é mover exatamente a metade da largura da div para o lado esquerdo. Para isso temos a propriedade transform com o valor translateX que move o elemento para direita se passarmos um valor positivo e se passarmos um valor negativo movemos ela para a esquerda, sempre trabalhando com o sentido horizontal (eixo X).

Como precisamos mover metade da largura da div, que é de 200px, moveremos então 100px e, este valor tem que ser negativo para que ela seja movida para a esquerda.

Se colocarmos o valor em px toda vez que mudarmos a largura da div será necessário alterar também o valor que acabamos de definir no translateX. Para deixar o código com uma manutenção mais feliz, podemos utilizar no lugar do -100px o valor de -50% e esse -50% será sempre a metade da largura que a div tem.

Vamos voltar no nosso arquivo position.css e adicionar o transform: translateX(-50%); e ver se conseguimos chegar no resultado esperado de deixar a nossa segunda div centralizada no sentido horizontal (eixo x):

position.css

.elementExample {
width: 200px;
height: 200px;
line-height: 200px;
color: #FFF;
text-transform: uppercase;
text-align: center;
cursor: pointer;
}
.elementExample_first {
position: absolute;
right: 0;
background-color: #6c5ce7;
}
.elementExample_second {
position: absolute;
left: 50%;
transform: translateX(-50%); /* adicionado essa linha */
background-color: #00b894;
}
.elementExample_last {
background-color: #d63031;
}
.elementExample-internal {
width: 100px;
height: 100px;
line-height: 100px;
background-color: #00cec9;
}

Dessa vez se você for até o browser teremos o resultado esperado:

Resultado após termos adicionado a transform: translateX(-50%)

Agora precisamos aplicar o mesmo conceito que fizemos no sentido horizontal (eixo x) e aplicar no sentido vertical (eixo y). Vamos adicionar primeiro a propriedade top com valor de 50% no seletor .elementExample_second que está no arquivo position.css:

position.css

.elementExample {
width: 200px;
height: 200px;
line-height: 200px;
color: #FFF;
text-transform: uppercase;
text-align: center;
cursor: pointer;
}
.elementExample_first {
position: absolute;
right: 0;
background-color: #6c5ce7;
}
.elementExample_second {
position: absolute;
left: 50%;
top: 50%; /* adicionado essa linha */
transform: translateX(-50%);
background-color: #00b894;
}
.elementExample_last {
background-color: #d63031;
}
.elementExample-internal {
width: 100px;
height: 100px;
line-height: 100px;
background-color: #00cec9;
}

Após salvar o arquivo position.css, vá até o seu browser e atualize ele, você terá o seguinte resultado visual:

Resultado no browser após ter adicionado o top: 50%

Tivemos o mesmo efeito de quando utilizamos o left: 50%, agora com o top: 50% a nossa div não está centralizada novamente, na verdade o que está centralizado é a parte do topo dela em relação a página, por isso que precisamos acrescentar na propriedade transform o valor translateY(-50%) para mover o elemento a metade da altura dele para cima. Volte ao arquivo position.css e adicione mais um valor para a propriedade transform que criamos no seletor .elementExample, o valor será translateY(-50%):

position.css

.elementExample {
width: 200px;
height: 200px;
line-height: 200px;
color: #FFF;
text-transform: uppercase;
text-align: center;
cursor: pointer;
}
.elementExample_first {
position: absolute;
right: 0;
background-color: #6c5ce7;
}
.elementExample_second {
position: absolute;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%); /* adicionamos o valor translateY(-50%) */
background-color: #00b894;
}
.elementExample_last {
background-color: #d63031;
}
.elementExample-internal {
width: 100px;
height: 100px;
line-height: 100px;
background-color: #00cec9;
}

Agora sim! Indo até o browser você verá que conseguimos implementar a segunda parte do nosso objetivo:

Conseguimos implementar a segunda parte do nosso objetivo

Nessa terceira e última parte do nosso objetivo só precisamos centralizar a div interna, mas dessa vez não em relação a página mas em relação a div vermelha que é o elemento pai da div interna. Para isso podemos utilizar as mesmas propriedades que utilizamos para centralizar a segunda div. Por tanto, precisamos voltar ao arquivo position.css e no seletor .elementExample-internal adicionar as 4 propriedades que utilizamos pra centralizar a nossa segunda div:

position.css

.elementExample {
width: 200px;
height: 200px;
line-height: 200px;
color: #FFF;
text-transform: uppercase;
text-align: center;
cursor: pointer;
}
.elementExample_first {
position: absolute;
right: 0;
background-color: #6c5ce7;
}
.elementExample_second {
position: absolute;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
background-color: #00b894;
}
.elementExample_last {
background-color: #d63031;
}
.elementExample-internal {
position: absolute; /* adicionamos essa linha e as 3 seguintes */
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
width: 100px;
height: 100px;
line-height: 100px;
background-color: #00cec9;
}

Indo até o browser, não teremos o comportamento que queremos em nosso objetivo, mas felizmente é o comportamento esperado. Lembre-se que o absolute pega como referência o browser, sendo assim o elemento interno também ficará no centro do browser, conforme a imagem a seguir:

A div interna centralizada em relação a tela

Felizmente temos mais uma regra no absolute que nos ajudará a executar o nosso objetivo. Para fazer com que a div interna respeite o seu pai deixando de vazar o tamanho dele, precisamos definir um position diferente de static para o pai do elemento que está com o position: absolute. O valor mais utilizado para o position no pai é relative porque essa propriedade apesar de criar um novo contexto, não libera o espaço dela no contexto do browser, dessa forma fica mais fácil prever o que acontecerá no layout.

Pra colocar em prática a teoria acima, vamos aplicar a position: relative na div vermelha que tem classe elementExample_last:

.elementExample {
width: 200px;
height: 200px;
line-height: 200px;
color: #FFF;
text-transform: uppercase;
text-align: center;
cursor: pointer;
}
.elementExample_first {
position: absolute;
right: 0;
background-color: #6c5ce7;
}
.elementExample_second {
position: absolute;
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
background-color: #00b894;
}
.elementExample_last {
background-color: #d63031;
}
.elementExample-internal {
position: absolute; /* adicionamos essa linha */
left: 50%;
top: 50%;
transform: translateX(-50%) translateY(-50%);
width: 100px;
height: 100px;
line-height: 100px;
background-color: #00cec9;
}

Voltando ao browser podemos ver que nosso objetivo está completo:

Chegamos no nosso objetivo

Se ficou qualquer dúvida e tem qualquer sugestão para melhorar nesse post e nos demais, por favor não deixe de falar nos comentários ou se preferir você pode me adicionar nas redes socias da vida, você me achará por MarcoBrunoBR tanto no twitter, facebook ou linkedin. Eu também gosto de usar um chat chamado Telegram, lá você também me achará por MarcoBrunoBR.

Até o próximo post :-)

--

--

Marco Bruno
CollabCode

Migrei de palhaço para Dev. Front-End/UX e agora eu trabalho como streamer de código