I am working on a Gantt chart but for the sake of this question trying to figure out how to add vertical gridlines to the following element, with placeholders instead of actual elements.
For context, the following code uses Tailwind (v4 but it would work the same with Tailwind v3) classes, so the CSS file is generated.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<div class="relative grid grid-cols-[auto_auto_120px_90px_100px]">
<!-- Header -->
<div class="col-span-full grid grid-cols-subgrid items-center rounded-md bg-neutral-100">
<span>Column 1</span>
<span>Column 2</span>
<span>Column 3 (Month 1)</span>
<span>Column 4 (Month 2)</span>
<span>Column 5 (Month 2)</span>
</div>
<!-- Data -->
<div class="col-span-full grid grid-cols-subgrid">
<span>Data 1.1</span><span>Data 2.1</span><span class="col-start-3 -col-end-1">Data 3.1 (bar)</span>
<span>Data 1.2</span><span>Data 2.2</span><span class="col-start-3 -col-end-1">Data 3.2 (bar)</span>
<span>Data 1.3</span><span>Data 2.3</span><span class="col-start-3 -col-end-1">Data 3.3 (bar)</span>
</div>
</div>
Which renders like I intend it to.
Now, for the vertical gridlines, I was thinking of superposing div
elements to my grid columns, with a div + div { border-left: 1px }
type of CSS rule: as the div
take up exactly the same screen area as the actual columns, borders would naturally be drawn between them.
If all the column widths were fixed or defined as percentage, I could easily define a separate grid with the same values, and have lines drawn with e.g. a type of rule. Since that is not the case, I was thinking of superposing another subgrid, so it can inherit the column widths of the parent element.
But while the new grid takes up the full area of my Gantt chart, it renders with only 1 column. For the sake of making the superimposed grid more visible in the next example, the added div
s are given a background color (blue) too.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<div class="relative grid grid-cols-[auto_auto_120px_90px_100px]">
<!-- Header -->
<div class="col-span-full grid grid-cols-subgrid items-center rounded-md bg-neutral-100">
<span>Column 1</span>
<span>Column 2</span>
<span>Column 3 (Month 1)</span>
<span>Column 4 (Month 2)</span>
<span>Column 5 (Month 2)</span>
</div>
<!-- Data -->
<div class="col-span-full grid grid-cols-subgrid">
<span>Data 1.1</span><span>Data 2.1</span><span class="col-start-3 -col-end-1">Data 3.1 (bar)</span>
<span>Data 1.2</span><span>Data 2.2</span><span class="col-start-3 -col-end-1">Data 3.2 (bar)</span>
<span>Data 1.3</span><span>Data 2.3</span><span class="col-start-3 -col-end-1">Data 3.3 (bar)</span>
</div>
<div class="absolute inset-0 col-span-full grid grid-cols-subgrid [&>*+*]:border-s-1 [&>*:nth-child(odd)]:bg-blue-300/50">
<div></div><div></div><div></div><div></div><div></div>
</div>
</div>
And obviously, my problem at this point is that the added grid renders full-width rows.
How can I make it so full-height columns are rendered instead?
I have saved this fiddle reproducing the issue; alternatively, you can also copy/paste my code in Tailwind's playground.
The stylesheet Tailwind would generate (apart from some CSS variables that were substituted by their values to make it all self-contained) is:
.relative {
position: relative;
}
.grid {
display: grid;
}
.grid-cols-\[auto_auto_300px_250px_300px\] {
grid-template-columns: auto auto 300px 250px 300px;
}
.col-span-full {
grid-column: 1 / -1;
}
.grid-cols-subgrid {
grid-template-columns: subgrid;
}
.items-center {
align-items: center;
}
.h-10 {
height: 2.5rem;
}
.rounded-md {
border-radius: 0.375rem;
}
.bg-neutral-100 {
background-color: rgb(245 245 245);
}
.col-start-3 {
grid-column-start: 3;
}
.-col-end-1 {
grid-column-end: -1;
}
.absolute {
position: absolute;
}
.inset-0 {
inset: 0;
}
.\[\&\>\*\+\*\]\:border-s-1 > * + * {
border-inline-start-width: 1px;
}
.\[\&\>\*\:nth-child\(odd\)\]\:bg-blue-300\/50 > *:nth-child(odd) {
background-color: rgb(147 197 253 / 0.5);
}
Took me a couple additional hours to figure out myself.
One possible solution is to drop the absolute
position and resort to grid placement.
It is not 100% clean as it uses a grid-rows-[repeat(1000000,auto)]
class but is IMHO very close (all it takes to support over 1M rows is to change the number in repeat
).
Once done, the header and data must be forced to the grid rows 1 and 2 respectively, while the superimposed grid must span over all columns and all rows.
Here is what the code looks like (with additional background colors to demonstrate the bar cells indeed span from column 3 to the last column)
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<div class="relative grid grid-cols-[auto_auto_120px_90px_100px] grid-rows-[repeat(1000000,auto)]">
<!-- Header -->
<div class="col-span-full row-start-1 grid grid-cols-subgrid items-center rounded-md bg-neutral-100 *:px-3">
<span>Column 1</span>
<span>Column 2</span>
<span>Column 3 (Month 1)</span>
<span>Column 4 (Month 2)</span>
<span>Column 5 (Month 2)</span>
</div>
<!-- Data -->
<div class="col-span-full row-start-2 grid grid-cols-subgrid *:px-3">
<span>Data 1.1</span><span>Data 2.1</span><span class="col-start-3 -col-end-1 bg-blue-300/25">Data 3.1 (bar)</span>
<span>Data 1.2</span><span>Data 2.2</span><span class="col-start-3 -col-end-1 bg-gray-300/25">Data 3.2 (bar)</span>
<span>Data 1.3</span><span>Data 2.3</span><span class="col-start-3 -col-end-1 bg-amber-300/25">Data 3.3</span>
</div>
<div class="col-span-full row-span-full grid grid-cols-subgrid [&>*+*]:border-s-1 [&>*+*]:border-gray-400">
<div></div><div></div><div></div><div></div><div></div>
</div>
</div>
Changes made on the parent grid, header or data rows do no break the vertical lines.
For instance, gaps can be added to the parent grid and that will not break the lines into several pieces (since each line is the border of only 1 element), though said gaps must be added to the Header and Data subgrids, not to the parent grid.