1. Comece com a marcação HTML
A marcação consistirá em duas seções:
- A primeira seção do herói incluirá visualmente apenas o cabeçalho e a imagem do perfil. Mas, na realidade, colocaremos um cabeçalho e um elemento wrapper que incluirá a imagem e um clone/duplicado do cabeçalho. Ao dizer clone, queremos dizer que seu conteúdo e aparência serão idênticos ao elemento de destino.
- A segunda seção incluirá o conteúdo principal da página. Claro, você pode ter muito mais seções em suas próprias páginas.
Aqui está a marcação necessária:
1 |
|
2 |
|
3 |
|
4 |
width="1308" height="1220" src="man-visual-designer.jpg" alt="">
|
5 |
|
6 |
Visual
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
2. Adicione o CSS
Vamos agora nos concentrar nos principais estilos.
Começaremos com esses alvos na seção de heróis.
- O título será branco enquanto o clone salmão.
- O clone será absolutamente posicionado dentro do elemento wrapper da imagem. Isso é
top
eleft
os valores de posição serão definidos por meio de JavaScript; o objetivo final é colocá-lo no topo do título exatamente na mesma posição. Mais sobre isso na próxima seção. Para que isso aconteça, devemos garantir que sua ordem de empilhamento seja maior que a do título. No nosso caso, isso ocorre porque o wrapper vem depois do cabeçalho. - O elemento wrapper da imagem terá
overflow: hidden
então o clone não pode exceder seus limites.
Os estilos associados:
1 |
/*CUSTOM VARIABLES HERE*/
|
2 |
|
3 |
.section-hero { |
4 |
display: flex; |
5 |
flex-direction: column; |
6 |
align-items: center; |
7 |
justify-content: center; |
8 |
max-width: 1000px; |
9 |
margin: 0 auto; |
10 |
}
|
11 |
|
12 |
.section-hero .h1 { |
13 |
font-size: 20vmin; |
14 |
line-height: 0.9; |
15 |
font-weight: bold; |
16 |
text-align: center; |
17 |
text-shadow: 2px 2px 10px #1a1423; |
18 |
}
|
19 |
|
20 |
.section-hero .hero-title-clone { |
21 |
position: absolute; |
22 |
color: var(--salmon); |
23 |
}
|
24 |
|
25 |
.section-hero .hero-img-wrapper { |
26 |
position: relative; |
27 |
margin-top: -10vh; |
28 |
overflow: hidden; |
29 |
}
|
30 |
|
31 |
.section-hero .hero-img-wrapper img { |
32 |
border-radius: 10px; |
33 |
}
|
Em relação aos estilos principais de conteúdo, um aspecto importante é que todas as seções irmãs após a do herói devem ter um valor maior z-index
valor. Dessa forma, o cabeçalho de rolagem sempre estará abaixo dessas seções.
No nosso caso, tudo o que temos abaixo é uma imagem de fundo fixa com texto sobre ela. Para garantir que o texto seja legível, colocaremos uma imagem sobreposta.
Os estilos relevantes:
1 |
.section-hero ~ .section { |
2 |
position: relative; |
3 |
z-index: 2; |
4 |
}
|
5 |
|
6 |
.section-text { |
7 |
background: url(man-walking.jpg) no-repeat fixed center right / cover; |
8 |
margin-top: 20vh; |
9 |
}
|
10 |
|
11 |
.section-text::before { |
12 |
content: ""; |
13 |
position: absolute; |
14 |
top: 0; |
15 |
left: 0; |
16 |
right: 0; |
17 |
bottom: 0; |
18 |
background: rgba(56, 36, 52, 0.5); |
19 |
}
|
20 |
|
21 |
.section-text div { |
22 |
position: relative; |
23 |
max-width: 700px; |
24 |
padding: 100px 0; |
25 |
margin: 0 auto; |
26 |
}
|
27 |
|
28 |
.section-text p { |
29 |
margin-top: 20px; |
30 |
}
|
3. Aplique o JavaScript
A primeira coisa que devemos fazer é colocar o clone no lugar do cabeçalho assim:
Isso deve acontecer quando todos os recursos da página tiverem sido carregados e durante o redimensionamento da janela. Em seus projetos, para evitar esse salto até que o clone fique na posição correta, você pode adicionar um pré-carregador ou algo parecido.
Nesse ponto, vamos chamar o setPos()
funcionar e seguir este plano:
- Pegue o
x
ey
posições do cabeçalho em relação à viewport. - Pegue o
x
ey
posições do elemento wrapper da imagem em relação à viewport. - Colocou o
top
eleft
valores de propriedade do clone subtraindo os valores do título dos valores do wrapper. Especialmente para evitar a disposição de nosso clone quando redimensionamos repentinamente a altura da janela, também temos que subtrair do finaltop
valorize a quantidade de nossa rolagem (explicamos como calcular isso no próximo parágrafo).
Em vez das posições x e y, podemos pegar igualmente os valores superior e esquerdo com qualquer diferença.
Para criar o efeito de paralaxe, enquanto rolamos, usaremos o transform
propriedade para mover o título e seu clone ao mesmo tempo e direção para que pareçam um único elemento. A velocidade do movimento será determinada pelo getSpeed()
função. Nossa velocidade base será de 1,1, o que significa que os elementos-alvo se moverão 10% mais rápido que os outros elementos. Altere esse valor para ver a diferença no efeito.
Com tudo isso em mente, aqui está todo o código JavaScript de que precisaremos:
1 |
const sectionHero = document.querySelector(".section-hero"); |
2 |
const heroTitle = sectionHero.querySelector(".hero-title"); |
3 |
const heroTitleClone = sectionHero.querySelector(".hero-title-clone"); |
4 |
const heroImgWrapper = sectionHero.querySelector(".hero-img-wrapper"); |
5 |
const speed = 1; |
6 |
|
7 |
window.addEventListener("load", setPos); |
8 |
window.addEventListener("resize", setPos); |
9 |
|
10 |
function setPos() { |
11 |
const { x: heroTitleX, y: heroTitleY } = heroTitle.getBoundingClientRect(); |
12 |
const { |
13 |
x: heroImgWrapperX, |
14 |
y: heroImgWrapperY |
15 |
} = heroImgWrapper.getBoundingClientRect(); |
16 |
|
17 |
heroTitleClone.style.top = `${heroTitleY - getSpeed() - heroImgWrapperY}px`; |
18 |
heroTitleClone.style.left = `${heroTitleX - heroImgWrapperX}px`; |
19 |
}
|
20 |
|
21 |
window.addEventListener("scroll", function () { |
22 |
const speed = `translateY(${getSpeed()}px)`; |
23 |
heroTitle.style.transform = speed; |
24 |
heroTitleClone.style.transform = speed; |
25 |
});
|
26 |
|
27 |
function getSpeed() { |
28 |
return this.pageYOffset * speed; |
29 |
}
|
Conclusão
Com menos de 30 linhas de código JavaScript, conseguimos construir esse lindo efeito de paralaxe que é um cenário perfeito para um site de portfólio ou sempre que você quiser criar um contraste entre o texto e seu fundo. Felizmente, você está convencido o suficiente para incorporá-lo em um de seus projetos.
Antes de fechar, vamos olhar novamente para o que criamos hoje: