
Web & Commerce Engineering
Build and ship a real web storefront and commerce engine end to end.
⚠ Digital content — withdrawal right waived on access
By purchasing this online course, you expressly consent that access is provided immediately upon order confirmation, and you acknowledge that — by giving this consent — your statutory right of withdrawal ceases as soon as access begins (§ 356 (5) BGB in conjunction with § 312g (2) no. 13 BGB). No refunds after access is granted.
⚠ Digitaler Inhalt — Widerrufsrecht erlischt bei Freischaltung
Mit dem Kauf dieses Online-Kurses stimmen Sie ausdrücklich zu, dass der Zugang unmittelbar nach Bestellbestätigung bereitgestellt wird, und bestätigen Ihre Kenntnis davon, dass Sie durch diese Zustimmung mit Beginn der Ausführung Ihr Widerrufsrecht verlieren (§ 356 Abs. 5 BGB i. V. m. § 312g Abs. 2 Nr. 13 BGB). Eine Rückerstattung nach erfolgter Freischaltung ist ausgeschlossen.
- Lifetime access to the full course
- Build-along Workbook — Claude Code right in your browser
- Progress tracking, topic by topic
- Certificate of completion when you finish
- Taught on real Kaern software & founder playbooks
After you get access, your course lives in My Courses — log in any time with your email.
Already bought it? Log in to read it.
Kaern Schools — Professional Track Instructor: Vera Stack: Static HTML/CSS/JS · Shopify storefronts · Cloudflare Workers + KV · Structured data / AEO · Analytics & lead capture
How this course works
Welcome. I'm Vera, and I'll be your tutor for the next seven modules. I've built and shipped the exact stack you'll learn here — the static marketing sites, the Shopify storefront behind shop.cyclewash.com, the Cloudflare Workers that glue it together, and the structured-data layer that gets these pages quoted by search engines and AI assistants. So everything in this course is real practice, not theory I read in a book.
Here's my promise and my ask. My promise: every concept is taught the way it actually shows up in a working build, with the trade-offs named honestly. My ask: do the hands-on exercises. You cannot learn web engineering by watching me — you learn it by typing, breaking things, and fixing them. Keep a browser open with DevTools the whole time.
Each module gives you learning objectives, lessons (with the script of what I actually say in class, a worked example from a real cycleWASH or Kaern Schools build, and a hands-on exercise), common mistakes, and checks for understanding. We finish with a capstone and a rubric. Let's build.
Module 1 — HTML, CSS & JavaScript Fundamentals and Semantics
Learning objectives
- Write semantic, valid HTML5 that communicates document structure to browsers, assistive tech, and crawlers.
- Use the CSS cascade, specificity, and the box model deliberately rather than by trial and error.
- Manipulate the DOM and handle events with modern, framework-free JavaScript.
- Explain how the browser turns bytes into pixels (parse → DOM/CSSOM → render tree → layout → paint).
- Choose the right element for the job, defaulting to native semantics over
divsoup.
Lesson 1.1 — Semantics: HTML is meaning, not decoration
Teaching script (Vera): "Let me start with the single most expensive habit I see in junior developers: treating HTML as a bag of divs to hang styles on. Think of an HTML document like the floor plan of a building. A <header>, a <nav>, a <main>, a <footer> — these are the labelled rooms. A screen reader is a visitor who's blind and navigates by reading the labels on the doors. A search crawler is a building inspector reading the same labels to file a report. If every room is labelled 'div', both visitors are lost.
When I built the cyclewash.com landing page, I had a choice for the product cards: wrap each in a <div class='card'>, or use an <article> with an <h3> and a <figure>. I chose <article> because each card is a self-contained unit of meaning — and that decision is why those cards became eligible for rich results later. Semantics is not pedantry; it's the foundation that performance, accessibility, and SEO all stand on. You get all three for free if you name your rooms correctly from the start.
So here's my question to you: look at a page you've built recently — how many <div>s could become a <section>, <nav>, <article>, or <button> instead?"
Worked example — cycleWASH product card:
<article class="product-card">
<figure>
<img src="/img/mini-platinum.webp" alt="Mini Platinum compact bicycle washing system" width="400" height="300" loading="lazy">
<figcaption>Mini Platinum — compact system</figcaption>
</figure>
<h3>Mini Platinum</h3>
<p>Space-saving automatic bicycle wash for workshops and showrooms.</p>
<a class="btn" href="/en/products/mini-platinum">View details</a>
</article>
Notice: real width/height attributes (they reserve layout space — we'll see why in Module 3), descriptive alt, a true heading, and an <a> for navigation rather than a click-handled div.
Hands-on exercise: Take a plain <div>-based version of a "Care Products" listing (three items, each with image, title, price, button) and rewrite it using only semantic elements. Run it through the W3C validator (validator.w3.org) and the browser's Accessibility tree (DevTools → Elements → Accessibility pane). Fix every warning.
Common mistakes:
- Using
<div onclick=...>instead of<button>or<a>— breaks keyboard and screen-reader access. - Multiple
<h1>s or skipped heading levels (<h1>straight to<h4>) that scramble the document outline. - Empty
alt=""on meaningful images, or missingaltentirely on decorative ones (decorative images should havealt="").
Check for understanding:
- Why does
<button>beat<div role="button" onclick>even when they look identical? - What is the difference between
<section>and<article>? - When should an image have
alt=""?
Lesson 1.2 — The cascade, specificity, and the box model
Teaching script (Vera): "CSS frustrates people because it feels like the rules apply randomly. They don't — they apply by a precise scoring system, and once you can score a selector in your head, the mystery evaporates. Specificity is a three-part number: IDs, then classes/attributes/pseudo-classes, then element/pseudo-element selectors. #header .nav a scores 1-1-1. A plain a scores 0-0-1. Higher number wins; ties go to whichever came last. Inline styles and !important are the nuclear options — and like nuclear options, using them is usually an admission that your architecture failed.
On the cyclewash sites I keep specificity flat on purpose: almost everything is a single class. That way I never fight myself later. The day you reach for !important to override your own earlier !important, you've entered specificity hell, and the only way out is to refactor.
The box model is the other half. Every element is a content box wrapped in padding, then border, then margin. The classic beginner bug — 'I set width 300px but it's 340px wide' — is because padding and border add on top unless you set box-sizing: border-box. I set that globally on line one of every stylesheet I write.
Question for you: if .btn and #cta .btn both set a colour, which wins, and why?"
Worked example — the global reset I open every cycleWASH stylesheet with:
*, *::before, *::after { box-sizing: border-box; }
:root {
--brand-blue: #1E83C7;
--brand-yellow: #FFC124;
--brand-green: #99C21D;
}
.btn {
background: var(--brand-yellow);
color: #111;
padding: 0.75rem 1.5rem;
border: 0;
border-radius: 6px;
}
Custom properties (--brand-blue) are the single source of truth for the cycleWASH palette — change the variable, the whole site updates.
Hands-on exercise: Given three conflicting rules targeting the same element, predict the final colour before loading it in the browser, then verify in DevTools → Computed (it shows you which rule won and crosses out the losers). Then refactor the rules so the intended one wins without !important.
Common mistakes:
- Forgetting
box-sizing: border-box, then padding-induced overflow. - Escalating specificity wars (
!importanton top of!important). - Hard-coding colour hexes throughout instead of using custom properties — guarantees an inconsistent palette.
Check for understanding:
- Score the specificity of
nav#main ul li.active a. - What does
box-sizing: border-boxchange about howwidthis interpreted? - Why are CSS custom properties better than repeating
#1E83C7in twenty places?
Lesson 1.3 — JavaScript, the DOM, and events
Teaching script (Vera): "JavaScript's job on a marketing site is small but critical: enhance, don't replace. The page must work as HTML first; JS makes it nicer. We call this progressive enhancement, and it's why the cycleWASH mobile menu still degrades gracefully.
The mental model you need is the DOM: the browser parses your HTML into a tree of objects, and JavaScript reads and writes that tree. document.querySelector finds a node; classList.toggle flips a class; addEventListener says 'when this happens, run that.' Three verbs and you can build most interactions.
The one concept that trips everyone is event delegation. Instead of attaching a click handler to fifty buttons, you attach one handler to their shared parent and check event.target. Events bubble up the tree, so the parent hears them all. It's like a teacher taking one register for the whole class instead of asking each child individually — far less work, and it still works for students who arrive late, i.e. elements added to the DOM after page load.
Here's my question: if I add a new button to the page after my JavaScript ran, why would a directly-attached handler miss it but a delegated one catch it?"
Worked example — the cycleWASH mobile nav toggle (vanilla, no framework):
<button class="nav-toggle" aria-expanded="false" aria-controls="site-nav">Menu</button>
<nav id="site-nav" hidden>...</nav>
<script>
const toggle = document.querySelector('.nav-toggle');
const nav = document.querySelector('#site-nav');
toggle.addEventListener('click', () => {
const open = toggle.getAttribute('aria-expanded') === 'true';
toggle.setAttribute('aria-expanded', String(!open));
nav.hidden = open;
});
</script>
Note the aria-expanded / aria-controls — the menu is accessible and functional. This exact bug (menu not toggling on mobile) was a real fix logged in the cycleWASH deploy notes.
Hands-on exercise: Build an accordion FAQ for the cycleWASH "Maintenance" section using event delegation: one listener on the <dl> container handles all <dt> clicks, toggling the matching <dd>. Add aria-expanded to each <dt> button.
Common mistakes:
- Attaching N handlers in a loop instead of delegating.
- Forgetting that
querySelectorreturns the first match (usequerySelectorAll+ iterate for many). - Building interactions that don't work without JS (a menu that's
display:nonein CSS and only revealed by JS strands no-JS users).
Check for understanding:
- What does event bubbling let you do?
- Difference between
textContentandinnerHTML, and why does the difference matter for security? - Why prefer
classList.toggle('open')over directly settingelement.style.display?
🔒 That’s the end of your free lesson
Unlock the full Web & Commerce Engineering — every remaining module, your build-along Workbook, progress tracking, and a certificate when you finish.
Already bought it? Log in to read the rest.