Download from GitHub

DNA Parallax Tutorial

Every example uses simple common layout with associated CSS:

		<section role="parallax-container">
		    <div parallax="anim-stage">
			Content will scroll during 0%-33% progress, then stop, and continue up during 66%-100%...
		    </div>
		</section>
	    
		section {
		    height: 200vh; /* 2x the screen to make scrolling longer */
		}

		/* Position fixed: ensures smooth animation across browsers */
		[parallax~="anim-stage"] {
		    position: fixed;
		    height: 100vh;
		    width: 100vw;
		    background-color: #EFEFEF;
		}

		/* We can hide whole content when it is off-screen = animation status is "off" */
		[parallax~="anim-stage"][parallax-status="off"] {
		    display: none;
		}

		/* Slide stage up nicely, and slide out after while */
		@keyframes anim-stage {
		    0%        {top: 100vh;}
		    33.3333%  {top: 0vh;}
		    66.6666%  {top: 0vh;}
		    100%      {top: -100vh;}
		}
	    

The section element will govern animation progress of nested animations thanks to role="parallax-container" attribute. Such element we call parallax container.

In addition when parallax container is off-screen it gets an attribute parallax-status="off". Analogically when animated (progress is between 0% and 100%) it has an attribute parallax-status="off".

There is also parallax-progress helper attribute set on all parallax containers and animated elements that holds animation progress. Check DOM Inspector to see how it changes. Similarly parallax-step attribute holds the same value rounded to nearest 5/10. You can use it in your CSS. For example to assign different background color when animation is between 10% and 19% you can use selector [parallax-step~="deca-10"] {background: silver;}.

This is simple example. Word "Content..." will appear on bottm when section element enters viewport: animation 0% - 33%. Then it will stop during timeline 33% - 66% and then continue up: 66% - 100%.

Content will scroll during 0%-33% progress, then stop, and continue up during 66%-100%...

Fly In & Rotate

Let define simple CSS animaton for fly-in and rotate effects. Effects start at 0% (parallax container enters the screen on bottom) and stop at 33% (parallax container having 200vh height is alligned with top of the screen).

		<div class="box" parallax="fly-in-left"></div>
		<div class="box" parallax="fly-in-right"></div>
	    
		@keyframes fly-in-right {
		    0%       {transform: translateX(100vh) rotate(360deg);}
		    33% {transform: translateX(0vh) rotate(0deg);}
		}

		@keyframes fly-in-left {
		    0%       {transform: translateX(-100vh) rotate(-360deg);}
		    33% {transform: translateX(0vh) rotate(0deg);}
		}
	    

Animations Combos and Modifiers

You can use previous fly-in-right and fly-out-right animations and you can combine them, reverse them or scale on timeline.

If you use attribute parallax="fly-in-right" it will apply animation as defined by @keyframes statement. If you suffix it with :reverse modifier it will apply the same animation in reverse order.

Wile fly-in-right will move element from right to center during 0% - 33% of timeline, fly-in-right:reverse will reverse the animation to start moving from center to left during 66% - 100% of timeline progress.

You can also combine the animations by specifying more then one in parallax attribute. E.g. parallax="fly-in-right fly-in-right:reverse" will merge animations into one where element flies in from right during 0% - 33% and then during 66% - 100% it flies back from where it came.

		<div class="box" parallax="fly-in-left fly-in-left:reverse"></div>
		<div class="box" parallax="fly-in-right fly-in-right:reverse"></div>
	    

Shifting and Scalling the Timeline

You can use also :shift(n%) and :scale(n) modifiers to delay or scale animation progress.

		<div class="row">
		    <div class="box" parallax="fly-in-left:shift(15%)  fly-in-left:reverse:shift(-5%)"></div>
		    <div class="box" parallax="fly-in-left:shift(5%)   fly-in-left:reverse:shift(5%)"></div>
		    <div class="box" parallax="fly-in-left:shift(-5%)  fly-in-left:reverse:shift(15%)"></div>
		    <div class="box" parallax="fly-in-right:shift(-5%) fly-in-right:reverse:shift(15%)"></div>
		    <div class="box" parallax="fly-in-right:shift(5%)  fly-in-right:reverse:shift(5%)"></div>
		    <div class="box" parallax="fly-in-right:shift(15%) fly-in-right:reverse:shift(-5%)"></div>
		</div>
		<div class="row">
		    <div class="box" parallax="fly-in-left:scale(1.3)  fly-in-left:scale(1.3):reverse"></div>
		    <div class="box" parallax="fly-in-left:scale(1.1)   fly-in-left:scale(1.1):reverse"></div>
		    <div class="box" parallax="fly-in-left:scale(0.9)  fly-in-left:scale(0.9):reverse"></div>
		    <div class="box" parallax="fly-in-right:scale(0.9) fly-in-right:scale(0.9):reverse"></div>
		    <div class="box" parallax="fly-in-right:scale(1.1)  fly-in-right:scale(1.1):reverse"></div>
		    <div class="box" parallax="fly-in-right:scale(1.3) fly-in-right:scale(1.3):reverse"></div>
		</div>
	    

