On some features in Safari 15

A new major version of Safari was pitched back in June at the Apple WWDC 2021 event. In the Design for Safari 15 (33min video, transcript available), Jen Simmons and Myles C. Maxfield walk us through some of the biggest changes we could expect for the web platform.

Last week Safari 15 was officially released as part of iOS/iPadOS 15. It was also included in a recent update to macOS Big Sur, although the release notes hint that it was initially planned for macOS Monterey.

Now that I've had the chance to play around with the new version, here are some personal highlights from the release notes.

More ways to specify colors

Safari 15 is the first browser to support the new color syntaxes defined in the CSS Color Level 4 spec.

HSL, and its close relative HSV, rework the RGB color model (basically squishing the RGB cube into a cylinder) to separate colors into more intuitive dimensions. For a long time, hsl() has been the only alternative to rgb() for specifying colors, and is unquestionably an improvement: it's very hard to imagine a RGB color by looking at the R/G/B components, and it's impractical for picking colors. By comparison, you can sort of imagine the attributes of a color just by reading its H/S/L components — what hue it has and how colorful, and light, it is — and it's easier to match a target color by adjusting Hue, Saturation, and Lightness sliders. (You can try this old-school color matching game in RGB vs. HSL mode to see the difference.)

The HWB color space makes picking colors even more intuitive: provide a hue, and optionally mix in some white and some black to obtain a color. In CSS it's available under the hwb() syntax.

HSL, HSV, and HWB all use attributes that are easier to reason about, but they're not really aligned to how we perceive colors. HSL has its drawbacks and so does HSV and, by extension, so does HWB. The CIELAB color space is much more perceptually uniform and now we can use it in CSS, with the lab() and lch() forms.

Finally, the color() function notation, which debuted in Safari 10.1 with support for the srgb and display-p3 predefined color spaces, is supplemented in Safari 15 with a few more:

A redesigned color picker

Safari 15 on mobile comes with redesigned form controls, the most spectacular of which is the color picker. It now includes three separate selection modes:

The three panels in the mobile Safari 15 color picker.

Other features include the ability to save colors for reuse, and an eyedropper to sample colors from the screen. Sampling a color switches the hex input to display-p3, which sort of makes sense (after all, the screen is able to render display-p3 colors) but on the other hand there's no concept of display-p3 hex code in CSS, which may confuse folks.

Since <input type='color'> only supports six-digit hex values, an opacity slider is not included in the picker like in native apps. On the other hand, one cool feature adopted from macOS is the ability to drag & drop one color well atop another to apply the value:

A built-in pull-to-refresh gesture

Safari 15 introduces a built-in pull-to-refresh gesture on mobile that's pretty handy.

I see it as especially beneficial to progressive web apps, where you don't have a way to refresh the page unless you implement a custom action. However, at the moment of writing, the gesture does not carry over to Progressive Web Apps.

It also seems that you can't disable the gesture using the overscroll-behavior CSS property, as it's not currently implemented in WebKit (tracking issue). Websites that implement their own similar gesture may suffer from a jarring double-refresh effect. If that's the case, the only course of action is to disable the custom behavior. Since overscroll-behavior-y is the most likely vehicle for preventing the built-in gesture when it becomes possible, you can use this JavaScript snippet to target problematic browser versions:

/*
Feature-detect Safari versions
with an unpreventable pull-to-refresh gesture.

How it works:

Safari 15 introduced support for the `xyz` color space,
while simultaneously being the last major browser engine
lacking support for `overscroll-behavior`.
*/

const isSafariWithUnstoppablePullRefresh =
window.CSS &&
CSS.supports &&
CSS.supports('(color: color(xyz))') &&
!CSS.supports('(overscroll-behavior-y: contain)') &&
!window.TouchEvent;

if (!isSafariWithUnstoppablePullRefresh) {
// initialize custom pull-to-refresh gesture
}

The theme-color HTML meta tag

Across platforms, Safari 15 is using the theme-color meta tag to tint the browser UI.

What I found surprising is the feature is not opt-in. In the absence of this meta tag, Safari will try to infer a tint for the top bar, and the color it chooses may not always be appropriate. It may be useful to include this meta tag to your HTML boilerplate, along with the other things that go in <head>, to avoid weird color combos.

Manuel Matuzović explores what you can and can't do with theme-color in this CSS-Tricks article.

A new tab bar

Safari debuted with a radical interface redesign that merged the old address bar and the navigation bar from previous versions into a single, floating URL bar at the bottom of the screen.

The change was met with both enthusiasm and reluctance. One concern with the floating tab bar was that it may stand in the way of things on the page. It was acknowledged and planned for: a bullet point under the CSS section in the release notes reads adjusted environment variable calculations where appropriate to adjust for the safe area of the new iOS design. As documented by Luke Channings, Safari 15 Beta did afford a combination of height: 100vh and env(safe-area-inset-bottom) to place a toolbar at the bottom of the screen without risking it being hidden behind the URL bar.

The final Safari 15 release back-pedalled into more familiar ground, with a tamer combined bottom bar, and an option to bring back the old top-anchored address bar. After a week of using it, the new UI seems to have mostly faded out of attention, and I appreciate the ease of switching tabs with a horizontal swipe. And although the Aa menu is becoming a bit of a kitchen sink cabinet, all in all I feel like this is a step in the right direction.

What about the changes to env()? As seen in this demo, they seem to have been reverted for the case we were interested in: env(safe-area-inset-bottom) is 0 when floating toolbar is shown, and it still obstructs the bottom part of the page.

For reference: Here's a browser test that shows the computed value of available env() properties, as well as 100vh and the -webkit-fill-available height.

The way out seems to be the new viewport units, in particular dvh (dynamic viewport height). Bramus has an explainer.