The Problem With Web Development Checklists, or: The Frontend Checklist, Revised

Published on June 19, 2019 (↻ April 12, 2024), filed under (RSS feed for all categories).

Checklists sound like a great way to make sure nothing gets forgotten for a mission or a project. That’s especially true when something valuable is at stake, as I personally learned when starting to make my helicopter pilot license and running around helicopters marking off, checklists (I didn’t finish my license and I don’t mean to show off). Yet checklists are problematic when they contain items that aren’t important—the unnecessary fluff causes unnecessary work and, in web development, unnecessary code.

In web development, checklists are also problematic because there are many different types of projects—which means that there’s only a small intersection of things that all projects have in common. Yet, just as with frameworks and libraries, where likewise more needs are assumed than our projects actually have—the main problem with public frameworks, as I noted in my frameworks book (updated)—, most checklists, and all I’ve seen so far, ignore this issue, asking to check for matters that are not relevant.

This may happen then for a particular reason: The beauty of the true and tiny number of commonalities between all projects and their needs is not perceived. Or discarded, as too simple, too unclever, too uninteresting. A taste? The “World’s Best HTML Template,” which provocatively but truthfully contains all code that any website needs and that easily gets dismissed out of hand. Very well: How is this helpful? But the dismissal also represents some intellectual laziness, not acknowledging how little, strictly speaking, any two websites really have in common.

Even when this accusation of laziness is harsh, then, and even when there can be some value in checklists (and frameworks), and even when some have managed to develop or use checklists (as well as frameworks) so that their application was nothing but advantageous, I’ll conclude this part with a recommendation:

For maximum quality, write your own checklists.

Val’s evenings are most interesting. Scholars, poets, travelers, and philosophers gather in his rooms for discussion and he learns many curious things.

Figure: It appears useful to learn curious things. (Copyright King Features Syndicate, Inc., distr. Bulls.)

This DYI is work, and yet I’ll now demonstrate why that work is rather needed. Here’s a quick and of course opinionated review of The Frontend Checklist, as of its May 23, 2019, checks, with brief commentary on what’s useful, questionable, and, at the moment, useless, without regard for the priority The Frontend Checklist assigns each item. (I share this with a lot of respect, then, as the following is not meant to downplay or dismiss the work that was done.)

The Frontend Checklist: Use 33, Question 13, Ignore 41 Items

Doctype: The doctype is HTML5 and is at the top of your HTML pages

👎: Meant is the doctype for living HTML (where the spelling “HTML5” has always been a bit silly) and yet this check is somewhat useless—there should be a doctype declaration, one that’s validated against, but there’s nothing inherently wrong with other doctypes.

Charset: The charset declared (UTF-8) is declared correctly

👎: Too vague, overly specific. There are many ways to declare an encoding (which is meant) and the encoding can well be recommended to be UTF-8 but may by all means also be something else—as long as the document actually uses and indicates that encoding.

Viewport: The viewport is declared correctly

✋: This is also rather vague, it’s also likely difficult to defend in all scenarios, but may be acceptable as a requirement.

Title: A title is used on all pages

đź‘Ť: This is important; absence of a title is easily caught, especially when validating, but the rule is, per se, okay.

Description: A meta description is provided, it is unique and doesn’t possess more than 150 characters

👎: I know it’s not a popular stance but from my view, meta descriptions are a software problem; and even if one maintains that they must be pushed on humans, it doesn’t follow that this was mandatory, that a website could not live without meta descriptions. It can (qed, per this very site).

Favicons: Each favicon has been created and displays correctly

✋: This is an odd rule, and the oddness begins with “each.” One can argue that having a favicon is good practice, but somewhat suggesting each of more than 45 (!) known icons needs to be supported to pass some random test looks crazy. As does the general situation around favicons.

Apple web app meta: Apple meta tags are present

👎: Too broad and unspecific. Apple has invented so much meta information over the years that following this guideline is akin to making every HTML page the size of the Encyclopædia Britannica. (There are useful Apple meta elements. Which ones these are exactly, beats me.)

Windows tiles: Windows tiles are present and linked

👎: Likewise too broad and unspecific—don’t take action. If it’s not clear how that’s too broad, imagine an HTML checklist item “HTML elements are present.” Or perhaps a shopping list, “groceries are present.” Guidelines like that have no value.

