Pare de chutar e aprenda como funciona a position: fixed

Marco Bruno
Jun 13 · 15 min read
Bora aprender como funciona o position: fixed para não precisar fazer umas gambiarras :-)

Quando estou gravando aulas de CSS do curso Do Front ao End e tirando dúvidas dos alunos pelo Discord da CollabCode sobre as propriedades de posicionamento do CSS, a position: fixed é a mais divertida de explicar :-)

Ah! Esse será o primeiro post que vou te propor um desafio final para você testar o seu conhecimento sobre o conteúdo passado aqui e outras coisas mais sobre CSS. Depois que terminar o desafio ou enquanto você estiver fazendo, entre lá no Discord da CollabCode clicando no link a seguir para você tirar suas dúvidas e compartilhar todo seu conhecimento:

Se tem dúvidas sobre outras propriedades de posicionamento do CSS, eu tenho um post que é o agregador para todos os posts que escrevi sobre o assunto:

Não diferente dos outros posts sobre as propriedades de posicionamento do CSS, neste nós teremos um objetivo e código inicial. Vou começar te mostrando o nosso código inicial e em seguida mostro qual será o objetivo que implementaremos durante o post.

Nosso layout inicial tem 3 arquivos: index.html, reset.css e position.css.

<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">

<title>Exemplo de como funciona a propriedade position: fixed</title>
<link rel="stylesheet" href="css/reset.css">
<link rel="stylesheet" href="css/position.css">
</head>
<body>
<header class="header">
<img class="header-logo" src="img/logo.png" alt="Logo do CollabCode">
</header>
<article>
<h1>Novos Vídeos toda segunda, quarta e sexta</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Labore dicta voluptate odit aperiam distinctio, minus unde alias assumenda, excepturi perferendis laborum dolores beatae? Quae sed, magnam sequi aspernatur sit error.
</p>
</article>
<aside class="banner">
Último vídeo
</aside>
<a class="button" href="">Assistir agora</a>
</body>
</html>
* {
margin: 0;
padding: 0;
border: 0;
}
body {
font-family: "Open Sans", sans-serif;
}
ul, ol, li {
list-style: none;
}
.header {
padding: 20px 40px;
border-bottom: 1px solid #222f3e;
margin-bottom: 30px;
}
.header-logo {
height: 50px;
}
.banner {
background-color: #5f27cd;
color: #FFF;
text-transform: uppercase;
text-align: center;
width: 200px;
height: 200px;
line-height: 200px;
}
.button {
display: block;
width: 160px;
height: 40px;
opacity: 0.95;
height: 60px;
line-height: 60px;
text-align: center;
color: #FFF;
text-decoration: none;
text-transform: uppercase;
background-color: #1dd1a1;
}
p {
margin-bottom: 20px;
}

Ah! Você também vai precisar do logo da CollabCode que usamos dentro da tag <header>, aí está ele:

Logo da CollabCode com o seu mascote Gueio

Se você abrir o arquivo index.html em seu browser (navegador) verá o seguinte resultado visual:

Nosso layout inicial

Nosso objetivo é deixar o menu fixo ao topo do browser, o botão verde fixo na parte inferior do browser e por último deixar a caixa roxa fixa do lado direito e centralizada no sentido horizontal (eixo y) do nosso browser. Quando eu falo fixo, estou querendo dizer que quando o usuário utilizar o scroll (barra de rolagem) os 3 elementos que comentei anteriormente ficam parados.

Nosso objetivo até o final do post

Vamos começar a implementar nosso objetivo pela tag aside que está na cor roxa. Primeiro vamos deixá-la do lado direito no topo em relação ao browser de forma que ela fique fixa no topo à direita mesmo se o usuário utilizar o scroll do browser. Para ficar fixa utilizaremos a propriedade position com o valor fixed e junto podemos utilizar a propriedade right com o valor 0 e a top com valor 0 para movermos a aside para o topo e a direita em relação ao browser. Aplicaremos essas três propriedades dentro do seletor .banner no arquivo position.css:

.header {
padding: 20px 40px;
border-bottom: 1px solid #222f3e;
margin-bottom: 30px;
}
.header-logo {
height: 50px;
}
.banner {
position: fixed;
top: 0;
right: 0;
background-color: #5f27cd;
color: #FFF;
text-transform: uppercase;
text-align: center;
width: 200px;
height: 200px;
line-height: 200px;
}
.button {
display: block;
width: 160px;
height: 40px;
opacity: 0.95;
height: 60px;
line-height: 60px;
text-align: center;
color: #FFF;
text-decoration: none;
text-transform: uppercase;
background-color: #1dd1a1;
}
p {
margin-bottom: 20px;
}

Salvando o arquivo position.css e abrindo o arquivo index.html no browser você terá o seguinte resultado visual:

Tag aside com position: fixed, top: 0 e right: 0

