A Pre Launch Checklist
Everything worth verifying before a page goes live, grouped so it can be worked through in about twenty minutes.
-
HTML Basics
- What is HTML: The Structure Layer of Every Web Page
- HTML Document Structure: DOCTYPE, html, head and body
- Elements, Tags and Attributes: The Vocabulary of HTML
- HTML Comments: Notes That Ship With Your Code
- Block Level and Inline Elements
- Writing and Running Your First HTML Page
- How a Browser Turns Markup Into a Page
- Text and Formatting
- Links and Navigation
- Images and Media
- Lists
- Tables
-
Forms
- Form Structure: form, action and method
- Input Types: Text, Email, Number, Date and the Rest
- Labels: The Most Important Element in a Form
- Checkboxes, Radio Buttons and Grouping
- select, option, optgroup and datalist
- textarea, File Uploads and Hidden Fields
- Buttons: submit, reset and button
- Built In Form Validation
- GET or POST: What Happens When a Form Is Submitted
- Semantic HTML
- HTML5 Features
- Head and Metadata
- HTML with CSS
- HTML with JavaScript
- Accessibility
-
HTML SEO
- How Google Works: Crawling, Indexing and Ranking
- SEO Friendly HTML Structure
- Titles and Descriptions That Earn Clicks
- Headings and Content Structure for Search
- Internal Linking and Anchor Text
- robots.txt and XML Sitemaps
- Canonical URLs and Duplicate Content
- Structured Data and JSON-LD
- Image SEO
- Core Web Vitals and Mobile Friendliness
- DevTools and Debugging
- Editor Productivity
- HTML Best Practices
- HTML Projects
- Advanced Projects
- Practice and Exams
Concept
The same handful of things go wrong at launch, every time. Working through a list catches almost all of them, and twenty minutes here saves a great deal afterwards.
Document basics
<!DOCTYPE html>is the first line, with nothing before it.<html lang="...">is set correctly.<meta charset="utf-8">is the first thing in the head.<meta name="viewport" content="width=device-width, initial-scale=1">is present.- The
<title>is unique and descriptive on every page. - The markup validates with zero errors.
Structure
- Exactly one
<h1>, describing the page rather than the site. - No skipped heading levels.
header,nav,mainandfooterlandmarks present.- One
mainper page. - Every
navlabelled when there is more than one. - Reading the headings alone describes the page.
Content
- Every
imghas analt; decorative images havealt="". - Every image and iframe has
widthandheight. - No click here or read more link text.
- Every
iframehas atitle. - Video has captions; audio has a transcript.
- Placeholder text and lorem ipsum are gone.
- Contact details and dates are correct.
Forms
- Every control has a visible, bound
label. - Every control has a
name. - Radio and checkbox groups are in a
fieldsetwith alegend. - Sensible
typeandautocompleteon every field. methodis stated explicitly and is POST for anything that changes data.- File uploads have
enctype="multipart/form-data". - Every submit button has an explicit
type. - A CSRF token is present on state changing forms.
- Errors are shown in text, not colour alone.
- Server side validation exists for every client side rule.
Links
- No broken internal links. Run a link checker.
- External links opening in a new tab carry
rel="noopener noreferrer"and say so. - Internal links point at canonical URLs, not redirects.
- The 404 page has navigation and a search box.
- No
href="#"used as a button.
Accessibility
- The page is fully usable with the keyboard alone.
- The focus indicator is visible everywhere.
- A skip link is the first focusable element and works.
- Body text meets 4.5 to 1 contrast; large text meets 3 to 1.
- No information conveyed by colour alone.
prefers-reduced-motionis honoured.- Anything moving for over five seconds can be paused.
- Icon only controls have accessible names.
- An automated accessibility scan reports no violations.
SEO
- Unique
titleandmeta descriptionon every page. - A self referencing absolute
canonicalon every page. - No stray
noindexfrom staging. robots.txtdoes not containDisallow: /.robots.txtdoes not block CSS or JavaScript.- An XML sitemap exists, is accurate and is referenced from
robots.txt. - Open Graph title, description, image and URL are set, with an absolute image URL.
- Structured data validates in the Rich Results Test.
- Search Console is verified and the sitemap submitted.
The two items in bold have removed entire sites from search. Check them in production, after deployment, not in the repository.
Performance
- Images compressed and sized appropriately.
loading="lazy"below the fold, never on the hero.fetchpriority="high"on the largest above the fold image.- Every script has
deferorasync. - Fonts use
font-display: swap. - Compression enabled on the server.
- Versioned asset names with long cache lifetimes.
- Lighthouse run, and field data checked after a week.
Mobile
- No horizontal scrolling at 320 pixels.
- Tap targets around 44 pixels with space between them.
- Form fields at 16 pixels or larger.
- Body text at 16 pixels or larger.
- The page works at 200 percent zoom.
- The same content is served as on desktop.
- Tested on a real device, not only in emulation.
Security
- HTTPS everywhere, with HTTP redirecting to it.
- No mixed content warnings in the console.
- No sensitive values in hidden fields or data attributes.
- No internal information in comments.
- External scripts carry
integrityandcrossorigin. - A Content Security Policy is in place.
frame-ancestorsset on sensitive pages.- Error pages do not reveal paths or stack traces.
Deployment
- One host form chosen; the other redirects.
- One trailing slash convention; the other redirects.
- All file names lower case, matching every link exactly.
- Old URLs redirected with 301, not to the home page.
- Console is clean of errors in production.
- Tested in at least two browsers.
- Analytics installed and receiving data.
A two minute console check
// duplicate ids
const ids = $$("[id]").map(el => el.id);
console.log("duplicate ids:", ids.filter((id, i) => ids.indexOf(id) !== i));
// images with no alt
console.log("no alt:", $$("img:not([alt])"));
// images with no dimensions
console.log("no dimensions:", $$("img:not([width]), img:not([height])"));
// weak link text
console.log("weak links:", $$("a").filter(a =>
/^(click here|read more|link|here|more)$/i.test(a.textContent.trim())));
// external links missing rel
console.log("missing rel:", $$("a[target='_blank']:not([rel*='noopener'])"));
// form fields with no name
console.log("no name:", $$("input, select, textarea").filter(el => !el.name));
// iframes with no title
console.log("untitled iframes:", $$("iframe:not([title])"));
// the heading outline
console.table($$("h1,h2,h3,h4,h5,h6").map(h => ({ level: h.tagName, text: h.textContent.trim() })));Important rules
- Check the SEO items in production, not in the repository.
- An automated scan does not replace the keyboard pass.
- Test on a real device before launch.
- Verify the deployed page, not the local one.
- Field performance data takes about a month to appear; check back.
Common mistakes
- Shipping a staging
noindexorDisallow: /. - Case mismatched file names that work locally and fail deployed.
- Placeholder text left in production.
- No analytics or Search Console until months later.
- Testing only the home page.
- Assuming a Lighthouse score means the page is accessible.
Best practices
- Keep this list in the repository and in the pull request template.
- Automate what can be automated: validation, links, accessibility, formatting.
- Do the keyboard pass on every feature, not only at launch.
- Verify the two bold SEO items in production immediately after deploying.
- Re run the list after any large change, not only at first launch.
Practice
- Work through the whole list on a page you have built and record what it found.
- Run the console check on three pages and fix everything it reports.
- Deploy a page and verify
robots.txtand the robots meta tag in production. - Automate three items from the list in a build script.