Aqui está uma versão simplificada do que tenho trabalhado via CodePen: https://codepen.io/moosearch/pen/EaxYjEP
Estou tentando implementar um layout de duas colunas de acordo com esta imagem: https://imgur.com/a/bj1tWCK
A coluna da esquerda é a barra lateral do menu; a coluna da direita contém o conteúdo principal. O bloco de conteúdo principal tem um banner horizontal que representaria a marca do departamento em que trabalho. O banner consiste em dois SVGs; um é o fundo listrado horizontalmente e o outro é o logotipo que está posicionado no SVG de fundo. Se o usuário rolar para baixo, o banner se esconderá parcialmente - apenas a parte inferior é mostrada e o logotipo desaparece. Se o usuário rolar de volta para cima, ele mostrará o banner por completo.
Problema: ao rolar de volta para o topo da página, o movimento não é suave. Ele é feito em dois movimentos, em vez de um movimento suave.
O movimento de dois passos tem me deixado louco há algum tempo e não está claro para mim o que exatamente está causando isso. Minha implementação seria satisfatória se não fosse por isso.
Código relevante...
HTML:
<div class="sidebar nav navbar flex-shrink-0" style="width: 280px">
<!-- sidebar... -->
</div>
<!-- This is for inserting the contents of the page -->
<main id="main-content-block" style="margin-top: -10px;">
<div id="banner-wrapper" class="banner-wrapper">
<div id="org-banner" class="banner">
<svg width="3000" height="130" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="3000" height="80" fill="red" />
<rect x="0" y="80" width="3000" height="25" fill="orange" />
<rect x="0" y="105" width="3000" height="25" fill="coral" />
</svg>
</div>
<div id="crest-container">
<div class="crestbg">
<svg width="125" height="125" xmlns="http://www.w3.org/2000/svg">
<rect x="0" y="0" width="125" height="125" fill="maroon" />
</svg>
</div>
</div>
</div>
<!-- Content -->
<hr>
</main>
CSS:
/* Note: I also use bootstrap.css styling, v5.3.3 */
body {
font-family: "Roboto";
display: flex;
flex-direction: row;
height: 100vh;
}
main {
height: 100vh;
flex-grow: 1;
overflow-y: auto;
padding: 10px 10px 10px 10px;
}
/* For banner */
#banner-wrapper {
position: sticky;
top: 0;
z-index: 10;
margin: -8px -10px 30px -10px;
height: 130px;
overflow: hidden;
transition: all 0.5s ease-out;
}
.banner svg {
height: 130px;
top: 0px;
}
/* Positions the crest within the banner BG. */
.crestbg svg {
height: 130px;
position: absolute;
top: 0px;
right: 40px;
}
.banner a {
text-decoration: none;
}
/* CSS for hiding banner partially when scrolling */
header {
height: 80px;
transition: all 0.5s ease-out;
}
header.scrolled {
height: 50px;
}
#banner-wrapper.scrolled {
top: -80px;
}
#crest-container.scrolled {
display: none;
}
JS:
// For banner scrolling.
const mainContentEle = document.getElementById('main-content-block')
mainContentEle.addEventListener('scroll', () => {
// Dependent on the SG banner dimensions and how it's designed. Change this as needed.
const scrollPixelCutoffValue = 80;
const headerElement = document.querySelector('header')
const svgBannerContainer = document.getElementById('banner-wrapper')
const crestContainer = document.getElementById('crest-container')
if (mainContentEle.scrollTop > scrollPixelCutoffValue) { // Adjust this value as needed
svgBannerContainer.classList.add('scrolled');
headerElement.classList.add('scrolled');
crestContainer.classList.add('scrolled');
} else {
svgBannerContainer.classList.remove('scrolled');
headerElement.classList.remove('scrolled');
crestContainer.classList.remove('scrolled');
}
return;
});
Editar: adicionei meu próprio CodePen para referência, caso o JSFiddle na resposta escolhida desapareça no futuro: https://codepen.io/moosearch/pen/wBvwyxx
Este é um problema conhecido no Chrome . Elementos fixos de posição causam efeito de salto ao tentar ajustar/animar a altura do elemento. Conforme sugerido na resposta aqui , uma solução é ter um elemento pai não móvel.
Abaixo, implementei uma solução que envolve uma combinação da técnica acima e posicionamento absoluto. Confira esta demonstração do JsFiddle .
Código completo:
Eu brinquei bastante com isso. Acredito que resolvi o "movimento suave" durante a rolagem.
No entanto, estou ciente de que isso causa duas regressões no seu código, mas acho que você pode aprender isso aqui.
Alterar o banner para posicionamento absoluto cria o efeito desejado. A margem superior negativa não é mais necessária.
Regressões: