I find I typically learn about new-to-me CSS when I’m struggling through a problem. Today’s issue is an age-old problem I have with flexbox and grid approaches to layout design.

Consider a client using your average CMS to insert your standard unordered list. Maybe it looks like this:

<p>Here is a list of books we'd recommend on the topic:</p>

<ul>
    <li><em>Book One</em></li>
    <li><em>Book Two</em> (our go-to on the topic)</li>
    <li>And finally, <em>Book Three</em></li>
</ul>

Very simple HTML and CSS.

But let’s say the client wants to change the list design. In today’s example, they want to replace each bullet with a checkmark icon, and they want the checkmark to sit on a yellow circle. Ideally, these elements are accessible and scale with the type. So, you write this code:

ul.checklist {
	list-style: none;
	padding-left: 0;
	margin:0;
}

ul.checklist li {
	// Add white space
	margin: 1em 0 0;
	// Create a grid layout for your new icons
	display: grid;
	grid-template-columns: 1.5em auto;
	gap: .5em;
	max-width: 100%;
	// Not necessary, but habitual
	position: relative;
}

ul.checklist li::before, ul.checklist li::after {
	// Correctly size the icon and background
	grid-column:1;
	grid-row:1;
	height:1.5em;
	width:1.5em;
	content:'';
}

ul.checklist li::before {
	// Background yellow
	background: var(--color-yellow-100);
	border-radius: 50%;
}

ul.checklist li::after {
	// Add the icon
	// The mask changes the fill of the SVG
	background-color: var(--color-black-100);
	mask: url('/assets/icons/checkmark.svg') no-repeat center;
	mask-size: contain;
}

Before reading or scrolling any further, see if you can guess the problem that will arise from this layout. (If you guess it correctly, you are smarter than me, because I always forget this is going to happen.)

Ready? OK, here’s a screenshot of where this breaks down in real-world use on a non-profit’s website:

A broken layout in a list item on a webpage. This is basically unreadable in its current form.

Basically, as far as the browser is concerned, each element in this <li> lines up with another column in the grid. So if the text in the <li> says Visit <a href="https://acme.co">our website</a> to learn more, that’s actually three elements (two text elements, one link element), and thus we have multiple column breaks.

The fix is easy:

li {
	display:contents;
}

I somehow missed the early writing about display:contents;, but there is very little written about this CSS feature anywhere, and it’s a handy one to know.

display:contents; is meant for use within flexbox or grid systems where child HTML elements like this break the flow of content. It’s support is decent (barring some tag-specific incompatibility). Its one downfall is that it breaks screen reader support; my understanding is that formatting is not read via screen readers when display:contents; is in use. (I am not positive this is accurate, but the situation used to be worse, and overall it seems fine today.)

To account for edge cases and be as specific as possible within a variety of CMSs, my new boilerplate for this (within a grid system) looks like this:

// Do not apply display:contents to paragraph tags inside li
ul.checklist li p {
	grid-column:2;
}

/**
 * For text inside an li that is not inside a p tag,
 * I want to support specific text formatting without breaking the grid.
 * This includes italics, bold, links, and code.
 * It does not include headings or anything else that might 
 * break the intended purpose of the design.
**/
ul.checklist li > a, ul.checklist li > strong, ul.checklist li > b, ul,.checklist li > i, ul.checklist li > em, ul.checklist li > code {
	display:contents
}

And just like that, you have child elements in a grid container with inline formatting that doesn’t break the flow of their parent.

Here’s how that checkbox looks with the above code applied:

A list item on a website that uses a checkmark instead of a bullet. The text inside the list item says: "They can visit the follow-up website, where they can use our church finder to find your church, learn more about Jesus, order helpful resources, and much more"