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.

Ilya Streltsyn: Use The CSS Property order

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 with order: 1

with DD with order: 3

with :after with order: 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.

Sime Vidas: Use The CSS Property display: contents

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)

(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!

Tweet This Great article by @BenNadel - Revisiting: Styling A Movie Cast List Using A Definition List And Flexbox Woot woot — you rock the party that rocks the body!







