Scroll - Shrinking Header
Update a component appearance based on the user’s scroll action, all CSS, no JS required.
Demo
The Incredible Shrinking Header
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.
Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.
HTML
<!-- No special HTML, just need a header to shrink -->
<header>
<h1>The Incredible Shrinking Header</h1>
</header>
<!-- And enough content to allow the page to scroll -->
<article>
<p>Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.</p>
<p>Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.</p>
<p>Lorem ipsum dolor sit amet consectetur adipiscing elit. Quisque faucibus ex sapien vitae pellentesque sem placerat. In id cursus mi pretium tellus duis convallis. Tempus leo eu aenean sed diam urna tempor. Pulvinar vivamus fringilla lacus nec metus bibendum egestas. Iaculis massa nisl malesuada lacinia integer nunc posuere. Ut hendrerit semper vel class aptent taciti sociosqu. Ad litora torquent per conubia nostra inceptos himenaeos.</p>
</article>CSS
/* Use custom properties for clarity */
:root {
--title-size-large: 3rem;
--title-size-small: 1rem;
--header-padding-large: 1rem;
--header-padding-small: .25rem;
--article-margin: calc(var(--logo-height-large) + (var(--header-padding-large) * 2));
}
figure.demo {
& header {
/* Fix to the top of the page, full-width */
position: sticky;
top: 0;
left: 0;
width: 100%;
/* Make logo and title align horizontally */
display: flex;
gap: 1rem;
align-items: center;
/* Make the header large */
& h1 {
padding: var(--header-padding-large);
font-size: var(--title-size-large);
}
/* Give the content some breathing room for the fixed header */
article {
/* The height of the logo, plus the header top & bottom padding */
margin-top: var(--article-margin);
}
}
}
/* Only apply if the user did NOT request reduced motion */
@media (prefers-reduced-motion: no-preference) {
/* Make sure the device supports scroll animation */
/** Note that if scroll animation is NOT supported, the page still works as a fixed header, and content just scrolls under it;
but that header is large, so you might also want to move the "make the header large" CSS into this @supports as well? **/
@supports (animation-timeline: scroll()) {
/** Note that because the header height is based on the content height, only the elements inside the header need to be animated **/
@keyframes shrink-header {
to {
padding: var(--header-padding-small);
font-size: var(--title-size-small);
}
}
/* Assign the animations to the elements */
figure.demo {
& h1 {
animation: shrink-header linear both;
/* You have to assign the scroll animation to all of the elements that you plan to animate */
/* Passing nothing into `scroll()` will assign the animation to the document scroll */
animation-timeline: scroll();
/* 100px is a magic number; the animation will start at 0 and end at 100px; choose whatever numbers you want */
animation-range: 0 100px;
}
}
}
}JS
No JS required.Baseline
CodePen
See the Pen on CodePen.