I saw a roadmap circulating recently that broke down the “ideal” path for learning frontend development. It started with HTML, moved to CSS basics, then responsive design, Flexbox, Grid, and finally frameworks. It looked clean. Logical.
And it made me realize exactly why so many web apps in 2026 feel like they’re held together by duct tape and prayers.
We treat HTML like the easy part. The thing you skim through in a weekend before getting to the “real work” of React hooks or whatever UI library is trending this month. But here’s the thing—I spend more time fixing bad HTML in code reviews than I do fixing complex JavaScript logic. Why? Because bad JavaScript breaks the feature. Bad HTML breaks the user.
If you’re building for the web today, you need to stop treating markup as a container for your CSS classes and start treating it as the skeleton of your entire application. Here is how I actually approach HTML after getting burned enough times to know better.
Semantics Aren’t Just for “Purists”
I used to roll my eyes at the people who would argue about <section> versus <article>. It felt like academic nitpicking. Who cares if it’s a div if it looks right?
Then I tried using a screen reader on a site I built.
It was a humbling experience. Actually, it was humiliating. I had clickable div elements everywhere. The screen reader didn’t announce them as buttons. It just said “text.” I had to tab through meaningless garbage to get to the main content. It was unusable.
Since then, my rule is simple: Use the element that does the job.
If you can click it and it goes somewhere, it’s an anchor (<a>). If you click it and it performs an action on the page, it’s a <button>. If it’s a list of things, use a <ul>. This isn’t just about accessibility (though that’s huge); it’s about free functionality. A native <button> gives you keyboard focus and “Enter” key support for free. If you use a div, you have to write JavaScript to re-implement functionality the browser gave you in 1995. That’s a waste of time.
The Document Outline is Your Map
Here is a mistake I see constantly, even from seniors. The heading structure is completely detached from reality. I’ll open a project and see an <h4> used just because the designer wanted the text to be 16px bold.
Don’t do that.
Your HTML headings (h1 through h6) create a tree structure for your content. Search engines use this. Screen readers use this to let users jump between sections. If you skip from h2 to h5 because “it looked better,” you’ve broken the map.
I separate structure from style religiously now. My HTML handles the hierarchy. CSS handles the visual size. You can make an <h1> look like a tiny footnote if you want (though, weird choice), but it needs to be an <h1> in the code.
Landmarks Save Lives
Another thing I’ve started enforcing in my team’s PRs: Landmarking.
Wrap your main content in <main>. Put your navigation in <nav>. Use <header> and <footer>. It sounds basic, but you’d be shocked how many “modern” apps are just a sea of nested divs with class names like .wrapper-main-content-inner.
Forms: The Graveyard of Good Intentions
I hate writing forms. Everyone hates writing forms. But forms are the primary way users talk to us, so we have to get them right.
The biggest sin? implicit labels. Or worse, no labels.
I once spent three hours debugging a form where clicking the text next to a radio button didn’t select the button. It turned out the developer had just slapped a <span> next to an <input> and called it a day.
Always link them explicitly:
<label for="email">Email Address</label>
<input type="email" id="email" name="email" required>
Notice the type="email"? That triggers the correct keyboard on mobile devices. If you use type="text" for everything, you’re forcing mobile users to switch keyboard layouts manually to find the “@” symbol. They will hate you for it, even if they don’t know why.
Modern HTML Features You Should Be Using
We are in 2026. Browsers are incredibly capable now. Stop pulling in massive JavaScript libraries to do things the browser can do natively.
The Dialog Element:
Remember when we needed 500 lines of JS and a z-index war to make a modal work? The <dialog> element has been solid for a couple of years now. It handles focus trapping, closing on escape, and backdrop styling natively. Use it.
Lazy Loading:
<img loading="lazy">. That’s it. That’s the optimization. You don’t need a complex Intersection Observer script for basic image loading anymore. I slap this on almost everything below the fold.
Details and Summary:
Building an accordion? Don’t write a click handler that toggles a class. Use <details> and <summary>. It works without JavaScript. It’s accessible by default. It’s magic.
The “Div Soup” vs. CSS Grid
The roadmap I mentioned earlier put “Grid” after “Flexbox.” I actually think they should be learned in tandem, but specifically for how they clean up HTML.
Before Grid, we needed wrapper divs. A container for the row, a container for the column, a container for the inner padding. It was a mess. With modern CSS Grid and Subgrid, you can flatten your HTML significantly.
I try to keep my DOM depth as shallow as possible. If I see a div that exists solely to add padding or margin, I ask myself if the parent grid could handle that spacing instead. Cleaner HTML is easier to read, easier to debug, and renders faster.
Validation and Feedback
Let’s talk about the user experience when things go wrong. Client-side validation is great, but don’t reinvent the wheel. The constraint validation API is built right into HTML.
Attributes like required, min, max, and pattern do 90% of the heavy lifting. I see developers writing complex regex functions in JS to check if a field is empty, completely ignoring the required attribute. Why write code you have to maintain when the browser has a C++ implementation that runs faster?
That said, don’t rely only on the browser’s default error bubbles—they can be ugly. But use the API (element.checkValidity()) to drive your custom UI. It keeps the logic centralized in the DOM configuration.
The Bottom Line
HTML isn’t just the thing you write before you get to the “fun” stuff. It’s the foundation. If you build a house on a swamp, it doesn’t matter how nice the curtains are.
When you start a new component, close your CSS file. Close your JS file. Write the HTML first. Make sure it makes sense as a document. Make sure the hierarchy is logical. Make sure the interactive elements are actually interactive elements.
Once that structure is solid, then you can paint it. Then you can make it dance. But get the bones right first.



