Vertical Timeline

Vertical Timeline

Today's resource is an easy to customize, responsive timeline. We used some CSS3 tricks and a bit of JavaScript to create some bounce animations that affect desktop users only, while on mobile the structure is more minimal.

Nucleo icons

Sponsored by Nucleo, a free application to collect, customize and export all your icons as icon font and SVG symbols. Made by the CodyHouse folks!

All the resources available on CodyHouse are released under the BSD-3-Clause license. You can support our project with a Paypal donation 🙌

We all are quite familiar with vertical timelines: all instant messaging applications use them. A current trend in web design is to use a similar structure, but to show a process rather than a sequence of events. That is why timeline-like structures are often used for the "How it works" page.

The inspiration for this nugget came from the Zurb University page.  The result is very clean yet dynamic, with room for big illustrations in the center.

Icons: Nucleo Library

Creating the structure

We wrapped the entire timeline into a <section> element. The .cd-timeline__block div represents a "block" of content. We then split the image/icon and the text content into 2 separates divs.

<section class="cd-timeline js-cd-timeline">
   <div class="cd-timeline__container">
      <div class="cd-timeline__block js-cd-block">
         <div class="cd-timeline__img cd-timeline__img--picture js-cd-img">
            <img src="img/cd-icon-picture.svg" alt="Picture">
         </div> <!-- cd-timeline__img -->

         <div class="cd-timeline__content js-cd-content">
            <h2>Title of section 1</h2>
            <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iusto, optio, dolorum provident rerum aut hic quasi placeat iure tempora laudantium ipsa ad debitis unde? Iste voluptatibus minus veritatis qui ut.</p>
            <a href="#0" class="cd-timeline__read-more">Read more</a>
            <span class="cd-timeline__date">Jan 14</span>
         </div> <!-- cd-timeline__content -->
      </div> <!-- cd-timeline__block -->

      <div class="cd-timeline__block js-cd-block">
         <!-- ... -->
      </div> <!-- cd-timeline__block -->

      <!-- ... -->
</section> <!-- cd-timeline -->

Adding style

We used a ::before selector in absolute position to create the vertical line. Images/icons are in absolute position too, this way it was super easy to create the responsive structure simply by adding a margin-left to the text content.

.cd-timeline {
  overflow: hidden;
  margin: 2em auto;

.cd-timeline__container {
  position: relative;
  width: 90%;
  max-width: 1170px;
  margin: 0 auto;
  padding: 2em 0;

.cd-timeline__container::before {
  /* this is the vertical line */
  content: '';
  position: absolute;
  top: 0;
  left: 18px;
  height: 100%;
  width: 4px;
  background: #d7e4ed;

2 bounce-in animations, both for the image/icon and the text content, have been created and are visible only for desktop users. For the animation to work we use 2 classes: .cd-is-hidden, which is used to hide by default all the content blocks that are off the viewport; when the user scrolls down, we add the .cd-timeline__img--bounce-in class to the .cd-timeline__img and the .cd-timeline__content--bounce-in to the .cd-timeline__content to make the elements visible and trigger the animation.

@media only screen and (min-width: 1170px) {
  .cd-is-hidden {
    visibility: hidden;
  } {
    visibility: visible;
    animation: cd-bounce-1 0.6s;

@keyframes cd-bounce-1 {
  0% {
    opacity: 0;
    transform: scale(0.5);

  60% {
    opacity: 1;
    transform: scale(1.2);

  100% {
    transform: scale(1);

Events handling

As explained in the "Adding style" section, we used JavaScript to hide content blocks which are off the viewport, using the class .cd-is-hidden. When user scrolls and a new block enters the viewport, we add the class .cd-timeline__img--bounce-in and the .cd-timeline__content--bounce-in to the .cd-timeline-img and the .cd-timeline-content (and remove the .cd-is-hidden class) to trigger the animation.

To do that, we created a VerticalTimeline object and defined a showBlocks() method to reveal the timeline blocks on scrolling:

function VerticalTimeline( element ) {
   this.element = element;
   this.blocks = this.element.getElementsByClassName("js-cd-block");
   this.images = this.element.getElementsByClassName("js-cd-img");
   this.contents = this.element.getElementsByClassName("js-cd-content");
   // ...

VerticalTimeline.prototype.showBlocks = function() {
   var self = this;
   for( var i = 0; i < this.blocks.length; i++) {
         if( self.contents[i].classList.contains("cd-is-hidden") && self.blocks[i].getBoundingClientRect().top <= window.innerHeight*self.offset ) {
            // add bounce-in animation

Join our newsletter

Get our monthly recap with the latest CodyHouse news