Advertisement
  1. Web Design
  2. Patterns
Webdesign

Building a Vertical Timeline With CSS and a Touch of JavaScript

by
Difficulty:IntermediateLength:MediumLanguages:

In this tutorial, we’ll learn how to build a responsive vertical timeline from scratch. First, we’ll create the basic structure with minimal markup and the power of CSS pseudo-elements. Then, we’ll use some JavaScript to add some transitional effects as we scroll down the page. 

Let’s get an idea of what we’ll be building (check out the larger version on CodePen).

1. HTML Markup

The markup we’ll use is pretty straightforward; a plain unordered list with a div element inside each of our list items. As we’re dealing with events along a timeline, we’ll give each list item a time element to display the year.

Additionally, we’ll wrap the whole thing within a section element with the class of timeline:

This gives us the following unstyled output:

2. Adding Initial CSS Styles

After some basic colors etc. (check out the upper section of the CSS in the pen below) we’ll define some structural CSS rules for the list items. We’ll also style the ::after  pseudo-element of these items:

I’ve removed the content within the list items to make this step clearer, giving us the following:

3. Timeline Element Styles

Now let’s style the div elements (we’ll call them “timeline elements” from now on) which are part of the list items. Again, we style the ::before pseudo-element of these elements. 

Also, as we'll see in a moment, not all divs share the same styles. Thanks to the :nth-child(odd) and :nth-child(even) CSS pseudo-classes, we’re able to differentiate their styles.

Have a look at the corresponding CSS rules below:

Then some styles for our odd elements:

Then finally the styles for our even elements:

With these rules in place (and our HTML once again complete with content) our timeline looks as follows:

The main difference between the “odd” and “even” divs is their position. The first ones have left:45px; while the second ones left:-439px;.  To understand the positioning of our even divs, let’s do some simple maths:

Width of each div + Desired spacing - Width of each list item = 400px + 45px - 6px = 439px

The second, less important difference is the generated arrow of their pseudo-element. That means, the pseudo-element of each of the “odd” divs have a left arrow, whereas the pseudo-element of each of the “even” divs displays as a right arrow. 

4. Adding Interactivity

Now that the basic structure of the timeline is ready, let’s figure out the new requirements: 

  • By default, the timeline elements (divs) should be hidden.
  • They should appear when their parent (list item) enters the viewport.

The first task is relatively straightforward. The second one, though, is a bit more complicated. We need to detect if the target elements (list items) are fully visible in the current viewport, then if that happens we reveal their child. To implement this functionality, we won’t use any external JavaScript library (e.g. WOW.js or ScrollReveal.js) or write our own complex code. Happily enough, there's a popular thread on StackOverlow about this issue. So first let’s take advantage of the proposed answer to test whether an element is visible in the current viewport or not. 

Here’s the simplified function that we’ll be using:

Add Class When in View

Next we add the in-view class to the list items which are visible in the current viewport. 

Note: it’s important we test if they’re visible in the following cases:

  • When the page loads
  • As we scroll down

If needed, we can make some additional tests (such as when the size of the browser window changes).

In our example, here’s the code we use:

Now that we’ve added our JavaScript, if we reload the page, we should see a result similar to this: 

Hiding and Revealing

Let’s now revisit our initial requirement. Remember, by default, all divs should be hidden. To achieve this, we use the visibility and opacity CSS properties. Furthermore, we use the translate3d() to move them 200px away from their original position. As long as their parent is in view, we’ll reveal them and remove the predefined offset. In this way, we create nice slide in effects.  

Lastly, another small thing we’ll do when an li is within the viewport, is to change the background color of its ::after pseudo-element.

The following styles take care of all that:

The following visualization shows the initial state of our timeline. Here you’re able to see the timeline elements because I've given them a touch of opacity just to illustrate where they’re initially located:

The default appearance of the timeline before the animations

And here’s the final state of the timeline:

The final appearance of the timeline after the animations

5. Going Responsive

We’re almost ready! The last thing we have to do is to make our timeline responsive. 

First, on what we’ll refer to as “medium screens” (>600px and ≤900px), we only make one small modification. Specifically, we decrease the width of the divs. 

Here are the rules that we have to change:

In such a case, the timeline looks like this:

On small screens however (≤600px), all timeline elements look the same; there are no differences between the “odd” and “even” divs. Again, we have to overwrite some CSS rules:

On smaller screens the timeline looks as follows:

Note: on small screens we use the vw unit to specify the width for the timeline elements. There aren’t any special reasons behind this approach. We could equally have used percentages or pixels.

Browser Support

The demo works well in most recent browsers and devices. On iOS devices, however, the timeline elements are always visible, instead of appearing as their parent enters the viewport. 

From my testing I’ve seen that on those devices the window.innerHeight and document.documentElement.clientHeight properties don’t return the actual viewport height. Specifically, they return a much larger number. As a result of that inconsistency, all list items receive the in-view class when the page loads. 

Although it’s not a big deal (you may want the animations only on large screens), if you know more about this issue or you’ve seen it before, don’t forget to leave details in the comments.

Conclusion

In this tutorial, we created a responsive vertical timeline. We’ve covered a lot of things, so let’s recap:

  • By using a simple unordered list and CSS pseudo-elements, we managed to build the main structure of our timeline. One downside to this approach though is that, as I’ve already mentioned in another article, CSS pseudo-elements aren’t 100% accessible, so keep that in mind.
  • We took advantage of a code snippet taken from a popular thread on StackOverflow to test whether the list items are in view or not. Then, we wrote our own CSS to animate their child elements. Alternatively, we could have used a JavaScript library or written our own code.

I hope you enjoyed the tutorial and you’ll use this timeline as the basis for building something interesting. If you have any questions, let me know in the comments below!

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.