Revisiting: Styling A Movie Cast List Using A Definition List And Flexbox
The other day, while basking in the awesome power of Flexbox, I took a stab at trying to style a movie cast list using a Definition List and CSS Flexbox. My approach used a pseudo-element and nested flexbox containers, which worked well. But, in response to my post, Ilya Streltsyn and Sime Vidas both came up with interesting ways simplify the CSS. And, since I've never used either of the techniques that they provided, I wanted to quickly revisit the post and share with you the solutions that they shared with me.
Run this demo in my JavaScript Demos project on GitHub.
View this code in my JavaScript Demos project on GitHub.
To quickly recap, my solution used a Definition List in which the DT
element implemented a nested Flexbox container. My "dots" where then defined as a pseudo-element inside of the nest container, with a flex-grow
of 1
that would consume all of the free space:
This worked perfectly well; but, required nested CSS Flexbox containers, which added a certain level of complexity. Both of the following solutions remove this Flexbox nesting.
order
Ilya Streltsyn: Use The CSS Property Ilya Streltsyn suggested moving the "dots" pseudo-element out of the DT
and into the parent DIV
container. This would make the pseudo-element the 3rd child of the Flexbox container which, by default, would render the "dots" at the end. But, by using the CSS property order
, we can tell the browser to render the "dots" in between the DT
and DD
elements:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>
Revisiting: Styling A Movie Cast List Using A Definition List And Flexbox
</title>
<style type="text/css">
a {
color: red ;
}
dl.cast-list {
font-family: monospace ;
font-size: 20px ;
width: 500px ;
}
dl.cast-list div {
/*
Setup the DT (character), DD (cast), and pseudo-element items as a
flexible layout.
*/
display: flex ;
margin: 5px 0px 5px 0px ;
}
dl.cast-list dt {
/*
Setup the DT (character) element to shrink, allowing for the dots to fill
up the free space.
*/
flex: 0 1 auto ;
margin: 0px 0px 0px 0px ;
order: 1 ;
}
dl.cast-list div:after {
border-bottom: 2px dotted #787878 ;
content: "" ;
/*
Define the pseudo-element as a SIBLING to both the DT and DD elements.
Configure it to grow, taking up all the free space with dots.
--
NOTE: We are using "order: 2" to place the ":after" element IN BEWTEEN
the DT and DD elements, VISUALLY, even through it is PHYSICALLY the last
child in the flex container.
*/
flex: 1 1 auto ;
margin: 0px 12px 5px 12px ;
order: 2 ;
}
dl.cast-list dd {
/*
Setup the DD (cast) element to shrink, allowing for the dots to fill up
the free space.
*/
flex: 0 1 auto ;
margin: 0px 0px 0px 0px ;
order: 3 ;
}
</style>
</head>
<body>
<h1>
Revisiting: Styling A Movie Cast List Using A Definition List And Flexbox
</h1>
<h2>
Using "order" — Thanks To Ilya Streltsyn
</h2>
<h3>
<a href="https://www.imdb.com/title/tt0168987/">
Better Than Chocolate
</a>
</h3>
<dl class="cast-list">
<div>
<dt>Lila</dt>
<dd>Wendy Crewson</dd>
</div>
<div>
<dt>Maggie</dt>
<dd>Karyn Dwyer</dd>
</div>
<div>
<dt>Kim</dt>
<dd>Christina Cox</dd>
</div>
<div>
<dt>Frances</dt>
<dd>Ann-Marie MacDonald</dd>
</div>
<div>
<dt>Carla</dt>
<dd>Marya Delver</dd>
</div>
</dl>
</body>
</html>
As you can see, we get the following three elements / pseudo-elements:
DT
withorder: 1
DD
withorder: 3
:after
withorder: 2
And while the :after
pseudo-element is the 3rd and last child, its order
gets the browser to render it visually as the 2nd child:
As you can see, this works quite nicely. The other two sibling elements need to have an explicit order
set. But, that's pretty trivial. Overall, I really like this approach.
display: contents
Sime Vidas: Use The CSS Property Sime Vidas' suggested leaving the pseudo-element where it is, but adding display: contents
to the DT
element in order to "unwrap" the term and the pseudo-element. display: contents
essentially removes the container from the DOM, allowing the container contents to act as if they were siblings to their descendant elements.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>
Revisiting: Styling A Movie Cast List Using A Definition List And Flexbox
</title>
<style type="text/css">
a {
color: red ;
}
dl.cast-list {
font-family: monospace ;
font-size: 20px ;
width: 500px ;
}
dl.cast-list div {
/*
Setup the DT (character), DD (cast), and pseudo-element items as a
flexible layout.
*/
display: flex ;
margin: 5px 0px 5px 0px ;
}
dl.cast-list dt {
/*
In order to avoid creating nested flexbox containers, we are going to use
the "display: contents" to "remove" the DT element from visual rendering.
This will promote the DT text and :after elements to be "siblings" of the
DD element, allowing a single flexbox container to affect all 3 items.
*/
display: contents ;
}
dl.cast-list dt:after {
border-bottom: 2px dotted #787878 ;
content: "" ;
/*
Setup the :after element to grow, filling up the free space with dots.
--
NOTE: Since we are using "display: contents" on the parent container,
this pseudo-element is logically rendered as a SIBLING of both the DT
TEXT (implicit element) and the DD element.
*/
flex: 1 1 auto ;
margin: 0px 12px 5px 12px ;
}
dl.cast-list dd {
/*
Setup the DD (cast) element to shrink, allowing for the dots to fill up
the free space.
*/
flex: 0 1 auto ;
margin: 0px 0px 0px 0px ;
}
</style>
</head>
<body>
<h1>
Revisiting: Styling A Movie Cast List Using A Definition List And Flexbox
</h1>
<h2>
Using "display: contents" — Thanks To Sime Vidas
</h2>
<h3>
<a href="https://www.imdb.com/title/tt0168987/">
Better Than Chocolate
</a>
</h3>
<dl class="cast-list">
<div>
<dt>Lila</dt>
<dd>Wendy Crewson</dd>
</div>
<div>
<dt>Maggie</dt>
<dd>Karyn Dwyer</dd>
</div>
<div>
<dt>Kim</dt>
<dd>Christina Cox</dd>
</div>
<div>
<dt>Frances</dt>
<dd>Ann-Marie MacDonald</dd>
</div>
<div>
<dt>Carla</dt>
<dd>Marya Delver</dd>
</div>
</dl>
</body>
</html>
As you can see, in this case, we're using display: contents
to "remove" the DT
container from the DOM. This promotes the DT
contents up one level in the DOM Tree, leaving us logically with:
- (promoted element) Text (cast)
- (promoted element)
:after
(dots) DD
As you can see, when I try to select the DT
element in the Chrome Dev Tools, no corresponding selection is made on the rendered page. This is because the DT
has been logically removed, allowing the contents of the DT
to move "up a layer" in the DOM Tree.
This is a pretty clever solution. But, I should caveat that display: contents
doesn't have perfect browser support. According to caniuse.com, neither IE nor Edge support it currently. And, some of the browser that do support it have some bugs when it comes to these accessibility of these elements.
A huge Thanks to Ilya Streltsyn and Sime Vidas who looked at my code-kata and suggested thoughtful ways to simplify my solution! That's what's so great about being part of the wonderful Web Development community. Y'all are good people!
Want to use code from this post? Check out the license.
Reader Comments
Does removing the definition term from the DOM introduce accessibility issues?
@Chris,
According to
caniuse.com
, there is some accessibility bugs; but, I have heard that those may have been fixed in recent versions. I am not entirely sure. That said, that's why I prefer the use oforder
in Flexbox.