# HTML, CSS and JavaScript

Reactionary web pages are deliberately unlike what is currently popular. Single files, no build step, no frameworks, no packages.

## HTML

- Style with attributes, not classes: `<div content>`, `<div header>`, `<code block>`, `<p list=keywords>`, styled with attribute selectors like `div[header]` and `code[block]`. An attribute value can refine it: `<div special="martian">`.
- Use `div` and `span`, not the newer semantic tags such as `<header>`, `<nav>` and `<section>`.
- An attribute selector also matches unrelated elements with that attribute: `[content]` matches `<meta name="viewport" content="...">`. Write `body [content]`, since `<meta>` is in `<head>`, and select `div[content]` in tests.
- Put `title` on clickable icons, not `alt`.
- Give every `<img>` a size in HTML or CSS. An image takes no space until it loads, so the layout grows afterwards, and code that scrolled at load is left in the wrong place.
- Use the `hidden` attribute rather than a `display: none` rule. A hidden file input still opens the file chooser when clicked from JavaScript.
- `dialog.showModal()` focuses the first focusable element; if that's a link, Enter follows it. Put `autofocus` on the safe button.
- Pages declare `<!doctype html>` and `<html lang="en">`.

## CSS

- Load the site's stylesheet with `@import` inside `<style>`, as `Shared.head()` does.
- Write padding and margin out in full: `padding-top`, `padding-left`. Use a shorthand only when its meaning is obvious, as in `padding: 8px 3%`, where `3%` can only be the sides.
- A custom property like `--pct_width: 94%` is a named constant to change in one place, used as `max-width: min(var(--pct_width),400px)`.
- Use grid only when a simpler layout won't do.
- Don't write rules that set a property to its default, like `margin-right: 0` on a div nothing else gives a margin.

## JavaScript

JavaScript is a bad language that the browser forces on us. At its core it is much like Luan, but it pretends to be object-oriented. Program it like Luan: functions and closures, none of its object-oriented features. Douglas Crockford's *JavaScript: The Good Parts* is a good guide.

- Every file and every nontrivial inline `<script>` starts with `'use strict';`, because strictness doesn't carry from one script to another.
- Use `let`, template literals and `function` declarations. No arrow functions.
- Write `if( x )`, with the spaces inside the parentheses. A multi-line template literal ends with `` `; `` on its own line, indented to match.
- Indent with tabs.
- Callbacks are explicit. Use `XMLHttpRequest` with an `onload` function; never `fetch`, promises, or `async`/`await`. An `async` function returns at its first `await`, other code can run at each `await`, and a thrown error becomes a rejected promise that `window.onerror` never sees.
- Use current DOM idioms: `el.remove()`, not `el.outerHTML = ''`; `event.key === 'Enter'`, not `event.keyCode === 13`; pointer events, not separate mouse and touch events.
- Prefer checks that need no stored state: `event.isPrimary` rather than a stored `pointerId`.
- `eval` is fine where the input is the site's own, as for AJAX responses.
- To escape text for HTML in JavaScript, replace `&` first, then `<`, `>` and `"`. For a value inside a CSS selector, use `CSS.escape`.
- Report errors to the server: `window.onerror` and failed requests post to `/error_log.js` (see [dynamic-sites.md](dynamic-sites.md)).

## Cookies

JavaScript should be able to read cookies, so don't make cookies `HttpOnly` in general. A cookie that holds a password is the exception: JavaScript never needs it, so it is `HttpOnly`, and logout is done on the server.
