Mobile, Small, Portrait, Slow, Interlace, Monochrome, Coarse, Non-Hover, First

Avatar of Andrés Galante
Andrés Galante on (Updated on )

A month ago I explored the importance of relying on Interaction Media Features to identify the user’s ability to hover over elements or to detect the accuracy of their pointing device, meaning a fine pointer like a mouse or a coarse one like a finger.

But it goes beyond the input devices or the ability to hover; the screen refresh rate, the color of the screen, or the orientation. Making assumptions about these factors based on the width of the viewport is not reliable and can lead to a broken interface.

I’ll take you on a journey through the land of Media Query Level 4 and explore the opportunities that the W3C CSS WG has drafted to help us deal with all the device fruit salad madness.

Media queries

Media queries, in a nutshell, inform us about the context in which our content is being displayed, allowing us to scope and optimize our styles. Meaning, we can display the same content in different ways depending on the context.

The Media Queries Level 4 spec answers two questions:

  • What is the device viewport size and resolution?
  • What is the device capable of doing?

We can detect the device type where the document is being displayed using the media type keywords all, print, screen or speech or you can get more granular using Media Features.

Media Features

Each Media Feature tests a single, specific feature of the device. There are five types:

We can use these features on their own or combine them using the keyword and or a comma to mean “or”. It’s also possible to negate them with the keyword not.

For example:

@media screen and ((min-width: 50em) and (orientation: landscape)), print and (not(color)) {
  ...
}

Scopes the styles to landscape orientated screens that are less than or equal to 50em wide, or monochrome print outputs.

The best way to understand something is by actually doing it. Let’s delve into the corner cases of a navigation bar to test these concepts.

The Unnecessarily Complicated Navbar

One of the best pieces of advice that Brad Frost gave us on “7 Habits of Highly Effective Media Queries” is not to go overboard.

The more complex we make our interfaces the more we have to think in order to properly maintain them. Brad Frost

And that’s exactly what I’m about to do. Let’s go overboard!

Be aware that the following demo was designed as an example to understand what each Media Feature does: if you want to use it (and maintain it), do it at your own risk (and let me know!).

With that in mind, let’s start with the less capable smaller experience, also know as “The mobile, small, portrait, slow, interlace, monochrome, coarse, non-hover first” approach.

The HTML structure

To test the media query features, I started with a very simple structure. On one side: a header with an h1 for a brand name and a nav with an unordered list. On the other side: a main area with a placeholder title and text.

See the Pen Part 1: Mobile, coarse, portrait, slow, monochromatic, non-hover first by Andres Galante (@andresgalante) on CodePen.

Default your CSS for less capable devices and smaller viewport

As I mentioned before, we are thinking of the less capable smaller devices first. Even though we are not scoping styles yet, I am considering an experience that is:

  • max-width: 45em small viewport, less than or equal to 45em wide
  • orientation: portrait portrait viewport, height is larger than width
  • update: slow the output device is not able to render or display changes quickly enough for them to be perceived as a smooth animation.
  • monochrome all monochrome devices
  • pointer: coarse the primary input mechanism has limited accuracy, like a finger
  • hover: none indicates that the primary pointing system can’t hover

Let’s take care of positioning. For portrait, small, touchscreen devices, I want to pin the menu at the bottom of the viewport so users have comfortable access to the menu with their thumbs.

nav {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
}

Since we are targeting touchscreen devices, it is important to increase the touch target. On Inclusive Design Patterns, Heydon Pickering mentions that it’s still unclear what the magical size of a touch area is, different vendors recommend different sizes.

Pickering mentions Anthony Thomas’s article about finger-friendly experiences and Patrick H Lauke research for The W3C Mobile Accessibility Taskforce into touch / pointer target size, and the main takeaway is, “…to make each link larger than the diameter of an adult finger pad”.

That’s why I’ve increased the height of the menu items to 4em. Since this is not scoped, it’ll be applied to any viewport size, so both large touchscreen devices like an iPad Pro and tiny smartphones alike will have comfortable touch targets.

li a {
  min-height: 4em;
}

To help readability on monochromatic or slow devices, like a Kindle, I haven’t removed the underlines from links or added animations. I’ll do that later on.

