The Tanuki Guide

E-book example for the Tanuki theme
Generated on December 28, 2025

Table of Contents

  1. Chapter 1: The Foundation
  2. Chapter 2: Modern CSS
  3. Chapter 3: JavaScript Essentials
  4. Chapter 4: Performance
  5. Chapter 5: Accessibility
  6. Print Version

Chapter 1: The Foundation

Chapter 1: The Foundation

Before we build castles in the sky, we must first understand the ground beneath our feet. The web is built on three fundamental technologies: HTML, CSS, and JavaScript. Each plays a crucial role in creating the experiences we use every day.

The Triad of Web Technologies

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.

HTML: The Structure

HTML (HyperText Markup Language) provides the semantic structure of web pages. Think of it as the skeleton of your website—the bones that give it shape and meaning.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My First Page</title>
</head>
<body>
    <header>
        <h1>Welcome</h1>
    </header>
    <main>
        <p>Hello, World!</p>
    </main>
</body>
</html>

Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident.

CSS: The Style

CSS (Cascading Style Sheets) controls the visual presentation. It's the skin, the clothes, the paint on the walls—everything that makes your site visually appealing.

body {
    font-family: system-ui, sans-serif;
    line-height: 1.6;
    color: #333;
}

h1 {
    color: #1e40af;
    font-size: 2.5rem;
}

Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam.

JavaScript: The Behavior

JavaScript brings interactivity to the web. It's the muscles and nervous system—the parts that let your site respond and react.

document.querySelector('button').addEventListener('click', () => {
    console.log('Button clicked!');
    alert('Hello, interactive web!');
});

The Document Object Model

The DOM is the bridge between your HTML and JavaScript. It represents your page as a tree of objects that can be manipulated programmatically.

ConceptDescription
NodeAny point in the DOM tree
ElementAn HTML element node
AttributeProperties of elements
TextText content within elements

Summary

In this chapter, we explored:

  • The three core technologies: HTML, CSS, and JavaScript
  • How each technology contributes to the web experience
  • The basics of the Document Object Model

Key Insight: Understanding these fundamentals deeply will make you a better developer. Don't rush past the basics—they're the foundation everything else is built upon.

In the next chapter, we'll dive deeper into modern CSS and explore the powerful layout systems available to us today.

Chapter 2: Modern CSS

Chapter 2: Modern CSS

CSS has evolved dramatically over the past decade. Gone are the days of float-based layouts and clearfix hacks. Today, we have powerful tools like Flexbox and Grid that make complex layouts straightforward.

The Flexbox Revolution

Flexbox (Flexible Box Layout) is designed for one-dimensional layouts—either rows or columns. It excels at distributing space and aligning items.

.container {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
}

.item {
    flex: 1;
}

Flex Direction and Wrapping

Lorem ipsum dolor sit amet, consectetur adipiscing elit. The flex-direction property controls the main axis:

.row { flex-direction: row; }        /* Default: left to right */
.column { flex-direction: column; }  /* Top to bottom */
.row-reverse { flex-direction: row-reverse; }
.column-reverse { flex-direction: column-reverse; }

Nulla facilisi. Sed euismod, nisl nec ultricies lacinia, nisl nisl aliquam nisl, eget aliquam nisl nisl sit amet nisl.

CSS Grid: Two-Dimensional Layouts

Grid Layout is the answer to two-dimensional layouts. It handles both rows and columns simultaneously.

.grid-container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: auto 1fr auto;
    gap: 2rem;
}

.header { grid-column: 1 / -1; }
.sidebar { grid-row: 2 / 3; }
.main { grid-column: 2 / 4; }

Grid Template Areas

For complex layouts, named grid areas provide clarity:

.layout {
    display: grid;
    grid-template-areas:
        "header header header"
        "sidebar main main"
        "footer footer footer";
    grid-template-columns: 200px 1fr 1fr;
}

.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }

Custom Properties (CSS Variables)

CSS Custom Properties bring the power of variables to stylesheets:

