Alan Shortis

Future responsiveness

This post is more than 4 years old

For nearly 10 years, media queries have been commonplace in styling websites for use across screen sizes and devices. The question 'should this site be responsive' is going away because, yes, in all but the rarest of cases, a website should be responsive to provide a good user experience. It's not just about mobile.

Defining responsive

What are we responding to? Until recently, a 'responsive' site would adapt based on the viewport size and maybe provide print styles. We can and should respond to much more than that, and there are media queries that can provide information on a user's preferences or hardware.

Each example will be written in CSS, but it's possible to use media queries can be used JavaScript too, via window.matchMedia().

Colour Scheme

The prefers-color-scheme media query can tell us if the user prefers a dark theme over a light one. In its simplest form, the media query can be obeyed and a theme or different stylesheet used to render a light or a dark theme.

Ideally, not only would different themes be provided but also a means to toggle between them and persist the chosen theme on repeat visits.

Motion

The prefers-reduced-motion media query can tell us if the user has opted to have less motion/animation in the operating system, which is especially important for people with motion-triggered vestibular spectrum disorder.

There are a couple of ways this can be implemented:

@keyframes slidein {
  100% {
    opacity: 1;
    transform: translateY(0);
  }
}

.content {
  animation: slidein 250ms 1 forward;
  opacity: 0;
  transform: translateY(-2rem);
}

@media (prefers-reduced-motion: reduce) {
  .content {
    animation: none;
    opacity: 1;
    transform: translateY(0);
  }
}

Here we have a subtle keyframes animation that will slide and fade in the content class, and the media query removes the animation if reduced motion is preferred. It might be necessary to change some other CSS properties depending on your pre/post animation settings.

A more sledgehammer approach is to to suppress animations globally:

@media (prefers-reduced-motion: reduce) {
  * {
    animation-delay: 0 !important;
    animation-duration: 0 !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0 !important;
  }
}

Here we are taking advantage of a couple of CSS features that we often want to avoid; the universal selector and !important. In this case, these are the right tools for the job.

By applying delay and duration of zero and ensuring animations only run once on every element, and using !important to increase specificity, we can write all animations and transitions normally knowing that their properties will be trumped if the media query matches the preferred settings. The downside of this is less control over a non-animated state which could lead to some jank, and also differentiating decorative animation (which you definitely want to stop) and animation with some meaning (which you may want to keep).

If using SASS, a great way to handle this is to place all animations inside a mixin which checks the media query:

@mixin should-animate {
  @media (prefers-reduced-motion: no-preference) {
    @content;
  }
}

.content {
  @include should-animate {
    animation: slidein 250ms 1 forwards;
  }
}

It's not always necessary to stop animations entirely; you could speed them up, slow them down, or just simplify. Animation can be very effective in showing that something has changed or is happening, more than a sudden change. Choose your strategy on a case-by-case basis.

In HTML

You can use this in the picture element as well as in CSS. In this example, we can show a still image by default, or show the animated version if the user has no preference for motion:

<picture>
  <source srcset="microwave.gif" media="(perfers-reduced-motion: no-preference)" />
  <img src="microwave.png" alt="A potato cooking in a microwave" />
</picture>

Transparency

The prefers-reduced-transparency media query states if the user has opted to have fewer transparent elements in the operating system.

.header {
  background-color: rgba(0, 0, 0, 0.5);
}

@media (prefers-reduced-transparency: reduce) {
  .header {
    background-color: rgba(0, 0, 0, 1);
  }
}

This has not yet been implemented in any browser, but the option exists in MacOS.

Pointer

The pointer media query can hint if the device has a touch screen or uses a mouse or other pointing device. For a rather reduced example we can make a form input larger on a touch (coarse) device:

input[type='checkbox'] {
  width: 1rem;
  height: 1rem;
}

@media (pointer: coarse) {
  input[type='checkbox'] {
    width: 2rem;
    height: 2rem;
  }
}

Data

The prefers-reduced-data media query could be used to adjust styles and assets to make a site as light weight as possible. For instance, we could choose not to serve fonts and instead specify a closely matching system font.

This isn't yet supported in any browser and is still a proposal, but the possibilities are pretty huge for mobile and people with limited data plans. How many times have you been in a situation where you have a terrible connection but need some information? If all you need is the phone number for the hotel you can't find, do you need their high res marketing images and custom fonts?

All of these new ways to tailor the experience based on a user's preferences help to move us closer to a better and more ethical web. It's not just about making a site look good on a phone, but making it work for everyone.