One Screen at a Time

One Screen at a Time

Build a swipe-through learning feed from scratch with plain HTML, CSS and JavaScript#

No framework. No build step. Needs no AI to run.

By Andrzej Stacherski.


Contents#

Before you begin

Part 1: Build the app

  1. Put one fact on the screen
  2. Turn one fact into a feed
  3. Stop repeating yourself
  4. Add buttons that feel good
  5. Remember you, and learn your taste (ending with Put it online)

Part 2: Final touches (extras)

  1. Extra: Dark mode, and a smooth switch
  2. Extra: Taking it further

Make it yours


Before you begin#

What you will build#

By the end of Chapter 5 you will have a real app, running at a real web address. It is a full-screen feed of short, surprising facts. You swipe or scroll up for the next one. You can like or dislike a fact, copy it, and the app learns which topics you enjoy and shows you more of them. It remembers you between visits. It never runs out.

You will write every line of it yourself, in plain HTML, CSS and JavaScript, with no framework and no build tools. The finished code is about 550 lines of JavaScript in eleven small files, plus a stylesheet.

Why this project#

Most tutorials teach a technique and then show you a snippet. You finish them knowing the name of something and unsure how to use it in a real page. This book works the other way round. You start with a task you can see (one fact on the screen), and each chapter takes on the next challenge that task throws at you. You meet JSON, fetch, loops, scroll-snap, web components, custom events, localStorage and view transitions because the app needs them right now, not because they are next in a syllabus.

Who this book is for#

  • You know the basics of HTML, CSS and JavaScript (see What you should already know, with a self-test) and have never finished a whole app without a framework.
  • You work with websites in an agency or a CMS (HubSpot, WordPress and the like) and want components that survive in a page you do not control.
  • You are a designer who codes a bit and wants to ship something real.

It is not for absolute beginners (it does not explain what a variable is), and it is not a framework comparison. There is no argument here against any tool. It is a way to understand what the platform already gives you.

What you should already know#

This book assumes you can read and write simple HTML, CSS and JavaScript. It does not assume you are good at them. Below is exactly what that means, so you can check yourself before you commit a weekend to it.

HTML: you should be comfortable with

  • The shape of a page: <!doctype html>, <head> and <body>, and what goes in each.
  • Common elements: headings, paragraphs, <article>, <main>, <button>, <link> and <script>.
  • Attributes: class, id, hidden, and custom data- attributes.

CSS: you should be comfortable with

  • Selectors: by tag, by class (.card), by id (#feed), and the descendant and child combinators (.card p, .card > p).
  • The box model: margin, padding, width and height.
  • Flexbox basics: display: flex, flex-direction, justify-content, gap.
  • Units: px, rem, % and vh.
  • Reading a media query. You do not need to write many.

JavaScript: you should be comfortable with

  • Variables with const and let, and the basic types: strings, numbers, booleans.
  • Functions, including arrow functions: (a) => a + 1.
  • Arrays and objects: reading, adding, looping over them, and the array methods filter and map.
  • Loops: for and for...of.
  • Template literals: `Hello ${name}`.
  • The DOM basics: document.querySelector, element.textContent, element.addEventListener('click', ...).
  • Opening your browser's developer tools and reading the Console.

You do not need to know any of these. The book teaches them where they appear:

fetch, JSON, async and await, promises, custom elements and web components, custom events, IntersectionObserver, localStorage, CSS custom properties, scroll-snap, view transitions, ES modules (import and export), destructuring and the spread operator, and the ideas behind accessibility.

Classes are the one thing worth having seen once. Chapter 3 uses class for custom elements and includes a five-line refresher, so you can start without them, but a little prior contact will make that chapter smoother.

A ten-minute self-test#

Read each question and its snippet, answer in your head, then check the answers below. If you can answer at least eight of the ten, you are ready. If fewer, spend a week on the gaps first (the free Learn web development course on MDN, and javascript.info, are both good for this) and come back. You will enjoy the book more.

  1. Is <link rel="stylesheet" ...> in the right place? What does it do?
<head>
  <title>Test</title>
  <link rel="stylesheet" href="style.css">
</head>
  1. Which elements does this rule select?
.card > p { margin: 0; }
  1. What does this do to the children of .card?
.card {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1rem;
}
  1. What is ids?
const facts = [{ id: 'a', t: 'space' }, { id: 'b', t: 'mind' }, { id: 'c', t: 'space' }];
const ids = facts.filter((f) => f.t === 'space').map((f) => f.id);
  1. What do first and rest hold?

(This one is a stretch. The book teaches it, so a wrong answer is fine.)

const [first, ...rest] = [10, 20, 30];
  1. When does the text change, and to what, using the ids from question 4?
const button = document.querySelector('button');
button.addEventListener('click', () => {
  button.textContent = `Clicked ${ids.length} times`;
});
  1. What does total([1, 2, 3]) return?
function total(list) {
  let sum = 0;
  for (const n of list) sum += n;
  return sum;
}
  1. What is user.langs.length afterwards?
const user = { name: 'Ada', langs: ['en', 'fr'] };
user.langs.push('de');
  1. What does this print? (The odd result is normal JavaScript. If you have seen it before, you are in good shape.)
console.log(typeof "5", "5" + 1, "5" * 2);
  1. What does this print? (Classes are the thing Chapter 3 refreshes, so this one is optional.)
class Counter {
  constructor() { this.n = 0; }
  add() { this.n++; return this; }
}
console.log(new Counter().add().add().n);

Answers

  1. Yes. It belongs in <head>, and it loads the stylesheet style.css into the page.
  2. Every <p> that is a direct child of an element with class card. A <p> nested deeper (inside a <div> inside the card) is not selected.
  3. It stacks them in a single column, centres that column vertically inside the card, and puts a 1rem space between children.
  4. ['a', 'c'].
  5. first is 10. rest is [20, 30].
  6. When the button is clicked. It becomes Clicked 2 times.
  7. 6.
  8. 3.
  9. string, then "51" (the 1 is joined on as text), then 10 (the 5 is treated as a number).
  10. 2.

What you need#

  • A text editor.
  • A modern browser (Chrome, Edge, Firefox or Safari, all recent).
  • Python 3 or Node, only to run a tiny local server. Nothing is installed into your project.
  • For the "Put it online" section: a free GitHub account and a free Netlify account.

No npm install. No build step. No account is needed for Chapters 1 to 4.

How the book works#

Each chapter is one task. It begins with what you will have by the end, shows the simplest thing that works, lets the challenge appear, and then introduces the idea that meets it. Each ends with:

  • Check it works. A short list of what you should see, and a table of common mistakes with their usual causes.
  • What just happened. A few sentences of recap.
  • Your turn. An easy exercise and a stretch exercise.

Every chapter has a checkpoint. The finished code for each chapter lives in a folder: code/ch01 to code/ch06. If your version stops working, compare it with the checkpoint, or start the next chapter from the checkpoint instead of your own. The book's listings were pasted straight from those folders, and every checkpoint was run in a browser.

Part 2 is optional. Chapters 6 and 7 are labelled Extra. Each opens with a "Skip this if..." note and tells you exactly where the code stands. Your app is complete without them. They make it nicer, and they cover what to do after it is live.

Check the documentation. Whenever the book explains a CSS, HTML or JavaScript term, it links to the matching page on MDN Web Docs. Follow those links. This book is one author's explanation, and an AI (including one that helps you write code) can be confidently wrong. The official documentation is kept up to date, lists every option, and is the place professionals actually look. Building that habit is worth more than any single technique here. At the end of the book, the Vocabulary collects every link in one place, as a record of what you have tackled and learned.

Conventions in the code#

You will see the same habits everywhere. They are chosen on purpose, and each is explained where you first meet it:

  • Plain files, no build. The browser runs exactly what you write.
  • Light DOM. Components are ordinary elements, styled by ordinary CSS. (Chapter 3 explains the choice.)
  • Prefixed names. Tags, classes and events all start with ml-, so nothing collides with other code.
  • Attributes in, events out. Simple settings go in as attributes, objects go in as properties, and news comes back as bubbling events named component:what-happened.
  • Defensive by default. Every call to storage, the network and the clipboard can fail, and the app says so instead of breaking.

A note on accessibility#

Accessibility is not an extra in this book and has no chapter of its own. It is built into every chapter, because it is far cheaper to do as you go than to retrofit. By the end you will have used real buttons, aria-label, aria-pressed, live regions, visible focus, comfortable touch targets, keyboard shortcuts and prefers-reduced-motion. You will also have measured colour contrast instead of guessing it. None of it is hard, and all of it matters to someone.

About the facts#

The 98 starter facts were chosen because they are well established, and where a figure is an estimate the explanation says "about". Facts do go stale or turn out to be wrong, though, unlike frameworks.


Turn the page, and put your first fact on the screen.