Exercise: Style a Playlist Without Adding Classes

Style the Road Trip Mix playlist with eight rules that reach every part through combinators, attribute selectors, pseudo-classes, pseudo-elements and :has(), without adding a single class, and let the checks confirm each one.

Apprentice · CSS · Updated

Road Trip Mix is a playlist page for a long drive to the coast: twelve songs, each with a title, an artist, a length and a Like checkbox. Two songs have explicit lyrics, one is playing now, and two are already liked. The page works, but every row looks the same. You'll make it look like a real music app, with striped rows, a highlighted song that's playing, badges, a play icon, hover and focus styles, and a pink border that appears when you like a song. There's a catch: the HTML has no classes and no ids, and you may not add any. Every style comes from the selectors in this chapter, and a check makes sure the HTML stays as it came.

That's how styling works on many real projects: the HTML comes from a content system, a template or a teammate's code, and your stylesheet has to reach it as it is.

Before you start

You need VS Code with Live Server, a current browser, and Node.js, set up as in Setup: VS Code, a Browser and Node.js. The exercise checks run the same way as in every exercise in this course: npm install once, then npm test. The exercise's README spells out each step.

Get the exercise code

In the Exercise box beside the lesson, choose Get the starter on GitHub to open its GitHub repository. Click Code, then Download ZIP, and unzip it into your css-in-depth folder. Open the folder in VS Code (File > Open Folder), and open index.html with Live Server.

The folder holds:

  • index.html: the playlist page. Ready to use, and it must stay exactly as it is.
  • styles.css: the style guide and the eight rules in a comment, ready-made rules for fonts and spacing, and a place for your rules. For you to finish.
  • page.test.js and package.json: the ten checks and what they need. You don't need to change these.

What to do

Here's one song as it is in index.html, the one that's playing now:

<li aria-current="true">
  <strong>Mile Marker 88</strong>
  <span>Coyote Radio</span>
  <span>4:05</span>
  <input type="checkbox" aria-label="Like Mile Marker 88">
</li>

The explicit songs have data-rating="explicit" on their <li> and an <abbr title="Explicit lyrics">E</abbr> badge after the length. The liked songs' checkboxes have checked.

Write eight rules under /* Your rules */ in styles.css, using the colors in the style guide at the top of the file:

  1. Stripes. Every even-numbered song (2, 4, 6 ...) gets a light gray background.
  2. Now playing. The song that's playing gets a pale yellow background. It's song 4, an even one, so this rule has to beat rule 1.
  3. Explicit badges. The E badge in the explicit songs gets a dark slate background and white text. The header's "min" is an <abbr> too, and it must stay plain.
  4. A play icon. A ▶ appears before the playing song's title.
  5. Hover. The song under the pointer turns light blue.
  6. Focus. A checkbox reached with the keyboard gets a thick blue outline, and a checkbox clicked with the mouse doesn't.
  7. Liked songs. A song whose checkbox is checked gets a pink border on its left, which comes and goes as the box is ticked and unticked.
  8. Outside links. The footer's link to another site gets a ↗ after it, and the link to the lyrics PDF doesn't.

Check your work

In VS Code's terminal (Terminal > New Terminal), from the exercise folder:

npm install
npm test

Before you write anything, two checks pass (the link line and the unchanged HTML) and eight fail. That's expected. Each failing check says Not yet: and which rule to look at. Some checks also change the page the way a person using it would: they move "now playing" to another song, tick and untick checkboxes, and add songs to the end of the list. A rule that names a song by its number passes at first and fails then, and the message says so.

The checks can't hover or press Tab, so check rules 5 and 6 in the browser too: move the pointer over the songs, and press Tab through the checkboxes.

Hints

  • Start from the song. Most rules reach the <li> first, then something inside it, with a combinator from Combinators: Descendant, Child and Sibling.
  • The HTML already says it. "Playing now", "explicit" and "goes to another site" are all written in attributes. Attribute Selectors shows how to read them, including ^=, read "starts with".
  • Two rules, one song. If song 4 stays gray, the stripe rule is winning. Score both selectors as in Specificity: Scoring a Selector, then look at their order.
  • Nothing shows? A ::before needs a content line (Pseudo-Elements: ::before, ::after and ::marker).
  • Styling a row by its checkbox is the job of :has() (Modern Selectors: :is(), :where() and :has()).

When you're done

The last lines of npm test say:

ℹ tests 10
ℹ suites 0
ℹ pass 10
ℹ fail 0

In the browser, the songs are striped, song 4 is yellow with a ▶ before its title, the two explicit songs have dark E badges, the liked songs have a pink left border, and the share link ends in ↗. Tick "Rest Stop Romance": its border appears with no JavaScript at all.

Now look back at your eight selectors. Which ones would still be right if the site added a thirteenth song, made a new song explicit, or started playing another song? Those are the ones that read the page instead of counting it.

So what

Real stylesheets are written for HTML you don't control. Reaching elements by their structure, their attributes and their state keeps your CSS working as the content changes, and it keeps the HTML clean for everyone who reads it, people and screen readers alike.

Key terms

Related