Commit a8d95d47 authored by adamjacobbecker's avatar adamjacobbecker

Improve accessibility (Section 508, WCAG)

This PR significantly improves Bootstrap's accessibility for users of assistive technology, such as screen readers. Some of the these changes add additional markup to the source examples, but we believe that the sacrifice in readability is worth achieving more widespread usage of accessibility best-practices.

What was done
- Added lots of [WAI-ARIA attributes](http://www.w3.org/WAI/intro/aria)
- Added `.sr-only` helper class, that is only readable by screen readers (and invisible for all other users). This lets us - make progress bars and paginations accessible to screen reading users.
- Advised users to always use label elements. For inline forms, they can hide them with `.sr-only`
- Added 'Skip navigation' link
- Added "Accessibility" section to getting-started.html.

What *wasn't* done
- Contrast issues (twbs#3572)
- Tooltips (twbs#8469)
- Documentation re: usage of icons, since they now live in a separate repo

Major props to all that contributed: @bensheldon, @jasonlally, @criscristina, and @louh. Feel free to chime in, guys, if I've left anything out.
parent d1e712d8
......@@ -17,6 +17,9 @@
<li>
<a href="#third-parties">Third party support</a>
</li>
<li>
<a href="#accessibility">Accessibility</a>
</li>
<li>
<a href="#license-faqs">License FAQs</a>
</li>
......
<div class="navbar navbar-inverse navbar-fixed-top bs-docs-nav">
<div class="navbar navbar-inverse navbar-fixed-top bs-docs-nav" role="navigation">
<div class="container">
<button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".bs-navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
......
<div class="bs-social">
<ul class="bs-social-buttons">
<li>
<iframe class="github-btn" src="http://ghbtns.com/github-btn.html?user=twbs&repo=bootstrap&type=watch&count=true" allowtransparency="true" frameborder="0" scrolling="0" width="100px" height="20px"></iframe>
<iframe class="github-btn" src="http://ghbtns.com/github-btn.html?user=twbs&repo=bootstrap&type=watch&count=true" allowtransparency="true" frameborder="0" scrolling="0" width="100px" height="20px" title="Star on GitHub"></iframe>
</li>
<li>
<iframe class="github-btn" src="http://ghbtns.com/github-btn.html?user=twbs&repo=bootstrap&type=fork&count=true" allowtransparency="true" frameborder="0" scrolling="0" width="102px" height="20px"></iframe>
<iframe class="github-btn" src="http://ghbtns.com/github-btn.html?user=twbs&repo=bootstrap&type=fork&count=true" allowtransparency="true" frameborder="0" scrolling="0" width="102px" height="20px" title="Fork on GitHub"></iframe>
</li>
<li class="follow-btn">
<a href="https://twitter.com/twbootstrap" class="twitter-follow-button" data-link-color="#0069D6" data-show-count="true">Follow @twbootstrap</a>
......
......@@ -6,12 +6,13 @@
<!-- Place anything custom after this. -->
</head>
<body data-spy="scroll" data-target=".bs-sidebar">
<a class="sr-only" href="#content">Skip navigation</a>
<!-- Docs master nav -->
{% include nav-main.html %}
<!-- Docs page layout -->
<div class="bs-header">
<div class="bs-header" id="content" role="banner">
<div class="container">
<h1>{{ page.title }}</h1>
<p>{{ page.lead }}</p>
......@@ -22,7 +23,7 @@
<!-- Callout for the old docs link -->
{% include old-bs-docs.html %}
<div class="bs-customize-placeholder">
<div class="bs-customize-placeholder" role="main">
<div class="container bs-docs-container">
<p class="lead">Until RC2, the Bootstrap 3 customizer will be disabled. In the mean time, snag the <a href="{{ site.repo }}/releases">compiled CSS and JavaScript</a>. Hang tight!</p>
</div>
......
......@@ -6,12 +6,13 @@
<!-- Place anything custom after this. -->
</head>
<body>
<a class="sr-only" href="#content">Skip navigation</a>
<!-- Docs master nav -->
{% include nav-main.html %}
<!-- Docs page layout -->
<div class="bs-header">
<div class="bs-header" id="content" role="banner">
<div class="container">
<h1>{{ page.title }}</h1>
<p>{{ page.lead }}</p>
......@@ -25,7 +26,7 @@
<div class="container bs-docs-container">
<div class="row">
<div class="col-lg-3">
<div class="bs-sidebar">
<div class="bs-sidebar" role="complementary">
<ul class="nav bs-sidenav">
{% if page.slug == "getting-started" %}
{% include nav-getting-started.html %}
......@@ -41,7 +42,7 @@
</ul>
</div>
</div>
<div class="col-lg-9">
<div class="col-lg-9" role="main">
{{ content }}
</div>
</div>
......@@ -50,7 +51,7 @@
<!-- Footer
================================================== -->
<footer class="bs-footer">
<footer class="bs-footer" role="contentinfo">
{% include social-buttons.html %}
<p>Designed and built with all the love in the world by <a href="http://twitter.com/mdo" target="_blank">@mdo</a> and <a href="http://twitter.com/fat" target="_blank">@fat</a>.</p>
......
......@@ -6,6 +6,7 @@
<!-- Place anything custom after this. -->
</head>
<body class="bs-docs-home">
<a class="sr-only" href="#content">Skip navigation</a>
<!-- Docs master nav -->
{% include nav-main.html %}
......@@ -16,7 +17,7 @@
<!-- Callout for the old docs link -->
{% include old-bs-docs.html %}
<div class="container">
<div class="container" role="contentinfo">
{% include social-buttons.html %}
<ul class="bs-masthead-links">
......
This diff is collapsed.
......@@ -1300,9 +1300,15 @@ For example, <code>&lt;section&gt;</code> should be wrapped as inline.
<h4>Requires custom widths</h4>
<p>Inputs, selects, and textareas are 100% wide by default in Bootstrap. To use the inline form, you'll have to set a width on the form controls used within.</p>
</div>
<div class="bs-callout bs-callout-danger">
<h4>Always add labels</h4>
<p>Screen readers will have trouble with your forms if you don't include a label for every input. For these inline forms, you can hide the labels using the <code>.sr-only</code> class.</p>
</div>
<form class="bs-example form-inline">
<input type="text" class="form-control" placeholder="Email">
<input type="password" class="form-control" placeholder="Password">
<label class="sr-only" for="exampleInputEmail">Email address</label>
<input type="text" class="form-control" id="exampleInputEmail" placeholder="Enter email">
<label class="sr-only" for="exampleInputPassword">Password</label>
<input type="password" class="form-control" id="exampleInputPassword" placeholder="Password">
<div class="checkbox">
<label>
<input type="checkbox"> Remember me
......@@ -1312,8 +1318,10 @@ For example, <code>&lt;section&gt;</code> should be wrapped as inline.
</form><!-- /example -->
{% highlight html %}
<form class="form-inline">
<input type="text" class="form-control" placeholder="Email">
<input type="password" class="form-control" placeholder="Password">
<label class="sr-only" for="exampleInputEmail">Email address</label>
<input type="text" class="form-control" id="exampleInputEmail" placeholder="Enter email">
<label class="sr-only" for="exampleInputPassword">Password</label>
<input type="password" class="form-control" id="exampleInputPassword" placeholder="Password">
<div class="checkbox">
<label>
<input type="checkbox"> Remember me
......@@ -1985,6 +1993,12 @@ For example, <code>&lt;section&gt;</code> should be wrapped as inline.
.element {
.clearfix();
}
{% endhighlight %}
<h3>.sr-only</h3>
<p>Hide an element to all users <em>except</em> screen readers. Necessary for following <a href="{{ page.base_url }}getting-started#accessibility">accessibility best practices</a>.</p>
{% highlight html %}
<a class="sr-only" href="#content">Skip to content</a>
{% endhighlight %}
</div>
......
......@@ -356,6 +356,17 @@ hr {
border-top: 1px solid #eeeeee;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0 0 0 0);
border: 0;
}
p {
margin: 0 0 10px;
}
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -206,6 +206,39 @@ img { max-width: none; }
<!-- Accessibility
================================================== -->
<div class="bs-docs-section">
<div class="page-header">
<h1 id="accessibility">Accessibility</h1>
</div>
<p class="lead">Bootstrap follows common web standards, and with minimal extra effort, can be used to create sites that are accessibile to users using assistive technology (AT). However, it's useful to take the following into consideration:</p>
<p>If your navigation contains many links and comes before your main content in the DOM, add a <code>Skip to content</code> link immediately after your opening <code>body</code> tag. <a href="http://a11yproject.com/posts/skip-nav-links/">(read why)</a></p>
{% highlight html %}
<body>
<a href="#content" class="sr-only">Skip to content</a>
...
<div class="container" id="content">
The main page content.
</div>
...
</body>
{% endhighlight %}
<p>Another "gotcha" has to do with how you nest your <code>header</code> elements. <a href="http://squizlabs.github.io/HTML_CodeSniffer/Standards/Section508/">Section 508</a> states that your largest header must be an <code>h1</code>, and the next header must be an <code>h2</code>, etc. This is hard to achieve in practice, but if the largest header on your site is smaller than Bootstrap's default 38px, you should consider modifying your stylesheets before using a smaller header element.</p>
<h4>Resources</h4>
<ul>
<li><a href="https://github.com/squizlabs/HTML_CodeSniffer">"HTML Codesniffer" bookmarklet for identifying accessibility issues</a></li>
<li><a href="http://a11yproject.com/">The A11Y Project</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Accessibility">MDN accessibility documentation</a></li>
</ul>
</div>
<!-- License FAQs
================================================== -->
......
......@@ -4,7 +4,7 @@ title: Bootstrap
base_url: "./"
---
<div class="bs-masthead">
<div class="bs-masthead" id="content" role="main">
<div class="container">
<h1>Bootstrap 3</h1>
<p class="lead">Sleek, intuitive, and powerful mobile-first front-end framework for faster and easier web development.</p>
......
......@@ -196,7 +196,7 @@ $('#myModal').on('show.bs.modal', function (e) {
<a data-toggle="modal" href="#myModal" class="btn btn-primary btn-lg">Launch demo modal</a>
<!-- Modal -->
<div class="modal fade" id="myModal">
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
......@@ -215,6 +215,17 @@ $('#myModal').on('show.bs.modal', function (e) {
</div><!-- /.modal -->
{% endhighlight %}
<div class="bs-callout bs-callout-warning">
<h4>Make modals accessible</h4>
<p>
Be sure to add <code>role="dialog"</code> to your primary modal div. In the example above, <code>div#myModal</code>.<br>
Also, the <code>aria-labelledby</code> attribute references your modal title. In this example, <code>h4#myModalLabel</code>.<br>
Finally, <code>aria-hidden="true"</code> tells assistive technologies to skip DOM elements.<br>
Additionally, you may give a description of your modal dialog. Use the <code>aria-describedby</code> attribute in the modal's primary <code>&lt;div&gt;</code> to point to this description (this is not shown in the above example).
</p>
</div>
<h2 id="modals-usage">Usage</h2>
<h3>Via data attributes</h3>
......@@ -344,10 +355,11 @@ $('#myModal').on('hidden.bs.modal', function () {
<h3>Within a navbar</h3>
<div class="bs-example">
<div id="navbar-example" class="navbar navbar-static">
<div id="navbar-example" class="navbar navbar-static" role="navigation">
<div class="container" style="width: auto;">
<a class="navbar-brand" href="#">Project Name</a>
<button class="navbar-toggle" type="button" data-toggle="collapse" data-target=".bs-js-navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
......@@ -481,7 +493,7 @@ $('.dropdown-toggle').dropdown()
<h2 id="scrollspy-examples">Example in navbar</h2>
<p>The ScrollSpy plugin is for automatically updating nav targets based on scroll position. Scroll the area below the navbar and watch the active class change. The dropdown sub items will be highlighted as well.</p>
<div class="bs-example">
<div id="navbar-example2" class="navbar navbar-static">
<div id="navbar-example2" class="navbar navbar-static" role="navigation">
<div class="navbar-inner">
<div class="container" style="width: auto;">
<a class="navbar-brand" href="#">Project Name</a>
......@@ -1671,6 +1683,10 @@ $('#myCollapsible').on('hidden.bs.collapse', function () {
</div>
{% endhighlight %}
<div class="bs-callout bs-callout-danger">
<h4>Accessibility issue</h4>
<p>The carousel component is generally not compliant with accessibility standards. If you need to be compliant, please consider other options for presenting your content.</p>
</div>
<h2 id="carousel-usage">Usage</h2>
......
......@@ -93,3 +93,17 @@ hr {
border-top: 1px solid @hr-border;
}
// Only display content to screen readers
// See: http://a11yproject.com/posts/how-to-hide-content/
// -------------------------
.sr-only {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment