Scroll-driven Animations in Pure CSS

Scroll-driven Animations in Pure CSS
Code Snippet:Pure CSS: Scroll-driven Animations (Responsive Webpage)
Author: Andrej Sharapov
Published: March 31, 2024
Last Updated: March 31, 2024
Downloads: 185
License: MIT
Edit Code online: View on CodePen
Read More

This code creates scroll-driven animations using pure CSS. It animates various sections of a webpage. The header transforms on scroll, and sections have smooth transitions. It’s helpful for adding engaging visual effects to websites.

Furthermore, you can use this code on any website to enhance its visual appeal without relying on JavaScript. It adds interactive animations triggered by scrolling, improving user engagement. Plus, it’s lightweight and easy to implement, ensuring a smooth browsing experience.

How to Create Scroll-driven Animations In Pure CSS

1. First of all, load the Google Fonts by adding the following CDN links into the head tag of your HTML document.

<link rel='stylesheet' href='https://fonts.googleapis.com/css2?family=Righteous&amp;display=swap'>

2. Set up the HTML structure of your webpage. Define sections that you want to animate upon scrolling. Ensure each section has a unique ID.

<header>
  <label class="menu" for="burger">
    <input id="burger" type="checkbox"/>
    <svg class="burger" viewBox="0 0 100 100" width="64">
      <path class="line top" d="m 30,33 h 40 c 13.100415,0 14.380204,31.80258 6.899646,33.421777 -24.612039,5.327373 9.016154,-52.337577 -12.75751,-30.563913 l -28.284272,28.284272"></path>
      <path class="line middle" d="m 70,50 c 0,0 -32.213436,0 -40,0 -7.786564,0 -6.428571,-4.640244 -6.428571,-8.571429 0,-5.895471 6.073743,-11.783399 12.286435,-5.570707 6.212692,6.212692 28.284272,28.284272 28.284272,28.284272"></path>
      <path class="line bottom" d="m 69.575405,67.073826 h -40 c -13.100415,0 -14.380204,-31.80258 -6.899646,-33.421777 24.612039,-5.327373 -9.016154,52.337577 12.75751,30.563913 l 28.284272,-28.284272"></path>
    </svg>
  </label>
  <nav>
    <ul>
      <li><a href="#masthead" title="masthead" style="--an:--masthead;--at:--masthead-s;">masthead</a></li>
      <li><a href="#tiles" title="tiles" style="--an:--tiles;--at:--tiles-s;">tiles</a></li>
      <li><a href="#text" title="text" style="--an:--text;--at:--text-s;">text</a></li>
      <li><a href="#two-columns" title="two-columns" style="--an:--two-columns;--at:--two-columns-s;">two-columns</a></li>
      <li><a href="#subscribe" title="subscribe" style="--an:--subscribe;--at:--subscribe-s;">subscribe</a></li>
    </ul>
  </nav>
</header>
<main>
  <section id="masthead" style="--name:--masthead-s;">
    <div class="flying-squares">
      <div class="square"></div>
      <div class="square"></div>
      <div class="square"></div>
    </div>
    <div class="masthead">
      <h1>masthead</h1>
      <p>Press on the heart if you are also a CSS Developer 😃.</p>
    </div>
  </section>
  <section id="tiles" style="--name:--tiles-s;">
    <div class="tile-section">
      <div class="tile-container">
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
        <div class="tile"></div>
      </div>
    </div>
  </section>
  <section id="text" style="--name:--text-s;">
    <div class="read">
      <div>Reading progress</div>
    </div>
    <div class="text">
      <h2>Smooth appearance of text when scrolling</h2>
      <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
      <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
      <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
      <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
      <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
      <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
      <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
      <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
      <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
      <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
      <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
      <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
      <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
      <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
      <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
    </div>
  </section>
  <section id="two-columns" style="--name:--two-columns-s;">
    <div class="two-columns">
      <h2>Picture arrived on the right</h2>
      <div class="content">
        <div class="cards">
          <div class="card">
            <h3 class="title">Card title</h3>
            <div class="subtitle">Subtitle</div>
            <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
          </div>
          <div class="card">
            <h3 class="title">Card title</h3>
            <div class="subtitle">Subtitle</div>
            <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
          </div>
          <div class="card">
            <h3 class="title">Card title</h3>
            <div class="subtitle">Subtitle</div>
            <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
          </div>
        </div>
        <div class="preview">
          <div class="img"></div>
        </div>
      </div>
    </div>
  </section>
  <section id="subscribe" style="--name:--subscribe-s;">
    <div class="subscribe">
      <h2>Subscribe now</h2>
      <p>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Culpa, tenetur deserunt! Obcaecati eius aut, facere porro amet atque laborum eos, numquam asperiores minus accusantium et tempore repellat voluptatum natus corrupti?</p>
      <form action="" method="POST">
        <input type="email" placeholder="Enter your email"/>
        <button class="btn" type="submit"><span>Subscribe</span></button>
      </form>
    </div>
  </section>
  <div class="scroll"><span>scroll</span>
    <div class="divider"></div><span>down</span>
  </div>
</main>
<footer><a href="https://twitter.com/intent/follow?screen_name=andrejsharapov" target="_blank"><span>X</span></a></footer>

3. Now, copy the following CSS code into your stylesheet or HTML file within a <style> tag. This CSS code contains animation rules for different sections of your webpage.

:root {
	--text-color: hsl(230 16% 28%);

	/* header */
	--header-bg: hsl(0 0% 100% / 75%);

	/* section */
	--section: hsl(0 0% 93%);
	--section-even: hsl(210deg 15% 92%);

	/* tiles */
	--red: hsl(10 83% 52%);
	--green: hsl(157 91% 43%);
	--blue: hsl(210 100% 45%);
	--purple: hsl(266 100% 67%);
	--yellow: hsl(49 100% 73%);
	--black: hsl(0 0% 0%);

	/*  */
	--cubic: cubic-bezier(0.25, 0.1, 0, 2.05);
}

* {
	box-sizing: border-box;
}

html {
	scroll-behavior: smooth;
}

body {
	margin: 0;
	display: grid;
	overflow-x: hidden;
	font-family: "Righteous", sans-serif;

	/* scope */
	timeline-scope: 
		--masthead-s, 
		--tiles-s, 
		--text-s, 
		--two-columns-s,
		--subscribe-s;
}

header {
	--show: none;
	--position: relative;
	--b: 0;
	--s: 10%;
	--nav-bg: var(--yellow);

	position: sticky;
	top: 0;
	z-index: 2;
	inline-size: 100%;
	transition: all 200ms linear;

	/* animation */
	animation: height-resize both linear;
	animation-timeline: scroll();
	animation-range: entry 0% exit 20%;

	.menu {
		position: fixed;
		top: 0.25rem;
		left: 0.25rem;
		z-index: 2;
		cursor: pointer;

		& input[type="checkbox"] {
			display: none;
		}

		.burger {
			display: var(--show);
      background-color: var(--header-bg);
			
			& path {
				fill: none;
				stroke: currentcolor;
				stroke-width: 3;
				transition: stroke-dasharray 400ms, stroke-dashoffset 400ms;

				&.top {
					stroke-dasharray: 40 172;
				}

				&.middle {
					stroke-dasharray: 40 111;
				}

				&.bottom {
					stroke-dasharray: 40 172;
				}
			}
		}

		&:has(input[type="checkbox"]:checked) {
			.burger {
				& path {
					&.top {
						stroke-dashoffset: -132px;
					}

					&.middle {
						stroke-dashoffset: -71px;
					}

					&.bottom {
						stroke-dashoffset: -132px;
					}
				}
			}
		}
	}

	& nav {
		position: var(--position);
		inline-size: inherit;
		display: flex;
		align-items: center;
		justify-content: center;

		/* blur background */
		background-color: var(--header-bg);
		backdrop-filter: blur(6px);

		& ul {
			list-style-type: none;
			display: flex;
			padding: 0;
			grid-column-gap: 3rem;

			& li {
				position: relative;
				padding: 0.5rem 1rem;
				text-transform: uppercase;
				color: var(--text-color);
				transition: transform 0.25s var(--cubic);

				&::after {
					position: absolute;
					content: "";
					left: 0;
					bottom: var(--b);
					z-index: -1;
					inline-size: 100%;
					block-size: var(--s);
					background-color: var(--nav-bg);
					transition: all 0.25s var(--cubic);
				}

				&:has(a:hover) {
					--b: 10%;
					--s: 70%;
				}
			}
		}
	}
}

