For most of my career, I did not respect HTML and CSS.
I would never have admitted it out loud. But somewhere underneath the job titles – backend engineer, then software architect, then cloud architect – I had quietly filed them under not real programming. HTML was markup. CSS was decoration. They were what you handed to “the frontend person” once the important work was finished. And the important work, in my mind, always happened on the server: the domain model, the transaction boundaries, the message queues, the JVM I was tuning at three in the morning, the payment flows that had to be correct to the last cent or someone’s salary did not land.
I spent more than a decade in Java and the languages around it. I wrote Servlets when Servlets were how you did it. I lived through JSP and JSF and their lifecycle ceremonies. I watched ColdFusion, classic ASP, PHP, and Rails each take a turn as the right answer. I built payment and FinTech systems in Munich – the kind of systems meant to outlive the people who write them. And in all of that time, I treated the browser as a dumb terminal sitting at the far end of a long, serious pipeline.
Then a junior engineer asked me a question so simple it embarrassed me.
We were staring at a response in the network tab – a React app, server-rendered, hydrated, the full modern circus. She pointed at the payload and said: “So in the end, all of this just becomes that?”
That. A document of angle brackets. HTML.
And it landed on me that I had spent eighteen years building elaborate machines whose entire purpose was to produce a few kilobytes of a markup language I had never once taken seriously.
Every framework I had ever used was, in the end, a very expensive way to generate HTML.
The premise
The browser only speaks three languages
Nobody tells you this while you are busy being impressed by your own backend.
The browser – the most widely deployed piece of software in human history, sitting on billions of phones, laptops, and televisions – fundamentally understands only three languages. HTML, which says what things are. CSS, which says how they look. JavaScript, which says what they do. That is the entire native vocabulary of the open web. Everything else is translation.
The implication runs deeper than it sounds. Servlets generate HTML. JSP generates HTML. JSF, for all its component machinery, generates HTML. ASP.NET, PHP, Django, Rails, Spring – every server-side framework that has ever mattered is, at its core, a sophisticated string-builder whose output is HTML and CSS. And on the client the story is identical. jQuery manipulated HTML. Angular compiled to it. React’s JSX becomes DOM nodes, which are HTML. Vue, Svelte, Solid – they differ only in how they get there. They all arrive at the same destination. Your TypeScript becomes JavaScript. Your Tailwind becomes CSS. Your beautifully architected component tree becomes, at the moment of truth, a document the browser can paint.
This is why I have come to think of HTML and CSS as something close to an operating system – not for a machine, but for content and layout on the web. An operating system is the layer everyone builds on top of and almost nobody thinks about. It is unglamorous precisely because it is load-bearing. The frameworks are the applications: they come, they go. HTML and CSS are the kernel. They stay.
So this is a tribute. To three languages I underestimated for far too long – and to the two of them I was rude enough not to call programming at all. To understand why they have earned it, you have to know where they came from. Because none of this was inevitable.
Structure
Says what each thing is: a heading, a list, a link. The skeleton every page is hung upon.
Presentation
Says how it all looks and where it sits. Declarative, responsive, and quietly brilliant.
Behaviour
Says what happens when you touch it. The pulse that turned documents into software.
I · The Document
HTML, the markup that refused to die
In March 1989, a British physicist at CERN named Tim Berners-Lee wrote a proposal for managing information across the lab’s tangle of incompatible computers. His manager, Mike Sendall, scrawled a now-famous verdict across the top of it: “Vague, but exciting.” That note is, in a very real sense, where your entire profession begins.
Over the following year Berners-Lee built the whole thing himself on a NeXT machine – the browser, the server, the addressing scheme, and a small markup language to tie documents together. On 20 December 1990 the first web page went live inside CERN. It described the project itself. Then, on 6 August 1991, he posted a message to a Usenet newsgroup called alt.hypertext inviting the world to try it. There was no launch event. There was a newsgroup post. The web announced itself the way a quiet person enters a room.
The early language was almost laughably small – a couple of dozen tags, just enough to mark a heading, a paragraph, a list, a link. But it carried one radical idea in its bones: the link. A document could point at any other document, anywhere, and the reader could simply follow it. That is the whole web, compressed into a single element.
The decision not to charge for it, not to patent it, is the reason you are reading this on an open web rather than inside some company’s walled product. The web stopped being a physicists’ tool and started becoming a place.
Then it grew up, awkwardly. HTML 2.0 arrived in 1995 with forms and tables. HTML 3.2 followed in 1997, then HTML 4.01 in 1999 – and there it stopped. For fifteen years there was no new numbered version of HTML. The standards world had convinced itself that the future was XML: strict, rigid, machine-perfect. HTML was to be reformulated as XHTML, where a single unclosed tag could break an entire page.
The web rebelled. In June 2004, a small group from the browser makers – Apple, Mozilla, Opera – proposed at a standards workshop that HTML be evolved rather than replaced. They were voted down, eight to eleven. Two days later they walked off and formed their own group, the WHATWG, with a charter that said, in effect, that HTML was not dead, and that the way forward was to keep it backward-compatible and let it grow. They were right. By 2007 the official body conceded and adopted their work as the basis for HTML5, whose first public draft appeared in January 2008 and which became an official recommendation on 28 October 2014. In 2019 the two sides signed a truce, and the browser makers’ “living standard” became the one true HTML – a specification that is never finished, only continuously improved.
HTML’s superpower is that it forgives you. Forget to close a tag, and it renders anyway.
That forgiveness is not sloppiness. It is a design philosophy, and it is the reason HTML is the most durable format in software. HTML5’s authors did something quietly brilliant: they wrote down exactly how a browser should handle broken, malformed, “tag soup” markup, so that every browser would handle it the same way. The result is a language that almost never refuses to run. A page written in 1991 still opens today. Try saying that about your favourite framework from even five years ago.
II · The Surface
CSS, the most underrated engineering on the web
My favourite detail in the whole story sits right at its beginning. Berners-Lee’s very first browser already had style sheets. He simply never published the syntax. He believed how to display a page was each browser’s business, not the author’s. So for the first few years, the web had no agreed way to say what anything should look like. Pages were styled, if at all, by abusing HTML itself: tables nested inside tables inside tables, transparent spacer images, the dreaded <font> tag. We were bending the structure of a document to fake its appearance, and it was a mess.
In October 1994, a Norwegian named Håkon Wium Lie – also at CERN – proposed a remedy he called Cascading HTML Style Sheets. A Dutch researcher, Bert Bos, who was building his own styling ideas into a browser, joined him. Together they made one decision that would define the next thirty years: they dropped “HTML” from the name, because the language ought to be able to style any document, not just web pages. CSS became its own thing. The first official version landed in December 1996.
And this is the part of CSS history people forget: it barely worked for years. Internet Explorer 3 shipped partial support in 1996 but mangled the box model. Netscape’s attempt was half-hearted. A whole generation of developers learned to distrust CSS during its unreliable childhood, and some of that distrust never fully went away. It is part of why CSS is still spoken about as the soft, easy corner of the stack.
That reputation is wrong, and it has always been wrong. CSS is one of the purest examples of declarative, constraint-based programming we have. You do not tell the browser how to lay out the page step by step. You describe the constraints – this column is flexible, this image must not exceed its container, this layout collapses to a single column below a certain width – and the browser’s layout engine solves the entire system for you, across every screen size you will never personally test. That is not decoration. That is engineering of a fairly advanced kind, and most languages we proudly call “real” cannot do it at all.
The proof arrived in 2003, when a designer named Dave Shea built the CSS Zen Garden: one fixed HTML file, restyled into wildly different designs using nothing but different CSS. It demonstrated, beyond argument, that content and presentation could finally be separated – the dream Berners-Lee had nearly a decade earlier.
Then, in May 2010, Ethan Marcotte published an article titled Responsive Web Design, and the ground shifted under everyone. He argued that a site should not be a fixed-width object but a fluid one that adapts to whatever screen it lands on, built from fluid grids, flexible images, and media queries that respond to the viewport. It was as much a philosophy as a technique, and it arrived precisely as the world went mobile. Everything we now take for granted – that a website simply works on your phone – descends from that one piece of writing.
What followed is a quiet golden age that is still going. Flexbox made one-dimensional layout sane. CSS Grid, which shipped across browsers in 2017, gave us real two-dimensional layout for the first time and retired decades of float hacks overnight. And the language has kept maturing: custom properties, so CSS finally has variables; clamp() for fluid typography; container queries, so a component can respond to its own space rather than the whole screen; and the :has() selector – a true parent selector developers had begged for since the 1990s, real and shipping since 2023. CSS today can do things that would have looked like science fiction to the person fighting Internet Explorer 5. We just still do not call it programming.
III · The Behaviour
JavaScript, the ten-day language that ate the world
The third member of the trio has the most improbable origin story in modern computing.
In May 1995, Netscape needed a scripting language for its browser, and needed it fast. They handed the job to a thirty-four-year-old engineer named Brendan Eich, who had, in fact, been hired to put a different, more academic language into the browser. Instead, under brutal deadline pressure, he built something new in ten days. Ten. He borrowed the curly-brace syntax from Java because Java was fashionable, the functions-as-values idea from Scheme, and the prototype-based object model from a language called Self. He stitched them into a working prototype and shipped it.
It was called Mocha, then LiveScript, and finally – in a marketing deal with Sun, the company behind Java – JavaScript. The name was a kind of lie: JavaScript and Java are about as related as a car and a carpet. But the name stuck, and so did the confusion that has tortured beginners ever since.
A language built in ten days, mocked for a decade, now runs on nearly every screen on Earth.
Its early life was hard. Microsoft built its own version, JScript, for Internet Explorer in 1996, and the “browser wars” produced years of incompatibility, where code that ran in one browser broke in another. To stop the bleeding, the language was handed to a standards body, and in June 1997 the first edition of ECMAScript – JavaScript’s official specification – was published. Professional programmers still treated it as a toy. For a long while, they were not entirely wrong.
The turn came in stages. Around 2005, a technique that let a page fetch data without reloading was finally given a name, AJAX, and suddenly web pages could behave like applications. In 2006, a library called jQuery papered over the browser differences that had tormented everyone, and made JavaScript pleasant to write for the first time. Then, in 2009, a project called Node.js did something nobody expected: it took the browser’s JavaScript engine and let JavaScript run on the server. The toy language had escaped its cage. You could now build an entire system, top to bottom, in one language.
And then, in June 2015, came the rebirth. ECMAScript 2015 – universally called ES6 – modernised the language wholesale: real classes, proper modules, arrow functions, promises for handling asynchronous work. Since then it has improved every single year, on a steady schedule, the way a serious language should. Engines like Google’s V8 made it genuinely fast through just-in-time compilation. The language Eich half-apologised for is now the most widely used in the world.
There is one honest footnote worth making. The browser today understands a fourth thing, WebAssembly, a compact binary format that lets code from other languages run at near-native speed. But even WebAssembly is not an escape from the trio: it mounts into the same DOM, draws to the same page, and reaches the user through the same HTML. The destination has not changed.
The pattern
Why the substrate always wins
Step back and look at the shape of it. In thirty years, the way we build for the web has been reinvented over and over. Servlets gave way to JSP, which gave way to JSF. jQuery gave way to Angular, which gave way to React, which is already being questioned by whatever comes next. The frameworks rise and fall like tides. I have learned three or four of them well enough to argue about them, and I have watched each one’s certainties quietly expire.
And underneath every one of those tides, the same three languages have sat completely still. HTML. CSS. JavaScript. They have been the destination for every framework, the target that every clever abstraction compiles down to. You can change everything about how you build a web page and change nothing about what a web page is.
This is the most useful lesson I know as an architect, and I had to be embarrassed into learning it.
The substrate outlives the framework
Frameworks are rentals: convenient, current, temporary. HTML, CSS, and JavaScript are the land you build on. Bet your deepest learning accordingly.
Declarative is not lesser
HTML and CSS describe what should be true and let the browser work out how. That is engineering at its most mature, not its most junior.
Backward compatibility is a promise
A page from 1991 still renders. The web chose never to break its past, and that choice is precisely why it endured while cleaner, stricter ideas died.
The boring layer is load-bearing
The least glamorous part of any stack is usually the part everything else depends on. Respect it before it humbles you. It humbled me.
When you are choosing what to bet a system on, learn to separate the framework from the substrate. The framework is a rental. The substrate is the land. Skills in a specific framework depreciate the moment it falls out of fashion. Understanding of the substrate – how the DOM actually works, how the cascade resolves a conflict, how the event loop behaves under load – never expires, because everything else is built on top of it and must, sooner or later, answer to it.
I think often now about that junior engineer’s question. “So in the end, all of this just becomes that?” I had heard it as naïve. It was the wisest thing said in the room that day.
The two languages I refused to call programming turned out to be the foundation the entire web is poured onto. The language built in ten days as a favour to a browser turned out to run the planet. None of them are the unsung part of the stack because they are simple. They are unsung because they are everywhere, and we stop seeing the things that are everywhere.
So here is my small correction, eighteen years late. The next time you type <!DOCTYPE html> at the top of a file, do it with a little respect. You are writing in the one language the web has tried, repeatedly, to replace, and has never once managed to live without.
Learn the framework to ship this year. Learn the substrate to still be standing in ten.