Using Pseudo-elements with CSS Grid

Originally published on Codepen

This week I’ve had a couple of scenarios where I’ve needed to build a hero section with a full-width image, a large heading and a translucent sidebar overlaying the image – where the sidebar bleeds to the edge of the viewport but (crucially) the content of the sidebar aligns to what I like to call the “wrapper” grid columns – i.e. the columns of the grid where we actually want to place our content. (I have a whole other post almost written on this!)

This seems to be a fairly common occurrence with the designs that are coming my way these days, and it seems like a prime case for using pseudo-elements (::before or ::after) as child items of the grid.

The markup for my grid looks like this:

<div class="grid">
	<div class="grid__fig">
	</div>
	<div class="grid__heading">
		<h1>CSS Layout News</h1>
	</div>
	<div class="grid__btn">
		<a href="#0">Subscribe</a>
	</div>
	<aside class="grid__sidebar">
		<ul class="sidebar__list">
			<li class="sidebar__item">...</li>
			<li class="sidebar__item">...</li>
			<li class="sidebar__item">...</li>
		</ul>
	</aside>
</div>

The div with a class of .grid is, unsurprisingly, our parent grid container, which we need to give the property attribute display: grid.

.grid {
	@media (min-width: 800px) {
		display: grid;
		grid-template-columns: [start] minmax(20px, 1fr) [wrapper-start] repeat(8, var(--col)) [sidebar-start] repeat(4, var(--col)) [wrapper-end] minmax(20px, 1fr) [end];
		grid-template-rows: minmax(3em, 1fr) auto minmax(auto, 1fr);
		grid-gap: var(--gutter);
		min-height: 100vh;
	}
}

Here I’m using CSS Variables to make the code more flexible and maintainable – if you need a primer I wrote a bit about them here. I’m also naming my grid lines to make it easy to place my items.

We have three direct children of the grid container: The background image (.grid__fig), the heading and the sidebar, which can all be placed on the grid. The grid line wrapper-end is where I want the content of the sidebar to end, but the sidebar background needs to end at the the very edge of the viewport – the end grid line. Rather than placing the sidebar like this:

.grid__sidebar {
	grid-column: sidebar-start / end;
}

I can place it where I want the content to go:

.grid__sidebar {
	grid-column: span 3 / wrapper-end;
}

(Rather than adding another named grid line, which might make the grid-template-columns property start to get a bit long-winded and confusing – particularly if we have even more items we want to place – I’m just using span 3 to indicate I want it to always span 3 columns, and wrapper-end as the line where I want it to end. It’s really useful to be able to switch the syntax around this way.)

Now I just need to create a pseudo-element for the sidebar background and place it on the grid. In order to act as a grid child item it needs to be a pseudo-element of the grid container, not of a grid child:

.grid::after {
	content: '';
	display: block;
	grid-column: sidebar-start / end;
	grid-row: 1 / 4;
	background-color: rgba(#f405ed, 0.5);
}

The sidebar background is now in front of the sidebar content, so we just need to tweak the z-index a little:

.grid__sidebar {
	grid-column: span 3 / wrapper-end;
	...
	z-index: 1;
}

Here’s the end result (a homage to the magnificent CSS Layout News!):

See the Pen CSS Grid – CSS Layout News example by Michelle Barker (@michellebarker) on CodePen.

###Resources

As always, there are super smart people who have written about this stuff in-depth: