Create a Gantt chart
Tags: webdev, css, learning, tutorial
Published: 2024-03-08 03:53:59

Here's what we'll cover:

-   Learn how to create a grid with cells of varying widths using the `grid-template-columns` property.
-   Add a gap between items with ease using the `grid-row-gap` property.
-   Discover how to precisely position a grid item using the `grid-column` property.

---

A **Gantt chart** is a visual tool that helps project managers track the start and end dates of various tasks involved in a project. Initially designed for manufacturing settings by [Henry Gantt](https://en.wikipedia.org/wiki/Henry_Gantt) in the early 1900s, this chart has now become popular across many industries.

Gantt charts are incredibly useful because they provide a quick overview of how different tasks are progressing and whether they are on schedule or behind. By using this chart, project managers can identify potential issues before they become major problems and adjust schedules accordingly. Furthermore, Gantt charts can be used to communicate project timelines and progress with stakeholders like team members or clients, ensuring that everyone is updated.

In this post, we'll guide you through creating a week-based Gantt chart using CSS grid. Check out the preview of the Gantt chart we'll be creating:

{% codepen https://codepen.io/phuocng/pen/zYXrNLx  %}

## Adding the header

We're going to add a header to our weekly Gantt chart, which will help us track the progress of tasks for different people throughout the week. You can use the same approach to create a monthly chart if needed.

The header will have six cells. The first cell will be left empty, and it will align with the assignee of each row. The other five cells will display the weekdays of a week, starting from Monday and ending with Friday.

Here's a simple markup of the header that you can use to get started:

```html
<div class="gantt">
    <!-- Header -->
    <div class="gantt__period">
        <div></div>
        <div>Mon</div>
        <div>Tue</div>
        <div>Wed</div>
        <div>Thu</div>
        <div>Fri</div>
    </div>
</div>
```

The Gantt chart header is set up using CSS grid. We create a grid container with the `display: grid` property and set the number and size of columns using `grid-template-columns`. In our case, we use six columns: one for the assignee name and five for each day of the week. To make sure long names or descriptions fit, we set the first column to a fixed width of 5rem.

Instead of writing out each individual column width, we use the `repeat(5, 1fr)` function. This function repeats the value `1fr` five times, creating five columns with equal width. The `1fr` unit lets us define flexible column widths that adjust based on available space. This way, our code is more concise and easier to maintain.

Here's what the CSS declarations for the header look like:

```css
.gantt__period {
    display: grid;
    grid-template-columns: 5rem repeat(5, 1fr);
}
```

{% codepen https://codepen.io/phuocng/pen/ZEZQLRd %}

## Organizing rows

To create each row of the chart, we use two sections: one displays the assignee's name, while the other shows the tasks assigned to them.

```html
<div class="gantt__row">
    <div class="gantt__assign">Assignee</div>
    <div class="gantt__tasks">
        <!-- Diplay tasks ... -->
    </div>
</div>
```

To achieve the desired layout, we'll use the same approach we used for the header. Specifically, we'll use the `display: grid` property to set up a grid container, and `grid-template-columns` to define the number and size of columns in the grid. In this case, we'll use two columns: one for the assignee's name and one for displaying tasks. The first column will have a fixed width of 5rem to provide enough space for long names or descriptions, while the second column will take up the remaining available space (`1fr`).

Here's an example of what the CSS declarations for each row might look like:

```css
.gantt__row {
    display: grid;
    grid-template-columns: 5rem 1fr;
}
```

Take a look at the chart now with the header and rows included.

{% codepen https://codepen.io/phuocng/pen/eYoJgKq %}

## Organizing tasks

The second column in each row shows the tasks with the CSS class `gantt__task`. These tasks have different variations depending on their current state, whether they are yet to be completed, already done, or overdue. You can customize the appearance of the tasks based on their states, such as by using different background colors.

```html
<div class="gantt__tasks">
    <div class="gantt__task gantt__task--done">...</div>
    <div class="gantt__task gantt__task--overdue">...</div>
    <div class="gantt__task gantt__task--todo">...</div>

    <!-- More tasks ... -->
</div>
```

The `.gantt__tasks` CSS class is what makes the tasks section of each row look the way it does. It's responsible for creating a grid container using the `display: grid` property. We've set up the container to have five columns, one for each day of the week, using `grid-template-columns`. The `repeat(5, 1fr)` function tells the container to repeat the value `1fr` five times, which makes five columns of equal width that grow or shrink depending on the available space.

To make the tasks easier to read, we've added a small gap between each one using `grid-row-gap: 0.25rem;`.

Here's what the CSS declarations of the `.gantt__tasks` look like:

```css
.gantt__tasks {
    display: grid;
    grid-row-gap: 0.25rem;
    grid-template-columns: repeat(5, 1fr);
}
```

## Indicating task duration

To specify how long a task should take, we use the `grid-column` property. This property indicates a grid item's size and position within the grid by specifying the start and end positions of its grid lines.

For instance, if we want to display a task that spans from Tuesday to Friday in the second row, we can set the `grid-column` property like this: `grid-column: 2 / 6;`. This means that the task will start at the second grid line of the column track and end at the sixth grid line, which correspond to Tuesday and Friday respectively.

```html
<div
    class="gantt__task gantt__task--todo"
    style="grid-column: 2 / 6"
>
    ...
</div>
```

Specifying this property for each task allows us to visualize how long each task takes and identify any potential overlaps or gaps in the schedule. You can see a demo of this feature in the playground below.

{% codepen https://codepen.io/phuocng/pen/XWQXpBW %}

## Making the chart easier to read

In order to make it easier for users to see the duration of each task, we will add vertical lines between the columns of the chart.

To do this, we will start by adding a new element to display the lines.

```html
<div class="gantt">
    <div class="gantt__lines"></div>
</div>
```

To position the lines within the chart, we use absolute positioning. This allows us to layer the lines behind the chart content and ensure they don't interfere with any other elements on the page.

To create the vertical lines of the chart, we use the `.gantt__lines` CSS class. It uses `position: absolute` to position them relative to their nearest positioned ancestor, which in this case is the `.gantt` container. The `left: 0` and `top: 0` properties set the starting position of the lines at the top-left corner of their container. The lines spans the full height of its container, thanks to the `height: 100%` property. And to ensure that the lines spans across all columns of the chart, we use the `width: 100%` property.

Lastly, we set a negative `z-index` value to make sure these lines are positioned behind all other elements on the page and don't overlap with any other content.

Here's what the CSS declarations for positioning lines look like:

```css
.gantt {
    position: relative;
    width: 100%;
}

.gantt__lines {
    position: absolute;
    left: 0;
    top: 0;
    height: 100%;
    width: 100%;
    z-index: -1;
}
```

To add vertical lines to our Gantt chart, we can split the lines element into six columns: one for the assignee's name and five for each day of the week. We can use CSS grid to make this happen.

To get started, let's create six empty `div` elements.

```html
<div class="gantt__lines">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
</div>
```

To create a six-column layout for our lines element, we need to set `grid-template-columns: 5rem repeat(5, 1fr);`. The `5rem` value sets the width of the first column, which will show the assignee names. The `repeat(5, 1fr)` function creates five columns with flexible width that grow or shrink based on available space.

We also need to define one row for our grid using `grid-template-rows: 1fr;`. This ensures that all vertical borders span across the full height of their container.

```css
.gantt__lines {
    display: grid;
    grid-template-columns: 5rem repeat(5, 1fr);
    grid-template-rows: 1fr;
}
```

Finally, we can add a border-right property to each grid cell by selecting all `div`s inside the lines element . This will give our project a clean and organized look.

```css
.gantt__lines div {
    border-right: 1px solid rgb(203 213 225 / 0.4);
}
```

Take a look at the final result of the steps we've been following:

{% codepen https://codepen.io/phuocng/pen/zYXrNLx %}

## Conclusion

To sum up, using CSS grid to create a Gantt chart is a quick and efficient method for displaying project schedules and timelines.

By assigning our tasks to rows and using the `grid-column` property to define their duration, we can quickly identify overlaps and gaps in the schedule. Adding vertical lines to the chart improves its readability and gives it a polished appearance. Overall, CSS grid offers a user-friendly approach to building dynamic layouts for Gantt charts.


---

If you found this series helpful, please consider giving the [repository](https://github.com/phuocng/css-grid) a star on GitHub or sharing the post on your favorite social networks 😍. Your support would mean a lot to me!

If you want more helpful content like this, feel free to follow me:

-   [DEV](https://dev.to/phuocng)
-   [GitHub](https://github.com/phuocng)
-   [Website](https://phuoc.ng)