Cloud Four Blog

Technical notes, War stories and anecdotes

A Responsive Guide to Type Sizing

When starting new projects, a CSS builder’s initial concerns tend to involve typography. Setting a typographic foundation with the right mixture of ingredients can form something solid enough to support many other building blocks of design. It’s an approach that makes structural sense.

Proportions are a key ingredient to the mixture. Calibrating your type proportions for a balance of aesthetics and order can be an obsessive undertaking. It’s a challenge getting proportions right for a given screen size, let alone any possible screen size. This process can be less challenging — even for responsive designs — if you use a modular scale and let math do the work for you.

Using a modular scale for typographic proportions

In his detailed article on the subject, Tim Brown demonstrates using a modular scale for composing type. He explains how compositions can benefit from using numbers that relate to each other in a meaningful way:

Modular scales[…] help us achieve a visual harmony not found in compositions that use arbitrary, conventional, or easily divisible numbers.

This modulation-based approach is particularly useful for determining type sizes. Selecting sizes using a ratio (instead of guessing) yields a more harmonious range of proportions.

With tools like this indispensable calculator, you can see how different bases and ratios affect your scale. These are the variables in your scale’s equation. The value produced by multiplying or dividing these variables is a step on your scale. Repeating the operation on each resulting value forms a new step:

Step Math Result
+3  40 × 2 80   
+2  20 × 2 40   
+1  10 × 2 20   
 0  none 10   
−1  10 ÷ 2  5   
−2   5 ÷ 2  2.5 
−3 2.5 ÷ 2  1.25
Example with a base of 10 and a ratio of 2

You can also associate each step in the sequence with the number of times the ratio has been multiplied or divided:

Step Math Result
+3 10 × 2 × 2 × 2 80   
+2 10 × 2 × 2     40   
+1 10 × 2         20   
 0 none 10   
−1 10 ÷ 2          5   
−2 10 ÷ 2 ÷ 2      2.5 
−3 10 ÷ 2 ÷ 2 ÷ 2  1.25

Experimenting with base and ratio parameters is a quick way to gauge how much proportional contrast is right for your project. Compare the following scales:

Due to their ratios, these scales have wildly differing degrees of change between each step. The “golden section” ratio yields much more change than the “minor third”. Consider how much change you’re likely to need, and how it correlates with varying screen sizes and content hierarchy.

Comparing two scale ratios

Scales with the ratios of 1.618 and 1.2 compared on modularscale.com

The balance of typographic contrast in scale is dependent on screen size. A scale that works well on a large screen may have too much contrast for a small screen (and feel obtrusive). Likewise, a scale that is harmonious on a small screen may be too subtle when viewed on a large screen.

One solution to this conundrum is to create a scale intended for small screens that is also capable of adapting for large ones. The first thing to consider when creating that scale is which ratio to use.

Step Font size Result
 0   1.0em
Abcdefg
+1   1.2em
Abcdefg
+2  1.44em
Abcdefg
+3 1.728em
Abcdefg
+4 2.074em
Abcdefg
+5 2.488em
Abcdefg
The minor third ratio (1.2) with a base of 1em

The minor third ratio of 1.2 yields a gradually changing range of sizes. They all feel reasonable for small screens, and are distinct enough for levels of typographic hierarchy. At step #5, the resulting size can still be used while retaining a reasonable number of characters per line. With these attributes, this ratio feels like a good selection for small screen proportions.1

Applying your scale from the ground up

After figuring out a scale that works well for your project, you’ll probably want to put it into practice. CSS offers a few options:

  1. Copying and pasting numbers for a bunch of property values
  2. Using preprocessors like Sass with built-in math capabilities
  3. Using the native CSS calc() function

The following examples employ option #3, using PostCSS in order to provide browser support for calc() and var(). If you prefer a different CSS processor, you can apply the same operations with that tool’s own arithmetic and variable syntax.2

For more complex modular scale applications, you should check out these plugins available for PostCSS and Sass:

They provide a cleaner syntax than calc() for getting scale values, and also support multiple values for base and ratio.

Configuring the variables

The first step is to define values for the ratio and base variables that much of the scale logic depends on:

:root {
  --ratio: 1.2;
  --base: 1;
  --base-em: calc(var(--base) * 1em);
  --base-px: calc(var(--base) * 16px);
}