:root {
    --color-primary: #3b82f6;
    --color-secondary: #10b981;
    --spacing-unit: 8px;
    --border-radius: 4px;
}

.button {
    background: var(--color-primary);
    padding: calc(var(--spacing-unit) * 2);
    border-radius: var(--border-radius);
}

Dynamic Theming

Variables can be changed at runtime with JavaScript:

document.documentElement.style.setProperty('--color-primary', '#8b5cf6');

Or scoped to specific elements:

.dark-theme {
    --color-background: #1a1a2e;
    --color-text: #eaeaea;
}

Container Queries

The newest addition to responsive design—container queries let you style based on parent size, not viewport:

.card-container {
    container-type: inline-size;
    container-name: card;
}

@container card (min-width: 400px) {
    .card {
        display: flex;
        flex-direction: row;
    }
}

Summary

Modern CSS provides powerful tools for layout and styling:

  • Flexbox for one-dimensional layouts
  • Grid for two-dimensional layouts
  • Custom Properties for maintainable, themeable CSS
  • Container Queries for component-based responsive design

Pro Tip: Don't choose between Flexbox and Grid—use both! Grid for page layouts, Flexbox for component internals.

Next, we'll explore JavaScript in depth and learn how to make our pages interactive.

Chapter 3: JavaScript Essentials

Chapter 3: JavaScript Essentials

JavaScript is the programming language of the web. From simple interactions to complex single-page applications, JavaScript powers the dynamic experiences users expect.

Variables and Data Types

JavaScript has three ways to declare variables:

var legacy = "Avoid this in modern code";
let mutable = "Can be reassigned";
const immutable = "Cannot be reassigned";

Primitive Types

// String
const name = "Tanuki";

// Number (integers and floats)
const count = 42;
const price = 19.99;

// Boolean
const isActive = true;

// Null and Undefined
const empty = null;
let notAssigned; // undefined

// Symbol (unique identifiers)
const id = Symbol('id');

// BigInt (large integers)
const huge = 9007199254740991n;

Functions

Functions are first-class citizens in JavaScript:

// Function declaration
function greet(name) {
    return `Hello, ${name}!`;
}

// Function expression
const greet = function(name) {
    return `Hello, ${name}!`;
};

// Arrow function
const greet = (name) => `Hello, ${name}!`;

// Arrow function with body
const greet = (name) => {
    const greeting = `Hello, ${name}!`;
    console.log(greeting);
    return greeting;
};

Higher-Order Functions

Functions that take or return other functions:

const numbers = [1, 2, 3, 4, 5];

// map: transform each element
const doubled = numbers.map(n => n * 2);
// [2, 4, 6, 8, 10]

// filter: keep elements that pass a test
const evens = numbers.filter(n => n % 2 === 0);
// [2, 4]

// reduce: combine elements into a single value
const sum = numbers.reduce((acc, n) => acc + n, 0);
// 15

Asynchronous JavaScript

The web is inherently asynchronous. JavaScript provides several patterns for handling async operations.

Promises

function fetchUser(id) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (id > 0) {
                resolve({ id, name: 'Tanuki' });
            } else {
                reject(new Error('Invalid ID'));
            }
        }, 1000);
    });
}

fetchUser(1)
    .then(user => console.log(user.name))
    .catch(error => console.error(error));

Async/Await

A cleaner syntax for working with Promises:

async function displayUser(id) {
    try {
        const user = await fetchUser(id);
        console.log(user.name);
    } catch (error) {
        console.error('Failed to fetch user:', error);
    }
}

Modules

Modern JavaScript uses ES Modules for code organization:

// math.js
export const PI = 3.14159;

export function add(a, b) {
    return a + b;
}

export default function multiply(a, b) {
    return a * b;
}
// main.js
import multiply, { PI, add } from './math.js';

console.log(PI);           // 3.14159
console.log(add(2, 3));    // 5
console.log(multiply(4, 5)); // 20

The DOM API

Interacting with the Document Object Model:

// Selecting elements
const button = document.querySelector('.submit-btn');
const items = document.querySelectorAll('.item');

