Debugging Common HTML Problems

A symptom to cause lookup for the problems that come up repeatedly, and the two minute checks that resolve most of them.

Concept

Most HTML bugs are one of about fifteen things. This note is a lookup table: find the symptom, check the listed causes in order.

The page renders strangely from a certain point

Most likely: an unclosed tag, or a stray character.

  1. Open the Elements panel and find where the tree stops matching your source.
  2. Run the validator; it names the mismatched tag.
  3. Check for an unescaped < in text content.
  4. Check for a comment that was never closed, which swallows everything after it.
<!-- everything after this is inside the comment -->
<!-- a note that never closes
<p>This paragraph does not render.</p>

My CSS is not applying

  1. Is the stylesheet loading? Network panel: a 404 or a redirect on the file.
  2. Is rel="stylesheet" present? Without it the browser does not treat the file as CSS.
  3. Is the selector matching? Select the element; the Styles pane lists every matching rule.
  4. Is the rule overridden? Struck through means something more specific won.
  5. Is it a case mismatch? Class names are case sensitive.
  6. Is the element actually there? The parser may have moved it.
  7. Is an inline style winning? Inline beats every selector.

My form field is not reaching the server

  1. Does it have a name? This is the answer most of the time. No name, no submission.
  2. Is it disabled? Disabled controls are not submitted. Use readonly if the value is still needed.
  3. Is it inside the form? Check the Elements panel, not the source - a parser repair may have moved it out.
  4. Is the checkbox checked? An unchecked box submits nothing at all.
  5. Is the method right? Check the Network panel Payload tab for what was actually sent.
  6. Is enctype set for a file upload? Without multipart/form-data only the file name is sent.
  1. Leading slash? /about is from the site root; about is from the current folder.
  2. Case? Servers are usually case sensitive; your local machine may not be.
  3. Trailing slash? Relative links resolve differently from /blog and /blog/.
  4. Two leading slashes? //images/x.png means another host.
  5. Is there a base element? It changes every relative URL on the page, including fragments.

My image is not showing

  1. Network panel: 404 means the path is wrong. Check case and the leading slash.
  2. Check the file extension matches the actual file.
  3. Check it is not blocked by a Content Security Policy - the console will say so.
  4. Over file://, a root relative path points at the disk root, not the site root.
  5. Check the file exists in the deployed build, not only locally.

My script cannot find an element

// Uncaught TypeError: Cannot read properties of null
document.getElementById("chart").textContent = "...";
  1. Does the script run before the element is parsed? Add defer.
  2. Does the selector match? Test it in the console.
  3. Is the id spelt and cased identically?
  4. Is the element created later? Use event delegation on a stable parent.
  5. Is it inside a template? Template contents are not in the document until cloned.

My page scrolls sideways on a phone

  1. An element with a fixed width larger than the viewport.
  2. An image with no max-width: 100%.
  3. A table or a pre block with no scroll container.
  4. A long unbroken string - a URL or a token - with no wrapping.
  5. Negative margins pushing content past the edge.
// find what is wider than the viewport
$$("*").filter(el => el.scrollWidth > document.documentElement.clientWidth)

My page jumps while loading

  1. Images or iframes without width and height.
  2. Web fonts loading and reflowing the text.
  3. Content inserted above existing content after load.
  4. Ad or embed slots with no reserved space.

The Rendering panel has a layout shift regions switch that highlights exactly what moved.

My label does not focus its field

  1. for and id must match exactly, including case.
  2. The id must be unique; a duplicate binds to the first.
  3. Labels only work with form controls, not with a div.
  4. Check the computed accessible name in the Accessibility pane.

My accented characters are broken

  1. Is <meta charset="utf-8"> present and first in the head?
  2. Is the file actually saved as UTF-8? Declaring it does not convert it.
  3. Does the HTTP header declare a different encoding? The header wins.
  4. For database content, is the connection charset also utf8mb4?

It works locally and breaks on the server

  1. Case sensitivity. The most common cause by a wide margin.
  2. Root relative paths. They work over HTTP and not over file://.
  3. Missing files not committed to version control.
  4. Different base path if the site is deployed in a subfolder.
  5. Caching serving an old file. Hard reload.
  6. A stray noindex or Disallow: / carried over from staging.

It works in one browser and not another

  1. Validate. Different browsers repair broken markup differently.
  2. Check support for any recent feature you used.
  3. Check the console in the failing browser specifically.
  4. Check for a vendor prefixed CSS property used without the standard one.

A two minute pre release 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])"));

// unhelpful link text
console.log("weak links:", $$("a").filter(a =>
  /^(click here|read more|link|here)$/i.test(a.textContent.trim())));

// form fields with no name
console.log("no name:", $$("input, select, textarea").filter(el => !el.name));

// the heading outline
console.table($$("h1,h2,h3,h4,h5,h6").map(h => ({ level: h.tagName, text: h.textContent.trim() })));

// anything wider than the viewport
console.log("overflowing:", $$("*").filter(el =>
  el.scrollWidth > document.documentElement.clientWidth));

Important rules

  • Debug against the Elements panel, not the source file.
  • Check the console before anything else.
  • A 404 in the Network panel is a path problem, not a code problem.
  • A missing name is the usual cause of a missing form value.
  • Case sensitivity explains most works locally, breaks deployed problems.

Common mistakes

  • Changing code before reading the error message.
  • Assuming the reported line number is where the mistake is.
  • Testing only in one browser.
  • Not validating.
  • Debugging a cached copy of the file.

Best practices

  • Read the console first, every time.
  • Validate before assuming a browser bug.
  • Keep the six check snippets above to hand.
  • Hard reload when a change refuses to appear.
  • Reproduce in a second browser before concluding anything.
  • Change one thing at a time.

Practice

  1. Break a page five different ways from this note and fix each using only DevTools.
  2. Run the six check snippets on a page you built.
  3. Remove a name attribute, submit, and find the problem from the Payload tab alone.
  4. Deploy a page with a case mismatch in a file name and observe the difference between local and server.

Useful resources

Hand picked references for this topic
Written by Lorens Mishra

Default administrator account created by the installer.

Continue reading

All HTML notes →
HTML

The Elements Panel

The Elements panel shows the live DOM, not your file. That difference is why it is the first place to look when markup behaves in a way the source doe...

Read more
HTML

Validating HTML

The validator catches nesting errors, duplicate ids and missing attributes in seconds. A page that renders is not the same as a page that is correct.

Read more

Discussion

0 comments
Sign in to join the discussion.

No comments yet. Be the first to say something.