A few days in the past, the Apple crew launched Safari 26.0! Is it an enormous deal? I imply, browsers launch new variations on a regular basis, the place they sprinkle in a pair or few new options. They’re, in fact, all helpful, however there aren’t often plenty of “huge leaps” between variations. Safari 26 is completely different, although. It introduces a lot of latest stuff. To be exact, it provides: 75 new options, 3 deprecations, and 171 different enhancements.
I’d formally name {that a} huge deal.
The WebKit weblog publish does a tremendous job breaking down every of the brand new (not solely CSS) options. However once more, there are such a lot of that the brand new stuff coming to CSS deserves its personal highlight. So, right now I wish to examine (and likewise strive) what I believe are essentially the most attention-grabbing options coming to Safari.
If you’re like me and don‘t have macOS to check Safari, you’ll be able to use Playwright as an alternative.
What’s new (to Safari)?
Safari 26 introduces a number of options you might already know from prior Chrome releases. And… I can’t blame Safari for seemingly lagging behind as a result of Chrome is transport new CSS at a scarily quick tempo. I respect that browsers stagger releases to allow them to refine issues in opposition to one another. Bear in mind when Chrome initially shipped position-area as inset-area? We acquired higher naming between the 2 implementations.
I believe what you’ll discover (as I did) that many of those overlapping options are a part of the larger effort in direction of Interop 2025, one thing WebKit is dedicated to. So, let’s look particularly at what’s new in Safari 26… not less than that’s new to Safari.
Anchor positioning
Anchor positioning is certainly one of my favourite options (I wrote the information on it!), so I’m so glad it’s arrived in Safari. We are actually one step nearer to extensively out there assist which implies we’re that a lot nearer to utilizing anchor positioning in our manufacturing work.
With CSS Anchor Positioning, we are able to connect an absolutely-positioned factor (that we could name a “goal”) to a different factor (that we could name an “anchor”). This makes creating issues like tooltips, modals, and pop-ups trivial in CSS, though it may be used for a number of layouts.
Utilizing anchor positioning, we are able to connect any two components, like these, collectively. It doesn’t even matter the place they’re within the markup.
<div class="anchor">anchor</div>
<div class="goal">goal</div>
Heads up: Despite the fact that the supply order doesn’t matter for positioning, it does for accessibility, so it’s a good suggestion to ascertain a relationship between the anchor and goal utilizing ARIA attributes for higher experiences that depend on assistive tech.
We register the .anchor factor utilizing the anchor-name property, which takes a dashed ident. We then use that ident to connect the .goal to the .anchor utilizing the position-anchor property.
.anchor {
anchor-name: --my-anchor; /* the ident */
}
.goal {
place: absolute;
position-anchor: --my-anchor; /* hooked up! */
}
This positions the .goal on the heart of the .anchor — once more, regardless of the supply order! If we wish to place it elsewhere, the only approach is utilizing the position-area property.
With position-area, we are able to outline a area round the .anchor and place the .goal in it. Consider it like drawing a grid of squares which can be mapped to the .anchor‘s heart, high, proper, backside and left.

For instance, if we want to place the goal on the anchor’s top-right nook, we are able to write…
.goal {
/* ... */
position-area: high proper;
}
That is only a style since anchor positioning is a world unto itself. I’d encourage you to learn our full information on it.
Scroll-driven animations
Scroll-driven animations hyperlink CSS animations (created from @keyframes) to a component’s scroll place. So as an alternative of working an animation for a given time, the animation will rely on the place the person scrolls.
We are able to hyperlink an animation to 2 varieties of scroll-driven occasions:
- Linking the animation to a scrollable container utilizing the
scroll()perform. - Linking the animation to a component’s place on the viewport utilizing the
view()perform.
Each of those capabilities are used contained in the animation-timeline, which hyperlinks the animation progress to the kind of timeline we’re utilizing, be it scroll or view. What’s the distinction?
With scroll(), the animation runs because the person scrolls the web page. The best instance is a type of studying bars that you just may see develop as you learn down the web page. First, we outline our on a regular basis animation and add it to the bar factor:
@keyframes develop {
from {
rework: scaleX(0);
}
to {
rework: scaleX(1);
}
}
.progress {
transform-origin: left heart;
animation: develop linear;
}
Notice: I’m setting transform-origin to left so it the animation progresses from the left as an alternative of increasing from the middle.
Then, as an alternative of giving the animation a length, we are able to plug it into the scroll place like this:
.progress {
/* ... */
animation-timeline: scroll();
}
Assuming you’re utilizing Safari 26 or the newest model of Chrome, the bar grows in width from left to proper as you scroll down the viewport.
The view() perform is analogous, but it surely bases the animation on the factor’s place when it’s in view of the viewport. That approach, an animation can begin or cease at particular factors on the web page. Right here’s an instance making pictures “pop” up as they enter view.
@keyframes popup {
from {
opacity: 0;
rework: translateY(100px);
}
to {
opacity: 1;
rework: translateY(0px);
}
}
img {
animation: popup linear;
}
Then, to make the animation progress because the factor enters the viewport, we plug the animation-timeline to view().
img {
animation: popup linear;
animation-timeline: view();
}
If we go away like this, although, the animation ends simply because the factor leaves the display screen. The person doesn’t see the entire thing! What we would like is for the animation to finish when the person is in the midst of the viewport so the complete timeline runs in view.
That is the place we are able to attain for the animation-range property. It lets us set the animation’s begin and finish factors relative to the viewport. On this particular instance, let’s say I need the animation to start out when the factor enters the display screen (i.e., the 0% mark) and finishes just a little bit earlier than it reaches the direct heart of the viewport (we’ll say 40%):
img {
animation: popup linear;
animation-timeline: view();
animation-range: 0% 40%;
}
As soon as once more, scroll-driven animations go approach past these two fundamental examples. For a fast intro to all there may be to them, I like to recommend Geoff’s notes.
I really feel safer utilizing scroll-drive animations in my manufacturing work as a result of it’s extra of a progressive enhancement that gained’t break an expertise even when it isn’t supported by the browser. Even so, somebody could desire lowered (or no) animation in any respect, which means we’d higher progressively improve it anyway with prefers-reduced-motion.
The progress() perform
That is one other characteristic we acquired in Chrome that has made its method to Safari 26. Humorous sufficient, I missed it in Chrome when it launched just a few months in the past, so it makes me twice as blissful to see such a helpful characteristic baked into two main browsers.
The progress() perform tells you the way a lot a worth has progressed in a variety between a place to begin and an ending level:
progress(<worth>, <begin>, <finish>)
If the <worth> is lower than the <begin>, the result’s 0. If the <worth> reaches the <finish>, the result’s 1. Something in between returns a decimal between 0 and 1.
Technically, that is one thing we are able to already do in a calc()-ulation:
calc((worth - begin) / (finish - begin))
However there’s a key distinction! With progress(), we are able to calculate values from blended information sorts (like including px to rem), which isn’t at present doable with calc(). For instance, we are able to get the progress worth formatted in viewport models from a numeric vary formatted in pixels:
progress(100vw, 400px, 1000px);
…and it’ll return 0 when the viewport is 400px, and because the display screen grows to 1000px, it progresses to 1. This implies it may typecast completely different models right into a quantity, and as a consequence, we are able to transition properties like opacity (which takes a quantity or proportion) based mostly on the viewport (which is a distance size).
There’s one other workaround that accomplishes this utilizing tan() and atan2() capabilities. I’ve used that strategy earlier than to create clean viewport transitions. However progress() vastly simplifies the work, making it way more maintainable.
Living proof: We are able to orchestrate a number of animations because the display screen measurement modifications. This subsequent demo takes one of many demos I made for the article about tan() and atan2(), however swaps that out with progress(). Works like a allure!
That’s a fairly wild instance. One thing extra sensible is perhaps lowering a picture’s opacity because the display screen shrinks:
img {
opacity: clamp(0.25, progress(100vw, 400px, 1000px), 1);
}
Go forward and resize the demo to replace the picture’s opacity, assuming you’re it in Safari 26 or the newest model of Chrome.
I’ve clamp()-ed the progress() between 0.25 and 1. However, by default, progress() already clamps the <worth> between 0 and 1. In response to the WebKit launch notes, the present implementation isn’t clamped by default, however upon testing, it does appear to be. So, for those who’re questioning why I’m clamping one thing that’s supposedly clamped already, that’s why.
An unclamped model could come sooner or later, although.
Self-alignment in absolute positioning
And, hey, examine this out! We are able to align-self and justify-self content material inside absolutely-positioned components. This isn’t as huge a deal as the opposite options we’ve checked out, but it surely does have a helpful use case.
For instance, I typically wish to place an absolutely-positioned factor straight within the heart of the viewport, however inset-related properties (i.e., high, proper, backside, left, and so forth.) are relative to the factor’s top-left nook. Which means we don’t get completely centered with one thing like this as we’d anticipate:
.absolutely-positioned {
place: absolute;
high: 50%;
left: 50%;
}
From right here, we may translate the factor by half to get issues completely centered. However now we now have the heart key phrase supported by align-self and justify-self, which means fewer shifting items within the code:
.absolutely-positioned {
place: absolute;
justify-self: heart;
}
Weirdly sufficient, I seen that align-self: heart doesn’t appear to heart the factor relative to the viewport, however as an alternative relative to itself. I discovered that may use the anchor-center worth to heart the factor relative to its default anchor, which is the viewport on this particular instance:
.absolutely-positioned {
place: absolute;
align-self: anchor-center;
justify-self: heart;
}
And, in fact, place-self is a shorthand for the align-self and justify-self properties, so we may mix these for brevity:
.absolutely-positioned {
place: absolute;
place-self: anchor-center heart;
}
What’s new (for the net)?
Safari 26 isn’t nearly maintaining with Chrome. There’s plenty of thrilling new stuff in right here that we’re getting our fingers on for the primary time, or that’s refined from different browser implementations. Let’s take a look at these options.
The constrast-color() perform
The constrast-color() isn’t new by any means. It’s really been in Safari Expertise Preview since 2021 the place it was initially known as color-contrast(). In Safari 26, we get the up to date naming in addition to some polish.
Given a sure colour worth, contrast-color() returns both white or black, whichever produces a sharper distinction with that colour. So, if we have been to supply coral as the colour worth for a background, we are able to let the browser resolve whether or not the textual content colour is extra contrasted with the background as both white or black:
h1 {
--bg-color: coral;
background-color: var(--bg-color);
colour: contrast-color(var(--bg-color));
}
Our personal Daniel Schwarz not too long ago explored the contrast-color() perform and located it’s really not that nice at figuring out the very best distinction between colours:
Undoubtedly, the primary shortcoming is that
contrast-color()solely resolves to both black or white. Should you don’t need black or white, nicely… that sucks.
It sucks as a result of there are instances the place neither white nor black produces sufficient distinction with the offered colour to fulfill WCAG colour distinction tips. There’s an intent to increase contrast-color() so it may return further colour values, however there nonetheless can be considerations about how precisely contrast-color() arrives on the “greatest” colour, since we might nonetheless have to think about the font’s width, measurement, and even household. All the time examine the precise distinction!
So, whereas it’s nice to lastly have constrat-color(), I do hope we see enhancements added sooner or later.
Fairly textual content wrapping
Safari 26 additionally introduces text-wrap: fairly, which is fairly (get it?) simple: it makes paragraphs wrap in a prettier approach.
You might keep in mind that Chrome shipped this again in 2023. However take discover that there’s a fairly (OK, that’s the final time) huge distinction between the implementations. Chrome solely avoids typographic orphans (brief final traces). Safari does extra to prettify the best way textual content wraps:
- Prevents brief traces. Avoids single phrases on the finish of the paragraph.
- Improves rag. Retains every line comparatively the identical size.
- Reduces hyphenation. When enabled, hyphenation improves rag but in addition breaks phrases aside. Generally, hyphenation must be saved to a minimal.
The WebKit weblog will get into a lot larger element for those who’re interested in what concerns they put into it.

That is just the start!
I believe these are all of the CSS options coming to Safari that you must look out for, however I don’t need you to suppose they’re the one options within the launch. As I discussed on the high, we’re speaking about 75 new Net Platform options, together with HDR Photos, assist for SVG favicons, logical property assist for overflow properties, margin trimming, and far, way more. It’s price perusing the full launch notes.

