Explore the latest advancements in CSS. Learn techniques and best practices for working with wide-gamut color, creating gorgeous typography, and writing simple and robust code. We'll also peer into the future and preview upcoming layout and typography features.
P3 color does just that. Apple started supporting wide gamut Display P3 on our hardware and software over seven years ago, first on iMac in late 2015, then iPad, and iPhone, beginning with iPhone 7. The P3 color gamut is capable of displaying 50% more colors than sRGB. The displays on modern devices are stunning. These all support wide gamut P3 with brighter colors and deeper saturation. And it's long past time for web design to take full advantage. There's a media query in CSS for testing color gamut support, when you need a way to conditionally specify CSS, depending on what the user's hardware and software can do. We shipped support for the Color Gamut Media Query back in 2016, in Safari 10.0. When it comes to picking a color, there are, of course, many ways to do it; named colors, hexadecimal values, the RGB function, which thinks in red, green and blue. HSL, for hue, saturation, and lightness, and HWB, with its hue, whiteness, and blackness. All of these ways of modeling color are capable of creating the same result. All of these models are limited to the sRGB color gamut. It's impossible to represent the colors that only exist in P3 if you use these color models. Because of that, there are four new ones now defined in CSS. LCH, OKLCH, LAB, and OKLAB. These models can represent colors in any gamut, including Display P3, or any other color gamut that might come to the web in the future. They're defined with three values each. In all four, the "L" represents Lightness LCH and OKLCH also take values for Chroma, or how intense that color is, and for Hue, or where on the color spectrum it lies. LAB and OKLAB declare a value along an A axis-- or where the color is along an axis that runs from green to red-- and a B axis--or how blue to yellow is it. You can create colors with LCH, OKLCH, LAB, and OKLAB by using new functions for each. If a browser has added support for P3, then these functions can represent colors that only exist in P3 as well as those within sRGB. We shipped support for these functions in Safari 15.0 and 15.4. Chrome, Edge, and Firefox are adding support this year, thanks to the Interop 2023 project. You can also define a color with the color() function and specify which color gamut to use. The color function takes values in red, green, and blue, plus alpha, after a slash. But what which color 100% green creates, for example, depends on the color gamut. We first shipped the ability to create P3 colors in CSS through the use of this color function in Safari 10.1, over six years ago. With the advent of these color gamuts and color models, the CSS Working Group defined additional tools that make use of their power. Their web standards are finally mature enough for us to ship these tools this year. Have you ever wanted to define a color in CSS, while referring to another color? It's been possible to do similar things in preprocessors for a while. Now, relative color syntax lets you do just that. Just like many ways to define a color, you start with one of the color functions. This determines which color model is used to do the mathematical calculations involved in creating the new color. Next, state which existing color you want to start from. Then take the channels from the function and manipulate them. In the first example, the R, G, and B channels are left alone, while / 0.7 tells the browser to give this color an opacity of 70%. In the second example in LAB, I've told the browser to calculate L divided by 2, which cuts the lightness in half and makes the color darker, while leaving the A and B channels alone. And in the third example, in OKLCH, I'll leave the L and H channels alone, while cutting the C, the chroma, by one third, which drains the intensity out of the color. Relative Color Syntax makes it quick work to define an entire palette of colors, handy when creating a design system.
The new color models also improve how we can define gradients. Here's a simple linear gradient that goes from white to blue. For years, these kinds of gradients were always calculated using the sRGB color space. Now, starting in Safari 16.2, we can explicitly state that we want the gradient to be calculated in sRGB, if that's what we want. Or we can change the color space. sRGB-linear is similar to sRGB, but smooths the transitions between colors in a more linear fashion. But you might notice that both of these transition through purple tones. If we switch to OKLAB, the colors calculated in the middle are far more blue, and perhaps that's what we'd prefer. LCH happens to create similar results, although not identical. OKLCH transitions through a spectrum of yellow, green, and teal. LAB happens to be far more purple. or we can use HSL or HWB if we like these results. It really depends on the project and the design effect we want. None of these are right or wrong. None of them is the best. It depends. There are a lot of new options for defining gradients. Switching color spaces has a huge impact. This also goes for animating changes in color. The color space affects the interpolation of what happens in between.
In fact, this year we increased the power of :has() by making it work with even more pseudo-classes. :has(:lang()) makes it possible to style anything on the page depending on the presence of a particular language. And :has() support for media pseudo-classes provide conditional styling depending on the states of audio and video playback.
The :dir pseudo-class fills in a gap when it comes to supporting language direction. Depending on the language being typeset, text can flow from left to right, or from right to left. This is often abbreviated LTR and RTL. These days, CSS has more and more logical properties, which allow you to refer to the start and end of the text flow, instead of left or right. For instance, use margin-inline-start and margin-inline-end, instead of margin-left and margin-right, to easily write CSS that works for every language. But not everything in your design can be handled using logical properties. This is where the new direction pseudo-class can be helpful. Here, I have an icon I'd like to transform depending on the direction of text. When the header has a direction of LTR, I'll rotate the SVG one way, and when the header is RTL, I'll rotate it the other way. This is a far simpler technique than what was used in the past to support multiple language direction. :user-valid and invalid, additions to :has(), and the :dir pseudo-class all make it easier to write robust and succinct code. This year also brings several features that make it possible to refine the details in your typography to absolute perfection.
Let's start with a look at the new line-height units. In CSS, we have many different kinds of units we can use to define a length. Some units are relative to the viewport size, like svh and lvh, or relative to a container's size, like cqb and cqi. Other units are relative to sizes in typography. One ex equals the x-height of the font. One ch, for character, matches the inline size of the zero character in a font. And one ic is the inline size of an ideographic character in CJK scripts-- inline size being width in a horizontal writing mode or height in a vertical writing mode. These units have been supported in browsers for a while. Well, there's a new unit that's also relative to a size in your typography: the lh unit, for line height, and rlh for root line height. These units let us connect anything in our layout to the amount of space between lines. For example, I set line-height to 1.4 on the root HTML element. Then I put a padding of 2rlh on the section element, this white card. Then I set headline and paragraph margins in the block direction to 1rlh. Now there's exactly as much space between the lines of text as if there were text there instead of space. That sets up what's known in typography as vertical rhythm. Line height units don't prevent situations that can disrupt vertical rhythm, but they do bring an incredibly simple tool to the web that gets us much closer to unlocking this long-standing typographical tradition, letting us create an intimate connection between type and the whitespace around the type.
There are many challenges in polishing digital typography on the web to the high standards of traditional typesetting. One of these has to do with font sizing. If you're a web designer, it's likely you're carefully choosing your font families and font sizes. But the font you want might not download or it might not be available on the user's operating system. That why it's best practice to declare a stack of fonts in font-family to provide a fallback plan to the browser. The first font that's found is the one that gets used. Similarly, how big a font appears visually at a specific size is not something a web developer can control. Here is SF Hello on the left, and Baskerville on the right. They're typeset to be exactly the same size, but SF Hello looks much larger because it fills more space inside its line box. It has a larger x-height. This difference is caused by choices that were made when the font files were created. Here, I've got an example where I'm typesetting an article with font-size: 1.4rem, and I'm defining a simple font stack for any code that's inside that article. You can see how the code looks smaller than the paragraph text. It's especially noticeable if you compare the Fs. If the code falls back to monospace, then it looks bigger than the paragraph text. We can try to compensate by adjusting the font-size for code to be 120% of the article font-size, which might even out the sizes when Courier is used, but if the browser falls back to monospace, then the code ends up even bigger than the paragraph text. What we need is a way to tell the browser, "Please just make these two fonts look like they're the same size," and let it figure out how. That's exactly what font-size-adjust does. It adjusts how big a font looks to create visual consistency.
I've added one line of CSS-- font-size-adjust: 0.47-- and now my typeset code is visually consistent with the paragraph text, even for both fonts in the stack. But why 0.47? What does this number mean? For any Latin font you might use on the web, there's a ratio between the font's size and its x-height. It's a bit arbitrary what that ratio is, but usually it's around 50%. By applying font-size-adjust: 0.47 to the article element, I'm actually telling the browser to resize every font inside the article-- paragraph font, code font, no matter which font is used from either stack-- so the x-height of each is always 47% of the specified font-size. I picked 0.47 because it's what made Iowan Old Style look the same as it does without font-size-adjust applied. We shipped support for these basic capabilities of font-size-adjust in Safari 16.4. In Safari 17, we're adding support for more advanced capabilities. Wouldn't it be better if you didn't have to track down a magic number like 0.47 to try and make every font match your main font? The from-font value lets you tell the browser to just figure it all out. Also in Safari 17, we're adding support for the two-value syntax, which lets you specify which metric should be used when creating size consistency. By default, it's ex-height, but you can instead use cap-height, ch-width, ic-width, or ic-height. Safari 17 also adds support for the size-adjust descriptor, which lets you make a similar kind of adjustment when you set-up a font with a @font-face rule. That's font-size-adjust. It let's you have a bit more control over something that cannot easily be controlled with font-size alone. But even with new line height units, and the ability to adjust the visual size of your type, there are still things that can create wonky unevenness in your line box sizing. We are working on a few solutions to this problem.
Text-box trim is one of them. In some ways, text-box-trim is similar to margin-trim. They both let you trim away unwanted white space, but in this case, on a text box. Have you ever struggled to get something to line up vertically on the web? This name is not vertically centered. Maybe it's clearer if I draw a line through the middle. The text is visually lower than center. This happens all the time on the web. But why? Well, actually the text box is vertically centered. But the glyphs are sitting lower down inside of this box. There's extra space above and below the letters that's reserved by the font. The amount of extra space above and below is not the same because the font doesn't need as much below as it does above and that's throwing off vertical centering. This extra space is incredibly important. It reserved for accent marks, vowel marks, and much more. But it can throw off typographic layout on the web. Text-box-trim gives us a way to trim away this extra space for the purposes of layout while still showing the entirety of all the glyphs. This doesn't just help with vertical centering. Here's an example where the extra space reserved for the font above the cap height makes it impossible to easily get the top of the headline to line up with the top of the image. By trimming away the extra space, lining things up becomes easy. This is all a work in progress. The property name already changed from leading-trim to text-box-trim. As of Safari Technology Preview 171, the code you see on the screen is how it works, but don't get too attached to these details. We expect it to keep changing. Perhaps it will become like this. Do try it out in Safari Technology Preview and let us know what you think. Early feedback from web designers and developers like you is how CSS becomes the best it can be.
Meanwhile, here's something that has great support across browsers and will soon come to Safari 17, Counter styles. You're probably very familiar with ordered lists in HTML, where using the element automatically numbers a list of items. CSS provides an easy mechanism for changing which numbering system is used. Here I'm applying list-style: devanagari. There are dozens of different predefined numbering systems that can be applied with one line of CSS, covering many languages around the world. But not all. What about Serbo-croatian? If I specify list-style: upper-serbo-croatian, I just get the default western Arabic numbers. This is where Counter Styles come in. I can define a numbering system, similar to how the browser does it. @counter-style, then the name I want to give it, then I define the qualities of the style. In this case, setting system to alphabetic, and listing the symbols. The W3C Internationalization Working Group has published a document of Ready-made Counter Styles that cover hundreds of cultures around the world. We've increased the number of languages supported by WebKit, and opened a discussion at the CSS Working Group about having all browsers ship support for all of these. But until that happens, you can copy code snippets from this document and paste them into your code. You can also style list counters to be something entirely custom. I've styled this list to count items in binary, with a minimum of four digits. And this one to cycle a set of emoji over and over. CSS Counters can also be used to number other content on the page, besides lists. Like headlines that begin each section in a long document. Here's an example. I've got three H2 headlines, with just words for each headline. In CSS, I create a counter by declaring counter-reset. I've named it "numbering" and I've set it to start counting after zero. Then, using a :before pseudo-element, I tell the browser to increment the counter and to display it in the content. By default, counters use western Arabic numbers--1, 2, 3-- but we can change that. Just like before, I can style the counter to be anything I want. That's how to create and style counters. But that's not everything we're doing this year to help you take your typography to the next level. In fact, there's a lot more CSS coming this year. In Safari 16.2, we also shipped support for last baseline alignment for Grid and Flexbox, plus several functions inside font-variant-alternates and @font-feature-values to further support Open Type features. Safari 16.4 also added support for the Media Queries range syntax and boolean logic, @property, and much more. Safari 16.5 also added support for CSS Nesting. And in Safari 17, we're also adding feature detection of font tech and font formats, contain-intrinsic-size, text-transform: full-width and full-size-kana and a lot more. We want to say a huge thank you to everyone who files issues, pings us on social media, or writes blog posts to let us know which web technology you needed implemented or improved most. We are listening, and your input does have impact. Please let us know what else you need. You can file bug reports and feature requests for web technology at bugs.webkit.org‚ the issue tracker for WebKit. Issues about the interface of Safari or anything about iOS, iPadOS, and macOS, file those at feedbackassistant.apple.com. Make sure you have the latest information about what is supported in Safari. We often hear from developers asking us to implement something that has actually already shipped. Caniuse is a fantastic resource for this. You can also keep up with the latest news on webkit.org, where you'll find in-depth articles about each release of Safari, the release notes for Safari Technology Preview, extensive documentation on Web Inspector, and more. Download Safari Technology Preview to keep up with what's coming in the future. It's updated about every two weeks, so it's got the very latest additions to WebKit. Safari Technology Preview also has all the new features that are ready to be previewed on by default. Or you can turn features on and off in the new Feature Flags pane in Safari Settings, starting in Safari 17, which you can get to from the completely redesigned Develop Menu, with its quick access for connecting Web Inspector on your Mac to websites and web apps on your iPhone, iPad, or other devices, including wirelessly, or test on devices you don't have in hand, by downloading free device simulators, and jumping into them from the Develop Menu, or from the redesigned Responsive Web Design Mode. Watch "Rediscover Safari developer features" at WWDC23 to learn about it all. Web apps are coming to Mac. Plus we've packed the year full of improvements to web apps on iPhone and iPad. "What's new in web apps" covers it all. And learn about new image formats coming to Safari and WebKit, including JPEG XL, and all about the new Managed Media Source API in "Explore media formats for the web." We are thrilled about just how much new web technology is shipping in WebKit and Safari this year and we hope you are too. And we can't wait to see what you make with it all. Thanks for watching.