There are three base-related properties defined here. This is to provide flexibility when different CSS units (or no units) are needed.

Next, you need to establish the range of scale steps you’re likely to use:

:root {
  --ms0: 1;
  --ms1: var(--ratio);                    /* 1.2   */
  --ms2: calc(var(--ratio) * var(--ms1)); /* 1.44  */
  --ms3: calc(var(--ratio) * var(--ms2)); /* 1.728 */
  --ms4: calc(var(--ratio) * var(--ms3)); /* 2.074 */
  --ms5: calc(var(--ratio) * var(--ms4)); /* 2.488 */
  --ms6: calc(var(--ratio) * var(--ms5)); /* 2.986 */
  --ms7: calc(var(--ratio) * var(--ms6)); /* 3.583 */
}

With these step properties defined, you can now compute them with your base to get values from your scale:

font-size: calc(var(--base-em) * var(--ms1)); /* 1.2em  */
font-size: calc(var(--base-em) * var(--ms2)); /* 1.44em */

Establishing default sizes

The browser default font-size paired with the scale step of 1.44 for line-height feels like an appropriate choice for body copy:

body {
  font-size: calc(var(--base-em) * var(--ms0));
  line-height: calc(var(--base) * var(--ms2));
}

Headings probably don’t need to consist of six different sizes (as there are other ways to differentiate them). However, if you do wish to incorporate a different size for each, you can use a series of steps from your scale:

h6 { font-size: calc(var(--base-em) / var(--ms1)); }
h5 { font-size: calc(var(--base-em) * var(--ms0)); }
h4 { font-size: calc(var(--base-em) * var(--ms1)); }
h3 { font-size: calc(var(--base-em) * var(--ms2)); }
h2 { font-size: calc(var(--base-em) * var(--ms3)); }
h1 { font-size: calc(var(--base-em) * var(--ms4)); }

In addition to heading font-size, you should also consider the values for line-height.

Using a lower step of the scale in this case can benefit readability when lines are wrapping:

h3, 
h2 { line-height: calc(var(--base) * var(--ms1)); }
h1 { line-height: calc(var(--base) * var(--ms0)); }

With these defaults for body copy and headings in place, you have a nice foundational hierarchy that works well on small screens:

Ratio of 1.2 on a small screen

A scale with a ratio of 1.2 applied to content on a 320×480 screen

Expanding your scale when proportional contrast is needed

Increasing screen sizes and viewing distances will reveal new typographic requirements for your layout. Your body copy and the contrast in scale of all typographic elements will likely need adjustments to suit the new context:

@media (min-width: 480px) {
  html { font-size: calc(var(--base-px) * var(--ms1)); }
}

Bumping the global font size like this is a practical adjustment that requires little effort. While this practice is common, it’s worth noting that even small tweaks like this can leverage steps from your modular scale. Rather than incrementing the size by an arbitrary few pixels or a percentage, you can use your scale to determine the new value.

In line with amplifying your body copy, you might also want to increase the amount of change between each heading size. You can do this by overriding the larger headings with sizes from higher up your scale:

@media (min-width: 768px) {
  h3 { font-size: calc(var(--base-em) * var(--ms3)); }
  h2 { font-size: calc(var(--base-em) * var(--ms4)); }
  h1 { font-size: calc(var(--base-em) * var(--ms5)); }
}
 
@media (min-width: 1024px) {
  h2 { font-size: calc(var(--base-em) * var(--ms5)); }
  h1 { font-size: calc(var(--base-em) * var(--ms6)); }
}
 
@media (min-width: 1360px) {
  h1 { font-size: calc(var(--base-em) * var(--ms7)); }
}

With these size adjustments in place, viewport width will determine how far up the scale your headings are allowed to climb:

(View the full CodePen to see how the text size responds.)

Broadening the usage of your scale

Limiting your scale’s influence to just specific elements would be highly illogical. You want flexible, abstracted styles to build complex interfaces with. Utility classes can provide that flexibility:

.u-textBigger { 
  font-size: calc(var(--base-em) * var(--ms1)); 
}
 
.u-textSmaller { 
  font-size: calc(var(--base-em) / var(--ms1)); 
}

With one ratio relating all the text sizes, anything affected by these classes will adhere to the steps of your scale. Even when combining or nesting the classes, the resulting text will remain in relative proportion:

<div class="u-textBigger">
  <h2>Now I'm as big as an H1</h2>
  <h3>Now I'm as big as an H2</h3>
  <p class="u-textSmaller">I haven't changed at all.</p>
</div>
 
<div class="u-textSmaller">
  <div class="u-textSmaller">
    <div class="u-textBigger">
      <span class="u-textBigger">Same as it ever was.</span>
    </div>
  </div>
</div>

TL;DR

  • Use a modular scale to define your typographic proportions.
  • Create a scale that is flexible enough to work on many screen sizes.
  • Use higher steps from your scale when more proportional contrast is needed.
  • Don’t limit the use of your scale to specific elements.

Further reading


Footnotes
  1. Using one base and one ratio isn’t the only way to arrive at a scale that works within small screen limitations. You can also create a multi-stranded scale by using multiple base or ratio values instead of just one. Here is an example using a secondary base value to shorten the distance between each step. See modularscale.com for a better explanation.
  2. The postcss-cssnext plugin can be used to transform the output of calc() and var().

Dare to Repeat Yourself (At First)

It was mid-afternoon on a Wednesday when my team started finding strange bugs in older versions of Internet Explorer. At first these appeared to be unrelated… until we noticed seemingly random chunks of style appeared to be missing entirely. What was going on?

After some digging, we found the issue: Our project had exceeded old IE’s infamous CSS selector limit. Weeks prior, I’d lost an argument to resist including a sizable framework in the project. Mentally, I was already patting myself on the back. “I told you so,” I practiced saying in my own head.

Then I looked at the compiled CSS, and realized it was actually my fault.

Whoops.

I’d designed a custom interface element that was pretty complex. Because we were using Sass, I used some fancy mixins and loops to avoid repetition between a handful of breakpoint-specific modifiers. It was easy to read, maintain and modify.

It was so easy, in fact, that I failed to notice that the compiled CSS made up about 25% of the total project’s styles! Even more embarrassingly, I discovered that I could replicate the exact same functionality without most of the loops. I ended up reducing the selector count for that component from 1,207 to just 42 (seriously).

While it was great to find and fix the problem, it shook me up a little. Sass didn’t write crap code; I did. I was so focused on automating my repetitive solution that I hadn’t stopped to ask myself if it was even the right solution.

We recently started using PostCSS for a few of our projects. Every PostCSS feature is a plugin, which we include as needed. So far, we’ve yet to include plugins for nesting, mixins or loops.

Every time we’ve thought to include those features, we’ve instead found a simpler way to do the same thing. Nesting gives way to descendent class names, mixins become utilities, loops are questioned entirely. The initial pain of having to repeat ourselves motivates us to approach the problem in a different way. Repetitive selectors that survive this process are intentional, because a human being actually wrote them.

I know that’s probably silly. It’s definitely not DRY. But there’s a fine line between “smarter stylesheets” and “dumber designer.” Embracing painful repetition by nerfing my preprocessor (especially in combination with analysis tools like Parker) helps me draw that line.

Shifty Tile Flyouts

Although my favorite projects will always be those that allow us to re-evaluate a user experience from the ground up, sometimes that isn’t realistic. That’s where Responsive Retrofitting comes in: The process of making small, surgical changes to existing interfaces to improve the small-screen experience incrementally.

Each and every retrofit is a little different, but patterns do emerge. In the past couple of years, I’ve noticed one particularly challenging bit of UI that’s cropped up multiple times for multiple clients.

Illustration of tile-based interface with flyout

Here’s how it works: We have tiles separated into rows and columns. Each tile represents some form of summary content; contact info or payment options, for example. Selecting a tile (or clicking an “edit” button therein) expands a flyout below with some sort of form content, which spans the entire available width and “pushes” down any tiles below.

Every time I’ve encountered this, it’s been implemented in the same way. Because the design is fixed-width, the number of columns in each row is predictable. Flyout elements are simply inserted between rows:

