From our sponsor: Chromatic - Visual testing for Storybook, Playwright & Cypress. Catch UI bugs before your users do.
This Blueprint is a template for a on scroll effect layout. We’ve had some requests on how to achieve this effect of animating elements once they are in the viewport and decided to create a Blueprint for it. It works with adding a class for animating the two sides of a section. There is an example effect defined and also some media queries for dealing with smaller screens.
On devices that support touch, we will not apply any effects due to the scrolling logic on touch devices. Please read more about this issue in this article by TJ VanToll: onscroll Event Issues on Mobile Browsers.
Resource credit: iPad PSD Flat Mockup by Pixeden.
The HTML
<div id="cbp-so-scroller" class="cbp-so-scroller"> <section class="cbp-so-section"> <article class="cbp-so-side cbp-so-side-left"> <h2>Lemon drops</h2> <p>Fruitcake toffee jujubes. Topping biscuit sesame snaps jelly caramels jujubes tiramisu fruitcake. Marzipan tart lemon drops chocolate sesame snaps jelly beans.</p> </article> <figure class="cbp-so-side cbp-so-side-right"> <img src="images/1.png" alt="img01"> </figure> </section> <section class="cbp-so-section"> <figure class="cbp-so-side cbp-so-side-left"> <img src="images/2.png" alt="img01"> </figure> <article class="cbp-so-side cbp-so-side-right"> <h2>Plum caramels</h2> <p>Lollipop powder danish sugar plum caramels liquorice sweet cookie. Gummi bears caramels gummi bears candy canes cheesecake sweet roll icing dragée. Gummies jelly-o tart. Cheesecake unerdwear.com candy canes apple pie halvah chocolate tiramisu.</p> </article> </section> <section> <!-- ... --> </section> <!-- ... --> </div>
The CSS
.cbp-so-scroller { margin-top: 50px; overflow: hidden; } .cbp-so-section { margin-bottom: 15em; position: relative; } /* Clear floats of children */ .cbp-so-section:before, .cbp-so-section:after { content: " "; display: table; } .cbp-so-section:after { clear: both; } /* Text styling */ .cbp-so-section h2 { font-size: 5em; font-weight: 300; line-height: 1; } .cbp-so-section p { font-size: 2em; font-weight: 300; } /* Sides */ .cbp-so-side { width: 50%; float: left; margin: 0; padding: 3em 4%; overflow: hidden; min-height: 12em; } /* Clear floats of children */ .cbp-so-side:before, .cbp-so-side:after { content: " "; display: table; } .cbp-so-side:after { clear: both; } .cbp-so-side-right { text-align: left; } .cbp-so-side-left { text-align: right; } .cbp-so-side-right img { float: left; } .cbp-so-side-left img { float: right; } /* Initial state (hidden or anything else) */ .cbp-so-init .cbp-so-side { opacity: 0; -webkit-transition: none; -moz-transition: none; transition: none; } .cbp-so-init .cbp-so-side-left { -webkit-transform: translateX(-80px); -moz-transform: translateX(-80px); transform: translateX(-80px); } .cbp-so-init .cbp-so-side-right { -webkit-transform: translateX(80px); -moz-transform: translateX(80px); transform: translateX(80px); } /* Animated state */ /* add you final states (transition) or your effects (animations) for each side */ .cbp-so-section.cbp-so-animate .cbp-so-side-left, .cbp-so-section.cbp-so-animate .cbp-so-side-right { -webkit-transition: -webkit-transform 0.5s, opacity 0.5s; -moz-transition: -moz-transform 0.5s, opacity 0.5s; transition: transform 0.5s, opacity 0.5s; -webkit-transform: translateX(0px); -moz-transform: translateX(0px); transform: translateX(0px); opacity: 1; } /* For example, add a delay for the right side: .cbp-so-section.cbp-so-animate .cbp-so-side-right { -webkit-transition-delay: 0.2s; -moz-transition-delay: 0.2s; transition-delay: 0.2s; } */ /* Example media queries */ @media screen and (max-width: 73.5em) { .cbp-so-scroller { font-size: 65%; } .cbp-so-section h2 { margin: 0; } .cbp-so-side img { max-width: 120%; } } @media screen and (max-width: 41.125em) { .cbp-so-side { float: none; width: 100%; } .cbp-so-side img { max-width: 100%; } }
Tiny break: 📬 Want to stay up to date with frontend and trends in web design? Subscribe and get our Collective newsletter twice a tweek.
The JavaScript
/** * cbpScroller.js v1.0.0 * http://www.codrops.com * * Licensed under the MIT license. * http://www.opensource.org/licenses/mit-license.php * * Copyright 2013, Codrops * http://www.codrops.com */ ;( function( window ) { 'use strict'; var docElem = window.document.documentElement; function getViewportH() { var client = docElem['clientHeight'], inner = window['innerHeight']; if( client < inner ) return inner; else return client; } function scrollY() { return window.pageYOffset || docElem.scrollTop; } // http://stackoverflow.com/a/5598797/989439 function getOffset( el ) { var offsetTop = 0, offsetLeft = 0; do { if ( !isNaN( el.offsetTop ) ) { offsetTop += el.offsetTop; } if ( !isNaN( el.offsetLeft ) ) { offsetLeft += el.offsetLeft; } } while( el = el.offsetParent ) return { top : offsetTop, left : offsetLeft } } function inViewport( el, h ) { var elH = el.offsetHeight, scrolled = scrollY(), viewed = scrolled + getViewportH(), elTop = getOffset(el).top, elBottom = elTop + elH, // if 0, the element is considered in the viewport as soon as it enters. // if 1, the element is considered in the viewport only when it's fully inside // value in percentage (1 >= h >= 0) h = h || 0; return (elTop + elH * h) <= viewed && (elBottom) >= scrolled; } function extend( a, b ) { for( var key in b ) { if( b.hasOwnProperty( key ) ) { a[key] = b[key]; } } return a; } function cbpScroller( el, options ) { this.el = el; this.options = extend( this.defaults, options ); this._init(); } cbpScroller.prototype = { defaults : { // The viewportFactor defines how much of the appearing item has to be visible in order to trigger the animation // if we'd use a value of 0, this would mean that it would add the animation class as soon as the item is in the viewport. // If we were to use the value of 1, the animation would only be triggered when we see all of the item in the viewport (100% of it) viewportFactor : 0.2 }, _init : function() { if( Modernizr.touch ) return; this.sections = Array.prototype.slice.call( this.el.querySelectorAll( '.cbp-so-section' ) ); this.didScroll = false; var self = this; // the sections already shown... this.sections.forEach( function( el, i ) { if( !inViewport( el ) ) { classie.add( el, 'cbp-so-init' ); } } ); var scrollHandler = function() { if( !self.didScroll ) { self.didScroll = true; setTimeout( function() { self._scrollPage(); }, 60 ); } }, resizeHandler = function() { function delayed() { self._scrollPage(); self.resizeTimeout = null; } if ( self.resizeTimeout ) { clearTimeout( self.resizeTimeout ); } self.resizeTimeout = setTimeout( delayed, 200 ); }; window.addEventListener( 'scroll', scrollHandler, false ); window.addEventListener( 'resize', resizeHandler, false ); }, _scrollPage : function() { var self = this; this.sections.forEach( function( el, i ) { if( inViewport( el, self.options.viewportFactor ) ) { classie.add( el, 'cbp-so-animate' ); } else { // this add class init if it doesn´t have it. This will ensure that the items initially in the viewport will also animate on scroll classie.add( el, 'cbp-so-init' ); classie.remove( el, 'cbp-so-animate' ); } }); this.didScroll = false; } } // add to global namespace window.cbpScroller = cbpScroller; } )( window );
Hvala na jos jednom super clanku 🙂
<3 iz Hrv
Thanks Mary. This is a really nice article. I’ve wanted to know more about this effect since I first saw it but never had the time. I can’t wait to play with your demo and see what effects I can add to it.
What a great timing! 🙂 I just finished my wireframe with this effect, thank you!
Looks good in safari 5.0.6 😀
Great stuff, as always! 🙂
<3 from HRV 🙂
your power of imagination is blessed!
Wow, great! Only a thing, in Chrome (28.0.1500.71) the document flicker when you scroll down. It’s all ok in Safari…
I’m seeing this flicker in Chrome as well. I’d be interested to see the underlying cause and how to fix that up.
great very useful.
thanks keep it up.
Simply AMAZING
Great example, is very simple and easy to use! =D
Loved!
Since long, i was waiting for tutorial like this. Many many thanks.
Excelente articulo MARY LOU, justo lo que necesita para el rediseño de mi web.
Thankss !!
I’m so surprised to see this blueprint working properly in IE10 and not working at all in Chrome… what’s wrong with my browsers ?!!
Anyway, Mary, another great work from you, thanks!
Nexus 7, chrome. It doesn’t work.
Lovely like always Mary.
I have one small question that I hope you can answer for me.
In all of your tutorials on codrops, your javascript is wrapped with this:
;( function( window ) { ... } )( window );
What does this do exactly? Is it a DOM ready function? Or are you passing the window object?
I am trying to move away from my reliance on jQuery towards a lighter JavaScript skill-set.
Cheers
Dean
The “;” on the first line prevents some nasty errors that can occur while minimizing/concatenating js files.
( function (window) { ... })(window);
This creates an annonymous and self-executing function to create an isolated scope, so you won’t pollute global namespace with your variables. It takes one argument — the window object. It is just a convenient way to create an alias for window object if you use it a lot. I usually see a slightly more advanced example of such a function:
( function (w, d, undefined) { ... })(window, document);
This aliases window as w, and document as d, and also makes sure undefined is undefined (that’s older js legacy, probably useless now).
Thanks for the reply Maciek.
You couldn’t have explained that better!
Cheers.
Thanks, I’ll try now. Something to learn…thanks again !
I hope you don’t mind such an ignorant question. I am taking online classes to improve my understanding of css, html and java, I just haven’t gotten to this particular part yet and online research has proved fruitless.
In WordPress, where specifically would you add the the html and javascript? I understand the css would go into the stylesheet/CSS, correct? I just haven’t been able to figure out the html and javascript part.
Again, I apologize for asking such a primary question. I guess I’m not working the search inquiries correctly to get the answer.
Your site has been a great resource in learning the basics of coding and seeing it work in an actual code situation. Thank you.
Hye,
The javascript can be written in footer.php i guess (since its included in every page).. And for HTML one of the relevant php files, though you should be careful while editing them.
Hope it helps.
Excellent Mary Lou!
As a friendly suggestion, consider doing the blueprint for a three column adaptive – responsive website (see the new Mashable) next.
Beautiful! But is there any way this can work on the iPad with touch scrolling?
I am trying to get this to fit my desired animation. I changed
this.sections = Array.prototype.slice.call( this.el.querySelectorAll( '.cbp-so-section' ) );
tothis.sections = Array.prototype.slice.call( this.el.querySelectorAll( '.featured-icon' ) );
hoping that it would target all of my divs with the class “featured-icon” but it returned this.el is null. Any tips?I’ve been trying to stop the effects when scrolling back up but didn’t succeed so far. This must be something very easy to achieve. Does anyone know how to do it.
Thank you!
Anyone?? :'(
On line 128 in cbpScroller.js, remove the line that says “classie.remove(el, “rm-animate”)
That should do the trick!!
Tiago,
All you have to do is remove the second conditional statement on line 61. i.e:
&& (elBottom) >= scrolled;
It doesn’t work in IE. Even the demo URL fails in rendering the effect in IE8 giving an error “Webpage error details – Message: JScript object expected
Line: 87 Char: 4 Code: 0 ” in the js file. Any comments ?
Not much does work in IE8, fortunately very few people use it.
Why isn’t this a jQuery plugin?
Beautiful work, I love it. Can anyone help me implement this concept on a joomla site, or has anyone done it successfully. I am trying but not there yet.
Create a custom html module for the html. Upload the css and js files to e.g. /templates/yourtemplate/css/ or …/js/ respectively and load them by adding references to the head of your template default layout (probably templates/layouts/default.php or theme.php or whatever. Then create a new empty article. Create a menu item to your article. Publish the custom html module to the mainbody position of your article (many templates have the option to override the main content output publishing a module to the mainbody position if yours doesn’t, just put the html in an article body). Bob’s yer uncle.
Is there a way to add a scroll to bottom that works with the slide in animation? I have been trying to implement a smooth scroll to bottom on this page, but it just jumps straight to the bottom. It seems that the slide in animation is over ridding anything I add. Thanks!
Thanks … 😀
Really fantastic, I was looking for this effect!
Is there any way to make the left and right classes overlap??
Hi Mary Lou,
I love your work – absolutely fantastic stuff!
One thing though, the demo texts are making me extremely hungry 🙂
All the best,
Jared
Does it works on Ipad?
I am getting some strange issue, which inturn breaks all my other jquery plugins.
I have slightly changed the HTML markup to be articles instead of figures, I do not want to use images but rather all text. I have not touched the JS code.
Website Design
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry’s standard dummy text ever since the 1500s
My JS console gives me this Uncaught TypeError: Cannot call method ‘querySelectorAll’ of null on line 87 of cbpScroller.js
Has anyone come across this issue?
I’m also have same problem. If someone know about how to fix it please let me know.
great tutorial!!
just one question, is it possible to delay the effect?
thanks
I’m trying everything on the site is behind him because the menu is fixed and does not know where I move this code to move backward.
Can someone help me
Hey, does anyone know how can I implement this to wordpress easily?
Much appreciated!
Yulong
I am seeing the Error come up in IE8, is there any way to work around this, so at least when it doesn’t work in the browser the error doesn’t come up?
Does anybody know how to change the background color? I cant seem to find it in the css
Thanks a lot!
Not all understand, but works very well.
And i fix a little moment, animate element once, it’s better, as for me.
This doesn’t work on mobile devices. Well It works there is just no animation.
Hello! I have a doubt. When i try to create new sections (like copy from to ) the cbp-so-scroller only animates the first section, the original one. How can i fix it, in order to duplicate several sections and only change the id to point to other menu item? Thank you so much, B.R. Rodrigo Maia.
The HTML:
Quisque gravida felis
Praesent
I had the same problem .. just replace
this.sections = Array.prototype.slice.call( this.el.querySelectorAll( '.cbp-so-section' ) );
with
this.sections = Array.prototype.slice.call( document.querySelectorAll( '.cbp-so-section' ) );
Hello!
Is there a way to incorporate this to a wix website? Thanks
Hello, somebody know how to use this awesome javascript code in the mobile and touch phones, i saw the article at the start, but i can’t modify the code, if somebody could help me, i will be gratefully, Thanks.
I wonder if this scroll effect will work with the page split to make a very cool effect.
Hello, would there be any possible way to resize images to fit screen size? I tried this with a 1920×1080 resolution and it works perfectly, but if I change my resolution to 1280×1024 , the images will be like cropped.
Is there a way to trigger the animation when the page is first loaded?
tell you what I love your work
Does this affect work with Chrome? When I click View Demo and then scroll the page, nothing happens. What am I suppose to see?
Same issue… strange !!!! Is it a fake ??
Same issue… strange !!!! I confirm, it is working on IE and Edge but does not work on Chrome….