The word that was not there
Eight places on elchi.dev rendered nothing where a word belonged, and without JavaScript both forms put personal data in the URL. The build refuses both now.
Eight places on elchi.dev rendered nothing where a word belonged. The line under our name in the footer of every page was one of them. The contact page had no label for its list of topics. Nobody noticed, because an empty element does not look broken. It looks like nothing.
The build now refuses to produce a page that asks for a text that does not exist. And the two forms on the site that send anything work without JavaScript, which they did not.
How a word goes missing
The texts on elchi.dev live in a catalogue, one per language, edited in our dashboard. A page asks for a text by its key, such as contact.topic_label, and the build puts the words in. When a key did not exist, the template quietly rendered an empty string. No error, no warning.
We did have a check. It compared the German catalogue with the English one and failed the build when a key existed in one and not the other. That catches a translation somebody forgot. It cannot catch a key missing from both, and that is what had happened: six keys the pages used had never been written in either language. Two more were typos for keys that did exist.
An empty paragraph is harmless to look at. An empty legend is not harmless to somebody using a screen reader: it is the name of a group of choices, and without it the topics on the contact form were a group of choices without a name.
What the build does now
The pages read the catalogue through a strict lookup. Asking for a key that does not exist stops the build, names the key and says where to add it. On its first run it found one more: the 404 page asked for a link text that had never existed and covered for it with a fallback written into the template.
The deploy script checks the result as well. It already refused a page with an empty heading. Now it also refuses a build that contains an empty paragraph, label, legend, list item, description list entry, link, button or emphasis, and an empty span unless it says it is decoration. The strict lookup catches a missing key; this catches anything else that renders nothing.
The forms, without JavaScript
The contact form and the configurator are sent by a script, which answers next to each field and never leaves the page. That part worked. What happened without the script was the problem.
Neither form said how it should be sent, and a form that says nothing is sent as GET. So a browser without JavaScript put the name, the email address and the whole message into the address bar. From there it goes into the browser's history, into server logs and into anything else that records addresses. It is rare for JavaScript to be off, but when it is, this is exactly the data that should not end up there.
Both forms now say method="post" and go to the same endpoint the script uses. Without a script, the browser checks the required fields itself, and the server answers with a page: a thank-you, or a page that says what the form needs and offers the way back, together with our email address and phone number.
One thing does not carry over. With a script, the form records when it appeared on screen, and an enquiry sent less than two seconds later is treated as a bot. Without a script there is no such timestamp, so that check does not apply. The hidden field that only bots fill in still does, and so does the rule that a message with more than four links is spam.
The point
A static site is fast because it is plain files. Plain files also do exactly what they say, including nothing, without complaint. The checks are there to make "nothing" loud.
Sources
- HTML Standard: form submission attributes, WHATWG, read
- Understanding Success Criterion 1.3.1: Info and Relationships, W3C, read