Pare de chutar e aprenda como funciona a position: fixed

Marco Bruno
CollabCode
Published in
15 min readJun 13, 2019
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.

index.html

<!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>

reset.css

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

position.csss

.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:

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:

position.css

.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:

position.css

.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:

position.css

.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:

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%:

position.css

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

--

--

Marco Bruno
CollabCode

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