frontend.fyi

The ONLY Proper Way to Make Article Layouts With CSS

You can make great layouts with both CSS Grid as well as Flexbox. However, when making article layouts with elements extending beyond the width of the main content, I've been using CSS Grid a lot lately.

🧑‍💻 🎥
... Almost ready!

During my career I’ve made quite some article layouts. Layouts where the text is centered, and different types of components are stacked on top of each other, forming a nice article.

It wasn’t an exception when the designer came up with a component that was halfway in the article, that extended beyond the width of the main content. It looked a bit like this.

All content is centered, except a single element

You notice that all elements are centered on the page. But of course the designer thought it looked nice if that big image extends the full width of the page!

Centering the page’s content is often done by adding a wrapper around the content, and center the wrapper by using margin: 0 auto;. However, if you then want to have content break out of thet wrapper, you have a challenge.

How I used to solve that challenge

There are two ways to have the content grow outside its parent container. The first option is to work with multiple wrappers, and have the large image not wrapped inside the container. This is not a perfect solution, because this doesn’t work well if you generate all these different components based on content added in a CMS for example.

So most of the time I went for the second option.

1
.wrapper {
2
max-width: 800px;
3
margin: 0 auto;
4
}
5
6
.large-image {
7
width: 100vw;
8
left: 50%;
9
transform: translateX(-50%);
10
}

This solution makes the image as wide as the screen, and by combining left and translateX, we pull it to the far left side of the screen, outside of the wrapper.

It can be a bit finicky to get to work though. Plus using 100vw could result in unwanted scrollbars. So despite the fact that this solution works, it still brought its challenges.

The CSS Grid solution

Luckily CSS Grid has evolved a lot lately. And what better use of CSS Grid, than building a grid, right? So let’s take a look at how we can create a similar result, but with CSS Grid and without the downsides.

Replacing the wrapper with a grid container

We’ll be using the following HTML to create the grid. This is a snippet from the live playground above, which is a far more extensive example.

1
<main>
2
<div class="container space-y-3">
3
<h1 class="text-2xl">From Webmasters to Web Wonders</h1>
4
<p>In the misty days of yore, when the internet was still a fresh-faced newcomer to the world, there existed a mythical creature known as the "Webmaster." Legend tells that this Webmaster was a lone ranger, doing everything from crafting pixel-perfect designs to managing server hiccups. The Webmaster was often seen sporting an oversized 'I ♥ HTML' t-shirt, using a dial-up connection, and juggling flaming CDs of early Photoshop versions. Oh, and let's not forget the critical task of selecting the right animated GIFs for their website. Sparkling unicorns? Why not!</p>
5
<img src="https://sandpack-frontendfyi.vercel.app/img/css-grid-article/webdev1.webp" />
6
<p>Back then, websites were simpler – a sprinkle of HTML here, a dash of CSS there, and voilà! Instant online masterpiece. And when something needed to be uploaded? Ah, enter the humble FTP – File Transfer Protocol. A Webmaster's trusty steed. Forget Vercel, Netlify, or any CI/CD pipelines. A few drags, a few drops, and your website was live for all 12 users on the internet to see.</p>
7
</div>
8
</main>

The space-y-3 tailwind class is only added to add some vertical spacing between the elements. This basic example would simply have the content extend to the edges of the page.

From Webmasters to Web Wonders

In the misty days of yore, when the internet was still a fresh-faced newcomer to the world, there existed a mythical creature known as the "Webmaster." Legend tells that this Webmaster was a lone ranger, doing everything from crafting pixel-perfect designs to managing server hiccups. The Webmaster was often seen sporting an oversized 'I ♥ HTML' t-shirt, using a dial-up connection, and juggling flaming CDs of early Photoshop versions. Oh, and let's not forget the critical task of selecting the right animated GIFs for their website. Sparkling unicorns? Why not!

Back then, websites were simpler – a sprinkle of HTML here, a dash of CSS there, and voilà! Instant online masterpiece. And when something needed to be uploaded? Ah, enter the humble FTP – File Transfer Protocol. A Webmaster's trusty steed. Forget Vercel, Netlify, or any CI/CD pipelines. A few drags, a few drops, and your website was live for all 12 users on the internet to see.

The first step is to make our container display grid, as well as define a grid layout.

1
.container {
2
display: grid;
3
grid-template-columns: 1fr [content-start] 720px [content-end] 1fr;
4
}

By doing this, we are defining a grid layout with 3 columns. In the center is a column that’s always 720 pixels wide, and then two equal parts on either side.

We also gave the center column a name called content. The -start and -end suffixes are CSS Grid standards, via which you can define grid colums based on their edges rather than their center.

For the center column this might not seem very logical, but as soon as we add a second named column that wraps the content column, it probably does:

1
.container {
2
display: grid;
3
grid-template-columns: [full-start] 1fr [content-start] 720px [content-end] 1fr [full-end]
4
}

By now defining the start and end of the full column too, we have two name slots that we can use to place our content in. We place the content by using the colum names full or content.

The first step is making a default, to center all content like we did in the previous example as well. We can approach it like this.

1
.container {
2
display: grid;
3
grid-template-columns: [full-start] 1fr [content-start] 720px [content-end] 1fr [full-end];
4
}
5
6
.container > * {
7
grid-column: content;
8
}

With this CSS we target every direct child of the container, and place it in the content column. That column is defined by the -start- and -end marks.

If we would render that, it would look like this (the example below uses 50% for the content instead of 720px, because the content column of this blog already is quite narrow).

From Webmasters to Web Wonders

In the misty days of yore, when the internet was still a fresh-faced newcomer to the world, there existed a mythical creature known as the "Webmaster." Legend tells that this Webmaster was a lone ranger, doing everything from crafting pixel-perfect designs to managing server hiccups. The Webmaster was often seen sporting an oversized 'I ♥ HTML' t-shirt, using a dial-up connection, and juggling flaming CDs of early Photoshop versions. Oh, and let's not forget the critical task of selecting the right animated GIFs for their website. Sparkling unicorns? Why not!

Back then, websites were simpler – a sprinkle of HTML here, a dash of CSS there, and voilà! Instant online masterpiece. And when something needed to be uploaded? Ah, enter the humble FTP – File Transfer Protocol. A Webmaster's trusty steed. Forget Vercel, Netlify, or any CI/CD pipelines. A few drags, a few drops, and your website was live for all 12 users on the internet to see.

By placing all children of the container inside the content column, we suddenly replicated the centered content! But we won’t stop there. We added a full column as well! How would we add that?

1
.container {
2
display: grid;
3
grid-template-columns: [full-start] 1fr [content-start] 720px [content-end] 1fr [full-end];
4
}
5
6
.container > * {
7
grid-column: content;
8
}
9
10
.container > .full-bleed {
11
grid-column: full;
12
}

We define a helper class called for example full-bleed, to which we assign the full grid colum. If we would add that class to the image, we suddenly have an image that extends the full width!

From Webmasters to Web Wonders

In the misty days of yore, when the internet was still a fresh-faced newcomer to the world, there existed a mythical creature known as the "Webmaster." Legend tells that this Webmaster was a lone ranger, doing everything from crafting pixel-perfect designs to managing server hiccups. The Webmaster was often seen sporting an oversized 'I ♥ HTML' t-shirt, using a dial-up connection, and juggling flaming CDs of early Photoshop versions. Oh, and let's not forget the critical task of selecting the right animated GIFs for their website. Sparkling unicorns? Why not!

Back then, websites were simpler – a sprinkle of HTML here, a dash of CSS there, and voilà! Instant online masterpiece. And when something needed to be uploaded? Ah, enter the humble FTP – File Transfer Protocol. A Webmaster's trusty steed. Forget Vercel, Netlify, or any CI/CD pipelines. A few drags, a few drops, and your website was live for all 12 users on the internet to see.

That’s literally all there is to position elements outside of the container. That’s so much simpler compared to the non-css grid solution.

Adding more columns

It also doesn’t end here, you could add as many extra columns as you like. You could for example add a wide column too.

1
.container {
2
display: grid;
3
grid-template-columns: [full-start] 1fr [wide-start] 140px [content-start] 720px [content-end] 140px [wide-end] 1fr [full-end];
4
}

This then adds a third named column that adds 140 pixels on both sides of the main content.

How would we make this responsive?

The final step is also getting this to work on mobile. It’s easier than you might think!

1
@media screen and (max-width: 1000px) {
2
.container {
3
display: grid;
4
grid-template-columns: 18px 1fr 18px;
5
grid-template-areas:
6
". content ."
7
"full full full"
8
". wide .";
9
}
10
}

Here you see we define grid-template-columns and grid-template-areas separately. By doing this, we can put the named columns unerneath each other, rather than next to each other.

First we’ve added 18 pixels of gap on either side, and the rest of the space is then used for the content. We do this for all rows, except the full content row, which expands into the 18 pixels too.

What about the dots?

The dots are names as well. They are named slots we’re not interested in (we don’t want to use them), and a convention in CSS is then to use a ”.” to indicate those slots are unused. You could also name them empty for example.

Summary

By defining these named columns in CSS Grid, we are able to render elements outside of the main grid, without using negative offsets. This makes it a lot easier to create article layouts, and it’s also a lot more flexible.

1
.container {
2
display: grid;
3
grid-template-columns: [full-start] 1fr [wide-start] 140px [content-start] 720px [content-end] 140px [wide-end] 1fr [full-end];
4
}
5
6
.container > * {
7
grid-column: content;
8
}
9
10
.container > .wide-bleed {
11
grid-column: wide;
12
}
13
14
.container > .full-bleed {
15
grid-column: full;
16
}
17
18
@media screen and (max-width: 1000px) {
19
.container {
20
display: grid;
21
grid-template-columns: 18px 1fr 18px;
22
grid-template-areas:
23
". content ."
24
"full full full"
25
". wide .";
26
}
27
}

Want to know more?

Make sure to watch to video, where I go even more into detail about making article layouts with CSS Grid.