<div class="Tiles">
  <div class="Tile">
    <div class="Tile-content">
      Tile 1
    </div>
  </div>
  <div class="Tile">
    <div class="Tile-content">
      Tile 2
    </div>
  </div>
  <div class="Tile">
    <div class="Tile-content">
      Tile 3
    </div>
  </div>
  <div class="Tile">
    <div class="Tile-content">
      Tile 4
    </div>
  </div>
  <div class="Flyout is-open js-flyout">
    <div class="Flyout-content">
      Flyout 1
    </div>
  </div>
  <div class="Flyout Flyout--2of4 js-flyout">
    <div class="Flyout-content">
      Flyout 2
    </div>
  </div>
  <div class="Flyout Flyout--3of4 js-flyout">
    <div class="Flyout-content">
      Flyout 3
    </div>
  </div>
  <div class="Flyout Flyout--4of4 js-flyout">
    <div class="Flyout-content">
      Flyout 4
    </div>
  </div>
  <div class="Tile">
    <div class="Tile-content">
      Tile 5
    </div>
  </div>
  <div class="Tile">
    <div class="Tile-content">
      Tile 6
    </div>
  </div>
  <div class="Flyout js-flyout">
    <div class="Flyout-content">
      Flyout 5
    </div>
  </div>
  <div class="Flyout Flyout--2of4 js-flyout">
    <div class="Flyout-content">
      Flyout 6
    </div>
  </div>
</div>

See the Pen Shifty Tiles: Part 1 by Tyler Sticka (@tylersticka) on CodePen.

The content order’s pretty messed up, but it works as intended. Or it would have, if it hadn’t been for that meddling Ethan Marcotte and those media queries of his. When you throw responsive into the mix, that predictable column count we depended on goes right out the window:

Animation of responsive tiles with flyout

We could listen to resize events and move the flyouts around with JavaScript. But you and I both know that’s a bad idea. Let’s see how we can solve this problem with CSS alone, maybe even improving the content order along the way.

To Float or Not To Float

If we revise our markup so that the tiles and flyouts are unified (instead of separated by arbitrary “rows”), we’ll discover that the floats we were using to arrange tiles side-by-side do not handle change well. Depending on which tile flyout is expanded, subsequent tiles attempt to float around it, resulting in an inconsistent (and frankly, upsetting) experience for wider viewports:

See the Pen Shifty Tiles: Part 2 by Tyler Sticka (@tylersticka) on CodePen.

Well that’s it, then! Floats don’t work, we need tiles to float, time to throw in the towel and handle this with JavaScript.

Not so fast!

Instead of floating the tiles, we can steal borrow a technique from the SUIT CSS grid component and use display: inline-block instead. Combined with vertical-align: top, the tallest tile in a row should push down everything beneath it (just like a tall image in a line of text would affect adjacent rows).

Let’s give it a whirl:

See the Pen Shifty Tiles: Part 3 by Tyler Sticka (@tylersticka) on CodePen.

Success! Even as flyouts shove their way between rows, the tiles retain their horizontal position.

But those flyouts are still awfully narrow at larger sizes. Let’s fix that.

Manifest Destiny

Our goal is for the flyouts to occupy 100% of the available width across all viewports. So far, they’re only ever as wide as the tiles themselves. If we’re decreasing tile widths at larger breakpoints, we should also increase flyout widths by the same factor.

If you’re using a preprocessor like Sass and you hate solving the same math problems over and over as much as I do, now’s a great time to write a mixin to handle this logic across multiple breakpoints:

@mixin generate-tile-grid($columns) {
  .Tile {
    // divide the available width by the number of columns
    width: (100% / $columns);
  }
 
  .Tile-flyout {
    // extend beyond the tile width by the same factor
    width: (100% * $columns);
  }
 
  .Tile-flyout:before {
    // adjust the position of the flyout caret
    left: (100% / 2 / $columns);
  }
}
 
@media (min-width: 30em) {
  @include generate-tile-grid(2);
}
 
/* etc. */

Here’s where that gets us:

See the Pen Shifty Tiles: Part 4 by Tyler Sticka (@tylersticka) on CodePen.

So close! The widths are correct, but we haven’t accounted for the tile’s changing horizontal position. Let’s revise that mixin we wrote, using :nth-child selectors to offset the flyouts per column:

@mixin generate-tile-grid($columns) {
  .Tile {
    width: (100% / $columns);
  }
 
  .Tile-flyout {
    width: (100% * $columns);
  }
 
  // for every column in this grid
  @for $column from 1 through $columns {
    .Tile:nth-child(#{$columns}n+#{$column}) {
      .Tile-flyout {
        // offset the left margin by the number of preceding columns
        margin-left: (-100% * ($column - 1));
      }
 
      .Tile-flyout:before {
        // adjust the caret position similarly
        left: (100% / $columns * ($column - 0.5));
      }
    }
  }
}

