Accessibility & Performance

Bootstrap 3 gets you a working, responsive TrailMap fast — but "it renders on every screen size" isn't the same as "everyone can actually use it," and "it loads" isn't the same as "it loads fast." This lesson covers both in one pass: the accessibility work Bootstrap does not do for you, and the real performance cost of the bundle you're shipping.

Part 1: Accessibility — What Bootstrap Bakes In

Some accessibility behavior ships with Bootstrap's components already. The Modal plugin, for example, renders with role="dialog" out of the box:

<div class="modal fade" id="trailModal" role="dialog" aria-labelledby="trailModalLabel">
  ...
</div>

That's a real head start, but it only covers the components you didn't hand-build yourself. Anything you assemble from raw markup — a Glyphicon-only button, an icon used purely for decoration — needs the ARIA attributes added by hand.

aria-hidden on Decorative Glyphicons

A Glyphicon is just a font character rendered through a <span>. When it carries no meaning on its own — it's sitting next to text that already says the same thing — screen readers shouldn't announce it at all. Mark it aria-hidden="true":

<!-- decorative: the button already says "Search Trails" -->
<button class="btn btn-primary">
  <span class="glyphicon glyphicon-search" aria-hidden="true"></span>
  Search Trails
</button>

.sr-only for Icon-Only Buttons

When the button has no visible text — just an icon, to save space — the Glyphicon is now the only clue to what the button does, so it can't be hidden. Instead, pair aria-hidden="true" on the icon with a .sr-only span that gives screen readers a real label:

<!-- icon-only: needs a screen-reader-only label -->
<button type="button" class="btn btn-default">
  <span class="glyphicon glyphicon-heart" aria-hidden="true"></span>
  <span class="sr-only">Save trail to favorites</span>
</button>
How .sr-only works: it doesn't use display:none (that would hide it from screen readers too). It positions the text off-screen with an absolute position and a 1px clip, so it stays in the accessibility tree while being invisible to sighted users.

Still Your Job: Focus, Contrast, Alt Text, Heading Order

None of Bootstrap's baked-in roles cover these — they depend on the actual content and design choices you make, so the framework can't do them for you:

ConcernWhat you have to do
Focus statesDon't strip Bootstrap's default focus outline with a blanket outline:none override — keyboard users need to see where focus is
Color contrastA custom @brand-primary (see the LESS Customization lesson) can look great and still fail WCAG contrast against white text — check the ratio after every recolor
Meaningful alt textA trail photo's alt should describe the trail ("Sunrise Ridge summit view"), not restate the filename or say "image"
Logical heading orderDon't skip from <h1> to <h4> because it "looked right" visually — screen reader users navigate by heading level

TrailMap Audit: The Navbar's Toggle Button

Revisit the collapsed navbar toggle from the earlier Navbar lesson. The three stacked bars are pure decoration — the button already needs a text label for anyone who can't see the icon-bars at all:

<!-- before: icon-bars with no accessible label -->
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#trailNavbar">
  <span class="icon-bar"></span>
  <span class="icon-bar"></span>
  <span class="icon-bar"></span>
</button>

<!-- after: aria-hidden on the bars, sr-only label on the button -->
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#trailNavbar">
  <span class="sr-only">Toggle navigation</span>
  <span class="icon-bar" aria-hidden="true"></span>
  <span class="icon-bar" aria-hidden="true"></span>
  <span class="icon-bar" aria-hidden="true"></span>
</button>
Audit result: this is actually the standard markup Bootstrap 3's own docs recommend for the navbar toggle — worth checking any TrailMap navbar you copy from an older example against this exact pattern, since it's easy to drop the .sr-only span when trimming markup down.

Part 2: Performance — What the Full Bundle Actually Costs

The CDN links at the top of every page in this track load the entire framework: all of bootstrap.min.css, all of bootstrap.min.js, and (if you add it) the full Glyphicons icon font — dozens of glyphs you'll never reference, shipped to every visitor regardless.

Full CDN bundleTrimmed custom LESS build
Every component's CSS, used or not (grid, all button variants, carousel, affix, tooltips...)Import only the LESS mixins/components TrailMap actually uses via @import in your own file
Full Glyphicons font file, for maybe 6 icons in useSubset the icon font, or skip Glyphicons for components that don't need them
All jQuery plugins bundled together in one bootstrap.min.jsBootstrap 3's individual plugin files can be concatenated selectively if you're not using, say, Affix or Carousel

The other lever is your own CSS: every override you write on top of Bootstrap is extra weight the browser has to parse in addition to the framework's rules. Fewer, more targeted overrides (or better — LESS variable changes that need no override CSS at all) keep the page's total stylesheet size down.

Up next: Every Bootstrap-3-specific pattern flagged across this whole track — LESS, Glyphicons, col-xs-*, Panels/Wells/Thumbnails, Affix, and more — gets pulled into one migration checklist in Migrating to Bootstrap 4.