// Creating elements
const div = document.createElement('div');
div.className = 'card';
div.textContent = 'Hello!';

// Modifying elements
button.classList.add('active');
button.setAttribute('disabled', true);
button.style.backgroundColor = 'blue';

// Event handling
button.addEventListener('click', (event) => {
    event.preventDefault();
    console.log('Clicked!');
});

// Appending to DOM
document.body.appendChild(div);

Error Handling

Robust error handling is crucial:

try {
    const data = JSON.parse(invalidJson);
    processData(data);
} catch (error) {
    if (error instanceof SyntaxError) {
        console.error('Invalid JSON:', error.message);
    } else {
        throw error; // Re-throw unexpected errors
    }
} finally {
    cleanup();
}

Summary

This chapter covered JavaScript fundamentals:

  • Variables and data types
  • Functions and higher-order functions
  • Asynchronous programming with Promises and async/await
  • ES Modules for code organization
  • DOM manipulation
  • Error handling

Remember: JavaScript is a multi-paradigm language. You can write imperative, functional, or object-oriented code. Choose the style that best fits your problem.

In the next chapter, we'll explore performance optimization techniques.

Chapter 4: Performance

Chapter 4: Performance

Performance is a feature. Slow websites lose users, reduce conversions, and rank lower in search results. This chapter covers the key strategies for building fast web applications.

Understanding Performance Metrics

Modern performance measurement focuses on user-centric metrics:

MetricWhat It MeasuresTarget
LCP (Largest Contentful Paint)Loading performance< 2.5s
FID (First Input Delay)Interactivity< 100ms
CLS (Cumulative Layout Shift)Visual stability< 0.1
TTFB (Time to First Byte)Server response< 200ms
FCP (First Contentful Paint)Initial render< 1.8s

Optimizing Loading Performance

Critical Rendering Path

The browser must complete several steps before rendering:

  1. Parse HTML → Build DOM
  2. Parse CSS → Build CSSOM
  3. Combine → Render Tree
  4. Layout → Paint → Composite
<!-- Inline critical CSS -->
<style>
    /* Only what's needed for above-the-fold content */
    body { font-family: system-ui; }
    .hero { height: 100vh; }
</style>

<!-- Defer non-critical CSS -->
<link rel="preload" href="styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">

Resource Hints

Tell the browser about resources you'll need:

<!-- DNS prefetch for external origins -->
<link rel="dns-prefetch" href="//api.example.com">

<!-- Preconnect for critical third parties -->
<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin>

<!-- Preload critical resources -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>

<!-- Prefetch likely next pages -->
<link rel="prefetch" href="/about">

Image Optimization

Images are often the largest assets on a page.

Modern Formats

<picture>
    <source srcset="image.avif" type="image/avif">
    <source srcset="image.webp" type="image/webp">
    <img src="image.jpg" alt="Description" loading="lazy">
</picture>

Responsive Images

<img
    srcset="small.jpg 400w, medium.jpg 800w, large.jpg 1200w"
    sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
    src="medium.jpg"
    alt="Description"
    loading="lazy"
    decoding="async"
>

JavaScript Performance

Code Splitting

Load only what's needed:

// Dynamic imports
const module = await import('./heavy-module.js');

// Route-based splitting (framework example)
const routes = {
    '/': () => import('./pages/Home.js'),
    '/about': () => import('./pages/About.js'),
    '/dashboard': () => import('./pages/Dashboard.js'),
};

Debouncing and Throttling

Control how often functions execute:

// Debounce: wait until action stops
function debounce(fn, delay) {
    let timeout;
    return (...args) => {
        clearTimeout(timeout);
        timeout = setTimeout(() => fn(...args), delay);
    };
}

// Throttle: limit execution rate
function throttle(fn, limit) {
    let inThrottle;
    return (...args) => {
        if (!inThrottle) {
            fn(...args);
            inThrottle = true;
            setTimeout(() => inThrottle = false, limit);
        }
    };
}

// Usage
const handleScroll = throttle(() => {
    console.log('Scroll position:', window.scrollY);
}, 100);