See the Pen Part 2: Mobile, coarse, portrait, slow, monochromatic, non-hover first by Andres Galante (@andresgalante) on CodePen.

Small landscape viewports, vertical large displays, or mouse pointers

For landscape viewports orientation: landscape, large portrait viewports like vertical monitors or tablets min-width: 45em, or small portrait devices with fine pointers like a stylus pointer: fine, users will no longer be using their thumbs on a handheld device; that’s why I unpinned the menu and put it at the top right of the header.

@media (orientation: landscape), (pointer: fine), (min-width: 45em) {
  main {
    padding-bottom: 1em;
    padding-top: 1em;
  }
  h1, nav {
    position: static;
  }
}

Since the menu and the brand name are already flexed and stretched, then they’ll accommodate themselves nicely.

For users that have a fine pointer like a mouse or a stylus, we want to decrease the hit target to gain the real estate on the main area:

@media (pointer: fine) {
  h1, li a {
    min-height: 2.5em;
  }
}

See the Pen Part 3: Mobile, coarse, portrait, slow, monochromatic, non-hover first by Andres Galante (@andresgalante) on CodePen.

Vertical nav for large landscape viewports

Vertical navigations are great for large landscape viewports (orientation: landscape) and (min-width: 45em), like a tablet or a computer display. To do that I’ll flex the container:

@media (orientation: landscape) and (min-width: 45em) {
  .container {
    display: flex;
  }
  ...
}

Notice that hit targets have nothing to do with the size of the viewport or style of navigation. If the user is on a large touchscreen device with a vertical tab, they’ll see larger targets regardless of the size of the width of the screen.

See the Pen Part 4: Mobile, coarse, portrait, slow, monochromatic, non-hover first by Andres Galante (@andresgalante) on CodePen.

Animations, decorations and edge cases

Animations are a great way to enhance interactions and help users achieve their goals quickly and easily. But some devices are incapable of producing smooth animations – like e-readers. That’s why I am limiting animations to devices that are capable of generating a good experience (update: fast), (scan: progressive), (hover: hover).

@media (update: fast), (scan: progressive), (hover: hover) {
  li a {
    transition: all 0.3s ease-in-out;
  }
}

I am also removing the text decoration on color devices:

@media (color) {
  li a { text-decoration: none; }
}

Removing underlines (via text-decoration) is tricky territory. Our accessibility consultant Marcy Sutton put it well:

Some users really benefit from link underlines, especially in body copy. But since these particular links are part of the navigation with a distinct design treatment, the link color just needs adequate contrast from the background color for users with low vision or color blindness.

We made sure the colors had enough color contrast to pass WCAG AAA.

I’m also increasing the border width to 2px to avoid “twitter” (real term!) on interlace devices like plasma TVs:

@media (scan: interlace) {
  li a, li:first-child a {
    border-width: 2px;
  }
}

And here is the final result:

See the Pen Part 5: Mobile, coarse, portrait, slow, monochromatic, non-hover first by Andres Galante (@andresgalante) on CodePen.

Test it out

Testing all this may not be that easy!. This example relies on flexbox, and some browsers have limited support for other modern CSS features. A Kindle, for example, won’t read @media, @support, or flexbox properties.

I’ve added float fallbacks here:

See the Pen Part 6: Mobile, coarse, portrait, slow, monochromatic, non-hover first by Andres Galante (@andresgalante) on CodePen.

You can open the full page example in different devices, landscape, or portrait and test it out!

How soon will we realistically be able to use all these features?

Now! That is, if you are ok offering different experiences on different browsers.

Today, Firefox doesn’t support Interaction Media Queries. A Firefox user with a fine pointer mechanism, like a mouse, will see large hit areas reducing the main area real estate.

Browser support for most of these features is already available and support for Interaction Media Features, support isn’t bad! I am sure that we will see it supported across the board soon.

Remember to test as much as you can and don’t assume that any of this will just work, especially in less capable or older devices.

There is more!

I’ve covered some of the Media Features along the example, but I left others behind. For example the Resolution Media Feature that describes the resolution of the output device.

My goal is to make you think beyond your almighty MacBook or iPhone with a retina display. The web is so much more and it’s everywhere. We have the tools to create the most amazing, flexible, inclusive, and adaptable experiences; let’s use them.