A simple timeline using CSS flexbox
As I added a /now page to the site I also decided to refresh my /about page and I figured it would be neat to have timeline element where I could list some of the larger events in my life.
To my surprise it wasn’t too difficult to create one that looks pretty clean—the flexbox feature in CSS is really good. In this post I’ll walk you through how I made this kind of timeline:
I was born in the north of Sweden
I got introduced to Visual Basic
Got together with Veronica
Markup
I like to start with the markup before moving on to styling.
I have two wrappers (timeline
and events
) around the different events (event
) that contains the event marker (svg
) and content with a time
and text
:
<!-- The first `1989` event -->
<!-- The circle is an svg -->
>
<!-- The event info -->
1989
I was born in the north of Sweden
<!-- etc ... -->
A simple line
Let’s start with the actual line in the timeline.
I chose to use the ::before pseudo-element on the events
div to simulate a line by setting the width and height:
{
// We need some content for the element to show up.
// Use absolute positioning to place the timeline at the very top.
// With a height and with the timeline will be a tall and thin box.
We also need to set the wrapper
to use relative positioning, otherwise the timeline will start from the top of the page, not the container:
{
}
I’ll also throw in a little bit of styling so it’s easier to see:
// For the tutorial I use slightly different colors,
// but you get the idea.
{ }
// Events use different classes to differentiate them.
{ }
{ }
{ }
// Make the time stand out
{
:;
}
// Just some extra spacing to make the timeline not merge
// with the surrounding text.
{ }
And we have our line for our timeline:
I was born in the north of Sweden
I got introduced to Visual Basic
Got together with Veronica
Alignment
The circle and event aren’t aligned, let’s try to fix that.
By using flexbox the event will display its content horizontally (with the circle to the left and the content to the right):
{
}
I was born in the north of Sweden
I got introduced to Visual Basic
Got together with Veronica
Close, but the circle seems off.
Remember that the circle is an svg 12 pixels wide and high and positioning will use 0,0
by default.
With relative positioning we can move the center of the circle to align it better:
{
}
I was born in the north of Sweden
I got introduced to Visual Basic
Got together with Veronica
But if you look closely this still doesn’t look correct. Turns out that centering things is the hardest problem in computer science, so don’t be discouraged.
To save you some grief, I found that align-items: baseline
does a better job than nudging top positioning:
{
}
{
}
I was born in the north of Sweden
I got introduced to Visual Basic
Got together with Veronica
(The alignment looks good enough to me, at least with the default font I use.)
Vertical spacing
It feels a bit cramped so lets space things out.
One way is to simply add a
but that would add a useless space below the last event (that we’d have to remove another way).
I think a cleaner way is to use flexbox and row-gap
to only specify spacing between elements:
{
{
// Lay out events column-wise instead of row-wise.
// Set some spacing between elements.
}
}
I was born in the north of Sweden
I got introduced to Visual Basic
Got together with Veronica
Making it responsive
What we’ve made is good for smaller screens but for larger screens I’d like to place the line in the middle and move some events to the left and some to the right.
I’ll use media queries to create a cutoff:
// Styling for wider screens goes here.
}
Even though I won’t include the media query in the following code snippets the media query should wrap them all.
Events to the left
The first thing I’d like to do is move the line to the middle:
{
// This centers the line horizontally.
// Remember that we used absolute positioning before.
}
I was born in the north of Sweden
I got introduced to Visual Basic
Got together with Veronica
(Use a wider screen to see the effects of our changes.)
Now, let’s move the marker to the timeline. First lets move the marker to be after the content in the layout ordering:
{
}
I was born in the north of Sweden
I got introduced to Visual Basic
Got together with Veronica
Secondly, we’ll make the content take up all the space to the left, pushing the marker on top of the line in the middle:
{
}
I was born in the north of Sweden
I got introduced to Visual Basic
Got together with Veronica
Lets move right-align the content and add some padding so the text won’t overlap with the marker:
{
}
I was born in the north of Sweden
I got introduced to Visual Basic
Got together with Veronica
Events to the right
To move events to the right side of the timeline all we have to do is tell flexbox to lay out elements from right to left instead of left to right:
// Use `nth-child(even)` to target every other event.
{
// Layout elements from right to left.
}
To make it look good lets add left aligned text and move the marker offset to be aligned over the line again:
{
{ }
// The marker used to be offset -6px, but now we
// move from the right.
{ }
}
I was born in the north of Sweden
I got introduced to Visual Basic
Got together with Veronica
We’re done
That’s all there is to the timeline I use. You can of course modify and expand on it in many ways but I quite like this simple styling.
With flexbox it was in the end fairly simple to get a basic timeline created and it’s one of my absolute favorite CSS features that manages to simplify many things that used to be very awkward.
Here’s the all the styling for the timeline we created in this post:
// The line in the middle.
{
}
{
// Needed for positioning the line.
// Add some space.
}
{
// Layout content and marker using flexbox.
// Align marker vertically.
}
{
// Adjust marker to center on the line.
}
// Some coloring to make our life easier.
{
}
{
}
{
}
{
:;
}
// Place the line in the middle.
{
}
// Layout the marker after the content.
.event .marker
}
.event .content // Make the content take 50% space so the marker
// will be placed at 50% (on top of the line).
// Event is to the left, align text towards the line.
// Avoid overlap with the marker.
}
// For these types, move the event to the right.
.event:is, .work, .projects) // Layout the content and marker from right to left.
// Now align text to the left.
{
}
// We used to offset the marker from the left with -6px,
// now we need to do it from the other side.
.marker
}
}
}