window.addEventListener('scroll', handleScroll);

Web Workers

Offload heavy computation:

// main.js
const worker = new Worker('worker.js');

worker.postMessage({ data: largeArray });

worker.onmessage = (event) => {
    console.log('Result:', event.data);
};

// worker.js
self.onmessage = (event) => {
    const result = heavyComputation(event.data);
    self.postMessage(result);
};

Caching Strategies

Service Worker Caching

// sw.js
const CACHE_NAME = 'v1';
const ASSETS = [
    '/',
    '/styles.css',
    '/app.js',
    '/offline.html',
];

self.addEventListener('install', (event) => {
    event.waitUntil(
        caches.open(CACHE_NAME)
            .then(cache => cache.addAll(ASSETS))
    );
});

self.addEventListener('fetch', (event) => {
    event.respondWith(
        caches.match(event.request)
            .then(response => response || fetch(event.request))
    );
});

Measuring Performance

Use the Performance API:

// Measure custom timings
performance.mark('start-operation');

// ... do work ...

performance.mark('end-operation');
performance.measure('operation', 'start-operation', 'end-operation');

// Get measurements
const measures = performance.getEntriesByName('operation');
console.log(`Operation took ${measures[0].duration}ms`);

Summary

Performance optimization requires attention to:

  • Core Web Vitals (LCP, FID, CLS)
  • Critical rendering path optimization
  • Image optimization and modern formats
  • JavaScript code splitting and async loading
  • Effective caching strategies
  • Continuous measurement and monitoring

Golden Rule: Measure first, optimize second. Don't guess where performance problems are—use real data from real users.

In our final chapter, we'll cover accessibility and inclusive design.

Chapter 5: Accessibility

Chapter 5: Accessibility

Accessibility (often abbreviated as a11y) ensures that websites work for everyone, including people with disabilities. It's not just about compliance—it's about creating better experiences for all users.

Why Accessibility Matters

Consider these statistics:

  • ~15% of the world's population has some form of disability
  • Many more have temporary or situational impairments
  • Accessible sites often have better SEO and usability for everyone

Remember: Accessibility is a spectrum, not a checkbox. Every improvement helps.

Semantic HTML

The foundation of accessibility is semantic HTML:

<!-- Bad: Divs for everything -->
<div class="header">
    <div class="nav">
        <div class="nav-item">Home</div>
    </div>
</div>

<!-- Good: Semantic elements -->
<header>
    <nav aria-label="Main navigation">
        <a href="/">Home</a>
    </nav>
</header>

Key Semantic Elements

ElementPurpose
<header>Introductory content
<nav>Navigation links
<main>Primary content
<article>Self-contained content
<section>Thematic grouping
<aside>Tangentially related content
<footer>Footer content

ARIA: When HTML Isn't Enough

ARIA (Accessible Rich Internet Applications) enhances semantics:

<!-- Role: Define what an element is -->
<div role="dialog" aria-labelledby="dialog-title">
    <h2 id="dialog-title">Confirm Action</h2>
    <p>Are you sure you want to proceed?</p>
</div>

<!-- State: Communicate dynamic changes -->
<button aria-expanded="false" aria-controls="menu">
    Open Menu
</button>
<ul id="menu" hidden>...</ul>

<!-- Properties: Provide additional context -->
<input
    type="search"
    aria-label="Search products"
    aria-describedby="search-help"
>
<p id="search-help">Enter product name or SKU</p>

Common ARIA Patterns

<!-- Live regions: Announce dynamic content -->
<div aria-live="polite" aria-atomic="true">
    Item added to cart
</div>

<!-- Error messages -->
<input
    type="email"
    aria-invalid="true"
    aria-describedby="email-error"
>
<p id="email-error" role="alert">
    Please enter a valid email address
</p>

Keyboard Navigation

All functionality must be accessible via keyboard:

// Custom keyboard navigation
document.addEventListener('keydown', (event) => {
    const { key } = event;

    switch (key) {
        case 'Escape':
            closeModal();
            break;
        case 'ArrowDown':
            focusNextItem();
            event.preventDefault();
            break;
        case 'ArrowUp':
            focusPreviousItem();
            event.preventDefault();
            break;
    }
});

