Our vertical timeline is so far one of the most popular resources on CodyHouse. Many of you asked us to include a horizontal timeline as well. Here it is!
Building a horizontal timeline was a bit tricky, because you can’t rely on the vertical (more intuitive) scrolling behaviour. We decided to separate timeline and events, with the first one working like a slider, while the second one occupying the full width and showing a single event at a time.
👋 Important: this experiment is built using the CodyHouse Framework.
Creating the structure
The HTML structure is composed by two main ordered lists: the first one containing the timeline dates and the second one the events.
An additional unordered list has been used for the navigation arrows (.cd-h-timeline__navigation
elements), and a span.cd-h-timeline__filling-line
to create the filling effect when a new event is selected.
<section class="cd-h-timeline js-cd-h-timeline margin-bottom-md">
<div class="cd-h-timeline__container container">
<div class="cd-h-timeline__dates">
<div class="cd-h-timeline__line">
<ol>
<li><a href="#0" data-date="16/01/2014" class="cd-h-timeline__date cd-h-timeline__date--selected">16 Jan</a></li>
<li><a href="#0" data-date="28/02/2014" class="cd-h-timeline__date">28 Feb</a></li>
<!-- other dates here -->
</ol>
<span class="cd-h-timeline__filling-line" aria-hidden="true"></span>
</div> <!-- .cd-h-timeline__line -->
</div> <!-- .cd-h-timeline__dates -->
<ul>
<li><a href="#0" class="text-replace cd-h-timeline__navigation cd-h-timeline__navigation--prev cd-h-timeline__navigation--inactive">Prev</a></li>
<li><a href="#0" class="text-replace cd-h-timeline__navigation cd-h-timeline__navigation--next">Next</a></li>
</ul>
</div> <!-- .cd-h-timeline__container -->
<div class="cd-h-timeline__events">
<ol>
<li class="cd-h-timeline__event cd-h-timeline__event--selected text-component">
<div class="cd-h-timeline__event-content container">
<h2 class="cd-h-timeline__event-title">Horizontal Timeline</h2>
<em class="cd-h-timeline__event-date">January 16th, 2014</em>
<p class="cd-h-timeline__event-description color-contrast-medium">
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Illum praesentium officia, fugit recusandae ipsa, quia velit nulla adipisci? Consequuntur aspernatur at, eaque hic repellendus sit dicta consequatur quae, ut harum ipsam molestias maxime non nisi reiciendis eligendi! Doloremque quia pariatur harum ea amet quibusdam quisquam, quae, temporibus dolores porro doloribus.
</p>
</div>
</li>
<li class="cd-h-timeline__event text-component">
<!-- event description here -->
</li>
<!-- other descriptions here -->
</ol>
</div> <!-- .cd-h-timeline__events -->
</section>
Adding style & Guidelines
Let's start from the events style: all the items are translated to the left, outside the viewport (translateX(-100%)
); the .cd-h-timeline__event--selected
class is added to the visible event item to move it back into the viewport (translateX(0)
).
4 classes have been used to create the slider animation: the .cd-h-timeline__event--enter-right
/.cd-h-timeline__event--enter-left
classes added to the selected event item entering the viewport from right/left, and the .cd-h-timeline__event--leave-right
/.cd-h-timeline__event--leave-left
classes added to the event item moving to the right/left while leaving the viewport. These classes are used to apply two different CSS animations: cd-enter-right
and cd-enter-left
.
.cd-h-timeline__events {
position: relative;
}
.cd-h-timeline__event {
position: absolute;
z-index: 1;
width: 100%;
left: 0;
top: 0;
transform: translateX(-100%);
opacity: 0;
animation-duration: 0.4s;
animation-timing-function: ease-in-out;
}
.cd-h-timeline__event--selected { // selected event info
position: relative;
z-index: 2;
opacity: 1;
transform: translateX(0);
}
.cd-h-timeline__event--enter-right,
.cd-h-timeline__event--leave-right { // animate event info
animation-name: cd-enter-right;
}
.cd-h-timeline__event--enter-left,
.cd-h-timeline__event--leave-left { // animate event info
animation-name: cd-enter-left;
}
.cd-h-timeline__event--leave-right,
.cd-h-timeline__event--leave-left {
animation-direction: reverse;
}
@keyframes cd-enter-right {
0% {
opacity: 0;
transform: translateX(100%);
}
100% {
opacity: 1;
transform: translateX(0%);
}
}
@keyframes cd-enter-left {
0% {
opacity: 0;
transform: translateX(-100%);
}
100% {
opacity: 1;
transform: translateX(0%);
}
}
About the timeline: the position of each date along the timeline is set using Javascript. Dates are not equally distributed along the timeline, but the distance between a date and the next one is proportional to the difference between these dates.
First of all, in the main.js file, we set a minimum distance between two consecutive dates, using the eventsMinDistance
property of the HorizontalTimeline
object; in our case, we set eventsMinDistance
= 60 (so the minimum distance will be 60px). We also set a maximum distance between events (eventsMaxDistance
= 200).
We then evaluate all the differences between a date and the following one; to do that we use the data-date
attribute added to each date. The minimum difference is then used as a reference to evaluate the distances between two consecutive dates.
About the date format: we used the date format DD/MM/YYYY, but you can also add time, if you need to take that into account. There are 3 different date formats you can use:
- DD/MM/YYYY -> day only;
- DD/MM/YYYYTHH:MM -> if you need to consider time too (e.g., 02/10/2015T19:45);
- HH:MM -> time only (for events happening within the same day).
⚠️ Note: if you need to initilize your rimeline at a later time (e.g., your timeline is populated with a delay), remove the .js-cd-h-timeline
class form the .cd-h-timeline
(so that the timeline is not initialized before the content has been loaded). Once the timeline is ready, use the HorizontalTimeline
object to initialize it:
new HorizontalTimeline(document.getElementByID('your-timeline-id'));