A bonafide CSS trick if there ever was one! @ShadowShahriar created a CodePen demo that uses pseudo-elements to place commas between list items that are displayed inline, and the result is a natural-looking complete sentence with proper punctuation.
How it works
The trick? First, it’s to make an unordered list an inline element with no markers or spacing:
ul {
padding: 0;
margin: 0;
display: inline;
list-style-type: none;
}
Next, we display list items inline so they flow naturally as text in a sentence:
li {
display: inline;
}
Then we add commas between list items by selecting their ::after
pseudo-element, and setting it’s content
property with a comma (,
) value.
li::after{
content: var(--separator);
}
Oh, but wait! What about the ol’ Oxford comma? Use :nth-last-of-type()
to select the second-to-last list item, and set its ::after
pseudo-element’s content
property to ", and"
before the last list item.
li:nth-last-of-type(2)::after{
content: ", and ";
}
We’re not done. @ShadowShahriar considers an edge case where there are only two items. All we need is to display an “and” between those two items, so:
li:first-of-type:nth-last-of-type(2)::after {
content: " and ";
}
I had to look that up on Selectors Explained to make sure I was reading it correctly. That’s saying:
The
after
pseudo-element… of a
<li>
element provided it is the first of its type in its parent and the nth of its type from the end (formula) in its parent.
What a mouthful! The final touch is a period at the end of the list:
li:last-of-type::after {
content: ".";
}
Using custom properties
We just looked at an abridged version of the actual code. @ShadowShahriar does a nice thing by setting a comma and the “and” as custom properties:
ul {
--separator: ",";
--connector: "and";
padding: 0;
margin: 0;
display: inline;
list-style-type: none;
}
That way, when we can swap those out for other ways to separate list items later. Nice touch.
This caught my eye not only for its clever use of pseudo-element trickery, but also for its simplicity. It’s using tried and true CSS principles in a way that supports semantic HTML — no extra classes, elements, or even JavaScript to help manipulate things. It almost makes me wonder if HTML could use some sort of inline list element (<il>
anyone???) to help support sentences convey list items without breaking out of a paragraph.
Not the same at all, but reminds me of this extremely fancy trick as well that handles seprator usage when line breaks get involved:
https://chriskirknielsen.com/blog/inline-lists-with-conditional-separators/
Really neat! Sadly, an unfortunate side effect of this approach is that the commas and the ‘and’ won’t be included when you highlight the text.
The three items example for example becomes
when you copy and paste it.
Still, this could be useful in contexts where you don’t need to select the text.
When copying the text the last and penultimate element will be joined together.
Time flies. I discussed this in 2003 and used it whenever IE was of no concern. For breadcrumb navigations this has been the preferred method ever since.
The final result is great. I wonder if screenreaders would have an easier time parsing this rather than plain text. Is there an advantage to this beyond it looking good?
Accessibility technology ignores pseudo elements, so they would read the list as a regular list element without the changes. It would be purely visual for sighted users.
In fact, it could potentially – I can’t say with certainty – lead to confusion of users with low vision, as they may be able to make out a single sentence, but which their AT interprets as a list of items.
While I can appreciate this being a neat way to do this I can’t figure out why you would want to do this.
The reasoning doesn’t make any sense to me:
“There were times when you probably wanted to show your list items in a paragraph or in a statement.”
Why not list the items in a paragraph or statement? Why bother with extra markup and styling when it’s not needed?
This trick is neat. What lead you to add extra markup here for this? Semantically speaking it might make sense, but have you tested how different screen readers announce these lists with pseudo-selectors?