What ever happened to progressive enhancement?
The web is a remarkable platform because the core building blocks of the web are resilient. You’ll learn this with your first line of HTML, if you get it wrong the browser takes its best guess. Misspell a CSS property, the browser will ignore it like nothing happened. Forget to declare a variable in JS, it won’t bring the whole webpage crashing to a halt. We take this for granted, but not many languages are like this. If you’re a programmer using a compiled language, you’re expected to be precise and the compiler will let you know if and when you’ve done something wrong. Why is this important? We’re breaking the resilience of the web unwittingly.
The web is resilient by default. As web developers, we can sometimes forget this. I work a lot with React in my job, and in almost all of my frontend side projects I rely on React. It makes working with components a breeze and gives the flexibility I want from a framework. The one issue is that React devours all, and it becomes a crutch to lean on. You may not realise until it’s too late!
I used to write CSS in separate files. I find myself writing CSS in React.
We used to write HTML, I now write JSX.
This abstraction has benefits, but it often comes at the expense of resilience. What we lose is the ability to embrace the web as a platform and employ progressive enhancement.
If a new feature comes out that you want to make use of, you can. Not everyone will see it, but that’s okay. The beauty of the web is that you can use new CSS features and older browsers won’t break, they’ll just ignore it. You can use custom HTML elements, and older browsers that don’t know what to do will simply render the body of the tag. This simple feature of the web is flexible and gives you the power to experiment.
I use React all the time. It’s become part of my toolset, a tool I reach for too often. When it comes to delivering powerful and rich interactive experiences, React handles it. Looking at progressively enhancement depending on the user’s browser, that’s a little more challenging. I’m not against React, it isn’t really the problem, the real problem is the reliance on a single tool to do the job. When I started using frameworks like React, it was to add complex interactivity to existing pages. It was to add little islands of interactivity that involved drag and drop interactions, dynamic fetching of data and complex user flows. These were just that, islands in an otherwise static (or server rendered) page. As time has progressed, it began to take the place of HTML pages to the point where SPAs were all the rage. We gained the ability to add rich functionality everywhere, but it came at a cost.
Issues arise when developers, maybe for easier styling, or they just don’t know, decide to use div and span for everything. This especially affects people who rely on accessibility affordances to browse and interact with the web. By not using elements like buttons, links, etc. properly, you’re removing those built-in features everyone relies on.
I’ve seen divs with
onClickhandlers that open a URL. The browser doesn’t handle this case very well. A user clicking on the element will be navigated to a new page, but what about trying to open in a new tab? Nope. How about copying the link? Not supported either.
Oversights like this breaks core features of the web. So, what can we do about it?
Start with the core. The foundation of the web is where it all started, HTML. Ensure your markup is semantic and uses the elements that make sense in the context. If an element is clickable, use a button. If it navigates to a new page, use a link. It’s tempting to want to avoid styling the elements that browser styles for you and instead opt for divs and spans, as they have minimal browser styles. Don’t do it. Everything can be styled the way you want with CSS with very few exceptions.
Use semantic HTML wherever you can. This will provide the experience users expect of the web. If a user is on an older browser or an underpowered device, they’ll still be able to see the content. If a user relies on navigation with keyboard, it should just work. Once you have a solid foundation to build on, you can move on to styling.
CSS is as powerful as it is scary for some web developers. It provides flexibility to design an experience that looks good and offers affordances to users. Embrace responsive design and make use of sizes that adapt to the person’s screen size. Use media queries to change the layout to adapt to different sizes, support light and dark mode and even reduce animations which would be uncomfortable to a person with vestibular motion disorder. The best part about both HTML and CSS is that you can layer on newer features whenever you like, and older browsers will simply ignore it. You’re not going to completely break the website for older browsers, you’re simply enhancing the experience for newer ones. The core of the site is still accessible. What do we do about the elephant in the room – what about JS?
React, Vue and Svelte are great frameworks, they also have some very popular frameworks that offer server-side rendering (SSR) and static site generation (SSG) too Next.js, Nuxt.js and SvelteKit respectively. These frameworks will lay the foundation of HTML and CSS and enhance it with JS afterwards. You don’t need to forgo modern tooling to make a resilient website, just consider building on a solid foundation.
One of the best resources I recommend for insight into how we got here and how we should help build a more robust web is Resilient web design by Jeremy Keith. Another surprising resource is from the UK Government Service Manual – Building a resilient frontend using progressive enhancement, it details a practical approach to progressive enhancement.