Assim que adicionamos a propriedade position com o valor fixed o nosso elemento roxo sai do contexto padrão do browser e fica em um novo contexto. Esse novo contexto fica à frente do contexto padrão do browser, além disso, é liberado o espaço que o elemento ocupava no contexto do browser. Por isso, o botão verde que estava abaixo do elemento roxo subiu e ocupou o lugar do elemento roxo.

Outro comportamento do position:fixed, é que a referência dele de alinhamento é o browser, por este motivo que no momento que utilizamos a propriedade right e top o elemento se posicionou no topo do browser e à direita.

Agora precisamos centralizar o elemento roxo no sentido vertical, para que isso aconteça podemos começar setando o valor de 50% na propriedade top. Volte ao arquivo position.css e faça essa alteração:

.header {
padding: 20px 40px;
border-bottom: 1px solid #222f3e;
margin-bottom: 30px;
}
.header-logo {
height: 50px;
}
.banner {
position: fixed;
top: 50%;
right: 0;
background-color: #5f27cd;
color: #FFF;
text-transform: uppercase;
text-align: center;
width: 200px;
height: 200px;
line-height: 200px;
}
.button {
display: block;
width: 160px;
height: 40px;
opacity: 0.95;
height: 60px;
line-height: 60px;
text-align: center;
color: #FFF;
text-decoration: none;
text-transform: uppercase;
background-color: #1dd1a1;
}
p {
margin-bottom: 20px;
}

Por favor, volte ao browser, atualize e você terá o resultado similar a este:

O elemento roxo não está centralizado com o top: 50%, mas a parte superior dele está

Olhando o resultado no browser podemos concluir que não conseguimos centralizar o elemento roxo, isso aconteceu porque quando colocamos o position: fixed ele não utilizou o centro do elemento roxo para efetuar o deslocamento dele, em vez disso ele pegou o topo porque utilizamos a propriedade top, se tivéssemos utilizado a propriedade bottom o deslocamento seria feito tendo como referência a parte de baixo do elemento. Para que fique de fato ao centro, precisamos mover a nossa caixa roxa, metade do tamanho dela para cima. Felizmente nós temos uma propriedade que torna possível de implementarmos esse comportamento, ela é a transform com o valor translateY(-50%).

A propriedade translateY é utilizada para deslocar o elemento no sentido vertical (eixo Y). Quando aplicado um valor negativo o elemento sobe e caso seja aplicado um valor positivo o elemento desce. Utilizamos um valor percentual dentro do translateY e diferente da propriedade top, o translateY não pega a altura do browser como referência, essa propriedade pega a altura do elemento onde ela foi aplicada e é este o comportamento que precisamos para deixar o nosso elemento roxo centralizado verticalmente. Por favor, volte ao arquivo position.css e adicione a transform: translateY(-50%) no seletor .banner:

.header {
padding: 20px 40px;
border-bottom: 1px solid #222f3e;
margin-bottom: 30px;
}
.header-logo {
height: 50px;
}
.banner {
position: fixed;
top: 50%;
right: 0;
transform: translateY(-50%);
background-color: #5f27cd;
color: #FFF;
text-transform: uppercase;
text-align: center;
width: 200px;
height: 200px;
line-height: 200px;
}
.button {
display: block;
width: 160px;
height: 40px;
opacity: 0.95;
height: 60px;
line-height: 60px;
text-align: center;
color: #FFF;
text-decoration: none;
text-transform: uppercase;
background-color: #1dd1a1;
}
p {
margin-bottom: 20px;
}
.button {
display: block;
width: 100px;
height: 40px;
opacity: 0.95;
height: 60px;
line-height: 60px;
text-align: center;
color: #FFF;
text-decoration: none;
text-transform: uppercase;
background-color: #1dd1a1;
}
p {
margin-bottom: 20px;
}

Só salvar o arquivo position.css, depois voltar para seu browser (não esquece de atualizar) e você verá o seguinte resultado visual:

Elemento roxo centralizado com sucesso :-)

Para finalizar essa primeira fase do nosso objetivo só precisamos deslocar o elemento roxo um pouco para a esquerda tendo como referência o lado direito do browser. Só precisamos então atribuir um valor positivo para a propriedade right que está no seletor .banner:

.header {
padding: 20px 40px;
border-bottom: 1px solid #222f3e;
margin-bottom: 30px;
}
.header-logo {
height: 50px;
}
.banner {
position: fixed;
top: 50%;
right: 5%;
transform: translateY(-50%);
background-color: #5f27cd;
color: #FFF;
text-transform: uppercase;
text-align: center;
width: 200px;
height: 200px;
line-height: 200px;
}
.button {
display: block;
width: 160px;
height: 40px;
opacity: 0.95;
height: 60px;
line-height: 60px;
text-align: center;
color: #FFF;
text-decoration: none;
text-transform: uppercase;
background-color: #1dd1a1;
}
p {
margin-bottom: 20px;
}

