<div class="timeline">
<div class="event">
<div class="event__body">
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus varius sodales purus, id gravida ipsum accumsan quis. Donec ultrices orci quis ex consequat mollis. Etiam in gravida enim. Etiam efficitur lorem id turpis auctor gravida. Ut condimentum dolor nibh, in hendrerit leo egestas at.
</div>
</div>
<div class="event">
<div class="event__body">
Nam magna felis, malesuada vitae elementum sit amet, tempus sed eros. Etiam ullamcorper elementum viverra. Morbi dictum metus id nibh congue, at lacinia felis iaculis. Etiam pretium augue in erat lobortis viverra. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Suspendisse facilisis, velit vel placerat faucibus, massa est eleifend turpis, ac tempor dui turpis at mi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.
</div>
</div>
<div class="event">
<div class="event__body">
Mauris malesuada arcu sed lacus tristique, a eleifend sem egestas. Pellentesque at malesuada nisi.
</div>
</div>
<div class="event">
<div class="event__body">
Nam et purus at elit vulputate molestie ac non eros. Proin mattis ligula velit, ut semper eros venenatis a. Vestibulum sagittis consectetur diam, molestie dapibus sem viverra a. Fusce felis augue, mollis id massa molestie, sagittis rutrum risus. In vel molestie elit, eget fringilla ante. Sed et elit blandit, tincidunt leo non, vehicula mi. Aenean tempus tincidunt eros vel tincidunt. Integer orci orci, gravida sit amet elit nec, luctus condimentum est.
</div>
</div>
<div class="event">
<div class="event__body">
Pellentesque sodales ultrices sem, eget convallis ante condimentum id. Fusce ac turpis ac ex tincidunt malesuada a ac est.
</div>
</div>
</div>
CSS
/* line in center */
.timeline {
position: relative;
width: 100%;
}
.timeline:before {
content: " ";
display: block;
position: absolute;
top: 0;
left: calc(50% - 2px);
width: 4px;
height: 100%;
background: red;
}
/* events */
.event {
position: absolute;
top: 0;
left: 0;
box-sizing: border-box;
width: 50%;
height: auto;
padding: 0 20px 0 0;
}
.event--right {
/* Move padding to other side.
* It is important that the padding does not change, because
* changing the height of an element (which padding can do)
* while layouting is not handled by the JavaScript. */
padding: 0 0 0 20px;
}
/* discs on timeline */
.event:after {
content: "";
display: block;
position: absolute;
top: calc(50% - 5px);
width: 0;
height: 0;
border-style: solid;
}
.event--left:after {
right: 0;
border-width: 10px 0 10px 20px;
border-color: transparent transparent transparent #de2d26;
}
.event--right:after {
left: 0;
border-width: 10px 20px 10px 0;
border-color: transparent #de2d26 transparent transparent;
}
/* event styling */
.event__body {
padding: 20px;
background: #de2d26;
color: rgba(255, 255, 255, 0.9);
}
JavaScript
// wrap in anonymous function to not pollute global namespace
(function() {
// find the minimium element in an array, and the index of it
function min(arr) {
var ind = -1, min = false, i;
for (i = 0; i < arr.length; ++i) {
if (min === false || arr[i] < min) {
ind = i;
min = arr[i];
}
}
return {
index: ind,
value: min
};
}
// position events within a single timeline container
function updateTimeline(timeline, minSpace = 10) {
var events = Array.from(timeline.querySelectorAll('.event')),
tops = [0, 0],
bottoms = [0, 0],
minTops = [0, 0];
// determine height of container, upper bound
timeline.style.height = events.reduce(function(sum, event) {
return sum + event.offsetHeight;
}, 0) + 'px';
// position events in timeline
events.forEach(function(event) {
// find highest point to put event at
// first put it with its top aligned to the lowest bottom - this will
// always yield a good solution, we check better ones later
var h = event.offsetHeight,
y = min(bottoms),
x = (y.index === 0 ? 0 : 50),
b = y.value + h,
m = (tops[1 - y.index] + bottoms[1 - y.index]) / 2;
event.className = 'event';
event.classList.add('event--' + (y.index === 0 ? 'left' : 'right'));
// try to squeeze element up as high as possible
// first try to put midpoint of new event just below the midpoint of
// the last placed event on the other side
if (m + minSpace - h / 2 > minTops[y.index]) {
y.value = m + minSpace - h / 2;
b = y.value + h;
}
// it would be even better if the top of the new event could move
// all the way up - this can be done if its midpoint is below the
// midpoint of the last event on the other side
if (minTops[y.index] + h / 2 > m + minSpace) {
y.value = minTops[y.index];
b = y.value + h;
...
Please Whitelist JSFiddle in your content blocker.
Help keep JSFiddle free for always by one of two ways:
Whitelist JSFiddle in your content blocker (two clicks)
Go PRO and get access to additional PRO features →
Join the 4+ million users, and keep the JSFiddle dream alive.
Ad-free
All ads in the editor and listing pages are turned completely off.
Fiddle Pages
Your fiddles accessible under a custom domain and a vanity path.
Use pre-released features
You get to try and use features (like the Palette Color Generator) months before everyone else.
Fiddle collections
Sort and categorize your Fiddles into multiple collections.
Private collections and fiddles
You can make as many Private Fiddles, and Private Collections as you wish!