Drumroll, please…

See the Pen Shifty Tiles: Part 5 by Tyler Sticka (@tylersticka) on CodePen.

…and boom goes the dynamite.

In Practice

Because this technique is initially counter-intuitive (at least to me), I kept the examples pretty simple. If you’re still a little fuzzy on how this interface pattern might work in practice, here’s a more complex demo involving hypothetical payment methods and their associated edit forms. Tap or click a tile to toggle:

See the Pen Responsive tiles with column-spanning flyouts by Tyler Sticka (@tylersticka) on CodePen.

Having retrofitted this type of UI multiple times now, I’d be remiss if I didn’t voice some concerns I have about its usability. Because the vertical position of subsequent tiles changes as flyouts expand and collapse, it can be frustrating to use on smaller screens without a nightmarish amount of fragile and jank-inducing scroll management. If redesigning is an option for this pattern, I recommend reading Luke W’s post about dropdowns for some much more straightforward alternatives.

Or better yet, drop us a line. Solving these problems is kind of our thing.

Introducing Leveller: Please Avoid Using It

This happens to me over and over: I have a multi-column grid of tiles, each with varying heights. This means the bottom of certain rows can appear jagged and difficult to scan visually:

See the Pen Leveller: Before by Tyler Sticka (@tylersticka) on CodePen.

Ideally, I’d use flexbox to solve that problem with a shockingly small amount of CSS (especially if you use Autoprefixer). Seriously, look how well that works:

See the Pen Leveller: Flexbox Alternative by Tyler Sticka (@tylersticka) on CodePen.

Sadly, that solution rarely makes it into production on the projects I’ve worked on. Sometimes browser support is the culprit. Other times we’ve inherited particularly uncooperative grid patterns (either from an existing project, or an overzealous framework).

Over the last few years, I wrote and re-wrote project-specific, bespoke JavaScript to solve this problem. I’ve finally accepted that it isn’t going away, at least not as quickly as I’d like it to.

So I’ve written a jQuery plugin for equalizing element heights. It’s called Leveller:

See the Pen Leveller: After by Tyler Sticka (@tylersticka) on CodePen.

Don’t use Leveller if you can help it. Flexbox is way more appropriate. If you only need to adjust min-height properties, Equalizer is a leaner, dependency-free solution.

But if all else fails, Leveller is available now on GitHub (and also via npm). Godspeed!

Two pretty-good techniques for styling tricky form elements

Confession time: For most of my career, I despised form elements. Checkboxes, radios, selects and file inputs seemed to gleefully defy what little control I expected from an HTML element. Their penchant for idiosyncracy drove me to almost as much hair-pulling and teeth-gnashing as IE6 or web-safe fonts.

These days, my frustration with form elements has quieted. Partly that’s because browsers and development tools are so much better. But more significantly, I now understand the benefits of surrendering some control to the operating system. As devices continue to accept a greater and greater variety of input methods (keyboard, mouse, touch, voice, gesture, remote, etc.) while browsers adopt an astounding variety of new input types , it’s a gift for vendors to provide default experiences consistent with the user’s expectations of the platform.

So I no longer strive for “pixel perfection” when styling form elements. I don’t need absolute control. All I want is something easy to tap that feels intentional.

When the browser defaults don’t get me there, here are my go-to workarounds.

Checkboxes and Radios: Styled Sibling

This technique works in any browser that supports CSS3 selectors (basically IE9+). If you read Radio-Controlled Web Design a few weeks ago, this should feel familiar. Let’s start with a checkbox example.

We’ll need a few HTML elements:

  • The <input> itself.
  • A dummy element to style (right next to the <input>).
  • A containing <label> that passes click events to the aforementioned <input>.

I like to wrap the <input> and dummy elements in a container to keep everything nice and tidy, but strictly speaking it isn’t required. Here’s what that markup might look like:

<label>
  <span class="checkbox">
    <input type="checkbox">
    <span class="checkbox-value" aria-hidden="true"></span>
  </span>
  Set phasers to stun
</label>

We’re now free to visually hide the checkbox, styling .checkbox-value however we like:

/* hide the "real" checkbox visually */
.checkbox input {
  border: 0;
  clip: rect(0 0 0 0);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 1px;
}
 
/* style the "fake" checkbox */
.checkbox-value {
  /* default/unchecked styles */
}
input:checked + .checkbox-value {
  /* checked styles */
}

When the user clicks the label, the click is passed along to the <input>, which toggles the state of :checked, which affects the appearance of .checkbox-value.

Here’s an example that styles the checkbox like an iOS-style switch:

See the Pen Styled checkbox by Tyler Sticka (@tylersticka) on CodePen.

Here’s the same idea applied to radio buttons with a slightly more conventional design (incorporating a base64-encoded SVG checkmark):

See the Pen Styled radios by Tyler Sticka (@tylersticka) on CodePen.

This technique has a few drawbacks. It requires some extra markup. It won’t work in IE8 or earlier without a fallback. It could probably use another pass for accessibility. But compared to most of the JavaScript solutions I’ve tried, this feels straightforward, consistent and predictable.

Selects and File Inputs: Transparent Overlay + JavaScript

For more complex elements like <select> and <input type="file">, we can’t get by on CSS alone (though it gets us further than one might expect).

Our markup is similar to the previous set of checkbox/radio examples, except we won’t need a <label> for click events:

<div class="select">
  <select>
    <option>Option 1</option>
    <option>Option 2</option>
    <option>Option 3</option>
  </select>
  <span class="select-value" aria-hidden="true"></span>
</div>

Instead of hiding the <select> entirely, we want to position it over the rest of our element, allowing it to intercept click events and correctly position any dropdown it may display. Because this technique relies on JavaScript, we’ll qualify some of our selectors with .js (since you’re probably already using Modernizr).

.js .select {
  position: relative;
  /* default styles */
}
.js .select:hover {
  /* hover styles */
}
.js .select.focus {
  /* focus styles */
}
 
/* nicer default styles for "real" <select> */
.select select {
  cursor: pointer;
  display: block;
  width: 100%;
}
/* hide and overlay when JavaScript is enabled */
.js .select select {
  left: 0;
  height: 100%;
  min-height: 100%;
  min-width: 100%;
  opacity: 0;
  position: absolute;
  top: 0;
}

Already, this “works.” Options will display on click. But there are some problems. The value doesn’t update. There are no hover or focus styles. That’s where JavaScript comes in!

(Although I’ve chosen to write this in jQuery for the sake of readability, remember: You Might Not Need jQuery!)

// For each .select element
$('.select').each(function(){
  // Save some elements as variables
  var $element = $(this);
  var $select = $element.find('select');
  var $value = $element.find('.select-value');
  // Bind event handlers to <select>
  $select.on({
    // On change or keyup, update the value text
    'change keyup': function () {
      $value.text($select.val());
    },
    // On focus, add the focus class
    'focus': function () {
      $element.addClass('focus');
    },
    // On blur, remove the focus class
    'blur': function () {
      $element.removeClass('focus');
    }
  });
  // Trigger the change event so the value
  // is current
  $select.trigger('change');
});

Here’s how all of that comes together:

See the Pen Styled select by Tyler Sticka (@tylersticka) on CodePen.

With some tweaks, the same basic technique can also work for file inputs (assuming experimental WebKit/Blink features aren’t your thing):

See the Pen Styled file input by Tyler Sticka (@tylersticka) on CodePen.

This idea isn’t new. Peter-Paul Koch wrote about it quite a while back. Yet I rarely see it in use outside of a few large mobile frameworks. I’m honestly not sure why.

…and beyond?

What do all of these examples have in common? They don’t mess with the form element too much! By worrying less about customizing behavior and more on simply triggering it, we can indulge some of our designerly impulses without discarding all a given platform has to offer.

Consistency and functionality… no hair-pulling or teeth-gnashing required!

Update: September 8, 2014

A reader pointed out that the select example wasn’t responding to keyboard input in Firefox. I discovered that Firefox doesn’t fire the change event for selects like other browsers do, so I’ve updated the demo and example code so that it binds to both change and keyup.

I also learned that Firefox doesn’t show the full dropdown on any keypress, but this seems to be true of unstyled <select> elements as well. I encourage developers to use these examples as a starting point, and to augment usability shortcomings on a case-by-case basis if the default browser behavior isn’t cutting it.