Over the decades we’ve worked on the web, we’ve documented a few things we consider best practices. Being consistent in these practices helps keep our work efficient and effective.
Please note, these practices aren’t comprehensive, and you may not agree with them. That’s okay because they’re primarily for our internal use at Faculty. You can rest assured that we’ve reached them only after debating multiple viewpoints. And we’ll probably continue to debate them and update as warranted.
Last updated: 23 Sep 2020
- Check color contrast and differentiation, especially if information is conveyed with color.
- Do not rely on color alone to convey information.
- Only provide
alttext for images when you would want the text read to a user, but always include the
altattribute, otherwise the filename will be read.
alt=""for images that are decorative and do not convey information or represent content.
- For acronyms and abbreviations, use
<abbr title="National Aeronautics and Space Administration">NASA</abbr>, after which you can just use the acronym or abbreviation.
- The expanded text of an abbreviation (represented by the
titleattribute) is not always capitalized. Choose the case based upon how it would be written if you did not abbreviate.
- Make sure to never break a user’s ability to use the tab key to get around.
- Refer to the A11Y Project Checklist for information on roles that should be added, proper form layout, etc.
- When doing anything that will update dynamically (think of a password strength meter), use something like
role="status" aria-live="polite" aria-relevant="all" aria-atomic="true". This makes it accessible to screen readers but allows the component to be hidden.
aria-hidden="true"if you have visual cues that are being conveyed elsewhere for screen readers.
- Account deletion requests are never accepted via email. The user’s identity must be verified.
- Minimum of 8 characters. No other rules. Additional rules only limit the possible password set.
- Make sure password managers work with your implementation.
- On sign-up pages, users should be encouraged to create long passwords with a variety of characters. The most important quality is the password length.
- Consider educating users with a password strength meter and a link to a separate page espousing the benefits of a strong password.
- Passwords must be hashed, not stored as plain text.
- Valid username characters are lowercase alphanumerics and hyphens. (Force lowercase.)
- Username changes are okay only if a tool has been built to handle it. Manual intervention is too prone to error.
- Where possible, the UI should prioritize name, so username restrictions don’t seem so important.
- If logging in uses the username, also allow email address to cut down on support requests from people forgetting their usernames.
- Usernames should be unique.
- Anything that can be added via the API can be taken via the API.
- Use forward-compatible code to accommodate database and API changes.
Date and time
- Server OS and platform time zones are always UTC.
- Whenever possible, use relative times such as “37 minutes ago” to avoid having to know a user’s time zone.
- Relative times should be accompanied by an absolute time in either local or UTC time attached to the element as a
- If user-specific times are necessary, be sure to ask them for the time zone, and store this with the user record.
- Apps must never write files to the tree where the Git repository is checked out (e.g., do not write to
/var/tmp/appname/if you need to write files to the filesystem.
- Use a primitive baseline pattern for validation to help users avoid obvious mistakes such as providing their username in place of their email address.
- If you want to check MX records to see if email is deliverable at the provided domain, that’s fine, but if a valid address is really important, send an email to verify. There is truly no other way.
- Force lowercase.
- Email addresses should be unique. Treat them like usernames.
- Use client-side validation when it makes the experience better, but never rely on it for security. Always verify input on the server.
- Carefully consider the experience of making a mistake. Are errors clear? Is the page subject to change blindness?
- Split frontend and backend codebases into separate repositories. This allows for separate deployments (and uneven provisioning) when an app is in production.
- Frontend repositories should be named after the app (or client) with no suffix. For example,
- Backend repositories should be named with a suffix of
- All repositories should have a GitHub service hook to relay activity to the appropriate IRC channel.
- Describe what was done. Humor is fine, but make sure clarity isn’t lost. Always be professional.
- Consider what context these message will be used for in the future, such as searching for a specific change.
- Progressive enhancement is a baseline requirement.
- Code for the smallest viewport first. A design that is coded to work on the smallest screen will work on the largest screen (even if it’s not beautiful), whereas the opposite is not necessarily true. The amount of code you have to override with
@mediaqueries with a mobile first approach will be comparable to the opposite, but with fewer surprises.
@media (min-width: x)to break gracefully to larger screens is more robust than
@media (min-width: x) and (max-width: y)or just
@media (max-width: x).
- Protect all POST requests with a CSRF token.
- Protect GET requests if they perform an action. (These should probably be POST requests.)
- Don’t regenerate the CSRF token more than once per session.
- For extra security, require a password for important actions like changing the email address or password, or deleting the account.
- Unsubscribe links (from emails) are GET, but the unsubscribe action itself should be a POST. It is acceptable to have the user arrive at a page with a form (or just a button) to unsubscribe. You can progressively enhance the unsubscribe form to auto-submit when the page loads to mimic the convenience of one-click unsubscribing.
- Include an
X-Frame-Optionsheader to mitigate this risk.
- Use it everywhere.
- See Accounts.
- Avoid third-party scripts whenever possible.
- Always indicate the character encoding in the
- Make sure you escape as necessary.
- Rely on well-vetted tools where possible.
- Don’t use sessions until you need them.
- Sessions should expire after one year, unless the user logs out, at which time the session and cookie should be removed.
- Reset the expiration with continued use, so the expiration is generally one year from the last visit, but don't reset constantly on every page.
- By default, use encrypted cookies for your session data store. Other options are valid, but make sure there’s a good reason.
- Adhere to best practices provided by search engines.
- If what you’re doing is creating content that search engines want to rank highly, and you’re adhering to their standards, you’re doing it right.
- If what you’re doing is best described as gaming the system, you’re doing it wrong. When this is the case, search engines have a responsibility and financial motive to change the game. Gaming the system is not a reliable strategy.
- Make the link text clear. This is helpful for SEO as well as for making the page more scannable.
- Use a good description for each page. Consider the appearance in search results.
- Every page should have a unique, clear title.
- Consider popular searches.
- Consider clarity of purpose.
- Choose smart fallback fonts, so your users always get the best reading experience available to them.
- Make sure your line lengths are not too long. A good rule of thumb is 60–70 characters per line.
- Create a typographic system and stick with it. A good type pairing with the right balance of contrast and harmony is worth the effort.
- Avoid using typefaces of similar style—such as Arial and Helvetica or Times New Roman and Georgia—because they do not provide enough typographic contrast.
- Make sure your typographic hierarchy provides enough contrast between sizes. A clear hierarchy helps people skim and quickly understand how information is organized.
Quotes and dashes
- Use proper quotes and apostrophes. Quotes & Accents is a good resource.
- A hyphen (
-) is used to break single words into parts or to join separate words into single words.
- An en dash (
–) is used for ranges or to illustrate the relationship between two different words.
- An em dash (
—) is used to separate thoughts, similar to how a semicolon might be used.
- Always confirm that you have the correct licenses for both desktop and web use.
- Don’t use underscores in URLs. Lowercase alphabetic characters and hyphens are preferred.
- Every page should have a unique URL. Think of what constitutes a page from a user's perspective.
- Where possible, use canonical URLs.
- Redirect www.example.com to example.com, so there's exactly one URL per resource, and it's as lean as possible.
- Carefully consider access to pages, and don't restrict or allow access accidentally.
- Consider the appearance when printed. Is it clear? Clear URLs help users navigate confidently.
- Consider someone sharing a URL with a friend. Does it take the friend where they expect? Is anything lost?
- If someone has to provide instructions for navigating to a page on your website rather than just the URL of that page, you're doing it wrong.
- Meet users where they are when possible. Pave the cowpaths.
- If you want to change user behavior, do so cautiously. Consider using fun.
- Have fun if you want, but scrolling should always work as expected.
- No acceleration or interruptions.
Get in touch
We love hearing from others who are also excited about things like web standards and progressive enhancement.
Send us a message and let us know how to get back to you.