Canonical: Use rel="canonical" to avoid duplicate content

👎: This is a poorly worded guideline because it simply, overly broadly assumes that there is, in fact, duplicate content (most sites probably don’t suffer from that). It would be a lot better if this said “if major parts of the content are also used on other pages, use rel="canonical" to reference the page that’s the source of truth,” or something like that.

Language attribute: The lang attribute of your website is specified and related to the language of the current page

đź‘Ž: No. But even if one insists on providing language information for a page, that can be done easier on the server-side.

Direction attribute: The direction of [reading] is specified on the html tag (it can be used on another HTML tag)

đź‘Ž: Meant is the html start tag (or html element), of course, but since absence of @dir defaults to ltr, the attribute does not need to be specified on LTR pages.

Alternate language: The language tag of your website is specified and related to the language of the current page

👎: It’s unclear what this rule is about. Document language has already been covered, site language is handled the same way, and language changes within a document do not work through “the language tag of the website.”

Conditional Comments: Conditional Comments are present for [Internet Explorer] if needed

đź‘Ž: No. (I thought Conditional Comments were dead.)

RSS feed: If your project is a blog or has articles, an RSS link was provided

👎: A wholehearted “yes” in spirit, but after Google’s war on feeds it’s become really hard to argue that feeds were a hard requirement, even for content sites. I personally really wish they were, I’m with this, but such a rule is not defensible unless feeds were as popular as they were, say, 2006–2013.

Inline critical CSS: The inline critical CSS is correctly injected in the [document] head

đź‘Ž: This rule depends on so many conditions (per the first paradigm it would only be justifiable on one-pagers) that it has no place (yet) in an all-purpose dev checklist.

CSS order: All CSS files are loaded before any JavaScript files in the [document] head

đź‘Ť: Not an iron rule but sound.

Facebook Open Graph

👎: No. This rule suggests every site must be catering for Facebook and that position cannot be held—for one it’s not hard to imagine that some sites don’t choose to do anything with Facebook, for another, and perhaps more importantly, even without special Facebook meta information sites can be shared on Facebook, even in an okay-looking way.

Twitter Card

đź‘Ž: No. The same as with Facebook. Nice to have, yes. Compulsory for every website out there, no.

HTML5 Semantic Elements: HTML5 Semantic Elements are used appropriately (header, section, footer, main…)

đź‘Ť: Yes: All HTML elements want to be used according to their purpose.

Error pages: Error 404 page and 5xx exist

✋: Tricky rule: In practice there’s already always some message, though it may not be very useful for the user. Yet a general demand for a 404 page may not provide anything more useful, and a demand to cover one, some, or all errors in the 500s range is too imprecise to form a good rule. Perhaps this could be saved by requiring a “useful page for 404 errors and other anticipated HTTP errors (like 401 in case of page authorization),” though that’s a bit vague, too.

noopener: In case you are using external links with target="_blank", your link should have a rel="noopener" attribute […]

đź‘Ť: One of several user agent problems forced on web developers, but yes.

Clean up comments: Unnecessary code needs to be removed before sending the page to production

✋: Yes and not yes. Yes because it’s surely an optimization step reducing payload (and eliminating a risk of conveying internal information—we used to think of this at Google), not yes because it may still depend, like when comments are few or desired (personally I like to point to meta information through comments).

W3C compliant: All pages need to be tested with the W3C validator to identify possible issues in the HTML code

đź‘Ť: Absolutely.

HTML lint: I use tools to help me analyze any issues I could have on my HTML code

👍: This seems somewhat complementary and secondary but, yes. (Then, “I use”? Some guidelines use first person, others second, and then they switch between active and passive voice; this may be something to revisit.)

Link checker: There are no broken links in my page, verify that you don’t have any 404 error

đź‘Ť: Yes.

Adblockers test: Your website shows your content correctly with adblockers enabled

✋: If a website contains ads, probably. But it may just be me here who not only believes it would be horrible to run after ad blockers—but that those ad blockers shouldn’t exist. (Indeed, I believe there are many strong reasons against ad blockers.)

Webfont format: WOFF, WOFF2 and TTF are supported by all modern browsers

đź‘Ž: Phrased as it is here, this rule makes no sense: Why and how would an author be required to check that all modern browsers support these three or any three font formats? But with this rule likely suggesting that one could safely use either format, the 2019 recommendation seems to be to use WOFF2 and WOFF.

Webfont size: Webfont sizes don’t exceed 2 MB (all variants included)

đź‘Ť: Arbitrary (perhaps still rather high) but, well.

Webfont loader: Control loading behavior with a webfont loader

👎: No. Keep it simple. Don’t fall for something that promises to reduce a complexity it itself compounds.

Responsive Web Design: The website is using responsive web design

đź‘Ť: Yes. Make the site or app be responsive.

[Print CSS]: A print stylesheet is provided and is correct on each page

đź‘Ť: Absolutely.

Unique ID: If IDs are used, they are unique to a page

đź‘Ť: A duplicate (this is taken care of with validation) but, yes.

Reset CSS: A CSS reset (reset, normalize or reboot) is used and up to date

👎: Absolutely not. I’m not sure what to think of the technical background and agenda of anyone requiring you to use a reset. Seriously—it’s 2019, year of ever more equal default styling, and this rule would be much more useful if it instead suggested to remove any resets—and to watch the code base shrink while nothing even happens.

JS prefix: All classes (or [IDs] used in JavaScript files) begin with js- and are not styled into the CSS files

đź‘Ž: Such a prefix is optional, could be anything, and could really also be tied to hooks used for styling if it forms a functional unit with respective component.

Embedded or inline CSS: Avoid at all cost [embedding] CSS in <style> tags or using inline CSS

đź‘Ž: Most of the time, yes, all of the time, no. Prominent edge cases: One-pagers can benefit from inline CSS code, and guaranteed unique styling could warrant that, too (for example, dimensions that may pertain to unique elements and that are unlikely to be repeated anywhere else).

Vendor prefixes: CSS vendor prefixes are used and are generated accordingly with your browser support compatibility

👎: Probably just poorly phrased as the rule appears appropriate once one adds “when needed.” Blindly requiring prefixes is poor advice.

Concatenation: CSS files are concatenated in a single file (not for HTTP/2)

✋: Perhaps not only not for HTTP/2, but also not in every single other case, and yet this is not a clear “no.”

Minification: All CSS files are minified

đź‘Ť: I could see exceptions but, yes.

Non-blocking: CSS files need to be non-blocking to prevent the DOM from taking time to load

đź‘Ť: Yes.

Stylelint: All CSS or SCSS files are without any errors

đź‘Ť: Yes, though be sure that this means valid CSS and effective Stylelint rules.

Responsive web design: All pages were tested with the correct breakpoints

đź‘Ť: Yes.

CSS validator: The CSS was tested and pertinent errors were corrected

đź‘Ť: Yes.

Desktop browsers: All pages were tested on all current desktop browsers (Safari, Firefox, Chrome, Internet Explorer, Edge…)

đź‘Ž: Yes, but no. Yes of course, in a sense of absolutely testing that a site or app works. But no for two reasons: 1) the actual browsers to test for depend on audience and priorities, 2) this rule could better be rephrased and combined with the following two checks:

Mobile browsers: All pages were tested on all current mobile browsers (Native browser, Chrome, Safari…)

đź‘Ž: No, make this one testing guideline that is dependent on audience and priorities.

OS: All pages were tested on all current OS (Windows, Android, iOS, Mac…)

đź‘Ž: No, make this one testing guideline that is dependent on audience and priorities.

Reading direction: All pages need to be tested for LTR and RTL languages if they need to be supported

đź‘Ž: This is already implicitly handled with the other testing requirements.

JavaScript inline: You don’t have any JavaScript code inline (mixed with your HTML code)

đź‘Ť: Yes. Perhaps one of the few remaining places where Separation of Concerns is not under (questionable) siege.

Concatenation: JavaScript files are concatenated

✋: Perhaps, as with CSS, not only not for HTTP/2, but also not in every single other case, but again not a clear “no.” Probably do this regardless.

Minification: JavaScript files are minified (you can add the .min suffix)

đź‘Ť: Rather yes.

noscript tag: Use [the] <noscript> tag in the HTML body if a script type on the page is unsupported or if scripting is currently turned off […]