Só salvar o arquivo position.css e voltar até o browser que teremos finalizado a primeira parte do nosso objetivo:

Primeira fase do objetivo finalizada, aside roxo no mesmo local do objetivo

Na nossa segunda fase vamos implementar o header (cabeçalho) fixo. Já que queremos algo fixo precisamos setar o valor da propriedade position para fixed no seletor .header que está no arquivo position.css:

header {
position: fixed;
padding: 20px 40px;
border-bottom: 1px solid #222f3e;
margin-bottom: 30px;
}
.header-logo {
height: 50px;
}
.banner {
position: fixed;
top: 50%;
right: 5%;
transform: translateY(-50%);
background-color: #5f27cd;
color: #FFF;
text-transform: uppercase;
text-align: center;
width: 200px;
height: 200px;
line-height: 200px;
}
.button {
display: block;
width: 160px;
height: 40px;
opacity: 0.95;
height: 60px;
line-height: 60px;
text-align: center;
color: #FFF;
text-decoration: none;
text-transform: uppercase;
background-color: #1dd1a1;
}
p {
margin-bottom: 20px;
}

Salvando e voltando ao nosso browser você terá o seguinte resultado visual:

Restultado visual quando adicionamos position: fixed para o nosso header

Conforme o esperado, nosso elemento header está em um novo contexto por causa do fixed e liberou o espaço que ocupava no contexto do browser. Outro comportamento do postion: fixed é que uma vez que não temos width e/ou height definido, o que define o tamanho dele é o conteúdo do elemento que está o position: fixed. Mas de alguma forma precisamos implementar um código que faça o nosso header ocupar 100% da largura do nosso browser. Portanto, precisamos voltar em nosso arquivo positiom.css e definir a propriedade width com o valor de 100%:

header {
position: absolute;
width: 100%;
padding: 20px 40px;
border-bottom: 1px solid #222f3e;
margin-bottom: 30px;
}
.header-logo {
height: 50px;
}
.banner {
position: fixed;
top: 50%;
right: 5%;
transform: translateY(-50%);
background-color: #5f27cd;
color: #FFF;
text-transform: uppercase;
text-align: center;
width: 200px;
height: 200px;
line-height: 200px;
}
.button {
display: block;
width: 160px;
height: 40px;
opacity: 0.95;
height: 60px;
line-height: 60px;
text-align: center;
color: #FFF;
text-decoration: none;
text-transform: uppercase;
background-color: #1dd1a1;
}
p {
margin-bottom: 20px;
}

Se for até o navegador e atualizá-lo, verá o resultado visual a seguir:

O conteúdo do nosso header está misturado com o conteúdo do site

Legal! Agora está me incomodando muito o fato do logo da CollabCode se misturar com o conteúdo que está atrás dela. Para resolver isso só precisamos definir uma cor de fundo para o nosso header com background-color: #FFF no nosso arquivo position.css:

.header {
position: fixed;
width: 100%;
background-color: #FFF;
padding: 20px 40px;
border-bottom: 1px solid #222f3e;
margin-bottom: 30px;
}
.header-logo {
height: 50px;
}
.banner {
position: fixed;
top: 50%;
right: 5%;
transform: translateY(-50%);
background-color: #5f27cd;
color: #FFF;
text-transform: uppercase;
text-align: center;
width: 200px;
height: 200px;
line-height: 200px;
}
.button {
display: block;
width: 160px;
height: 40px;
opacity: 0.95;
height: 60px;
line-height: 60px;
text-align: center;
color: #FFF;
text-decoration: none;
text-transform: uppercase;
background-color: #1dd1a1;
}
p {
margin-bottom: 20px;
}
Conteúdo não está mais misturado, mas não conseguimos ver o titulo que está atrás do nosso header

Eita! Onde foi parar o nosso título que estava misturado com o logo da CollabCode? Ela continua atrás do nosso header só que agora o header tem uma cor de fundo definida que faz com que o nosso título não fique mais visível. Para resolver isso precisamos empurar o nosso título um pouco para baixo, vamos aplicar um padding-top de 140px em nosso article:

article {
padding-top: 140px;
}
.header {
position: fixed;
width: 100%;
background-color: #FFF;
padding: 20px 40px;
border-bottom: 1px solid #222f3e;
margin-bottom: 30px;
}
.header-logo {
height: 50px;
}
.banner {
position: fixed;
top: 50%;
right: 5%;
transform: translateY(-50%);
background-color: #5f27cd;
color: #FFF;
text-transform: uppercase;
text-align: center;
width: 200px;
height: 200px;
line-height: 200px;
}
.button {
display: block;
width: 160px;
height: 40px;
opacity: 0.95;
height: 60px;
line-height: 60px;
text-align: center;
color: #FFF;
text-decoration: none;
text-transform: uppercase;
background-color: #1dd1a1;
}
p {
margin-bottom: 20px;
}

Atualize seu browser e você terá o resultado visual a seguir, agora com o título aparecendo abaixo do nosso header:

Assim sim, agora nosso header está finalizado também, só que não!

O resultado visual já está certo mas temos uma pegadinha em nosso header, a largura dele é um pouco maior do que nós precisamos, ele está ultrapassando a largura do nosso navegador, só não apareceu um scroll vertical porque o nosso header está com a position: fixed. Vamos voltar no arquivo position.css e trocar o position: fixed por position: static e você verá o scroll vertical acontecendo:

article {
padding-top: 140px;
}
.header {
position: static;
width: 100%;
background-color: #FFF;
padding: 20px 40px;
border-bottom: 1px solid #222f3e;
margin-bottom: 30px;
}
.header-logo {
height: 50px;
}
.banner {
position: fixed;
top: 50%;
right: 5%;
transform: translateY(-50%);
background-color: #5f27cd;
color: #FFF;
text-transform: uppercase;
text-align: center;
width: 200px;
height: 200px;
line-height: 200px;
}
.button {
display: block;
width: 160px;
height: 40px;
opacity: 0.95;
height: 60px;
line-height: 60px;
text-align: center;
color: #FFF;
text-decoration: none;
text-transform: uppercase;
background-color: #1dd1a1;
}
p {
margin-bottom: 20px;
}

Atualize o seu browser e você verá terá o seguinte resultado:

Header com postion: static e com scroll vertical

Agora o que está causando esse scroll vertical? Nós temos um width: 100% no nosso header, esse 100% é exatamente a largura do elemento pai do header que no nosso caso é o browser então se tivermos um navegador com 1920px de largura também teremos o header com 1920px de largura? Sim isso é verdade, mas em nosso header também temos um padding: 20px 40px que é adicionado 20px de respiro interno no topo e na parte inferior dele e 40px de respiro interno no lado esquerdo e lado direto. Esses respiros internos que aplicamos nos lados direito e esquerdo por padrão são somados à largura que definimos na propriedade width e dessa forma a largura do nosso header fica maior que a largura (2000px) do nosso browser (1920px), como ilustrado na imagem a seguir.

Lousa explicando como funciona o básico do box-model

Felizmente para resolver isso é bem simples, só precisamos mudar o comportamento padrão da propriedade box-sizing de content-box para border-box. Uma vez que definirmos o box-sizing com border-box o valor definido no width será respeitado de fato conforme ilustrado na imagem a seguir:

Comportamento do box-model com box-sizing: border-box

Agora que entendemos o que estava de errado com a largura do nosso header e já estudamos como resolver, bora implementar. Vá até o arquivo position.css e adicione o box-sizing: border-box no header e volte o position: fixed:

article {
padding-top: 140px;
}
.header {
position: fixed;
box-sizing: border-box;

width: 100%;
background-color: #FFF;
padding: 20px 40px;
border-bottom: 1px solid #222f3e;
margin-bottom: 30px;
}
.header-logo {
height: 50px;
}
.banner {
position: fixed;
top: 50%;
right: 5%;
transform: translateY(-50%);
background-color: #5f27cd;
color: #FFF;
text-transform: uppercase;
text-align: center;
width: 200px;
height: 200px;
line-height: 200px;
}
.button {
display: block;
width: 160px;
height: 40px;
opacity: 0.95;
height: 60px;
line-height: 60px;
text-align: center;
color: #FFF;
text-decoration: none;
text-transform: uppercase;
background-color: #1dd1a1;
}
p {
margin-bottom: 20px;
}

Atualizando seu browser você terá o serguinte resultado:

Header funcionando sem pegadinhas

Pronto! O próximo passo é o desafio final onde você vai testar seu conhecimento. Lembre-se que se você tiver dúvidas pode mandar lá no Discord da CollabCode. Partiu desafio final.

Desafio final

Sabe o botão fixo na parte inferior da nossa page que está na cor verde com o conteúdo assitir agora, esse é o desafio que você terá que implementar, conforme está no gif a seguir:

Desafio final

Isso é tudo que queria passar te conhecimento pra você sobre o position: fixed até o próximo post que parece mais um livro…kkkk

Ah! É bem possível que eu tenha esquecido algum ponto, então recomendo que você também leia a documentação lá na MDN: https://developer.mozilla.org/pt-BR/docs/Web/CSS/position

CollabCode

Aqui é o ponto de encontro entre quem quer aprender e quem pode ensinar, de forma colaborativa.

Marco Bruno

Written by

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

CollabCode

Aqui é o ponto de encontro entre quem quer aprender e quem pode ensinar, de forma colaborativa.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade