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:
- Screen Dimensions Media Features detect the viewport size and orientation.
- Display Quality Media Features identify the resolution and update speed.
- Color Media Features spot the amount of colors a device is capable to displaying.
- Interaction Media Features find if a device is able to hover and the quality of its input device.
- Scripting Media Features recognize if scripting languages, for example javascript, are supported.
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 wideorientation: portrait
portrait viewport, height is larger than widthupdate: 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 devicespointer: coarse
the primary input mechanism has limited accuracy, like a fingerhover: 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.
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.
Very useful article Andrés, thank you. I still consider myself as a self-taught beginner who’s managed to cobble together a personal and a business website, which probably look laughably simple, but I’ve done it without using templates or CMS. Knowing how to design for mobile devices is crucial, and I know I don’t spend enough time on research, preferring to plough ahead with development, but I will endeavour to follow up on the points you raise here to improve my sites [as time allows!]. Cheers!
Hey Jon, things moves so fast in the CSS world that we are all self-taught beginner :)
Ping me on twitter if I can help you in anwyay.
Thank you- just starting out in web design and articles like this definitely help point me in the right direction of what I need to be considering. thanks again
Cool! I am glad it was helpful :) Thanks for reading it
Very nice article!
Can I copy this style for my site, and later make my own ammendments? (I am just starting out, both designing and learning)
Sure, go ahead :)
Nice article, Andres. I learned some good tips for navigation on different devices. Thanks!