@media (width <= 48rem) {
	body {
		&:has(input[id="burger"]:checked) {
			scrollbar-gutter: stable;
			overflow-y: hidden;
		}
	}

	header {
		--position: absolute;
		--translateY: -100%;
		--show: block;
		--nav-bg: var(--green);

		& nav {
			top: 0;
			translate: 0 var(--translateY);

			inline-size: 100%;
			block-size: 100dvh;
			padding-inline: 1rem;
			transition: all 200ms ease-in-out;

			& ul {
				block-size: 100%;
				flex-direction: column;
				justify-content: space-evenly;
			}
		}

		& .menu {
			&:has(input[type="checkbox"]:checked) {
				& ~ nav {
					--translateY: 0;
				}
			}
		}
	}
}

@keyframes height-resize {
	to {
		padding-block: 0;
	}
}

:is(h1, h2) {
	margin: 0;
	font-size: calc(2rem + 0.25vw);
}

a {
	text-decoration: none;
	color: currentColor;

	/* animation */
	animation: avtive-link both linear;
	anchor-name: var(--an);
	animation-timeline: var(--at);

	&:not(:hover) {
		opacity: calc(0.5 + var(--active, 0));
	}
}

section {
	min-block-size: 100vh;
	background-color: var(--section);

	/* for animation */
	view-timeline-name: var(--name);

	&:nth-child(even) {
		--section: var(--section-even);
	}
}

.flying-squares {
	position: absolute;
	z-index: 1;
	
	.square {
		position: inherit;
		width: 15vw;
		height: 15vw;
		rotate: 0.4turn;
		background-color: var(--square-color);
		top: var(--y);
		left: var(--x);
		opacity: 0.3;
		rotate:  var(--rx) var(--ry) var(--rz) 0.55turn;
		animation: flying 2s infinite alternate both;
		
		&:nth-of-type(1) {
			--y: 17vh;
			--x: 8vw;
			--rx: 0.5;
			--ry: 2.1;
			--rz: 1.6;
			--square-color: var(--red);
			
			animation-delay: 1s;
		}
		
		&:nth-of-type(2) {
			--y: 8vh;
			--x: 76vw;
			--rx: 1.7;
			--ry: 2.3;
			--rz: 2.1;
			--square-color: var(--purple);
		}
		
		&:nth-of-type(3) {
			--y: 60vh;
			--x: 40vw;
			--rx: 1.75;
			--ry: 3.5;
			--rz: 2.7;
			--square-color: var(--green);
			
			animation-delay: 0.5s;
		}
	}
}

@keyframes flying {
	to {
		translate: 0 -5vh;
	}
}

.masthead {
	max-inline-size: 100vw;
	block-size: 100vh;
	overflow: hidden;
	display: grid;
	place-content: center;
	padding-inline: 1rem;

	& h1 {
		position: fixed;
		top: 50%;
		left: 50%;
		translate: -50% -50%;
		text-transform: uppercase;

		/* 	animation	 */
		animation: scale-up both linear, fade-away both linear;
		animation-timeline: var(--name);
		animation-range: entry-crossing 70% exit 90%, exit 10% exit 70%;
	}
}

@keyframes scale-up {
	100% {
		top: 0;
		scale: 5;
	}
}

@keyframes fade-away {
	100% {
		opacity: 0;
	}
}

.tile-section {
	position: sticky;
	top: 0;
	max-inline-size: 100vw;
	block-size: 200vh;
	overflow: hidden;

	& .tile-container {
		position: absolute;
		top: 50%;
		left: 50%;
		translate: -50% -50%;
		scale: 3;
		inline-size: 100%;
		block-size: 100vh;
		display: grid;
		grid-template: repeat(4, 1fr) / repeat(5, 1fr);
		rotate: 0.12turn;

		& .tile {
			inline-size: 100%;
			block-size: 100%;
			background-color: var(--tile);

			/* animation */
			animation: tile both linear;
			/* 			animation-timeline: scroll(root); */
			animation-timeline: var(--name);
			animation-range: entry 100% exit 0%;

			&:nth-of-type(5n + 2),
			&:nth-of-type(5n + 4) {
				--tile: var(--green);
				--vertical: 100%;
				--horizontal: 100%;

				&:nth-of-type(odd) {
					--tile: var(--red);
					--vertical: 100%;
					--horizontal: -100%;
				}
			}

			&:nth-of-type(5n + 1),
			&:nth-of-type(5n + 3),
			&:nth-of-type(5n + 5) {
				--tile: var(--blue);
				--vertical: -100%;
				--horizontal: 100%;

				&:not(:nth-of-type(odd)) {
					--tile: var(--yellow);
					--vertical: -100%;
					--horizontal: -100%;
				}
			}
		}
	}
}

@keyframes tile {
	0% {
		translate: 0 0;
	}

	50% {
		translate: 0 var(--vertical);
	}

	100% {
		translate: var(--horizontal) var(--vertical);
	}
}

.text {
	max-inline-size: 80ch;
	margin-inline: auto;
	padding: 3rem 1rem;
	counter-reset: chapter 0;

	& > *:not(h2) {
		text-wrap: pretty;
		counter-increment: chapter 1;

		/* animation */
		animation: show-text both linear;
		animation-timeline: view(y 80vh auto);

		&::before {
			content: counter(chapter, upper-roman) ". "; /* lower-alpha */
		}
	}
}

/* :has(.text) {
	counter-reset: chapter 0;
	
	& p {
		counter-increment: chapter 1;
	}
	
	.read > * {
		&::after {
			content: ' ' counter(chapter) '%';
		}
	}
} */

@keyframes show-text {
	from {
		opacity: 0;
	}

	to {
		opacity: 1;
	}
}

.read {
	position: fixed;
	top: 68px;
	left: 0;
	z-index: 3;
	inline-size: 0;
	max-inline-size: 100%;
	text-align: right;
	white-space: nowrap;
	padding-block: 0.125rem;
	padding-inline-end: 0.5rem;
	background-image: linear-gradient(
		0.25turn,
		var(--red),
		var(--yellow),
		var(--green),
		var(--blue),
		var(--purple)
	);
	opacity: 0;
	transition: opacity 200ms linear;

	/* animation */
	animation: read-text both linear;
	animation-timeline: var(--name);
	animation-range: entry 100% exit 100%;

	& div {
		filter: invert(100%);
	}
}

@keyframes read-text {
	1% {
		opacity: 1;
	}

	99% {
		inline-size: 100%;
		opacity: 1;
	}

	100% {
		opacity: 0;
	}
}

.two-columns {
	--columns: 1;
	--translateX: 0;

	max-inline-size: 80ch;
	margin-inline: auto;
	block-size: 100%;
	padding: 3rem 1rem;

	.content {
		display: grid;
		grid-template-columns: repeat(var(--columns), 1fr);
		place-content: center;
		gap: 2rem;

		.cards {
			margin-block-start: 2rem;
			display: flex;
			flex-direction: column;
			justify-content: space-between;

			.card {
				box-shadow: inset 0 0 0.125rem var(--text-color);

				/* animation */
				animation: show both linear;
				animation-timeline: var(--name);
				animation-range:  entry-crossing var(--range-start);
				
				&:nth-of-type(1) {
					--range-start: 10%;
				}
				
				&:nth-of-type(2) {
					--range-start: 40%;
				}
				
				&:nth-of-type(3) {
					--range-start: 70%;
				}

				&:not(:last-of-type) {
					margin-block-end: 2rem;
				}

				& * {
					margin: 0;
					padding-inline: 1rem;
				}

				.title {
					padding-block-start: 1rem;
				}

				.subtitle {
					padding-block-start: 0.25rem;
					padding-block-end: 1rem;
					opacity: 0.5;
				}

				& p {
					padding-block-end: 1rem;
				}
			}
		}
	}

	.preview {
		position: relative;
		margin-block: 2rem;
		block-size: calc(100% - 1rem);

		.img {
			left: var(--translateX);
			block-size: inherit;
			min-block-size: 24rem;
			object-fit: cover;
			background: var(--red);
		}
	}
}

@media (width >= 48rem) {
	.two-columns {
		--columns: 2;
		--translateX: 150%;

		.preview {
			.img {
				position: absolute;
				top: 0;
				aspect-ratio: 0.5;

				/* animation */
				animation: fade-right both linear;
				animation-timeline: scroll(root);
				animation-range: entry 5% exit 90%;
			}
		}
	}
}

@keyframes fade-right {
	to {
		left: 0;
	}
}

@keyframes show {
	from {
		opacity: 0;
	}
	
	to {
		opacity: 1;
	}
}

.subscribe {
	max-inline-size: 80ch;
	margin-inline: auto;
	block-size: 100vh;
	padding: 3rem 1rem;
	display: grid;
	place-content: center;
	text-align: center;

	& form {
		position: relative;
		margin-block-start: 2rem;

		/* animation */
		animation: slide-up both linear;
		animation-timeline: var(--name);
		animation-range:  entry-crossing 40%;

		& input {
			inline-size: 100%;
			border: 0;
			min-block-size: 3rem;
			margin-block-end: 1rem;
			padding-inline: 0.5rem;
			font-size: calc(1rem + 0.25vw);
			box-shadow: 0 0 0.125rem var(--text-color);
			
			&:focus {
				outline: thin solid var(--purple);
			}
		}

		& button {
			padding: 0.75rem 1rem;
			text-transform: uppercase;
			cursor: pointer;
			background-color: var(--purple);
			border: 0;
			
			&:focus {
				outline: thin solid var(--purple);
			}
			
			& span {
				font-weight: 700;
				filter: invert(100%);
			}
		}
	}
}

@keyframes slide-up {
	from {
		scale: 0;
	}
	
	to {
		scale: 1;
	}
}

.scroll {
	position: fixed;
	top: 50%;
	left: 0.35rem;
	translate: 0 -50%;
	writing-mode: vertical-lr;
	rotate: 0.5turn;
	display: flex;
	align-items: center;
	gap: 0.5rem;
	opacity: 0.5;

	& .divider {
		inline-size: 2rem;
		block-size: 2px;
		background-color: currentColor;
		opacity: 0.5;
	}

	& span {
		text-transform: lowercase;
		font-weight: bold;
	}
}

@keyframes avtive-link {
	50% {
		--active: 1;
	}
}

footer {
	display: grid;
	place-content: center;
	padding-block: 1rem;

	& a {
		--active: 1;

		padding: 0.5rem 1rem;
		background-color: var(--black);

		& span {
			filter: invert(75%);
		}
	}
}

Feel free to customize animation properties such as duration, timing, and effects to suit your website’s design and theme.

That’s all! hopefully, you have successfully created Scroll-driven Animations on your website. If you have any questions or suggestions, feel free to comment below.

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.

About CodeHim

Free Web Design Code & Scripts - CodeHim is one of the BEST developer websites that provide web designers and developers with a simple way to preview and download a variety of free code & scripts. All codes published on CodeHim are open source, distributed under OSD-compliant license which grants all the rights to use, study, change and share the software in modified and unmodified form. Before publishing, we test and review each code snippet to avoid errors, but we cannot warrant the full correctness of all content. All trademarks, trade names, logos, and icons are the property of their respective owners... find out more...

Please Rel0ad/PressF5 this page if you can't click the download/preview link

X