Full Power of CSS

You are not limited to rotate and translate animations. You can use the full power of CSS animations.

		<div class="sky-box" parallax="sky">
		    <div class="box" parallax="crazy"></div>
		</div>
	    
		.sky-box {
		    width: 100vw;
		    height: 100vh;
		    display: flex;
		    align-items: center;
		    justify-content: center;
		    background-image: url("sky.jpg");
		    background-attachment: fixed;
		    background-repeat: repeat;
		}

		@keyframes sky {
		    0% {background-position: 0vw 40vh;}
		    33% {background-position: 0vw 0vh;}
		    66% {background-position: -40vw 0vh;}
		    100% {background-position: -40vw -40vh;}
		}

		@keyframes crazy {
		    0% {
			transform: translate(-50vw, -50vh) rotate(-720deg) scale(0.5) skewX(60deg);
			opacity: 0;
			filter: blur(5px);
		    }
		    33% {
			transform: translate(0vh, 0vh) rotate(0deg) scale(1) skewX(0deg);
			opacity: 1;
			background-color: rgb(255, 0, 0);
			filter: blur(0px);
		    }
		    50% {
			transform: translate(0vh, 0vh) rotate(0deg) scale(1) skewX(-60deg);
			filter: blur(10px);
		    }
		    66% {
			transform: translate(0vh, 0vh) rotate(0deg) scale(1) skewX(0deg);
			opacity: 1;
			background-color: rgb(0, 255, 0);
			filter: blur(0px);
			border-radius: 0px;
		    }
		    100% {
			transform: translate(0vw, 50vh) rotate(720deg) scale(2);
			background-color: rgb(0, 0, 255);
			opacity: 0;
			border-radius: 60px;
		    }
		}
	    

Paging

You can see the paging on the right side. Trick is very easy. We want to animate each gear symbol based on associted parallax container position. We can bind any animation to position of any other element using parallax-container CSS selector.

		<div class="paging">
		    <a href="#s1" parallax="paging-button" parallax-container="#s1">⚙</a>
		    <a href="#s2" parallax="paging-button" parallax-container="#s2">⚙</a>
		    <a href="#s3" parallax="paging-button" parallax-container="#s3">⚙</a>
		    <a href="#s4" parallax="paging-button" parallax-container="#s4">⚙</a>
		    <a href="#s5" parallax="paging-button" parallax-container="#s5">⚙</a>
		</div>
	    
		@keyframes paging-anim {
		    0% {
			background-color: rgb(0, 0, 0);
			transform: scale(1) rotate(0deg);
		    }
		    50% {
			background-color: rgb(255, 0, 0);
			transform: scale(2) rotate(720deg);
		    }
		    100% {
			background-color: rgb(0, 0, 0);
			transform: scale(1) rotate(1440deg);
		    }
		}
	    

Understanding Progress Measurement

You can link any parallax animation to a position of any other element relatively to a screen view.

Linked element is called parallax container and is determined as follows.

  1. If animated element has parallax-container="CSS_SELECTOR" attribute then linked element will be selected by evaluating given CSS selector.
  2. If any parent element of animated element or animated element itself has a keyword parallax-container in its role attribute it will be used as parallax container.
  3. Otherwise the animated element's position itself will be used as default parallax container.

The parallax container's position starts at 0% when it is just bellow visible screen, 50% in the very middle, and ends at 100% just above visible screen.

Tip: Use browser's DOM Inpsector to inspect parallax-progress attribute on animated element or its linked parallax container element.

0%
33.33%
50%
66.66%
100%
0%
25%
50%
75%
100%
0%
33.33%
50%
66.66%
100%

Becoming a Parallax Container

As explained above any animated element can became parallax container itself. Animation progress will then depend on animated element's position relative to a screen. You can achieve easily quite interesting effects.

		<div class="box" parallax="fly-in-left fly-in-right:reverse" role="parallax-container"></div>
		<div class="box" parallax="fly-in-left fly-in-right:reverse" role="parallax-container"></div>
		<div class="box" parallax="fly-in-left fly-in-right:reverse" role="parallax-container"></div>
		<div class="box" parallax="fly-in-left fly-in-right:reverse" role="parallax-container"></div>
		<div class="box" parallax="fly-in-left fly-in-right:reverse" role="parallax-container"></div>
		<div class="box" parallax="fly-in-left fly-in-right:reverse" role="parallax-container"></div>
	    
The End