Exercise: An Animated Game Start Screen

Bring Star Hopper's start screen to life with twinkling stars, a title that slides in, buttons that lift on hover and focus and a looping loading bar, then calm it all for reduced motion, while the tests check every rule.

Journeyman · CSS · Updated

Star Hopper is a made-up space game, and its start screen is ready except for one thing: nothing moves. The stars are frozen dots, the title sits still, the buttons don't answer when you point at them, and the loading bar is a full stripe that never loads. A game's first screen sets the mood, and motion is how this one should say "the galaxy is alive, press Start". Your job is the motion, all of it in CSS, and then a calmer version of it for players who asked their device for less. Tests check each part as you go.

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. Then open the folder in VS Code.

The folder holds:

  • index.html: the start screen: twelve stars, the title, a tagline, the Start, How to play and High scores buttons, and the loading bar. Ready to use: don't change it.
  • styles.css: Part 1 is the look of the screen, ready to use. Part 2 is where your motion goes. For you to finish.
  • page.test.js and package.json: the tests that check your rules. You don't need to change these.
  • README.md: the same steps as this lesson, and the checklist of what to watch for.

Everything you need is in the folder: the page and its look are handed over, so you can spend your time on the motion.

What to do

Open index.html with Live Server first. Here's the part of the page you'll animate, as it is in the HTML you were given:

<h1 class="title">Star Hopper</h1>

<nav class="menu" aria-label="Game menu">
  <button class="menu-button start-button" type="button">Start</button>
  <button class="menu-button" type="button">How to play</button>
  <button class="menu-button" type="button">High scores</button>
</nav>

<div class="loading" role="status">
  <p class="loading-label">Loading the galaxy…</p>
  <div class="loading-bar">
    <div class="loading-fill"></div>
  </div>
</div>

The stars are twelve <span class="star"> elements in a <div class="sky"> behind everything. Part 1 already gives each star its place and its own animation-delay, so they'll twinkle at different times once they have an animation.

Write each part in Part 2 of styles.css, saving and watching the page after each one:

  1. Twinkling stars. A @keyframes rule takes a star from dim to bright (with opacity, and scale if you like). Play it on .star: about 1.5 seconds, forever, going back and forth.
  2. A title that slides in. A @keyframes rule starts the title 3rem above its place and see-through. Play it on .title once: about 0.7 seconds, ease-out, starting 0.3 seconds after the page opens. During those 0.3 seconds the title waits, hidden, at its starting point, so it never jumps.
  3. Buttons that lift. When a menu button is hovered or has keyboard focus, it moves 4px up with translate and its shadow grows. A transition on .menu-button makes the lift take about 150ms, up and back down.
  4. A loading bar. A @keyframes rule grows .loading-fill from nothing to its full width with scale (not width), from its left edge, about every 2 seconds, forever.
  5. Motion that respects the reader. After your other rules, a @media (prefers-reduced-motion: reduce) rule stops the stars and the loading bar, swaps the title's slide for a short fade (or no animation), and keeps the buttons still on hover and focus.

Every @keyframes rule animates only transform (translate, rotate, scale) and opacity.

Check your work

Open a terminal in VS Code (Terminal > New Terminal) and run npm install once, to download what the tests need. After that, run the tests whenever you like:

npm test

At first, the first test passes (the page is already there) and the other nine fail. Each part you finish turns its tests green. A failing test's message says what it found, for example .title has animation-fill-mode none, so during the 0.3s delay it sits in its normal place, then jumps up to start sliding.

The tests read your rules; they can't watch anything move. So reload the page and watch it too, and then turn on reduced motion in the developer tools' Rendering panel (from Motion That Respects the Reader: prefers-reduced-motion) and watch it again. The README's checklist says what to look for.

Hints

  • An animation that doesn't play is nearly always a name in animation that doesn't match its @keyframes name exactly, or a missing duration. Keyframe Animations lists both.
  • Two times in one line. In animation and in transition, the first time is the duration and the second is the delay.
  • A title that jumps before it slides needs a fill mode. Which one shows the first frame during the delay?
  • A lift that snaps back down has its transition on the hover rule. Transitions: Smooth Changes shows where it belongs.
  • A bar that grows from the middle is growing around its center. Transforms: Move, Turn and Grow shows how to move the point it grows from.
  • Reduced motion that changes nothing? A media query adds no specificity, so check where yours sits in the file.

When you're done

Every test is green, and npm test prints:

> exercise-css-game-start-screen@1.0.0 test
> node --test

✔ 1) index.html links styles.css, and has the start screen (1.7841ms)
✔ 2) the stars twinkle: a @keyframes animation on .star that plays forever (5.4028ms)
✔ 3) the title slides in once, after 0.3 seconds, with no jump (0.7118ms)
✔ 4) the loading bar fills again and again, with scale, not width (0.5371ms)
✔ 5) every @keyframes rule animates only transform and opacity (0.1688ms)
✔ 6) every menu button lifts on hover and on keyboard focus (3.2172ms)
✔ 7) the lift is a transition on .menu-button, so it runs up and back down (1.7919ms)
✔ 8) styles.css has a prefers-reduced-motion media query (0.1118ms)
✔ 9) with reduced motion, the stars and the loading bar stop looping (1.0445ms)
✔ 10) with reduced motion, the title and the buttons don't move (2.1469ms)
ℹ tests 10
ℹ suites 0
ℹ pass 10
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 707.946

Your times will differ. Now look at your screen with reduced motion on. Is there still something that tells a player the galaxy is loading? If the bar is still, what could the label or a gentle fade do instead?

So what

A spinner that says "wait", a button that says "you're on me", a title that says "welcome": you've written the motion games and apps use everywhere, kept it smooth with transform and opacity, and made sure it never makes a player feel sick.

What Module 6 unlocks

You can now design a page from a blank file: lay it out, make it fit any screen, give it a look, a theme and motion. Module 6 is about CSS on a real team. You'll learn to name and organize styles so other people can work with them (and so you can, six months later), how to decide whether a framework such as Bootstrap or Tailwind is worth it for a project, and how to find and fix a broken layout fast with the developer tools. It's the module that turns "I can write CSS" into "I can work on anyone's CSS".

Key terms

Related