Journal
Resources for learning front-end web development
A designer colleague recently asked me what course or resources I would recommend for learning front-end web development. She mentioned React at the beginning but I suggested that it’d be better to start by learning HTML, CSS, and JavaScript. As for React: it’s a subset or offshoot of JavaScript so it makes sense to understand vanilla JS first.
For future reference, here are my tips.
Everything in one place
Google’s web.dev training resource have also been adding some excellent guides, such as:
Another great one-stop shop is MDN Web Docs. Not only is MDN an amazing general quick reference for all HTML elements, CSS properties, JavaScript APIs etc but for more immersive learning there are also MDN’s guides.
Pay attention to HTML
One general piece of advice is that when people look at lists of courses (whether or not they are new to web development) they ensure to learn HTML. People tend to underestimate how complicated, fast-moving and important HTML is.
Also, everything else – accessibility, CSS, JavaScript, performance, resilience – requires a foundation of good HTML. Think HTML first!
Learning CSS, specifically
CSS is as much about concepts and features – e.g. the cascade and specificity, layout, responsive design, typography, custom properties – as it is about syntax. In fact probably more so.
Most tutorials will focus on the concepts but not necessarily so much on practicalities like writing-style or file organisation.
Google’s Learn CSS course should be pretty good for the modern concepts.
Google also have Learn Responsive Design.
If you’re coming from a kinda non-CSS-oriented perspective, Josh W Comeau’s CSS for JavaScript Developers (paid course) could be worth a look.
If you prefer videos, you could check out Steve Griffith’s video series Learning CSS. Steve’s videos are comprehensive and well-paced. It contains a whole range of topics (over 100!), starting from the basics like CSS Box Model.
In terms of HTML and CSS writing style (BEM etc) and file organisation (ITCSS etc), here’s a (version of a) “style guide” that my team came up with for one of our documentation websites. I think it’s pretty good!
CSS and HTML Style Guide (to do: add link here)
For more on ITCSS and Harry Roberts’s thoughts on CSS best practices, see:
- Manage large projects with ITCSS
- Harry’s Skillshare course on ITCSS
- Harry’s CSS Guidelines rulebook
- Harry’s Discovr demo project
Learning JavaScript
I recommended choosing a course or courses from CSS-Tricks’ post Beginner JavaScript notes, especially as it includes Wes Bos’s Beginner JavaScript Notes + Reference.
If you like learning by video, check out Steve Griffith’s JavaScript playlist.
Once you start using JS in anger, I definitely recommend bookmarking Chris Ferdinandi’s Methods and APIs reference guide.
If you’re then looking for a lightweight library for applying sprinkles of JavaScript, you could try Stimulus.
Learning Responsive Design
I recommend Jeremy Keith’s Learn Responsive Design course on web.dev.
Lists of courses
You might choose a course or courses from CSS-Tricks’ post Where do you learn HTML and CSS in 2020?
Recommended books
- Resilient Web Design by Jeremy Keith. A fantastic wide-screen perspective on what we’re doing, who we’re doing it for, and how to go about it. Read online or listen as an audiobook.
- Inclusive Components by Heydon Pickering. A unique, accessible approach to building interactive components, from someone who’s done this for BBC, Bulb, Spotify.
- Every Layout by Heydon Pickering & Andy Bell. Introducing layout primitives, for handling responsive design in Design Systems at scale (plus so many insights about the front-end)
- Atomic Design by Brad Frost. A classic primer on Design Systems and component-composition oriented thinking.
- Practical SVG by Chris Coyier. Learn why and how to use SVG to make websites more aesthetically sharp, performant, accessible and flexible.
- Web Typography by Richard Rutter. Elevate the web by applying the principles of typography via modern web typography techniques.
Collected web accessibility guidelines, tips and tests
At work, I’m sometimes asked accessibility questions or to provide guidelines. I’m with Anna Cook in considering myself an accessibility advocate rather than an expert however I have picked up lots of tips and knowledge over many years of developing websites. So I thought it’d be useful to gather some general web accessibility tips and tests in one place as a useful reference.
Caveats and notes:
- this is a living document which I’ll expand over time;
- I’m standing on the shoulders of real experts and I list my references at the foot of the article; and
- if I’ve got anything wrong, please let me know!
Table of contents
- If you only had 5 minutes
- Content structure
- Semantic HTML and ARIA
- Favour native over custom components except where they have known issues
- Make custom components convey state accessibly
- Forms
- Links and buttons
- Ensure keyboard support
- Content resizing
- Better link text
- Supporting high contrast mode
- Skip links
- Navigation and menus
- Modal dialogues
If you only had 5 minutes
If someone had a web page and only had 5 minutes to find and tackle the lowest hanging fruit accessibility-wise, I’d probably echo Jeremy Keith’s advice to ensure that the page covers the following:
- uses heading elements sensibly
- uses landmarks (representing roles like
banner,navigation,main,contentinfo) - marks up forms sensibly (for example using labels and appropriate buttons)
- provides images with decent text alternatives
(Note: headings and landmarks are used by screen reader users to get a feel for the page then jump to areas of interest.)
Spending just 5 minutes would be bad, of course, and you shouldn’t do that. The point is that if pushed, the above give good bang-for-your-buck.
Content structure
The page’s content should be well structured as this makes it easier to understand for all, especially people with reading and cognitive disabilities.
It should consist of short sections of content preceded by clear headings. Use the appropriate heading level for the place in the page. Don’t use an inappropriate heading level to achieve a given appearance such as a smaller size. Instead use the appropriate heading element then use CSS to achieve your desired style.
It should employ lists where appropriate. It should place the most important content at the beginning of the page or section to give it prominence.
Check your page for any long passages of text with no structure. Ensure that sufficient prominence is given to the most important information and calls to action.
Semantic HTML and ARIA
While there are generic HTML elements like div and span, there are many more HTML elements that perform a specific role and convey that role to browers and other technologies. Choosing and using semantic HTML elements appropriately is a very good practice.
Also, using semantic HTML elements is preferable to bolting on semantics via attributes since the semantics are conveyed natively avoiding redundancy and duplication. As Bruce Lawson says, “Built-in beats bolt-on, bigly”.
Apply ARIA carefully. No ARIA is better than bad ARIA.
Landmarks
Create a small number of landmarks using the appropriate HTML elements.
For some landmark-generating elements it’s appropriate to bolster them with a label or accessible name. For example with nav and aside, i) there’s a decent chance there might be multiple on the page; and ii) each instance creates a landmark even when it’s nested within a deeper HTML element. So it’s helpful to distinguish each different landmark of the same type by using sensible accessible names otherwise you’d get multiple navigation menus all represented by the same “navigation” in the Landmarks menu. In the case of the section element it needs an acessible name in order for it to act as a region landmark. For all of these you can use aria-labelledby set to the id of an inner heading, or use aria-label.
Note that when using multiple <header> (or footer) elements on a page, where one and one only is a direct child of body while the others are used within article or similar elements, there’s perhaps less need to add custom accessible names. That’s because only a direct child of body will be treated as a landmark and the others won’t, therefore they won’t be butting against each other in a screen reader’s Landmarks menu and need distinguished.
Correct use of aria-label and aria-labelledby
Use the aria-label or aria-labelledby attributes (only when necessary) on interactive elements – buttons, links, form controls – and on landmark regions. Don’t use them on <div>s, <span>s, or other elements representing static/noninteractive text-level semantics, such as <p>, <strong>, <em>, and so forth, unless those elements’ roles have been overridden with roles that expect accessible names.
Favour native over custom components except where they have known issues
Native components require very little work, are familiar to users, and are generally accessible by default. Custom components can be built to appear and behave as designers want, but require much more effort to build and are challenging to make accessible.
There are exceptions. Since the native options are flawed across browsers, accessibility experts recommend using custom solutions for:
- form error field messages
- focus indicator styles
Make custom components convey state accessibly
Now that you’re building a custom component you don’t get accessibility out of the box. Whether it’s a Like button or a disclosure widget, you can’t rely on a visual change alone to convey a UI change to all users. You’ll need to use the right element (note – it often starts with a button) and then use ARIA to convey states such as pressed or expanded to screen reader users.
Forms
Because in the industry form fields are often handled with JavaScript and not submitted, people sometimes question whether form fields should live inside a form (<form>). My answer is yes, and here’s why.
Using the form element improves usability and accessibility
Using a <form> provides additional semantics allowing additional accessibility. It helps assistive devices like screen readers better understand the content of the page and gives the person using them more meaningful information.
By putting form fields inside a form we also ensure we match user expectations. We support the functionality (such as the different ways of submitting a form) that users expect when presented with form fields.
If you’re thinking “but what about form fields that don’t look like form fields?” then you’ve entered the problem territory of “deceptive user interfaces” – the situation where perceived affordances don’t match actual functionality, which causes confusion for some people. This is to be avoided. We shouldn’t use form fields (nor a <form>) when they are not appropriate. A checkbox, radio button, or select menu is meant to gather information. So if your goal is instead to let the user manipulate the current view, use a button rather than checkboxes or radio buttons.
References:
- Why use a form element when submitting fields with JavaScript
- Lea Verou and Leonie Watson’s discussion regarding Toggles
- My conversation about forms with accessibility expert Adrian Roselli
Using the form element simplifies your JavaScript for event handling
Using the form element can also make it easier for you to meet user expectations in your JS-powered experience. This is because it gives you a single element (form) and event combination that allows listening to multiple interactions. With a form element you can add a listener for the submit() event. This event fires automatically in response to the various ways users expect to submit a form, including pressing enter inside a field.
Anchors and buttons
To let the user navigate to a page or page section, or download a file, use an anchor element.
To let the user trigger an action such as copying to clipboard, launching a modal or submitting a form, use a button element.
Anchors should include an href attribute otherwise the browser will treat it like a non-interactive element. This means the link will not be included in the expected focus order and will not present a pointer to mouse users like it should. These days there is no remaining use case for an anchor without an href. We no longer need named anchors to create link-target locations within the page because we can use the id attribute (on any element) for that. And if you want an interactive element that does not link somewhere, you should use button.
Do not remove the focus outline from links and buttons in CSS, unless it’s to provide a better version.
Ensure you always give links and buttons an accessible name, even when they use icons rather than text. This might be through visually hidden text or perhaps using an ARIA-related attribute.
Ensure keyboard support
Web pages need to support those who navigate the page by keyboard.
Use the tab key to navigate your page and ensure that you can reach all actionable controls such as links, buttons and form controls. Press the enter key or space bar to activate each control.
If during your test any actionable control is skipped, receives focus in an illogical order, or you cannot see where the focus is at any time, then keyboard support is not properly implemented.
Content resizing
Try zooming your page up to 400%. In Chrome, Zoom is available from the kebab menu at the top-right, or by holding down command with plus or minus.
Content must resize and be available and legible. Everything should reflow.
Relative font settings and responsive design techniques are helpful in effectively handling this requirement.
Relatedly, setting font-sizes in px should be avoided because although a user can override the “fixed-ness” with zoom, it breaks the user’s ability to choose a larger or smaller default font size (which users often prefer over having to zoom every single page).
Better link text
Blind and visually impaired users use a screen reader to browse web pages, and screen readers provide user-friendly access to all the links on the page via a Links menu. When links are encountered in that context, link text like “Click here” and “Read more” are useless.
Check your web page to ensure that links clearly describe the content they link to when read out of context.
Better link text also improves the flow and clarity of your content and so improves the experience for everyone.
Supporting high contrast mode
Some people find it easier to read content when it’s in a particular colour against a specific background colour. Operating systems provide options to allow users to configure this to their preference. Websites must support support the user’s ability to apply this.
On a Windows computer go to Settings > Ease of access and turn on High contrast mode. On macOS go to System preferences > Accessibility settings > Display and select “Invert colours”.
Having changed the contrast, check that your web page’s content is fully visible and understandable, that images are still visible and that buttons are still discernible.
Skip links
Websites should provide a “Skip to content” link because this provides an important accessibility aid to keyboard users and those who use specialised input devices. For these users, having to step through (typically via the tab key) all of the navigation links on every page would be tiring and frustrating. Providing a skip link allows them to bypass the navigation and skip to the page’s main content.
To test that a website contains a skip link, visit a page then press the tab key and the skip link should appear. Then activate it using the enter key and check that focus moves to the main content area. Press tab again to ensure that focus moves to the first actionable element in the main content.
Navigation and menus
When developing a collapsible menu, place your menu <button> within your <nav> element and hide the inner list rather than hiding the <nav> element itself. That way, we are not obscuring from Assistive Technologies the fact that a navigation still exists. ATs can still access the nav via landmark navigation. This is important because landmark discovery is one of the fundamental ways AT users scan, determine and navigate a site’s structure.
Modal dialogues
You probably don’t want to set the dialogue’s heading as an <h1>. It likely displays content that exists on the page (which already has an <h1>) at a lower level of the document hierarchy.
References
- Using HTML landmark roles MDN article. And Adrian R’s suggested additions
- Navigation (landmark) role, on MDN
- Tetralogical’s Quick Accessibility Tests video playlist and Tetralogical’s accompanying article
- Basic accessibility mistakes I often see in audits by Chris Ferdinandi
- Sara Soueidan’s video tutorial Practical tips for building more accessible front-ends
- Adrian Roselli’s Responsive type and zoom
- Heydon Pickering’s tweet about buttons in navs and Scott O’Hara’s follow up article Landmark Discoverability
- Tetralogical’s Foundations: native versus custom components
- Ben Myers on where to use aria labelling attributes
Collapsible sections, on Inclusive Components
It’s a few years old now, but this tutorial from Heydon Pickering on how to create an accessible, progressively enhanced user interface comprised of multiple collapsible and expandable sections is fantastic. It covers using the appropriate HTML elements (buttons) and ARIA attributes, how best to handle icons (minimal inline SVG), turning it into a web component and plenty more besides.
Icon has Cheezburger (a Clearleft dConstruct newsletter)
Jeremy Keith deconstructs the cheeseburger icon and—referencing Luke Wroblewski’s Obvious Always Wins mantra—argues that while icons alone look tasty they risk users failing to understand and engage.
BBC WebCore Design System
Here’s the BBC’s Storybook UI explorer containing the components and layouts for making the front end of a BBC web experience.
From designing interfaces to designing systems (on The history of the web)
A history of Design Systems by Jay Hoffman taking in (amongst other milestones) the notion of Front-end Style Guides, followed by the arrival of Bootstrap, then Brad Frost’s Atomic Design, culminating in the dawn of the Design System movement with Jina Anne’s Clarity Conference.
Buttons and links: definitions, differences and tips
On the web buttons and links are fundamentally different materials. However some design and development practices have led to them becoming conceptually “bundled together” and misunderstood. Practitioners can fall into the trap of seeing the surface-level commonality that “you click the thing, then something happens” and mistakenly thinking the two elements are interchangeable. Some might even consider them as a single “button component” without considering the distinctions underneath. However this mentality causes our users problems and is harmful for effective web development. In this post I’ll address why buttons and links are different and exist separately, and when to use each.
Problematic patterns
Modern website designs commonly apply the appearance of a button to a link. For isolated calls to action this can make sense however as a design pattern it is often overused and under-cooked, which can cause confusion to developers implementing the designs.
Relatedly, it’s now common for Design Systems to have a Button component which includes button-styled links that are referred to simply as buttons. Unless documented carefully this can lead to internal language and comprehension issues.
Meanwhile developers have historically used faux links (<a href="#">) or worse, a DIY clickable div, as a trigger for JavaScript-powered functionality where they should instead use native buttons.
These patterns in combination have given rise to a collective muddle over buttons and links. We need to get back to basics and talk about foundational HTML.
Buttons and anchors in HTML
There are two HTML elements of interest here.
Hyperlinks are created using the HTML anchor element (<a>). Buttons (by which I mean real buttons rather than links styled to appear as buttons) are implemented with the HTML button element (<button>).
Although a slight oversimplification, I think David MacDonald’s heuristic works well:
If it GOES someWHERE use a link
If it DOES someTHING use a button
A link…
- goes somewhere (i.e. navigates to another place)
- normally links to another document (i.e. page) on the current website or on another website
- can alternatively link to a different section of the same page
- historically and by default appears underlined
- when hovered or focused offers visual feedback from the browser’s status bar
- uses the “pointing hand” mouse pointer
- results in browser making an HTTP
GETrequest by default. It’s intended to get a page or resource rather than to change something - offers specific right-click options to mouse users (open in new tab, copy URL, etc)
- typically results in an address which can be bookmarked
- can be activated by pressing the return key
- is announced by screen readers as “Link”
- is available to screen reader users within an overall Links list
A button…
- does something (i.e. performs an action, such as “Add”, “Update” or "Show")
- can be used as
<button type=submit>within a form to submit the form. This is a modern replacement for<input type=submit />and much better as it’s easier to style, allows nested HTML and supports CSS pseudo-elements - can be used as
<button type=button>to trigger JavaScript. This type of button is different to the one used for submitting a<form>. It can be used for any type of functionality that happens in-place rather than taking the user somewhere, such as expanding and collapsing content, or performing a calculation. - historically and by default appears in a pill or rounded rectangle
- uses the normal mouse pointer arrow
- can be activated by pressing return or space.
- implictly gets the ARIA button role.
- can be extended with further ARIA button-related states like
aria-pressed - is announced by screen readers as “Button”
- unlike a link is not available to screen reader users within a dedicated list
Our responsibilities
It’s our job as designers and developers to use the appropriate purpose-built element for each situation, to present it in a way that respects conventions so that users know what it is, and to then meet their expectations of it.
Tips
- Visually distinguish button-styled call-to-action links from regular buttons, perhaps with a more pill-like appearance and a right-pointing arrow
- Avoid a proliferation of call-to-action links by linking content itself (for example a news teaser’s headline). Not only does this reduce “link or button?” confusion but it also saves space, and provides more accessible link text.
- Consider having separate Design System components for Button and ButtonLink to reinforce important differences.
- For triggering JavaScript-powered interactions I’ll typically use a
button. However in disclosure patterns where the trigger and target element are far apart in the DOM it can make sense to use a link as the trigger. - For buttons which are reliant on JavaScript, it’s best to use them within a strategy of progressive enhancement and not render them on the server but rather with client-side JavaScript. That way, if the client-side JavaScript is unsupported or fails, the user won’t be presented with a broken button.
Update: 23 November 2024
Perhaps a better heuristic than David MacDonald’s mentioned above, is:
Links are for a simple connection to a resource; buttons are for actions.
What I prefer about including a resource is that the “goes somewhere” definition of a link breaks down for anchors that instruct the linked resource to download (via the download attribute) rather than render in the browser, but this doesn’t. I also like the inclusion of simple because some buttons (like the submit button of a search form) might finish by taking you to a resource (the search results page) but that’s a complex action not a simple connection; you’re searching a database using your choice of search query.
References
- Get safe, by Jeremy Keith
- Buttons vs. Links, by Eric Eggert
- The Button Cheat Sheet, by Manuel Matuzović
- A complete guide to links and buttons on CSS-Tricks
- The Links vs Buttons Showdown, by Marcy Sutton
HTML with Superpowers (from Dave Rupert)
Here’s a great new presentation by Dave Rupert (of the Shop Talk show) in which he makes a compelling case for adopting Web Components. Not only do they provide the same benefits of encapsulation and reusability as components in proprietary JavaScript frameworks, but they also bring the reliability and portability of web standards, work without build tools, are suited to progressive enhancement, and may pave the way for a better web.
Dave begins by explaining that Web Components are based on not just a set of technologies but a set of standards, namely:
- Custom Elements (for example
<custom-alert>) - Shadow DOM
- ES Modules
- the HTML
<template>element
Standards have the benefit that we can rely on them to endure and work into the future in comparison to proprietary technologies in JavaScript frameworks. That’s good news for people who like to avoid the burnout-inducing churn of learning and relearning abstractions. Of course the pace of technology change with web standards tends to be slower, however that’s arguably a price worth paying for cross-platform stability and accessibility.
Some of Web Components’ historical marketing problems are now behind them, since they are supported by all major browsers and reaching maturity. Furthermore, web components have two superpowers not found in other JavaScript component approaches:
Firstly, the Shadow DOM (which is both powerful and frustrating). The Shadow DOM provides encapsulation but furthermore in progressive enhancement terms it enables the final, enhanced component output which serves as an upgrade from the baseline Light DOM HTML we provided in our custom element instance. It can be a little tricky or confusing to style, however, although there are ways.
Secondly, you can use web components standalone, i.e. natively, without any frameworks, build tools, or package managers. All that’s required to use a “standalone” is to load the <script type=module …> element for it and then use the relevant custom element HTML on your page. This gets us closer to just writing HTML rather than wrestling with tools.
Dave highlights an education gap where developers focused on HTML, CSS, and Design Systems don’t tend to use Web Components. He suggests that this is likely as a result of most web component tutorials focusing on JavaScript APIs for JavaScript developers. However we can instead frame Web Component authoring as involving a layered approach that starts with HTML, adds some CSS, then ends by applying JavaScript.
Web Components are perfectly suited to progressive enhancement. And that progressive enhancement might for example apply lots of complicated ARIA-related accessibility considerations. I really like the Tabs example where one would create a <generic-tabs> instance which starts off with simple, semantic, resilient HTML that renders headings and paragraphs…
<generic-tabs>
<h2>About</h2>
<div>
<p>About content goes here. Lorem ipsum dolor sit amet…</p>
</div>
<h2>Contact</h2>
<div>
<p>Contact content goes here. Lorem ipsum dolor sit amet…</p>
</div>
</generic-tabs>
…but the Web Component’s JavaScript would include a template and use this to upgrade the Light DOM markup into the final interactive tab markup…
<generic-tabs>
<h2 slot="tab" aria-selected="true" tabindex="0" role="tab" id="generic-tab-3-0" aria-controls="generic-tab-3-0" selected="">About</h2>
<div role="tabpanel" aria-labelledby="generic-tab-3-0" slot="panel">
<p>About content goes here. Lorem ipsum dolor sit amet…</p>
</div>
<h2 slot="tab" aria-selected="false" tabindex="-1" role="tab" id="generic-tab-3-1" aria-controls="generic-tab-3-1">Contact</h2>
<div role="tabpanel" aria-labelledby="generic-tab-3-1" slot="panel" hidden>
<p>Contact content goes here. Lorem ipsum dolor sit amet…</p>
</div>
</generic-tabs>
The idea is that the component’s JS would handle all the complex interactivity and accessibility requirements of Tabs under the hood. I think if I were implementing something like Inclusive Components’ Tabs component these days I’d seriously consider doing this as a Web Component.
Later, Dave discusses the JavaScript required to author a Custom Element. He advises that in order to avoid repeatedly writing the same lengthy, boilerplate code on each component we might use a lightweight library such as his favourite, LitElement.
Lastly, Dave argues that by creating and using web components we are working with web standards rather than building for a proprietary library. We are creating compatible components which pave the cowpaths for these becoming future HTML standards (e.g. a <tabs> element!) And why is advancing the web important? Because an easier web lowers barriers: less complexity, less tooling and setup, less gatekeeping—a web for everyone.
How to debug event listeners with your browser’s developer tools (on Go Make Things)
On the page, right-click the element you want to debug event listeners for, then click Inspect Element. In chromium-based browsers like MS Edge and Google Chrome, click the Event Listeners tab in Developer Tools. There, you’ll see a list of all of the events being listened to on that element. If you expand the event, you can see what element they’re attached to and click a link to open up the actual event listener itself in the JavaScript.
Conditional border-radius in CSS (by Ahmad Shadeed via CSS-Tricks)
Here’s a “media query free” CSS one-liner which lets you set an element to have no border-radius when it is the full width of the viewport, but otherwise to have a border-radius.
It uses the same 9999 multiplication technique as Every Layout do to create a toggle.
Great for Card components which need to be full-width and non-rounded only on narrow viewports.