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.
- ⭐️ Icons: Nucleo, icon organizer & icon library
👋 A new version of this component is available. Download now →.
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="container max-width-lg cd-timeline__container">
<div class="cd-timeline__block">
<div class="cd-timeline__img cd-timeline__img--picture">
<img src="assets/img/cd-icon-picture.svg" alt="Picture">
</div> <!-- cd-timeline__img -->
<div class="cd-timeline__content text-component">
<h2>Title of section 1</h2>
<p class="color-contrast-medium">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>
<div class="flex justify-between items-center">
<span class="cd-timeline__date">Jan 14</span>
<a href="#0" class="btn btn--subtle">Read more</a>
</div>
</div> <!-- cd-timeline__content -->
</div> <!-- cd-timeline__block -->
<div class="cd-timeline__block">
<!-- ... -->
</div> <!-- cd-timeline__block -->
</div>
</section> <!-- cd-timeline -->
Adding style
We used a ::before
selector in absolute position to create the vertical line.
.cd-timeline {
overflow: hidden;
padding: var(--space-lg) 0;
}
.cd-timeline__container {
position: relative;
padding: var(--space-md) 0;
&::before { // this is the timeline vertical line
content: '';
position: absolute;
top: 0;
left: 18px;
height: 100%;
width: 4px;
background: var(--cd-color-2);
}
}
We used Flexbox to align content and image inside each cd-timeline__block
element:
.cd-timeline__block {
display: flex;
@include breakpoint(md) {
&:nth-child(even) {
flex-direction: row-reverse; // for even blocks -> lay out content from right to left
}
}
}
.cd-timeline__img {
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
@include breakpoint(md) {
order: 1; // flex order -> place the image after cd-timeline__content
}
}
.cd-timeline__content {
flex-grow: 1; // expand element so that it takes up all the available space inside its parent
@include breakpoint(md) {
width: 45%;
flex-grow: 0; // prevent element from growing inside its parent
}
}
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-timeline__img--hidden/.cd-timeline__content--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.
@include breakpoint(md) { // animations
.cd-timeline__img--hidden, .cd-timeline__content--hidden {
visibility: hidden;
}
.cd-timeline__img--bounce-in {
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-timeline__img--hidden/.cd-timeline__content--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-timeline__img--hidden
and .cd-timeline__content--hidden
classes) 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("cd-timeline__block");
this.images = this.element.getElementsByClassName("cd-timeline__img");
this.contents = this.element.getElementsByClassName("cd-timeline__content");
// ..
};
VerticalTimeline.prototype.showBlocks = function() {
var self = this;
for( var i = 0; i < this.blocks.length; i++) {
(function(i){
if( self.contents[i].classList.contains("cd-timeline__content--hidden") && self.blocks[i].getBoundingClientRect().top <= window.innerHeight*self.offset ) {
// add bounce-in animation
self.images[i].classList.add("cd-timeline__img--bounce-in");
self.contents[i].classList.add("cd-timeline__content--bounce-in");
self.images[i].classList.remove("cd-timeline__img--hidden");
self.contents[i].classList.remove("cd-timeline__content--hidden");
}
})(i);
}
};