At 10up, we aim to create the best possible experience for both our clients and their customers; not for the sake of using cool, bleeding edge technologies that may not have widespread browser support. Our markup embodies this approach.
Markup is intended to define the structure and outline of a document and to offer semantic structure for the document’s contents. Markup should not define the look and feel of the content on the page beyond the most basic structural concepts such as headers, paragraphs, and lists.
At 10up, we employ progressive enhancement to ensure that the sites we build for our clients are accessible to as many users as possible.
Progressive enhancement means building a website that is robust, fault tolerant, and accessible. Progressive enhancement begins with a baseline experience and builds out from there, adding features for browsers that support them. It does not require us to select supported browsers or revert to table-based layouts. Baselines for browser and device support are set on a project-by-project basis.
It’s important that our clients and their customers are able to use the products that we create for them. Accessibility means creating a web that is accessible to all people: those with disabilities and those without. We must think about people with visual, auditory, physical, speech, cognitive and neurological disabilities and ensure that we deliver the best experience we possibly can to everyone. Accessibility best practices also make content more easily digestible by search engines. Increasingly, basic accessibility can even be a legal requirement. In all cases, an accessible web benefits everyone.
At a minimum, all 10up projects should pass WCAG 2.1 Level A Standards. A baseline compliance goal of Level A is due to WCAG guideline 1.4.3 which requires a minimum contrast ratio on text and images, as 10up does not always control the design of a project.
For design projects and projects with a global marketplace (companies with entities outside the US), Level AA should be the baseline goal. The accessibility level is elevated for global markets to properly comply with EU Functional Accessibility Requirements, which aligns closely with WCAG 2.0 Level AA. Having direct access to the designer also allows for greater accessibility standards to be achieved.
While Section 508 is the US standard, following the guidance of WCAG 2.0 will help a project pass Section 508 and also maintain a consistent internal standard. If a project specifically requires Section 508, additional confirmation testing can be done.
ARIA also allows us to describe certain inherent properties of elements, as well as their various states. Imagine you’ve designed a site where the main content area is split into three tabs. When the user first visits the site, the first tab will be the primary one, but how does a screen reader get to the second tab? How does it know which tab is active? How does it know which element is a tab in the first place?
ARIA attributes can be added dynamically with JavaScript to help add context to your content. Thinking about the tabbed content example, it might look something like this:
<ul role="tablist">
<li role="presentation">
<a href="#first-tab" role="tab" aria-selected="true" id="tab-panel-1">Panel 1</a>
</li>
<li role="presentation">
<a href="#second-tab" role="tab" aria-selected="false" id="tab-panel-2">Panel 2</a>
</li>
</ul>
<div role="tabpanel" aria-hidden="false" aria-labelledby="tab-panel-1">
<h2 id="first-tab">Tab Panel Heading</h2>
</div>
<div role="tabpanel" aria-hidden="true" aria-labelledby="tab-panel-2">
<h2 id="second-tab">Second Tab Panel Heading</h2>
</div>
You can see how effortless it is to make our tabbed interface accessible to screen readers. Be sure to add visibility attributes like aria-hidden
with JavaScript. If it is added manually in HTML and JavaScript doesn’t load, the content will be completely removed from screen readers.
Forms are one of the biggest challenges when it comes to accessibility. Fortunately, there are a few key things that we can do to ensure they meet accessibility standards:
Each form field should have its own <label>
. The label element, along with the for
attribute, can help explicitly associate a label to a form element adding readability for screen readers and assistive technology.
Form elements should also be logically grouped using the <fieldset>
element. Grouped form elements can be helpful for users who depend on screen readers or those with cognitive disabilities.
Finally, we should ensure that all interactive elements are keyboard navigable, providing easy use for people with vision or mobility disabilities (or those not able to use a mouse). In general, the tab order should be dictated by a logical source order of elements. If you feel the need to change the tab order of certain elements, it likely indicates that you should rework the markup to flow in a logical order or have a conversation with the designer about updates that can be made to the layout to improve accessibility.
Bypass blocks are HTML flags within a document that allow users that rely on screen readers, keyboard navigation or other assistive technologies to bypass certain page elements or skip to a specific section of a page with ease. They most often manifest themselves in the form of skip links and ARIA landmark roles
Skip links are ideally placed immediately inside of the <body>
tag so that they are discovered and announced as early as possible.
While these links are often used to skip to a page’s main content section they can link to different sections of the page if necessary and several links can be added if multiple areas of interest are in the page.
An example of what a skip link might look like in a template file:
<a class="skip-link screen-reader-text" href="#main">
<?php esc_html_e( 'Skip to content', 'my-domain' ); ?>
</a>
Skip links make use of CSS to hide them from sighted users while keeping them accessible for screen readers. Usually the styles are attached to a screen-reader-text
class of some kind. This CSS is used to position the links off the screen then use :focus
styles to make the link visible for sighted keyboard users.
Due to some browsers not moving keyboard focus when they move visual focus, it is essential to also enhance this feature with JavaScript. The popular Underscores starter theme came bundled with a good option that can be used as a starting point if you need to support browsers with this issue.
ARIA is a descriptive layer on top of HTML to be used by screen readers. It has no effect on how elements are displayed or behave in browsers. We use these ARIA Landmark Roles (banner, navigation, main, etc.) to provide a better experience to users with disabilities. Landmark role are another type of bypass block. Screen readers can see these as major document regions and navigate to them directly without having to parse through all the content in between.
Landmark roles should be used with skip links (not instead of), so we can be sure and offer support for older assistive technology platforms that may not yet support the specification.
Example:
<header role="banner">
{ Site Banner }
<nav role="navigation">{ Main Navigation }</nav>
</header>
<main role="main">{ Main content }</main>
<footer role="contentinfo">{ Site Footer }</footer>
In most cases, maintaining baseline accessibility requirements for a project can be an automated process. While we can’t test everything, and we still need some manual testing, there are certain tools that allow us to keep our finger on the pulse of a project’s accessibility compliance.
Automating accessibility tests is easy with a tool like pa11y, which is a command line tool that runs HTML Code Sniffer over a URL.
It is easily installed through npm: npm install pa11y --save-dev
and can be added into a package.json
file as a separate npm script as to not collide with other build processes that may be running on a project:
"scripts": {
"pa11y": "pa11y --ignore notice https://projectname.test"
},
Running this process allows the engineer to be alerted if a code-level or design change violates the project’s accessibility standards.
Automated testing will often only get you so far; that is why we also recommend getting a human’s eye on the accessibility in a project and executing manual tests alongside any automation. This process is largely done by an engineer reviewing the interface in a browser or screen reader and involves running your project through all of the WCAG guidelines at the compliance level that is applicable to your specific project (A, AA, or AAA). The WCAG Quickref is a great place to see all these guidelines in one place. Internally, we also have a spreadsheet template to help manage this process.
Manual accessibility testing should be run in conjunction with automated testing to help identify all the potential areas of improvement on a project as well as resolve false-positives that may appear during the automated testing process. Tests should be run on a reasonable sample size of templates to help produce the most comprehensive analysis possible - preferably the same templates used in the automated testing process.
Combining automated and manual testing practices allows 10up to maintain a high level of compliance on all projects and it is critical to the work we do.
At 10up, we pride ourselves in writing clean, semantic markup. Semantic markup can be defined as: “the use of HTML markup to reinforce the semantics, or meaning, of the information in web pages rather than merely to define it’s presentation or look. Semantic HTML is processed by traditional web browsers as well as by many other user agents. CSS is used to suggest its presentation to human users” (definition from Wikipedia -https://en.wikipedia.org/wiki/Semantic_HTML).
Semantic elements are elements with clearly defined meaning to both the browser and the developer. Elements like <header>
, <nav>
, <footer>
, or <article>
do a much better job of explaining the content that is contained within the element than <span>
or <div>
. This does not mean that we do not use <div>
s in our markup, only that we prefer the right tool (or in this case semantic element) for the job.
Websites should be written using the least amount of markup that accomplishes the goal. In the interest of engineering maintainable projects, it’s imperative that two completely different types of readers are accounted for: humans and browsers. Writing minimal markup makes it easier for developers to read and understand in a code editor. Valid markup is easier for browsers to process.
We test our markup against the W3C validator to ensure that it is well formed and provides a fairly consistent experience across browsers.
At 10up, we often work with large codebases. As such, it’s important to optimize markup for human readability. This allows developers to quickly rotate in and out of projects, eases onboarding processes, and improves code maintainability.
Always use tabs for indentation. Doing this allows developers to set their editor preferences for tab width.
When mixing PHP and HTML together, indent PHP blocks to match the surrounding HTML code. Closing PHP blocks should match the same indentation level as the opening block. Similarly, keep PHP blocks to a minimum inside markup. Doing this turns the PHP blocks into a type of tag themselves. Use colon syntax for PHP loops and conditionals so that it’s easier to see when a certain loop ends within the block of markup.
Bad:
<ul>
<?php
foreach( $things as $thing ) {
echo '<li>' . esc_html( $thing ) . '</li>';
}
?>
</ul>
Good:
<ul>
<?php foreach( $things as $thing ) : ?>
<li><?php echo esc_html( $thing ); ?></li>
<?php endforeach; ?>
</ul>
As part of our mission to write clean, semantic markup, avoid writing unnecessary presentational markup. Markup should always dictate what the content is, and CSS should dictate how the content looks. Mixing these two concerns makes maintaining code more difficult.
This is not to say that multiple classes on an element are unacceptable. Contextual modifier classes are certainly acceptable and encouraged.
Schema.org is the result of collaboration between Google, Bing, Yandex, and Yahoo! to provide the information their search engines need to understand content and provide the best search results possible. Adding Schema.org data to your HTML provides search engines with structured data they can use to improve the way pages display in search results.
For example, if you’ve ever searched for a restaurant and found that it had star reviews in its search results, this is a product of Schema.org and rich snippets.
Schema.org data is intended to tell the search engines what your data means, not just what it says.
To this end, we use Schema.org data where relevant and reasonable to ensure that our clients have the best search visibility that we can provide.
Schema.org data can be provided in two forms: “microdata” markup added to a page’s structure or a JSON-LD format. Google prefers developers adopt JSON-LD, which isolates the data provided for search engines from the markup meant for user agents. Even though the JSON-LD spec allows linking to data in an external file, search engines currently only parse JSON-LD data when it appears within a <script type="application/ld+json">
tag, as shown below.
Schema.org markup should be validated against the Google Structured Data Testing Tool.
For examples of Schema markup on components, check out the 10up WordPress Component Library
In order to create more maintainable projects, developers should use classes for CSS and IDs for JavaScript. Separating concerns allows markup to be more flexible without risking breaking both styles and any JavaScript that may be attached to the element on which someone is working.
When using JavaScript to target specific elements in your markup, prefix the ID of the element that is being targeted with js-
. This indicates the element is being targeted by JavaScript for your future self as well as other developers that may work on the project.
When writing markup that does not have wide browser support, using polyfills can help bring that functionality to those older browsers. Providing support for older browsers is incredibly important to the business objectives of our clients. In an effort to prevent code bloat, we only provide polyfills for features that are functionally critical to a site.
At 10up, the concept of feature detection is used to test browser support for new features that do not yet have full support across the board. The concept of feature detection is to test if a feature is supported by the browser and if not supported, conditionality run code to provide a similar experience with browsers that do support the feature. While popular feature detection libraries exist, there are feature detection techniques for JavaScript and @supports at-rule for CSS that can be utilized.
If accessibility starts with HTML, media is how we make it come alive. Creating accessible media is not only the responsibility of an editorial team, but it is our responsibility as engineers to ensure the systems we put in place promote and support the creation of accessible media. It can generally be put into three buckets: images, audio, and video. When looking for direction in these areas we turn to the rules laid out by the Web Content Accessibility Guidelines (WCAG).
To read more about any of the guidelines outlined in this section, please visit the WCAG quickref document. Some of the more aggressive guidelines in Level AAA are not mentioned here. Be sure to check with your project lead about the accessibility compliance level you need to follow.
Images are the most common form of media we encounter in our day to day work. WCAG guidelines pertaining to images are: 1.1.1 Non-text content and 1.4.4 Images of text. Following these two rules will ensure that our images always have alternative text and any time text is represented in an image there is always a purely text-based version of it available for users of assistive technology.
Between audio and video, we certainly deal with video more often, but there are some WCAG guidelines that encompass both, such as: 1.2.2 Audio/Video-only and 1.2.3 Audio Descriptions or Media Alternative. Both these guidelines address the creation of text-based versions of the media being presented to a user. This typically comes in the form of an audio track on a video, or a transcript outputted on the page somewhere. As an aside, outputting a transcript will help the content get indexed by search engines, rather than just having the content inside a media element (audio/video)
Audio is an important part of the work we do; making that content accessible to all users is extremely valuable. Guideline 1.4.1 Audio Control is related to autoplaying audio. The general rule is: don’t autoplay audio. However, if you do, and that audio is playing for more than three seconds, 1.4.1 states that either a mechanism must be available to pause or stop the audio, or a mechanism must be available to control audio volume independently from the overall system volume level. This is important for any user with an auditory disorder.
When putting video on the Web (that contains dialog), guideline 1.2.2 states that captions must be present, without exception. While we can’t always control the content that’s placed on a site, we can be sure to guide clients towards a situation for compliance by suggesting transcription services. Other than alternative text, dealing with captions is the most common media accessibility issue you’ll likely have to deal with.
SVG has become a prevalent means for displaying rich vector graphics. SVG images are great for graphics with well-defined lines and simple color palettes that can be defined algorithmically, e.g. logos, iconography, and illustrations. Here are a few known benefits of SVG:
Be mindful that SVGs have potential limitations as well:
Combining SVG images in a single file (usually called svg-defs.svg
) has the benefit of helping limit HTTP requests within a document that contains multiple icons. An SVG sprite file can be embedded within a document and referenced within the template source with a <use>
element. The creation of this icon system should be automated through your build process. Read Icon Systems with SVG Sprites for more information.
When placing an SVG in markup (i.e. inline) be sure to use the following guidelines:
alt=""
can be used: <img alt="">
, or<svg aria-hidden="true">
If the SVG is meaningful then use <title>
and possibly even <desc>
or aria-label
to describe the graphic. Also, be sure to add an id
to each element, and appropriate ARIA to overcome a known bug in Chrome and Firefox.
<!-- role="img" to exclude image from being traversed by certain browsers w/ group role -->
<svg role="img" aria-labelledby="uniqueTitleID uniqueDescID">
<title id="uniqueTitleID">The Title</title>
<desc id="uniqueDescID">Description goes here...</desc>
</svg>
Use aria-label
if the SVG is linked and has no supporting text.
<a href="http://twitter.com/10up" aria-label="Follow 10up on Twitter">
<svg><use xlink:href="#icon-twitter"></use></svg>
</a>
Many tools for creating SVG are notorious for including unnecessary markup. We recommend running all SVG through SVGO(MG) or using tooling, like gulp-svgmin