👎: This may still require a little study and an essay delivering the final blow to the topic but as it’s gotten almost impossible to use the Web without JavaScript, guidelines requiring to have things work without JavaScript seem out of date, for out of touch with reality.

Non-blocking: JavaScript files are loaded asynchronously using async or deferred using [the] defer attribute

âś‹: Probably good advice, but probably not mandatory.

Modernizr: If you need to target some specific features you can use a custom Modernizr to add classes in your <html> tag

👎: “You can” makes no good guideline.

ESLint: No errors are flagged by ESLint (based on your configuration or standards rules)

âś‹: Probably good, but both the push to use ESLint as well as vagueness with respect to the ruleset make this a questionable requirement.

Optimization: All images are optimized to be rendered in the browser; WebP format could be used for critical pages (like [the] Homepage)

👍: I find “optimized to be rendered in the browser” a bit odd (“compressed for suitable quality”?) but, yes. WebP doesn’t seem ready to me yet but does of course work with fallbacks.

picture/srcset: You use picture/srcset to provide the most appropriate image for the current viewport of the user

đź‘Ž: No, please. For one, scrset on img may be a more compact alternative. For another, just img may do as well.

Retina: You provide layout images 2Ă— or 3Ă—, support retina display

👎: No, not as a rule of thumb (at least not for me). There are enough cases when higher quality images don’t warrant the extra effort and code.

Sprite: Small images are in a sprite file (in the case of icons, they can be in an SVG sprite image)

✋: It probably depends but with the growing reach of both HTTP/2 and inlining SVGs I’d deem sprites to diminish in importance.

Width and height: Set width and height attributes on <img> if the final rendered image size is known (can be omitted for CSS sizing)

👎: Apart from when intrinsic sizing works, don’t we all work with CSS sizing?

Alternative text: All <img> have an alternative text which describe the image visually

đź‘Ť: Absolutely!

Lazy loading: Images are lazy-loaded (a noscript fallback is always provided)

👎: As you can tell, the beef I’m having with many checklist points is not necessarily the practice itself but rather the lack of conditions and qualifiers. Why always load lazily—what if there are just a handful of icons of negligible file size? Don’t throw tooling at all the things. (As for lazy-loading, using loading=lazy makes everything easier.)

Progressive Enhancement: Major functionality like main navigation and search should work without JavaScript enabled

👎: Yes to Progressive Enhancement, but no as this is really just aiming at the scenario of no or disabled JavaScript—see my comment about the noscript element.

Color contrast: Color contrast should at least pass WCAG AA (AAA for mobile)

👍: Yes, though I’m not sure about the stricter rule for mobile—my hunch, and yet just a hunch, is that that may be too strict.

h1: All pages have an h1 which is not the title of the website

👎: Also a little hunch-y for in need of more research and elaboration, this may be an antiquated guideline if one assumes that user agents could just put headings in relation. For example, on a page where the highest heading level is an <h3>, pronounce this the highest, and set other headings in relation. If there’s an <h1> and then a <h3>, don’t throw a “skipped heading” tantrum but relay <h1> as most important, <h3> as next important. If heading order was relative instead of absolute, authoring and accessing could both become easier. (Given CSS implications, maybe this is something for a different forum.)

Headings: Headings should be used properly and in the right order (h1 to h6)

đź‘Ť: No to absolute order, but yes to relative order (see above).

Specific HTML5 input types are used: This is especially important for mobile devices that show customized keypads and widgets for different types

đź‘Ť: Yes, except for number, perhaps.

Label: A label is associated with each input form element; in case a label can’t be displayed, use aria-label instead

đź‘Ť: Yes.

Accessibility standards testing: Use the WAVE tool to test if your page respects the accessibility standards

âś‹: Yes on testing, no to limiting this to WAVE: There are quite a few accessibility testing tools out there.

Keyboard navigation: Test your website using only your keyboard in a previsible order; all interactive elements are reachable and usable

đź‘Ť: Yes.

Screen reader: All pages were tested in two or more screen readers (such as JAWS, VoiceOver, and NVDA)

✋: “Two” needs elaboration when apparently three or more comparable options are given (otherwise, why give the choice of JAWS, VoiceOver, and NVDA?). When these and other options are all equal, testing in one screenreader would do. (I cannot credibly answer this, I’m not an expert when it comes to current web standard support in screenreaders.)

Focus style: If the focus is disabled, it is replaced by visible state in CSS

đź‘Ť: Yes.

Page weight: The weight of each page is between 0 and 500 KB

đź‘Ž: What is “page weight” here (just the HTML?), and what justifies the 500 KB that look quite random?

Minified HTML: Your HTML is minified

đź‘Ť: I could see exceptions but, yes.

Lazy loading: Images, scripts and CSS need to be lazy loaded to improve the response time of the current page

👎: No, they don’t “need to.” Performance can be stellar without lazy loading; lazy loading is context-dependent.

Cookie size: If you are using cookies be sure each cookie doesn’t exceed 4,096 bytes and your domain name doesn’t have more than 20 cookies

đź‘Ť: Probably.

DNS resolution: DNS of third-party services that may be needed are resolved in advance during idle time using dns-prefetch

👍: I’m not sure about making this a fixed rule but on the other hand it’s something that does speed things up.

Preconnection: DNS lookup, TCP handshake and TLS negotiation with services that will be needed soon is done in advance during idle time using preconnect

đź‘Ť: Probably.

Prefetching: Resources that will be needed soon (e.g. lazy loaded images) are requested in advance during idle time using prefetch

👎: Probably not. In this case I’m switching course because when the guidelines end up requiring everything to be preconnected and prefetched, the rules become meaningless and should rather be filed as requests with vendors (prefetch everything). Requiring all resources to be loaded in advance looks exaggerated to me.

Preloading: Resources needed in the current page (e.g. scripts placed at the end of <body>) [are requested] in advance using preload

đź‘Ť: Probably.

Google PageSpeed: All your pages were tested (not only the homepage) and have a score of at least 90/100

đź‘Ť: Maybe.

Google Analytics: Google Analytics is installed and correctly configured

đź‘Ž: No. First, only when you actually need it, second, there are other analytics tools.

Headings logic: Heading text helps to understand the content in the current page

👎: What is this rule about—heading levels or copy?

sitemap.xml: A sitemap.xml exists and was submitted to Google Search Console

✋: Originally a clear “no” because Google seems pretty good in catching pages on websites (unless not linked or excluded in robots.txt), but perhaps there’s something I miss and need for certainty outweighs such practical concerns.

robots.txt: The robots.txt is not blocking webpages

đź‘Ž: Very likely just poorly phrased as of course, there could be very good reasons to block pages. Therefore, a general ban on exclusions appears overdone.

Structured data: Pages using structured data are tested and are without errors

đź‘Ť: If they do, yes.

Structured data helps crawlers understand the content in the current page

👎: What does that mean or, for understanding, what’s a good counter-example for this—are there structured data that would confuse crawlers in a way that’s unrelated to content and not affected by the previous guideline?

Sitemap HTML: An HTML sitemap is provided and is accessible via a link in the footer of your website

đź‘Ž: No, because not every website needs a sitemap and even if it would, there could be more suitable locations for their link than in the footer.

Pagination link tags: Provide rel="prev" and rel="next" to indicate paginated content

đź‘Ž: No, because search engines, at least Google and now, seem to be able to figure out pagination without extra and therefore unnecessary code.

❧ I believe this makes for a particular review of contemporary web development priorities, and certainly for substantial feedback for The Frontend Checklist. They, then, should not feel deterred: Their own great potential may not necessarily lie in an always applicable checklist for web developers (then, as we see, the list gets a lot shorter), but to make it a skeleton, a foundation for less experienced developers to learn about details and qualifiers of the craft.

There are problems with checklists, but they’re certainly not without use.

Was this useful or interesting? Share (toot) this post, or maybe treat me to a coffee. Thanks!

About Me

Jens Oliver Meiert, on September 30, 2021.

I’m Jens, and I’m an engineering lead and author. I’ve worked as a technical lead for companies like Google and as an engineering manager for companies like Miro, I’m close to W3C and WHATWG, and I write and review books for O’Reilly and Frontend Dogma.

With my current move to Spain, I’m open to a new remote frontend leadership position. Feel free to review and refer my CV or LinkedIn profile.

I love trying things, not only in web development, but also in other areas like philosophy. Here on meiert.com I share some of my views and experiences.