Focus Management

/* Never hide focus entirely */
:focus {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

/* Use :focus-visible for mouse users */
:focus:not(:focus-visible) {
    outline: none;
}

:focus-visible {
    outline: 2px solid var(--color-focus);
}
// Manage focus when content changes
function openModal() {
    modal.hidden = false;
    modal.querySelector('[autofocus]').focus();
}

function closeModal() {
    modal.hidden = true;
    triggerButton.focus(); // Return focus to trigger
}

Color and Contrast

Ensure sufficient color contrast:

ContextMinimum Ratio (WCAG AA)
Normal text4.5:1
Large text (18px+ bold, 24px+)3:1
UI components3:1
/* Good contrast */
.text {
    color: #1a1a1a;
    background: #ffffff;
    /* Contrast ratio: 16.1:1 */
}

/* Don't rely on color alone */
.error {
    color: #dc2626;
    border-left: 4px solid #dc2626;
}

.error::before {
    content: "⚠ Error: ";
    font-weight: bold;
}

Images and Media

<!-- Informative images need alt text -->
<img src="chart.png" alt="Sales increased 25% in Q4 2024">

<!-- Decorative images should be hidden -->
<img src="decorative.svg" alt="" role="presentation">

<!-- Complex images need longer descriptions -->
<figure>
    <img src="diagram.png" alt="System architecture diagram" aria-describedby="diagram-desc">
    <figcaption id="diagram-desc">
        The system consists of three main components:
        the API gateway, the processing service, and the database layer...
    </figcaption>
</figure>

<!-- Video with captions -->
<video controls>
    <source src="tutorial.mp4" type="video/mp4">
    <track kind="captions" src="captions.vtt" srclang="en" label="English">
</video>

Forms

Accessible forms are crucial:

<form>
    <div class="field">
        <label for="name">Full Name *</label>
        <input
            type="text"
            id="name"
            name="name"
            required
            aria-required="true"
            autocomplete="name"
        >
    </div>

    <fieldset>
        <legend>Notification Preferences</legend>

        <div>
            <input type="checkbox" id="email-notify" name="notify" value="email">
            <label for="email-notify">Email notifications</label>
        </div>

        <div>
            <input type="checkbox" id="sms-notify" name="notify" value="sms">
            <label for="sms-notify">SMS notifications</label>
        </div>
    </fieldset>

    <button type="submit">Subscribe</button>
</form>

Testing for Accessibility

Automated Testing

// Example with axe-core
import { axe } from 'axe-core';

async function runAccessibilityTests() {
    const results = await axe.run();
    console.log('Violations:', results.violations);
}

Manual Testing Checklist

  • Navigate the entire page using only keyboard
  • Test with a screen reader (VoiceOver, NVDA)
  • Zoom to 200% and verify layout
  • Check with Windows High Contrast mode
  • Verify all images have appropriate alt text
  • Confirm form errors are announced

Summary

Building accessible websites requires:

  • Semantic HTML as the foundation
  • ARIA for enhanced semantics where needed
  • Full keyboard navigation support
  • Sufficient color contrast
  • Alternative text for images
  • Accessible forms with proper labeling
  • Regular testing with assistive technologies

Final Thought: Accessibility benefits everyone. Curb cuts help wheelchair users, but also parents with strollers, travelers with luggage, and delivery workers with carts. Digital accessibility works the same way.


Conclusion

Congratulations on completing "The Art of Web Development"! You've learned:

  1. The foundational triad of HTML, CSS, and JavaScript
  2. Modern CSS layout techniques with Flexbox and Grid
  3. JavaScript essentials for interactive applications
  4. Performance optimization strategies
  5. Accessibility best practices for inclusive design

The web is constantly evolving, but these fundamentals remain constant. Master them, and you'll be prepared for whatever comes next.

Happy coding!

Print Version

© 2025 The Tanuki Guide