Your website is making me sick — or why you should respect the preferences of your users

There’s an accessibility setting in macOS and iOS that allows users to reduce motion in the interface. On iOS, this removes animations in the OS itself and well made apps should also respect this setting. In CSS there’s a media query for it; (prefers-reduced-motion: reduce), which has for example been supported in Safari since version 10.1. If you are using animations on your website, consider adding this snippet to your stylesheet.

@media screen and (prefers-reduced-motion: reduce) {
  * {
    transition-duration: 0.001ms !important;
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}

But why didn’t I remove the transition and animation durations altogether? Well, retaining the durations but changing them to something that’s imperceptible to the human eye, helps to avoid breaking anything that is tied to CSS-based animations. Make sure test your site, though. I’ve seen stuff break in the weirdest of ways with this styling, so your mileage may vary. Resetting animation-iteration-count disables infinite animations, instead of making the loop crazy fast!

Browser and OS support

Almost all of the major browsers has had support for a good while, the exception being Legacy Edge, which lacks support entirely. Check caniuse.com for more details.

Supporting browsers can read this preference from the OS of your choice. A few examples:

  • Windows 10: Settings → Ease of Access → Display → Show animations in Windows.
  • Windows 7: Control Panel → Ease of Access → Make the computer easier to see → Turn off all unnecessary animations (when possible).
  • macOS: System Preferences → Accessibility → Display → Reduce motion.
  • iOS/iPadOS: Settings → General → Accessibility → Reduce Motion.
  • Android 9+: Settings → Accessibility → Remove animations.

Remember, respect your users. ❤️

Touch ID with sudo

When the first MacBook Pro with a Touch ID sensor was released, I was thoroughly excited. Rightly so. Apps like 1Password was quick to implement support for it. There was one thing that was missing though; authentication with sudo.

There’s an XKCD for every situation

I’m almost ashamed that after having owned at least two MacBook Pros with Touch ID, I didn’t find out until today about this. So it’s time to write it down. Hat tip to Stanislas for showing me the way.

Edit (as root) /etc/pam.d/sudo:

# sudo: auth account password session
auth       sufficient     pam_smartcard.so
auth       sufficient     pam_tid.so		# <= Add this line!
auth       required       pam_opendirectory.so
account    required       pam_permit.so
password   required       pam_deny.so
session    required       pam_permit.so

For clarity, the line you want to add (as seen above) is:

auth       sufficient     pam_tid.so

That’s all you need! Oh, and your finger, of course! 😉

Labs are back!

Maybe two or three years ago, I added a section called “Labs” that didn’t actually contain anything. I kept it up for far too long and I never got around to adding the planned content. Well, no more! In a spur of inspiration and motivation, I whipped something up today so that I could finally get some content in. For starters, it’s just some of the more popular CodePens I’ve made over the years. More stuff to come.

Considering viewports

Following yesterdays Apple event, I spent the morning perusing my RSS feed, as I do most mornings. One of the articles from developer Michael Tsai pondered the screen sizes of the new iPhone models. He compiled a list of most available models (including the older 5s/SE that’s no longer as easy to buy) and their viewport sizes in CSS pixels, or the unit he chose to describe them with; points.

iPhone Model Width Height
5s/SE 320 pts 568 pts
12 mini 360 pts 780 pts
8/SE 2 375 pts 667 pts
11 Pro 375 pts 812 pts
12/12 Pro 390 pts 844 pts
XR/11/11 Pro Max 414 pts 896 pts
12 Pro Max 428 pts 926 pts

The iPhone 12 Mini is the model that I believe will be the “people’s iPhone”. That is to say, it’ll most likely be the top seller. With that in mind, it’s interesting to note the width of the device. 360 CSS pixels. I’ve noticed in my day job that our designers have designed with the iPhone 8/SE 2 in mind, that is to say that they make their most narrow designs 375 CSS pixels. While that might be a problem in and of itself since there’s still plenty of devices out there that is reporting 320 CSS pixels and you should cater to these too, it’s interesting to note that our designers will at least have to shave off 15 CSS pixels in their future designs, since this will very likely be the majority for the future.

Then again, if we all just built stuff fully flexible and did not cater to a specific minimum viewport, this wouldn’t be a problem at all.

The war against sticky toolbars continue

The wars against sticky toolbars, annoying overlays, unwarranted modals and scroll-locking continues. It’s a never-ending war of attrition. It’s been close to a year since I last updated my bookmarklet and since, I’ve come across more annoying ways to mess with the user experience on different websites.

Scenarios that my bookmarklet didn’t handle:

  • Setting overflow: hidden !important thus escalating the specificity wars further (my original script just set overflow: unset; which didn’t override !important styles)
  • The above styling was not just set on the <body> element, but also the <html> element, sometimes at the same time to really make sure that the poor user can’t scroll

No need to beat around the bush, this is the updated script.

const elements = document.querySelectorAll('body *');
const containers = document.querySelectorAll('html, body');

containers.forEach(el => {
  if (getComputedStyle(el).overflow === 'hidden') {
    el.style.setProperty ('overflow', 'unset', 'important');
  }
});

elements.forEach(function (element) {
  if (["-webkit-sticky", "sticky"].includes(getComputedStyle(element).position)) {
    element.style.position = "unset";
  }
  else if(["fixed"].includes(getComputedStyle(element).position)) {
    element.parentNode.removeChild(element);
  }
});

The biggest changes are that I had to use body.style.setProperty instead of body.style.overflow in order to also set !important. In addition, I’m also checking for that styling on the <html> element and unset it there if needed.

As always, below is the packaged bookmarklet for you to drag into your own bookmarks. This time featuring a cool emoji, fitting the situation.

☠️ unSticky

Big thanks to Joacim de la Motte for providing valuable feedback and helping me improve the script.