How can I avoid layout shift with CSS grid-template-columns on page load?

1.3k views Asked by At

I am using the following CSS to create a grid of tiles on my site.

.columns-grid-maxcolumns { display:grid; grid-auto-flow:row; grid-template-columns:repeat(auto-fit,minmax(20em,1fr)); align-content:start; margin:1em; gap:1em; }

The code works fine, however I am getting a "layout shift" when loading the page. If I go into developer mode and throttle bandwidth and load the page, I first see one column, then two columns, then three columns, etc. depending on how wide the screen is. Is there a way to avoid this layout shift on page load? Site is https://portfoliotoolbox.com

2

There are 2 answers

0
Seann Herdejurgen On

I figured out a solution on my own using the following media queries:

@media (min-width:730px) { .columns-grid-maxcolumns section { max-width:calc((100vw - 1em) / 2 - 1em); } }
@media (min-width:1066px) { .columns-grid-maxcolumns section { max-width:calc((100vw - 1em) / 3 - 1em); } }
@media (min-width:1402px) { .columns-grid-maxcolumns section { max-width:calc((100vw - 1em) / 4 - 1em); } }
@media (min-width:1696px) { .columns-grid-maxcolumns section { max-width:calc((100vw - 1em) / 5 - 1em); } }

In this solution, my tiles are defined in <section> tags. If CSS calc() function supported integer floor arithmetic, you can avoid media queries. The number of columns displayed = floor((100vw - 1em) / 22em). These numbers are represented as constants 2, 3, 4 and 5 in the media queries above.

UPDATE

I had to hardcode grid-template-columns based on media queries to get rid of layout shift altogether. For 5 or more columns, I simply default to the original declaration for grid-template-columns which works for an arbitrary number of columns and suffers from layout shift.

.columns-grid-maxcolumns { display:grid; grid-auto-flow:row; grid-template-columns:1fr; align-content:start; margin:1em; gap:1em; }
.columns-grid-maxcolumns section { border-radius:1ex; max-width:calc(100vw - 2em); }
@media (min-width:730px) { .columns-grid-maxcolumns { grid-template-columns:1fr 1fr; } .columns-grid-maxcolumns section { max-width:calc((100vw - 1em) / 2 - 1em); } }
@media (min-width:1066px) { .columns-grid-maxcolumns { grid-template-columns:1fr 1fr 1fr; } .columns-grid-maxcolumns section { max-width:calc((100vw - 1em) / 3 - 1em); } }
@media (min-width:1402px) { .columns-grid-maxcolumns { grid-template-columns:1fr 1fr 1fr 1fr; } .columns-grid-maxcolumns section { max-width:calc((100vw - 1em) / 4 - 1em); } }
@media (min-width:1696px) { .columns-grid-maxcolumns { grid-template-columns:repeat(auto-fit,minmax(20em,1fr)); } }
0
gns On

You can try using auto-fill instead of auto-fit. That should solve the layout shift issue in your case. Refer to this excellent guide for the difference between the two. https://css-tricks.com/auto-sizing-columns-css-grid-auto-fill-vs-auto-fit/