Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS Simple Gantt Chart (Compact)

I'm trying to generate a simple gantt chart with html and css and I'm need to figure out how to make it compact, meaning if there is whitespace available the bar should try to fit in a previous row while maintaining the same x distance.

Context:

  • X axis is a timeline in months
  • Each item starts and ends at a given month
  • Width and margin are being generated via JS for each element

Current Output: enter image description here

Desired Output: enter image description here

Constraints

  • A JS solution is ok but ideally the solution will not require using an overkill existing js library as the code will be run on a browser extension which would expose a lot of compatibility issues.
  • The items do not need to be dynamically movable as for the most part this will be similar to a rendered image.
  • No more than 30 items will be rendered.

Current Implementation Snippet: [Edit] I've slightly changed the snippet to demonstrate the need for fixed distance from x.

.timeline div {
    height: 10px;
    background: black;
    margin: 2px;
}
<div class="timeline">
  <div style="width: 80px; margin-left: 0px;"></div>
  <div style="width: 40px; margin-left: 35px;"></div>
  <div style="width: 45px; margin-left: 40px;"></div>
  <div style="width: 100px; margin-left: 135px;"></div>
  <div style="width: 160px; margin-left: 270px;"></div>
  <div style="width: 185px; margin-left: 385px;"></div>
</div>

Other solutions I've tried:

Originally I started by rendering in JS a monthly matrix of squares and appending an element for each matching month and then using some convoluted logic to help the rendering but I realized it kept getting more and more complex so I backtracked to check if I was absolutely sure there was no simpler solution.

like image 958
Marco Yammine Avatar asked Apr 24 '26 16:04

Marco Yammine


1 Answers

In the end the ultimate solution was to use css-grid by having a container with the following CSS:

.timeline_container {
    display: inline-grid; // all contents of the container will be treated as grid elements
    grid-auto-columns: 40px; // defines the default width of each column
    grid-auto-rows: 40px; // defines the height of each row

    /* the line below is the key part to making it compact/dense */
    grid-auto-flow: row dense; // keeps rows compact by filling available row whitespace
}

And each child element with the following CSS:

.timeline_item {
    grid-column: 3 / 5; // defines start and end column where the item
}

So the following HTML would render exactly the way I needed it to:

<div class='timeline_container'>
    <div class='timeline_item'></div>
    <div class='timeline_item'></div>
    <div class='timeline_item'></div>
</div>

I've written a more detailed article about the solution: https://www.cvtimeline.com/creating-a-gantt-timeline-with-css-grid/

css-grid rocks!!!

like image 104
Marco Yammine Avatar answered Apr 26 '26 04:04

Marco Yammine