Streaming is available in most browsers,
and in the Developer app.
-
What’s new in CSS
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.
Resources
- MDN Web Docs - Web Extensions API
- Safari Release Notes
- Safari Technology Preview
- Submit feedback
- Web Inspector Reference
- WebKit Open Source Project
Related Videos
WWDC23
- Explore media formats for the web
- Meet Safari for spatial computing
- Rediscover Safari developer features
- What’s new in web apps
- What’s new in Web Inspector
WWDC22
-
Download
♪ ♪ Jen: Hello, I'm Jen Simmons, a Safari and WebKit Evangelist here at Apple. It's been a fantastic year for WebKit. We've already shipped more than 140 new web technologies in multiple releases of Safari throughout this year, and we have several dozen more new web technologies coming this fall. There's so much, there's no way we can cover it all, so we decided to focus on CSS. In this session, we'll take a look at some of the most exciting new features in CSS, including brand-new possibilities with layout, a whole generation of color tools that make full use of today's amazing displays, productive ways to solve tricky problems with new pseudo-classes, and CSS that lets you take your typography to the next level. I'm going to share things that have already shipped, things that will ship in Safari 17, and things we're working on for the future. To see the future today, download Safari Technology Preview. It's there you'll find Masonry Layout. For years, this has been a popular layout pattern on the web. It's a great way to pack content of different sizes. You can accomplish a layout with this shape by using CSS Multicolumn, if it's OK that the content order starts in the first column, flows down below the viewport, goes back up to the top the second column, flows down it, then on to the third column, and so on. If this works for your project, great. CSS Multicolumn is a layout mechanism that's been in browsers for decades. But often this doesn't work. Instead, designers want their content to flow across the page, placing each item in whichever column puts it as close to the top as possible. Which is especially needed when more content gets loaded at the bottom as the user scrolls. So websites have had to use JavaScript to accomplish this. But JavaScript is slower at layout than CSS, and it's more fragile. It's harder to code. Layout really belongs in CSS. A proposal for creating Masonry as part of CSS Grid was started several years ago and implemented in Firefox as an experiment behind a flag. We believe in this idea and we'd like to see it come to the web, so now it's in Safari Technology Preview-- on by default-- where you can try it out, tell us what you think, and help us move it forward. Here's an example. I created this typical Masonry layout with very little CSS. display: grid gets us started, and grid-template-columns gives us flexible columns that automatically increase in number when more space is available. Then grid-template-rows: masonry packs items into a Masonry pattern in the row direction with just one line of code. Making this part of CSS Grid gives us tremendous flexibility. You can define Masonry in one dimension, and use the power of Grid to do anything you want in the other dimension, like making the columns different sizes with fr units, or making the first column fixed-width, while the middle is flexible using an fr unit, and the third is made flexible with a minmax value. Combining Masonry with Grid makes for a far more powerful mechanism than the popular JavaScript library. This is all still a work in progress. More discussion is needed in the CSS Working Group, where browser makers and others come together to agree on a path forward, including work to make sure that it's fully accessible. We look forward to shipping Masonry in Safari once it's ready. What is ready to be shipped in browsers today? Margin trim. The new margin-trim property makes it easy to remove margins from elements that push up against their container. Let me explain. Imagine we have a headline and three paragraphs. They all have top and bottom margins, which provide space between them, as well as space above and below the whole group. There's also padding applied to the container, the article element with a class of card. The margin above the headline and the top padding on the container get added together to determine how much space there is between the top edge of the box and that first line of text. Same on the bottom. The margin below the last paragraph gets added to the bottom padding on the container, which probably adds up to more whitespace than intended. What we want instead is to only have the padding on the top and bottom and to not have any margins involved. This will give us more uniform space around the box. What we need is a way to eliminate any margins that push up against the container. You've probably attempted to handle this by manually removing the top margin from the headline and the bottom margin from the last paragraph and, well, hoping for the best. But then unexpected content shows up. Maybe another instance starts with an h3, and no one wrote that code, or somebody sticks an h2 in the middle and it's missing its top margin. Margin trim gives us a better solution. Instead, you can ask for exactly what you want by applying margin-trim: block to the container. We've added support for margin-trim in Safari 16.4. You can also use margin-trim: inline to trim margins in the inline direction. That's margin trim. It simply solves a common need in a more robust manner. CSS for layout has really matured over the last six years since the advent of CSS Grid in March of 2017. Today's layouts are a radical improvement over what we did a decade ago. In the same timespan, there's been another radical leap forward that's gone a bit unnoticed by web designers and developers: a leap in color. The world is full of color, especially outside. The dynamic range, the saturation, all the nuances and possibilities. Imagine this diagram represents every color the human eye might possibly see. A line around a subset of these colors shows what can be represented in sRGB, the default color gamut on the web, which has served us well. It's certainly better than what we used the '90s, but it'd be great to move past the limitations of sRGB and convey more of the visual spectrum.
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.
The same impact applies when mixing colors together. Yeah, you can now mix colors in CSS. Starting in Safari 16.2, there's a new color-mix function. You list two colors to mix and specify which color space to use, and the browser mixes them together. You might recognize this purplish-blue from the middle of the gradient. We can instead switch to any of the other color spaces that we looked at for using with gradients. These all create different results. By default, color mix makes the new color from 50% of one color and 50% of the other. But you can change it to be any ratio you would like, 80/20, or 30/70. You can also set the two numbers to be less than 100% total, which makes the color translucent. Here, I've set white to 30% and blue to 30%, giving the resulting color an opacity of 60%. You can even use the currentcolor keyword to mix the current text color with whatever you'd like. In this case, I'm mixing a dark green link color with 40% white to create a lighter green to use with the hover color. There's a lot here. The P3 color gamut, new color models and functions, the ability to change color spaces for gradients and animations, new ways to define colors by altering the channels of an existing color or through mixing-- there's a lot of potential here when it comes to leveraging color in our designs for the web. One last thing to know about support for P3 color. Not only does the browser need to support certain features in CSS or JavaScript that make use of P3 color, and of course, the user's operating system and display need to support it, but also the browser needs to support rendering in P3 for each particular part of the web page, in different portions of the DOM. You'll want to check into the details for each browser before assuming that it works universally. Let me give you an update on P3 in Safari. We shipped support for images in P3 seven years ago in Safari 10.0. In Safari 10.1, we added overall support for P3 for most of the web page. In Safari 15.2, we added support inside the Canvas element. And in Safari 16.4, we added support for P3 in WebGL Canvas through the use of drawingBufferColorSpace. As for developer tools, in Safari 13.1, we shipped a color picker in Web Inspector that makes it easy to find colors that are only available in P3, or to convert a color from one color model to another. And in Safari 15.2, we added support for P3 to the Web Inspector graphics tab. We still have a little bit more work to do. First, to extend support inside WebGL Canvas to include the use of unpackColorSpace. And to add support for P3 in SVG filters, which we've not done yet, because there's still ongoing debate about the web standard. For now, if you apply an SVG Filter, colors will be flattened into sRGB in every browser. It's truly an exciting time to rethink color on the web, especially since so many of these features will finally be available across browsers. Advancements in CSS not only change what's possible to design, but they also make it easier to code those designs.
The :user-valid and :user-invalid pseudo-classes provide a way to style forms depending on whether or not a user has correctly filled out a field. For years, the :valid and :invalid pseudo-classes seemed like they'd be really helpful. I want to style this form field to alert a user when they've made a mistake. So I'll try the :invalid pseudo-class to select an invalid input. With :has input:invalid, I'll target the label. And with a ::before pseudo-element, I'll insert an "x", so communication doesn't depend on color alone. Let's look at the result. When someone starts to-- yeah, that's not great. As soon as a user starts to type, the browser marks it invalid because it's not yet a valid email address. Because :invalid marks input wrong before users even have a chance to get it right, developers have been using JavaScript for this instead. user-valid and user-invalid fix this problem. They use a more complex algorithm to determine when a form field is considered valid or invalid. We shipped it in Safari 16.5. Now we can see the improved result. No red warning if they've if they've got it right. And if someone does fill out the field incorrectly, the red warnings appear after they've left the field, when we want to warn them to go back and fix it. As you can see, :user-invalid is especially powerful when it's combined with :has().
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.
-
-
2:49 - Masonry layout, example 1
main { display: grid; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); grid-template-rows: masonry; }
-
3:20 - Masonry layout, example 2
main { display: grid; grid-template-columns: 1fr 2fr 3fr; grid-template-rows: masonry; }
-
3:24 - Masonry layout, example 3
main { display: grid; grid-template-columns: 10rem 1fr minmax(100px, 300px); grid-template-rows: masonry; }
-
5:28 - Margin trim
.card { background-color: #fcf5e7; padding: 2rlh; margin-trim: block; } h2, p { margin: 1rlh 0; }
-
7:25 - Color gamut media query
.card { background-color: #fcf5e7; padding: 2rlh; margin-trim: block; } h2, p { margin: 1rlh 0; }
-
-
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.