News – WebKit https://webkit.org Open Source Web Browser Engine Thu, 05 Mar 2026 00:18:00 +0000 en-US hourly 1 https://wordpress.org/?v=6.9.1 Announcing Interop 2026 https://webkit.org/blog/17818/announcing-interop-2026/ Thu, 12 Feb 2026 17:00:59 +0000 https://webkit.org/?p=17818 Exciting news for web developers, designers, and browser enthusiasts alike — Interop 2026 is here, continuing the mission of improving cross-browser interoperability. For the fifth year in a row, we are pleased to collaborate with Google, Igalia, Microsoft, and Mozilla to make web technology more consistent and reliable across our browsers.

Introducing Interop 2026

Making your website work in every browser can be a challenge, especially if browser engines have implemented the same web technology in slightly different ways. The Interop Project tackles this challenge by bringing the major browser engines together to improve the same set of features during the same year. Each feature is judged on whether or not it fully aligns with its official web standard — the formal technical specifications that define how each web technology should work. This helps accelerate progress toward a more reliable, consistent platform to build on.

Safari has already implemented many of the features included in Interop 2026. In fact, we were the first browser to ship contrast-color(), Media pseudo-classes, shape(), and Scoped Custom Element Registries. Plus, we have support for Anchor Positioning, Style Queries, Custom Highlights, Scroll Snap, View Transitions and much more. We’re excited that these technologies are being included as focus areas in Interop 2026, ensuring they get implemented across all browsers and any remaining interoperability gaps are closed.

We will also be focused on adding support for the following features: advanced attr(), the getAllRecords() method for IndexedDB, WebTransport, and the JavaScript Promise Integration API for Wasm. Together, these four areas make up 20% of the Interop 2026 score. They are exciting new features that solve real needs.

Focus Areas for 2026

The Interop Project measures interoperability through Web Platform Tests — automated tests that check whether browsers conform to web standards. Interop 2026 is ambitious, covering twenty focus areas. Fifteen are brand new. And five are carryovers from Interop 2025.

Anchor positioning

Anchor positioning is a carryover from Interop 2025, where significant progress was made to empower developers to position elements relative to each other. This year’s focus will be on clarifying the spec, resolving test issues, and increasing the reliability of this powerful layout feature.

Advanced attr()

The CSS attr() function lets you bridge the gap between structural data and visual presentation by pulling values directly from HTML attributes into your CSS, making styles more dynamic and context-aware without the overhead of JavaScript. While attr() has long been supported for the content property, advanced attr() extends it to work across all CSS properties with type conversion — letting you use HTML attribute values as colors, lengths, angles, and other data types. Now that security concerns have been worked through in the specification, browser makers are united in our excitement to ship this long-awaited capability with strong interoperability.

Container style queries

Style queries let you apply styles conditionally, based on the value of a custom property (aka, variable) as defined at a certain container. Similar to how Container size queries let your CSS respond to the size of the container, style queries let it respond to theme values, state flags, and other contextual data.

@container style(--theme: dark) {
  .card {
    background: #1a1a1a;
    color: #ffffff;
  }
}

Style queries started shipping in recent years, including in Safari 18.0. Interop 2026 will help ensure this powerful tool works consistently everywhere.

contrast-color()

The contrast-color() function in CSS returns a color — either black or white. It puts the burden on the browser to choose whichever has higher contrast with the color specified in the function.

.button {
  background: var(--brand-color);
  color: contrast-color(var(--brand-color));
}

By having the browser make the choice, you can architect your design system in a simpler fashion. You don’t need to manually define every color pairing. Safari and Firefox both shipped support in 2025, and now Interop 2026 will ensure this powerful function works consistently across all browsers.

Note, contrast-color() does not magically solve all accessibility concerns. Read about all the details in How to have the browser pick a contrasting color in CSS.

CSS Zoom

The CSS zoom property scales an element and its contents, affecting layout and making the element take up more (or less) space. Unlike transform: scale(), which is purely visual, zoom changes how the element participates in layout.

.card {
  zoom: 1.5; /* Element is 150% larger and takes up more space */
}

While zoom was supported in browsers for years as a non-standard property, it’s been plagued by inconsistencies in edge cases and how it interacts with other layout features. Now that it’s standardized, CSS zoom returns as a focus area in Interop 2026, continuing from 2025.

Custom Highlights

The CSS Custom Highlight API lets you style arbitrary text ranges without adding extra elements to the DOM. Using JavaScript, you create a highlight range, then style it with the pseudo-elements.

The ::highlight() pseudo-element is perfect for highlighting in-page search results, customizing syntax highlighting in code editors, creating an app that allows collaborative editing with user cursors, or any situation where you need to visually mark text without changing the document structure. The ::target-text pseudo-element styles the text that’s scrolled to when a user taps a link with a text fragment.

With implementations progressing across browsers, Interop 2026 ensures these highlighting capabilities work consistently, giving you reliable tools for text-based interactions.

Dialog and popover additions

The <dialog> element and popover attribute have transformed how developers build overlays on the web. Dialog was part of Interop 2022 and Popover was in Interop 2024. This year, three recent enhancements to these features make up this focus area for Interop 2026.

The closedby attribute lets you control how users can dismiss dialogs:

<dialog closedby="any">
<!-- Can be closed by clicking outside or pressing Escape -->
</dialog>

The popover="hint" attribute creates subordinate popovers that don’t dismiss other auto popovers — perfect for tooltips:

<div popover="hint" id="tooltip">
  This tooltip won’t close the menu!
</div>

The :open pseudo-class matches elements with open states, working with <dialog>, <details>, and <select>:

dialog:open {
  animation: slideIn 0.3s;
}

Together, these additions make building accessible, user-friendly UI overlays easier than ever.

Fetch uploads and ranges

The fetch() method is getting three new powerful capabilities for handling uploads and partial content.

ReadableStream request bodies enable true streaming uploads, letting you upload large files or real-time data without loading everything into memory first:

await fetch('/upload', {
  method: 'POST',
  body: readableStream,
  duplex: 'half'
});

Enhanced FormData support improves multipart uploads and responses.

Range header support allows partial content requests, essential for video streaming and resumable downloads:

fetch('/video.mp4', {
  headers: { 'Range': 'bytes=0-1023' }
});

These enhancements bring fetch() up to par with more specialized APIs, reducing the need for custom solutions.

getAllRecords() for IndexedDB

IndexedDB is a low-level API that lets you store large amounts of structured data in the browser, including files and blobs. It’s been supported in browsers for many years.

Now, IndexedDB is getting a significant performance boost with the new getAllRecords() methods for IDBObjectStore and IDBIndex. These methods allow you to retrieve records in batches and in reverse order:

const records = await objectStore.getAllRecords({
  query: IDBKeyRange.bound('A', 'M'),
  count: 100,
  direction: 'prev'
});

It’s just this new method that’s being included in Interop 2026. The score only reports the percentage of getAllRecords() tests that are passing — not all IndexDB tests.

JSPI for Wasm

WebAssembly has opened the door for running high-performance applications in the browser — games, productivity tools, scientific simulations, and more. But there’s been a fundamental mismatch. Many of these applications were originally written for environments where operations like file I/O or network requests are synchronous (blocking), while the web is fundamentally asynchronous.

The JavaScript Promise Integration API (JSPI) bridges this gap. It lets WebAssembly code that expects synchronous operations work smoothly with JavaScript’s Promise-based async APIs, without requiring you to rewrite the entire application. This means you can port existing C, C++, or Rust applications to the web more easily, unlocking a wider range of software that can run in the browser.

Interop 2026 will ensure JSPI works consistently across browsers, making WebAssembly a more viable platform for complex applications.

Media pseudo-classes

We’ve proposed media pseudo-classes for inclusion in the Interop Project for many years in a row. We are excited that it’s being included this year!

Seven CSS pseudo-classes let you apply CSS based on the playback state of <audio> and <video> elements:

These all shipped in Safari many years ago, but without support in any other browser, most developers don’t use them — or even know they exist. Instead developers need JavaScript to sync UI state with media playback state.

It’s far simpler and more efficient to use media state pseudo-classes in CSS.

video:buffering::after {
  content: "Loading...";
}
audio:muted {
  opacity: 0.5;
}

They are especially powerful combined with :has(), since it unlocks the ability to style anything on the page based on playback state, not just elements that are descendants of the media player.

article:has(video:playing) {
  background-color: var(--backgroundColor); 
  color: contrast-color(var(--backgroundColor));
  transition: background-color 0.5s ease;
}

Learn more about the power of :has() in Using :has() as a CSS Parent Selector and much more.

Navigation API

If you’ve built single-page applications, you may have experienced the pain of managing navigation state with history.pushState() and popstate events. Navigation API gives you a cleaner, more powerful way to intercept and control navigation.

This focus area is a continuation of Interop 2025, where significant progress was made to empower developers to initiate, intercept, and modify browser navigation actions. This year continues work on interoperability, to get the overall score up from the 92.3% test pass result during Interop 2025. Plus, there’s one new feature being added — the precommitHandler option. It lets you defer navigation until critical resources are ready, preventing jarring flashes of incomplete content.

navigation.addEventListener('navigate', (e) => {
  e.intercept({
    async precommitHandler() {
      // Load critical resources before commit
      await loadCriticalData();
    },
    async handler() {
      // Render the new view
      renderPage();
    }
  });
});

Interop 2026 will ensure Navigation API works reliably across browsers, a solid foundation for web applications.

Scoped custom element registries

Working with web components, you may have run into a frustrating limitation: the global customElements registry only allows one definition per tag name across your entire application. When two different libraries both define a <my-button> component, they conflict.

The CustomElementRegistry() constructor solves this by letting you create scoped registries. Different parts of your application — or different shadow roots — can have their own definitions for the same tag name.

const registry = new CustomElementRegistry();
registry.define('my-button', MyButtonV2);
shadowRoot.registry = registry;

This is especially valuable for microfrontends, component libraries, and any situation where you’re integrating third-party web components.

Safari 26.0 was the first browser to ship Scoped custom element registries. Inclusion in Interop 2026 will help ensure this capability works consistently across all browsers.

Scroll-driven Animations

Scroll-driven animations let you more easily create animations that respond to scroll position, now entirely in CSS. As a user scrolls, the animation progresses — no JavaScript needed. You can build scroll-triggered reveals, progress indicators, parallax effects, and interactive storytelling experiences.

Define animations with standard CSS keyframes, then connect them to scroll using animation-timeline:

.reveal {
  animation: fade-in linear forwards;
  animation-timeline: view();
  animation-range: entry 0% entry 100%;
}

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

Use view() to trigger animations as elements enter and exit the viewport, or scroll() to tie animations to a scrolling container’s position. Learn much more in A guide to Scroll-driven Animations with just CSS.

We shipped support for scroll-driven animations in Safari 26.0. Interop 2026 will help ensure this feature works consistently across all browsers.

Scroll Snap

CSS Scroll Snap controls the panning and scrolling behavior within a scroll container, creating carousel-like experiences:

.carousel {
  scroll-snap-type: x mandatory;
  overflow-x: scroll;
}
.carousel > * {
  scroll-snap-align: center;
}

Scroll Snap has been supported in all modern browsers for many years. But like many of the older CSS specifications, multiple rounds of changes to the specification while early versions were already shipping in browsers created a deep lack of interoperability. With a far more mature web standard, it’s time to circle back and improve interoperability. This is the power of the Interop Project — focusing all the browser teams on a particular feature, and using automated tests to find inconsistencies and disagreements.

shape()

For years, when you wanted to create a complex clipping path to use with clip-path or shape-outside you’ve been limited to polygon(), which only supports straight lines, or SVG paths, which aren’t responsive to element size changes.

Now, the shape() function lets you create complex shapes with path-like commands (move, line, curve). It gives you the best of both worlds — curves like SVG paths, but with percentage-based coordinates that adapt as elements resize.

.element {
  clip-path: shape(
    from 0% 0%,
    line to 100% 0%,
    line to 100% 100%,
    curve to 0% 100% via 50% 150%,
    close
  );
}

We shipped support for the shape() function in Safari 18.4. And we look forward to Interop 2026 improving browser implementations so you can confidently use it to render of complex, responsive curves.

View transitions

View Transitions was a focus area in Interop 2025, narrowly defined to include same-document view transitions and view-transition-class. These features allow for smooth, animated transitions between UI states within a single page, as well as flexible control over styling those transitions.

While Safari finished Interop 2025 with a score of 99.2% for view transitions, the overall interoperability score is at 90.8% — so the group decided to continue the effort, carrying over the tests from 2025.

For Interop 2026, the focus area expands to also include cross-document view transitions. This allows you to create smooth, animated transitions in the moments between pages as users navigate your site, rather than an abrupt jump when new page loads. Cross-document view transitions shipped in Safari 18.2. Learn more about it in Two lines of Cross-Document View Transitions code you can use on every website today.

Web Compat

Web compatibility refers to whether or not a real world website works correctly in a particular browser. When a site works in one browser, but not another — that’s a “compat” problem. This focus area is made up of a small collection of Web Platform Tests selected because the fact they fail in some browsers causes real websites to not work in other browsers — thus creating problems for both web developers and users.

Each time Web Compat has been a focus area as part of the Interop Project, it’s targeted a different set of compat challenges. This year, Interop 2026’s web compatibility work includes:

WebRTC

WebRTC (Web Real-Time Communication) enables real-time audio, video, and data communication directly between browsers, without requiring plugins or intermediate servers. You can build video conferencing apps, live streaming platforms, peer-to-peer file sharing, and collaborative tools.

Having reached a 91.6% pass rate, WebRTC continues as a focus area in 2026, building on the progress made during Interop 2025. We’re looking forward to fixing the long tail of interop issues of the main spec for WebRTC.

WebTransport

WebTransport provides a modern way to transmit data between client and server using the HTTP/3 protocol. It gives you low-latency bidirectional communication with multiple streams over a single connection. You get both unreliable datagram support (like UDP) for speed and reliable stream support (like TCP) for guaranteed delivery.

const transport = new WebTransport('https://example.com/endpoint');
await transport.ready;
const stream = await transport.createBidirectionalStream();
// Stream data efficiently

WebTransport is ideal for gaming, real-time collaboration tools, and applications where you need more control than WebSocket provides but don’t want to manage WebRTC’s complexity. Being part of Interop 2026 ensures WebTransport works consistently across all browsers, making it a reliable choice for real-time data transmission.

Investigation Efforts: A Look Ahead

In addition to the focus areas, the Interop Project includes four investigation areas. These are projects where teams gather to assess the current state of testing infrastructure and sort through issues that are blocking progress.

Accessibility testing

Continuing from previous years, the Accessibility Testing investigation aims to work towards generating consistent accessibility trees across browsers. This effort will improve the WPT testing infrastructure for accessibility on top of the foundation from Interop 2024. This work ensures that accessibility features are reliable and consistent, helping developers create more inclusive web experiences.

JPEG XL

JPEG XL is a next-generation raster graphics format that supports animation, alpha transparency, and lossy as well as lossless compression. We shipped support for it in Safari 17.0. This investigation will focus on making the feature properly testable by developing comprehensive test suites, opening up the possibility that JPEG XL could be a focus area in the future.

Mobile testing

The Mobile Testing investigation continues work started in 2025. This year, we will focus on improving infrastructure for mobile-specific features like dynamic viewport changes which are crucial for building responsive mobile web experience that billions of users rely on every day.

WebVTT

Continuing from 2025, the WebVTT investigation addresses a critical challenge facing the web platform. Developers cite WebVTT’s inconsistent behavior across browsers as a major reason for choosing other subtitling and captioning solutions. Our investment in WebVTT last year primarily consisted of validating and fixing the existing test suite, as well as making any necessary spec changes along the way. We are excited to continue that effort this year to ensure synchronized text tracks and closed captioning work seamlessly across the web.

A more interoperable web

Interop 2026 brings together twenty focus areas that matter to you as a web developer. Some, like attr() and contrast-color(), give you more flexible ways to architect your CSS. Others, like Scroll-Driven Animations and View Transitions, let you create smoother, more engaging experiences without reaching for JavaScript. Features like WebTransport and the Navigation API give you more powerful tools for building modern web applications.

Just as important are the focus areas working to fix long-standing inconsistencies — ensuring Scroll Snap works reliably, bringing all browsers up to speed on shape(), and solving real-world compatibility problems that have been frustrating developers and breaking sites.

The WebKit team is committed to making these features work consistently across all browsers. Whether you’re building a design system, a single-page application, a video streaming platform, or anything in between, Interop 2026 is working to give you a more reliable foundation to build on.

Here’s to another year of making the web better, together!

]]>
WebKit features for Safari 26.3 https://webkit.org/blog/17798/webkit-features-for-safari-26-3/ Wed, 11 Feb 2026 18:00:49 +0000 https://webkit.org/?p=17798 Safari 26.3 is here, with practical improvements for performance and user experience. This release gives you new tools for optimizing how your content is delivered and better control over navigation in single-page applications. We’ve also fixed issues developers have run into with anchor positioning, multi-column layouts, and other features — making them more robust and reliable. Plus, we’ve refined the everyday browsing experience by fixing issues we found while testing real websites.

Video in visionOS

Now in Safari 26.3 in visionOS, fullscreen video playback automatically dims the user’s surroundings to help put the focus on content.

A floating rectangular image of a dog running at a dog show, covered by the site "The Ultimate Spectacular". This rectangle is floating in a world covered by sandy hills, with mountains in the background, and a big cloudy sky above. This is a 3D environment in visionOS. The image is a video that's full brightness, while the environment around it is not as bright as normal. It's dimmed.
Now when a user plays a video in Safari (like this trailer on YouTube for Top Dogs) and enters fullscreen, the world around the video is dimmed in visionOS 26.3.

Zstandard

Safari 26.3 supports Zstandard (Zstd), a compression algorithm you can use to make your website’s files smaller before sending them to browsers. Like gzip and Brotli, it compresses text-based assets — HTML, CSS, JavaScript, JSON, and SVG — so less data travels over the network.

Zstandard decompresses quickly, reducing the workload on users’ devices. It also compresses fast enough to do on-the-fly, whereas Brotli is typically pre-compressed during your build process.

To use it, configure your server to compress responses with Zstandard and send the Content-Encoding: zstd header. Servers will automatically fall back to other compression methods for browsers that don’t have support yet.

Zstandard support is available in Safari 26.3 on iOS 26.3, iPadOS 26.3, visionOS 26.3, and macOS Tahoe 26.3 — and not in Safari 26.3 on earlier versions of macOS. This is because support comes from the system networking stack used by Safari.

Navigation API

When building single-page applications with the Navigation API, you might need a reliable way to cancel ongoing work when a navigation gets interrupted. Maybe the user clicked another link before the previous navigation finished, they hit the back button, or your code called navigation.navigate() again. Whatever the reason, you don’t want to keep processing a navigation that’s no longer relevant.

In Safari 26.3, the Navigation API exposes a AbortSignal on NavigateEvent which triggers when the navigation is aborted, giving you a standard way to clean up and cancel work:

navigation.addEventListener('navigate', (event) => {
  event.intercept({
    async handler() {
      const response = await fetch('/api/data', {
        signal: event.signal  // Automatically cancels if navigation is aborted
      });

      const data = await response.json();
      renderContent(data);
    }
  });
});

If the user navigates away before the fetch completes, the request automatically cancels. You can also listen to the signal’s abort event to clean up other resources like timers or animations.

This gives you fine-grained control over what happens when navigations don’t complete, helping you avoid memory leaks and unnecessary work.

Bug fixes and more

Along with the new features, WebKit for Safari 26.3 includes additional improvements to existing features.

CSS

  • Fixed a style resolution loop that occurred when a position-try box was inside a display: none ancestor. (163691885)
  • Fixed an issue where anchor-positioned elements repeatedly transitioning from display: block to display: none cause position jumps during animation. (163862003)
  • Fixed an issue where fixed-positioned boxes using position-area were incorrectly included in the scrollable containing block calculation. (164017310)
  • Fixed an issue where text-decoration: underline was rendered too high when text-box-trim was applied to the root inline box. (165945326)
  • Fixed a multi-column layout issue where the widows and text-indent properties are applied cause an incorrect indent on the portion of the paragraph that flows into the next column. (165945497)
  • Fixed an issue where CSS cursors like move, all-scroll, ew-resize, and ns-resize did not display correctly. (166731882)

DOM

  • Fixed incorrect timestamp handling and switched to use the raw touch timestamp. (164262652)

Media

  • Fixed an issue where the fullscreen button in visionOS inline video controls did not visually indicate interactivity by extending the glow effect to all button.circular elements. (164259201)
  • Fixed Video Viewer mode for iframe videos on macOS. (164484608)
  • Fixed an issue where Safari could not play live videos when the sourceBuffer content is removed and re-added causing the seek to not complete. (165628836)

Rendering

  • Fixed an issue where positioned or transformed <img> elements containing HDR JPEGs with gain maps would incorrectly render as SDR. (163517157)

Safe Browsing

  • Fixed a bug where if Safe Browsing queried for an entry on the Public Suffix List, and a Safe Browsing vendor responded that the whole effective TLD was unsafe, the whole site would be marked as unsafe. (168155375)

Feedback

We love hearing from you. To share your thoughts, find us online: Jen Simmons on Bluesky / Mastodon, Saron Yitbarek on BlueSky / Mastodon, and Jon Davis on Bluesky / Mastodon. You can follow WebKit on LinkedIn.

If you run into any issues, we welcome your bug report. Filing issues really does make a difference.

You can also find this information in the Safari release notes.

]]>
Interop 2025: A year of convergence https://webkit.org/blog/17808/interop-2025-review/ Fri, 06 Feb 2026 17:45:28 +0000 https://webkit.org/?p=17808 Interop 2025 has come to a close, and the results speak for themselves. Now in its fourth year, the Interop project brings together Apple, Bocoup, Google, Igalia, Microsoft, and Mozilla to identify the areas of the web platform where interoperability matters most to you as a web developer — and then do the work to get there. This year was the most ambitious yet: the group selected 19 focus areas and 5 investigation areas spanning CSS, JavaScript, Web APIs, and performance. At the start of 2025, only 29% of the selected tests passed across all browsers. By the end of the year, the Interop score reached a 97% pass rate — and all four experimental browsers (Chrome Canary, Edge Dev, Firefox Nightly, and Safari Technology Preview) reached 99%.

Interop 2025 end of year results. Chrome Canary, Edge Dev, Firefox Nightly, and Safari Technology Preview all have a score of 99%. The overall interop score is 97%.

Each year, the Interop project chooses its focus areas through a collaborative process with proposals, research into what web developers need, and debates about priorities. For Interop 2025, our team advocated for including focus areas that we knew would require significant engineering investment from WebKit — because we knew those areas would make a real difference to you. The results show that commitment paid off. Safari made the largest jump of any browser this year, climbing from 43 to 99.

As always, this year’s focus areas were chosen based on developer feedback, including results from the State of CSS survey, and we’re proud of how much ground we covered. The 19 focus areas touched nearly every corner of the platform. On the CSS and UI side, the project tackled Anchor Positioning, View Transitions, @scope, backdrop-filter, text-decoration, Writing modes, Layout (both Flexbox and Grid, continued from prior years), and the <details> element. For APIs and platform features, we worked on the Navigation API, Storage Access API, URLPattern, Modules, the scrollend event, WebRTC, and WebAssembly. And on the health and compatibility front, there was focused work on Core Web Vitals, Pointer and Mouse events, removing Mutation events, and general web compatibility. Five investigation areas — accessibility testing, Gamepad API testing, mobile testing, privacy testing, and WebVTT — laid groundwork for future Interop cycles.

We want to highlight three focus areas that were especially meaningful this year.

  • Anchor positioning lets you position popovers, tooltips, and menus relative to any element purely in CSS — no JavaScript positioning libraries required. It’s one of the most requested CSS features of the last several years, and it now works interoperably across all browsers.
  • Same-document View Transitions allow smooth, animated transitions between UI states natively in the browser, along with the new view-transition-class CSS property for flexible styling of those transitions. We shipped support in fall 2024, in Safari 18.0 and Safari 18.2. Web developers are excited about View Transitions! This extra attention on interoperability across browsers means it’s ready for you to use.
  • Navigation API — a modern replacement for history.pushState() — gives single-page applications proper navigation handling with interception, traversal, and entries. We shipped support in Safari 26.2, and we’re glad to see it arrive interoperably from the start.
The graphs of scores across the year. A black line shows the overall interoperability rising from around 30% in January to 97% at the end. A blue line representing Safari's progress rises from 43% to be the best score at the top in December, almost at 100%. Orange representing Firefox starts just above Safari, and also follows a similar trajectory across the year. Edge and Chrome have kind of flat progress, starting around 80 and converging with all the other lines at the top at the end.

The graph above tells the story of the year: every browser engine invested heavily, and the lines converge at the top. That convergence is what makes the Interop project so valuable — the shared progress that means you can write code once and trust that it works everywhere.

We want to thank our colleagues across the industry who made this possible. Interoperability is one of the foundational strengths of the web, and we remain committed to this collaboration. You can explore the full results, including scores for each individual focus area, on the Interop 2025 dashboard.

]]>
WebKit Features for Safari 26.2 https://webkit.org/blog/17640/webkit-features-for-safari-26-2/ Fri, 12 Dec 2025 18:30:35 +0000 https://webkit.org/?p=17640 Safari 26.2 is a big release. Packed with 62 new features, this release aims to make your life as a web developer easier by replacing long-standing frustrations with elegant solutions. You’ll find simpler ways to create common UI patterns with just a few lines of HTML or CSS, and no JavaScript — like auto-growing text fields with CSS field-sizing, and buttons that open/close dialogs and popovers with command and commandfor HTML attributes. Navigation API makes building single-page apps more straightforward. Full width numbers are normalized, and text shaping across element boxes is supported for languages like Arabic. Anchor Positioning expands with the position-visibility property and much more. The cursor property works on pseudo-elements. Improvements to Initial Letter make it easier to create drop-caps. CHIPS brings back partitioned cookies, this time opt-in. WebXR on visionOS now supports WebGPU. And much, much more. Plus, this release resolves 165 bugs. It’s a release that makes the web more dependable, letting you spend less time working around browser inconsistencies and more time accomplishing your goals.

HTML

HTML is 35 years old, yet keeps evolving to make web development easier. Recent years have brought many small but powerful HTML innovations that simplify building dynamic user interfaces — letting you solve common use cases with HTML and CSS alone, “paving the cowpaths”, and reducing the need for JavaScript or third-party frameworks. Safari 26.2 delivers several more such features.

Button commands

Before, using a button on a web page to trigger a client-side action required JavaScript. Now, you can use command and commandfor attributes in HTML to control popovers and dialogs.

Use the commandfor attribute to tie the button to the id of the element it affects. And use the command attribute to tell the browser which action to take. There are six predefined values for the command attribute. These map to existing JavaScript methods. Fordialogelements: show-modal, close, and request-close. And for any HTML element with thepopover attribute: show-popover, hide-popover, and toggle-popover.

You can also observe custom commands in JavaScript through events. Custom commands are named using --foobar syntax, and used declaratively in HTML as command="--foobar".

Finding content

Safari 26.2 adds support for auto-expanding the details element. Now, anytime someone uses “Find” in Safari to search the page, if the search result is hidden inside a closed details element, the element will automatically expand to reveal the text. Also, if the user navigates to a URL that contains a Text Fragment and the targeted fragment is inside a closed details, it will automatically expand.

Similarly, Safari 26.2 adds support for the hidden=until-found attribute. You can apply this to any element in HTML, causing the content to not be rendered as part of the page, until a user searches for it. Then it appears.

<div hidden="until-found">
  <p>This content is hidden, but will be found by search!</p>
</div>

Thebeforematch event fires on an element with hidden=until-found just before it’s revealed by a find-in-page search. This allows you to run JavaScript to prepare the content, update analytics, or perform other actions before the hidden content becomes visible to the user.

Off-screen radio buttons now automatically scroll into view when focused. This is especially helpful when users navigate with keyboard shortcuts or screen readers, improving accessibility.

ARIA Index Text attributes

Safari 26.2 adds support for thearia-colindextext andaria-rowindextext attributes, which provide human-readable alternatives to aria-colindex and aria-rowindex.

The previously-supported options use numeric values to indicate a cell’s position within a table or grid. Now aria-colindextext and aria-rowindextext let you provide more meaningful labels. This is particularly valuable when columns use letters (like A, B, C in a spreadsheet) or when rows represent time periods, categories, or other non-numeric sequences. When both attributes are present, assistive technologies announce the human-readable text instead of the number, giving users better context as they navigate complex tables and grids.

Full width number normalization

Full-width characters are commonly used in Japanese, Chinese, and Korean text input. Safari 26.2 converts certain full-width characters into normalized equivalents for <input type="number"> fields. Now full-width digits (0123) become standard digits (0123); full-width minus signs (-) become standard minus signs (-); and full-width dots (.) become standard periods (.) This normalization lets users type numbers naturally in their language while ensuring the input works correctly as a number value. Also, disallowed characters are now immediately rejected.

And more

You might remember that HTML5 was originally intended to provide an outlining algorithm — where a website could use multiple h1 headlines on a page, and the browser would assign levels to each headline based on the overall DOM structure of elements. In practical terms, this idea didn’t work out and it was never widely implemented in browsers. Developers simply use h2, h3, h4, etc to convey levels of headline. To go with the intended original behavior in HTML5, the default UA styling for h1 elements was specified to visually change the headline when it was a child of article, aside, nav, or section — making the font-size and margin smaller and smaller each time it was nested. In Safari 26.2, following a recent HTML standard change, those UA styles are being removed.

When viewing web content in a Mac Catalyst app on macOS 26.2, elements with a title attribute will now display the tooltip when a user hovers.

CSS

Shrink wrapping form fields

Safari 26.2 adds support for the field-sizing property. Applying field-sizing: content causes the input and textarea form fields to shrink-wrap their content and grow as more text is entered. This eliminates the need for JavaScript to resize form fields dynamically. You can use min-height, min-width, max-height, and max-width to keep the field within the range you desire.

CSS Calc functions

In recent years, CSS has gained many powerful mathematical abilities, adding to its maturity as a programming language. Safari 26.2 brings three new functions — random(), sibling-index() and sibling-count().

The random() function lets you include a randomly generated value from a specified range in your calculations. For example, random(0, 100, 2) will choose an even number between 0 and 100, while random(0turn, 1turn) will be a fraction of a turn — basically, any decimal between 0 and 360 degrees. Learn all about what the CSS random function can do in our article, Rolling the dice with CSS random().

The sibling-count() function counts up the number of elements that are siblings of the current element, and returns a number, while sibling-index() will tell you which numbered item this one is — the 4th item for example. They make it incredibly easy to do things you’ve probably wished you could do for years.

For example, today, CSS Grid makes it trivial to proportion space in a layout with fr units — but in the days of float-based responsive layouts, this code would have been incredibly helpful (and still is today):

.gallery-item {
  width: calc(100% / sibling-count());
}

It calculates a width for an item by dividing the total width available by the total number of sibling items in the DOM. When there’s four items, the width of each is 25%. When there’s five items, each is 20%.

CSS has had nth-child() for a long time, letting you target a specific numbered item. The sibling-index() function is similar, telling you which number item a particular one is in the order.

This demo uses random() to generate the random rotation distance and sibling-index() to generate the angle for each of the wheel items.

Text shaping across inline boxes

Safari 26.2 adds support for text shaping across inline boxes. This is especially impactful for scripts like Arabic, N’Ko and many others where the letters join together and change appearance as text is rendered. The word “مرحبا” in Arabic (which means “hello” or “welcome”) is spelled using these letters: م ر ح ب ا — which then change their shapes and work together to create مرحبا. Before Safari 26.2, such letters would not combine if they were wrapped in separate elements. Of course, it’s not common to wrap an individual letter in the middle of a word with a span or other inline element, but there are good use cases for this — especially, perhaps, when wanting to change the color of the letters in teaching how the writing system works, like this:

There’s still more work to do in this space to support the full range of different behaviors of the many kinds of text shaping around the world.

Initial letter improvements

Initial letter was originally created by folks at Apple and implemented over a decade ago in Safari 9. It was created behind a -webkit- prefix, as was best practice at that time. Since then, the CSS web standard has matured to handle more complex use-cases. Safari 26.2 updates our implementation, adding support for decimal values in the initial-letter property. This can be especially helpful if you need to make a slight adjustment to better fit your font. Also, support for web fonts was added in March 2024 with Safari 18.4. The -webkit- prefix is still required, but these updates make it very usable in the meantime.

Anchor positioning improvements

Safari 26.2 adds several refinements to Anchor Positioning, which originally shipped in Safari 26.0. First, Safari 26.2 supports for flip-x and flip-y options in position-try-fallback. These keywords allow an anchored element to flip along the x- or y-axis when it would otherwise overflow its container.

The new position-visibility property lets you control when anchor-positioned elements are visible. For example, use no-overflow to hide an element when it overflows its container. Other values include always, anchors-visible, inherit, initial, revert, revert-layer, and unset.

The position-try property now works on pseudo-elements like ::before, ::after, and ::backdrop, which were previously unaffected. This means pseudo-elements can be repositioned using fallback strategies just like regular elements.

There are also many updates to the WebKit implementation of Anchor Positioning, listed in Bug Fixes below.

Color improvements

After being the first browser to ship new color spaces to CSS, color-mix(), relative color syntax, and contrast-color(), we’re excited to bring even more improvements in Safari 26.2.

The color-mix() function blends two color values and returns the result. Previously, developers were required to list a color space as the first argument of the function, like this: color-mix(in srgb, magenta, pink). Since many developers used srgb out of habit, the results were often sub-optimal. Starting with Safari 26.2, you can use color-mix() without listing a color space — and get oklab as the default. You can just say color-mix(magenta, pink)
and you’ll get the same result as if you’d written color-mix(in oklab, magenta, pink). The Oklab color space is an especially good choice when blending colors, since the mathematical model is designed to make adjustments based on how humans perceive color, rather than pure numbers. Learn more about wide-gamut P3 color on the web in this video from WWDC.

Safari 26.2 also adds support for thescrollbar-color property. It takes two values — one for the color of the scrollbar thumb (the part that moves) and the second for the scrollbar track (the background). Note in all browsers, the track background color only has an effect according to how that particular operating system works, and is dependent on how the user has their personal settings for scrollbars configured. Along with scrollbar-width and scrollbar-gutter, the scrollbar-color property completes the set of modern properties for styling scrollbars, making it a good time to stop using the original ::-webkit-scrollbar pseudo elements.

Safari 26.2 also adds display-p3-linear to the predefined set of color spaces available for use, alongside of display-p3, srgb and others.

P3 is still a better color space to use in most cases, but having support for P3 Linear provides an easy way to use linear color math while optimizing performance compared to other options like rec2100-linear.

accent-color legibility

The accent-color property allows for the customization of form controls with native appearance, but certain color choices could make text or indicators within the control hard to read. Safari 26.2 fixes these issues in both light and dark mode while maintaining a consistently-displayed color across all form controls. To achieve this, the following behaviors are performed:

For elements with a light color scheme, if the luminance of the accent color is greater than 0.5, the displayed accent color is clamped back down to 0.5 while preserving the hue.

For elements with a dark color scheme, if the luminance of the accent color is less than 0.5, the displayed accent color is clamped back down to 0.5 while preserving the hue. If the luminance of the accent color is greater than 0.5, then the following controls adapt in order to remain legible:

  • checkboxes display with a dark check
  • radio buttons display with a dark indicator
  • submit buttons display with dark text by default
  • switch controls display with an increased drop shadow for the thumb in the on-state

Text decoration improvements

In Safari 26.2, the text-decoration property is a proper shorthand for all four of the longhand properties: text-decoration-line, text-decoration-color, text-decoration-style and text-decoration-thickness. This means you can combine separate underline qualities for underlines, overlines and sidelines into one CSS rule like this: text-decoration: green wavy underline 3px. This turned out to be a large project, requiring significant refactoring of decades-old code to untangle the interaction between text-decoration and editing code.

The text-decoration-line property now supports the new spelling-error and grammar-error values, which let you emulate the respective native error markers. For example, this code will take the browser’s default styling for spelling errors (whatever that might be) and apply it to the span of text:

.span {
  text-decoration-line: spelling-error;
}

(If you want to override the browser’s default styling for spelling or grammar errors, you can target it with ::spelling-error or ::grammar-error and apply styling as desired — a feature that shipped in Safari 17.4 and is supported in Chromium browsers.)

Finally, Safari 26.2 provides bug fixes for text decoration. The text-decoration-thickness and text-underline-offset have been fixed to properly work in vertical writing modes. And the default computed value for text-emphasis-style: filled|open has been corrected to be filled|open circle instead of filled|open dot in horizontal typographic modes.

@scope

The @scope rule now correctly handles implicit scoping roots when used with constructed and adopted stylesheets in shadow DOM contexts. Previously, styles defined in constructed stylesheets might not have properly respected the shadow boundary as an implicit scope.

This improvement ensures that when you create a CSSStyleSheet programmatically and adopt it into a shadow root, any @scope rules without an explicit root will correctly treat the shadow root as the implicit scoping boundary:

const sheet = new CSSStyleSheet();
sheet.replaceSync(`
  @scope {    .item { padding: 1em; }  }`);
shadowRoot.adoptedStyleSheets = [sheet];

This is particularly important for developers building design systems and component libraries using the Constructable Stylesheets API, which is a common pattern in modern Web Components.

WebKit for Safari 26.2 supports using :host as the scoping root in @scope rules. This allows you to create scoped styles that target the shadow host element, making it easier to write encapsulated component styles.

@scope(:host) {
  /* Styles scoped to elements within the shadow host */
  .component {
    color: blue;
  }
}

This feature enhances the ability to write modular, component-based styles while maintaining proper encapsulation boundaries in Web Components.

Safari 26.2 adds support for using the :scope pseudo-class when the scoping root matches the :visited pseudo-class. This allows you to create sophisticated scoping patterns that take link visitation state into account.

@scope (a:visited) {
  :scope {
    color: green;
  }
}

MathML

A new value forfont-family is now available in Safari 26.2, named math. This moves a previously directly-coded stack of fonts intended for use with mathematical expressions from being defining in the UA style sheet for just the <math> element to a new rule that can be called anywhere with font-family: math. Math fonts include specialized data for equation layout — things like stylistic variants for stretching glyphs, proper handling of superscripts and subscripts, brackets that span multiple lines, and double-struck characters.

The newmath-shift CSS property gives you the ability to create a more tightly compacted rendering of formulas by using math-shift: compact to reduce the vertical shift of superscripts.

More CSS

Safari 26.2 adds support for cross-origin() and referrer-policy() CSS URL modifiers. These let you control CORS and referrer behavior directly in CSS when loading resources like images or fonts, without needing HTML attributes or server headers. You can now specify these policies inline with your url() functions for more granular control over resource fetching.

The cursor property now works on pseudo-elements like ::before and ::after. Previously, you couldn’t change the cursor when hovering over content generated by pseudo-elements — now you can style them just like regular elements, giving you more control over the user experience and visual feedback throughout your interface.

Positioned boxes in scrollable containing blocks can now overflow in the scrollable direction. Previously, positioned elements might be clipped or behave unexpectedly when they extended beyond their scrollable container. This fix ensures that positioned content can properly overflow in the direction the container scrolls, making it easier to create complex layouts with scrollable regions and absolutely or fixed positioned elements.

Web API

Navigation API

Safari 26.2 adds support for the Navigation API. A modern replacement for the History API, it’s designed to give you better control over browser navigation. For years, web developers have relied on the History API (pushState, replaceState, and the popstate event) to build single-page applications, but it had significant limitations — you couldn’t intercept link clicks or form submissions, the popstate event only fired for back-forward navigation, and managing navigation state was cumbersome. The Navigation API solves these problems with a cleaner, more powerful interface.

The key feature is the navigate event, which fires for all types of navigation — link clicks, form submissions, back-forward buttons, and programmatic changes. You can intercept these navigations and handle them client-side, making it much easier to build SPAs without routing libraries. The API is also promise-based, so you can easily coordinate async operations like data fetching with navigation changes, and it includes built-in state management for each navigation entry. Here’s a simple example of client-side routing:

navigation.addEventListener('navigate', (event) => {
  // Only intercept same-origin navigations
  if (!event.canIntercept) return;

  event.intercept({
    async handler() {
      // Fetch and display new content
      const response = await fetch(event.destination.url);
      const html = await response.text();
      document.querySelector('main').innerHTML = html;
    }
  });
});

With this code, all link clicks and navigation within your site are automatically intercepted and handled client-side, turning your multi-page site into a single-page application with just a few lines of code.

Scrollend

Safari 26.2 adds support for the scrollend event, which fires once when scrolling definitively completes. Whether triggered by user gestures, keyboard navigation, smooth scrolling, or JavaScript, this event gives you a reliable signal that scrolling has finished. Previously, developers had to debounce the scroll event with timers to detect when scrolling stopped, which was imprecise and required guessing at appropriate delay values.

The scrollend event is useful for tasks that should only happen after scrolling is done, like lazy-loading content, updating UI based on final scroll position, or saving scroll state. Instead of firing dozens of times during a scroll, you get one clean event when it’s actually over.

document.addEventListener('scrollend', () => {
  // Scrolling has completely finished
  const scrollPosition = window.scrollY;
  localStorage.setItem('scrollPosition', scrollPosition);

  // Or lazy-load images now in view
  loadVisibleImages();
});

This fires once when scrolling stops, giving you a clean, reliable way to respond to the final scroll position without any timer-based guesswork.

View Transitions

Safari 26.2 adds support for document.activeViewTransition, which exposes the currently active View Transition. This gives you direct access to the transition object while it’s running, allowing you to check its state, wait for specific phases to complete, or programmatically control the transition. You can use this to coordinate other animations or UI updates with your View Transitions, or to handle cases where you need to know if a transition is already in progress before starting a new one.

Text Interaction

WebKit for Safari 26.2 adds support for document.caretPositionFromPoint(). This method is useful whenever you want to convert screen coordinates (x, y) into a text position in the document, giving you character-level precision for sophisticated text interaction (like building text editors, annotation tools, or custom selection interfaces).

Pointer and Touch Events

Safari 26.2 adds support for fractional coordinates in PointerEvent and TouchEvent properties like clientX, clientY, pageX, pageY, offsetX, offsetY, and screenX/screenY. Previously, these values were rounded to whole numbers, but they now include sub-pixel precision as decimal values (like 150.7 instead of 151). This gives you more accurate position data for touch and pointer interactions, which is useful for precise drawing applications, gesture recognition, or smooth animation tracking. Note that MouseEvent coordinates remain whole numbers, so if you’re handling multiple input types, you may see different precision levels depending on the event type.

As part of Interop 2025, Safari 26.2 continues to improve the interoperability of Pointer and Mouse Events. Early implementations of these events predated any official web standard, leading to inconsistencies across browsers. In 2022, the Interop Project took on Pointer and Mouse Events as an investigation to sort out the complexities and chart a path forward. The official web standard for Pointer Events was first published in November 2024, and WebKit now further aligns with that maturing specification.

Service Workers

Safari 26.2 improves asynchronous URL error handling in Service Workers. Invalid or malformed URLs now properly throw catchable errors in async operations, allowing you to handle URL errors gracefully with try/catch blocks.

Cookie Store

Safari 26.2 adds support in the Cookie Store API for handling cookieStore.set() calls with an empty string path. Previously, passing an empty string for the path parameter could cause issues or unexpected behavior. Now you can explicitly set a cookie with an empty path string, and the API will handle it correctly, giving you more flexibility in how you manage cookie paths programmatically.

The CookieStore API originally shipped in Safari 18.4. Now, with Safari 26.2, it enforces stricter validation for special cookie name prefixes to prevent misuse. Cookies with certain prefixes have special security meanings: the __Host- prefix indicates an extra-secure cookie (must be secure, no domain, path must be /), and the __Secure- prefix signals it must be sent over HTTPS only. Cookies with invalid names like __Host-Http- and __Http- are now rejected.

And more

Safari 26.2 removes support for the overflowchanged event, which was never standardized. This event fired when an element’s overflow state changed, but modern alternatives like ResizeObserver offer more robust ways to detect layout changes.

Performance API

Safari 26.2 adds support for two tools that measure the performance of web applications, Event Timing API and Largest Contentful Paint.

The Event Timing API lets you measure how long it takes for your site to respond to user interactions. When someone clicks a button, types in a field, or taps on a link, the API tracks the full timeline — from the initial input through your event handlers and any DOM updates, all the way to when the browser paints the result on screen. This gives you insight into whether your site feels responsive or sluggish to users. The API reports performance entries for interactions that take longer than a certain threshold, so you can identify which specific events are causing delays. It makes measuring “Interaction to Next Paint” (INP) possible.

Largest Contentful Paint (LCP) measures how long it takes for the largest visible element to appear in the viewport during page load. This is typically your main image, a hero section, or a large block of text — whatever dominates the initial view. LCP gives you a clear signal about when your page feels loaded to users, even if other resources are still downloading in the background.

Web Inspector

Web Inspector now shows Largest Contentful Paint entries in the Timelines tab, both in the Layout & Rendering timeline and in the events list. This makes it easier to see exactly when your page’s largest visible element rendered, and to correlate that timing with other layout and rendering work happening on the page.

Web Animations API

Safari 26.2 adds support for theoverallProgress property on the Animation interface. It gives you a number between 0 and 1 that represents how far the animation has progressed toward completion. Unlike tracking individual iterations, this tells you the progress across the entire animation — so if you have an animation set to run three times, overallProgress tracks the journey from start to finish across all three iterations.

The Animation.commitStyles() method now works with completed animations, letting you persist their final state as inline styles. You can run an animation to completion, lock in the result, and remove the animation itself — keeping the visual effect while freeing up resources.

JavaScript

Safari 26.2 adds support for Math.sumPrecise(), which sums multiple numbers with better floating-point accuracy. Regular addition accumulates rounding errors with each operation — adding 12 numbers means 11 separate additions, each losing a bit of precision. Math.sumPrecise() performs the entire sum as a single operation, eliminating accumulated error.

Safari 26.2 adds support for Map.prototype.getOrInsert() and WeakMap.prototype.getOrInsert(), letting you retrieve a value or insert a default if the key doesn’t exist — all in one operation. This simplifies the common check-then-set pattern, making code that builds up data structures cleaner and more efficiently.

WebAssembly

WebKit for Safari 26.2 adds support for Wasm Memory resizable buffer APIs. They give you more control over how WebAssembly memory is allocated and managed, allowing code in both Wasm and JavaScript to directly access the same memory space for efficient communication.

JS String Builtins now let Wasm modules import string constants without substantial glue code, reducing memory usage for some Wasm applications. They also enable working directly with JavaScript strings without calling imported JavaScript functions, avoiding the overhead of Wasm-to-JavaScript calls.

Safari 26.2 also adds two resizable ArrayBuffer methods to WebAssembly to allow conversion between fixed-length and resizable memory buffers. The WebAssembly.Memory.prototype.toResizableBuffer() method converts a WebAssembly memory instance to use a resizable ArrayBuffer, whose maximum size is determined by the memory’s maximum property. The WebAssembly.Memory.prototype.toFixedLengthBuffer() method converts a WebAssembly memory instance to use a fixed-length ArrayBuffer, which is the traditional WebAssembly memory behavior.

Back in September 2025, Safari 26.0 added support for WebAssembly.JSTag to bridge exception handling between JavaScript and WebAssembly. When JavaScript throws an exception into Wasm, the exception is wrapped with a JSTag so WebAssembly can catch and handle it appropriately.

WebGPU in WebXR

Support for WebXR first shipped in Safari 18.0 in visionOS 2 in September 2024. It relied on WebGL for rendering 3D graphics. In September 2025, Safari 26.0 added support for WebGPU for use cases outside of WebXR. WebGPU is similar to WebGL in its capabilities, but it’s designed to better match how modern GPUs work, resulting in better performance and more flexibility. Now with Safari 26.2 on visionOS, WebXR supports WebGPU. This means you can build experiences in WebXR with the full power of WebGPU.

Safari 26.2 also adds support for using GPUTexture objects as depth-stencil attachments in rendering operations and resolve attachments in WebGPU render passes. Depth-stencil attachments are special textures used during 3D render. Depth tracks how far away each pixel is from the camera, while stencil creates masks and templates that control which pixels get rendered. This change simply updates to the very latest specification now allowing texture in JavaScript anyplace you would have used texture.createView() in the past. Now, both are supported.

SVG

Safari 26.2 brings many improvements to SVG. First, the <a> element now supports the type attribute, which lets you specify the MIME type of the linked resource. For instance:

<svg>
  <a href="destination.svg" type="image/svg+xml">
    <text x="10" y="20">Click me</text>
  </a>
</svg>

The repeatEvent in SVG animations is an event that fires each time an SVG animation element repeats its iteration, now supported to better align with the SMIL specification and match other browsers. Safari 26.2 also supports the onbegin event handler property defined in the SVGAnimationElement IDL (Interface Definition Language) that fires when an SVG animation starts.

The async attribute in SVGScriptElement controls whether a script should be executed asynchronously, matching the behavior of HTMLScriptElement.

<svg xmlns="http://www.w3.org/2000/svg" width="400" height="200">
  <script href="external-script.js" async="true"/>
  <!-- or -->
  <script href="another-script.js" async="async"/>
</svg>

Safari 26.2 supports the hreflang attribute on SVGAElement. It specifies the language of the linked resource, matching the functionality of HTMLAnchorElement to improve SVG link handling.

And see the list of bug fixes below for the full picture of the improvements to SVG.

WebRTC

Safari 26.2 adds support for the encrypted field to RTCRtpHeaderExtensionParameters. This gives you as a developer more fine-grained control over which metadata is visible to network intermediaries versus what remains private end-to-end. The RTCRtpHeaderExtensionParameters WebRTC API interface describes Real-time Transport Protocol header extensions used in media streams. Additional metadata alongside the already-encrypted media payload, might include audio levels, video orientation, timing information and custom application data.

Canvas

WebKit for Safari 26.2 removes the non-standard legacy drawImageFromRect. Created in the earliest days of Canvas API, it was originally intended to be an intuitive way to draw a rectangular portion of an image, but it never became part of the official Canvas specification. Instead the standard drawImage() method provides this functionality, supported since Safari 2.

Web Compatibility

Safari 26.2 ships support for CHIPS (Cookies Having Independent Partitioned State) once again. Originally shipped in Safari 18.4 in March 2025, CHIPS was temporarily removed in Safari 18.5 for further refinement.

Beginning with Intelligent Tracking Prevention 1.0 in 2017, we began unconditionally partitioning cookies. Over the next two year, WebKit’s implementation evolved based on feedback, until in 2019 we stopped partitioning cookies. Based on this experience, CHIPS was designed as a way to give site owners control over whether their cookies are partitioned.

Now, partitioned cookies let third-party content — like embedded chat widgets, payment processors, or SaaS tools in iframes — opt-in to using cookies on a specific site without enabling cross-site tracking. Safari blocks setting and accessing cross-site cookies when partitioning was not requested.

If siteB.example is embedded in an iframe on siteA.example and sets a partitioned cookie, that cookie is only accessible when siteB.example appears on siteA.example — not on other sites.

To create a partitioned cookie, add the Partitioned attribute along with SameSite=None and Secure:

Set-Cookie: TestCookie=12345; SameSite=None; Secure; Partitioned

Or in JavaScript:

document.cookie = "TestCookie=12345; SameSite=None; Secure; Partitioned";

Safari partitions cookies by site (not origin), matching other browsers. This means news.siteA.example and mail.siteA.example share the same partition since they’re subdomains of siteA.example.

If you need access to unpartitioned third-party cookies, continue using the Storage Access API with document.requestStorageAccess().

WebDriver

WebDriver in Safari 26.2 makes it easy to write automated tests that exercise different user scenarios involving the Storage Access API. Using the new Set Storage Access WebDriver command, a test can validate what happens when cross-site storage access is granted or denied (i.e., when calling document.requestStorageAccess()). The Set Permissions WebDriver command has been extended to support the storage-access key. This allows a test to validate website behavior when the user has configured permissions to always accept or reject such storage-access requests.

WebKit API

Now in iOS 26.2, iPadOS 26.2, macOS 26.2, watchOS 26.2 and visionOS 26.2, WebKit supports exporting more types of WebPage content using SwiftUI Transferable APIs — now including .png, .flatRTFD, .rtf, and .utf8PlainText.

Web Extensions

Safari 26.2 brings some much-requested APIs for developers of extensions. These enhancements make it easier than ever for you to help your users get started using a Safari Web Extension.

First, from your native iOS, iPadOS, and visionOS application, it’s now possible to determine if your Safari Web Extension has been turned on by the user. To do so, call SFSafariExtensionManager.stateOfExtension(withIdentifier identifier: String) async throws -> SFSafariExtensionState. The SFSafariExtensionState result has an isEnabled boolean property that lets your app know if the extension has been turned on.

Once you’ve determined the state of your extension, you may want to help your user understand where to turn it on. With one function call, you can deep link into Safari Extension Settings directly into the view for your extension. To do so, call
SFSafariSettings.openExtensionsSettings(forIdentifiers: [``String``]) async throws and pass in an array of the composed identifiers for your extension(s) as the extensionIdentifiers argument. If you pass a single identifier, the user will be deep linked directly into settings for that extension. If you pass multiple identifiers, the user will be deep linked into Safari Extension Settings and see the list of all installed extension, highlighting the rows of the extensions whose identifiers you passed in.

Finally, if you’re currently shipping a Safari App Extension, Safari 26.2 on macOS introduces improvements to the migration path for your users. Previously, it’s been possible to associate your web extension with an app extension and replace it during an upgrade. By making this association, it would automatically turn the web extension on and hide the app extension. In Safari 26.2 and later, if the Safari web extension replaces a single Safari app extension, Safari also migrates web permissions and the setting that indicates whether the user allows the extension in Private Browsing. Safari only migrates website permissions if the Safari web extension does not require more website access than the Safari app extension.

Also introduced browser.runtime.getVersion() as a simplified synchronous method to retrieve the installed extension version, replacing the common pattern of runtime.getManifest().version.

Bug fixes and more

Along with the new features, WebKit for Safari 26.2 includes additional improvements to existing features.

Accessibility

  • Fixed Voice Control number and name overlays not labeling content inside iframe elements. (118252216)
  • Fixed incorrect accessibility bounds of SVG roots, ensuring assistive technologies have access to the correct geometry. (153782363)
  • Fixed an issue where <label> elements targeted by aria-labelledby stopped providing accessibility text to assistive technologies after dynamic page changes. (158906980)

Animations

  • Fixed inheritance of additional animation properties (animation-timing-function, animation-play-state, animation-iteration-count, and animation-direction) in ::view-transition pseudo-elements to improve style consistency. (156131284)
  • Fixed animation-name resolution to correctly find matching @keyframes within tree-scoped and shadow DOM contexts. (156484228)
  • Fixed a bug where extremely large animation-duration values could cause the page to become unresponsive. (158775366)
  • Fixed Animation.commitStyles() so that custom properties are properly committed to the target element. (158919736)
  • Fixed Animation.commitStyles() to correctly commit logical properties as their corresponding physical properties. (158920529)

Browser

  • Fixed: Safari now reports a frozen OS version in its user agent string on iOS 26 and iPadOS 26, showing the last version released before iOS 26. (156170132)

CSS

  • Fixed -webkit-user-select: none disabling find-in-page in Safari. (8081660)
  • Fixed incorrect z-ordering for position: sticky elements. (90572595)
  • Fixed getComputedStyle to correctly ignore ::first-letter and ::first-line styles on flex containers, to reflect used style. (94163778)
  • Fixed style invalidation so that :scope selectors always match even when the scoping root is unavailable. (135907710)
  • Fixed propagation of the body element’s writing-mode to the document element to match the CSS Writing Modes Level 4 specification. (149475070)
  • Fixed @position-try so that revert-layer correctly only reverts the position-try origin instead of affecting other cascade origins. (154355428)
  • Fixed positioned boxes in scrollable containing blocks to overflow in scrollable direction. (155625030)
  • Fixed anchor-center so that when an anchored element has no anchor in the same containing block, it correctly falls back to behaving like center as specified. (155768216)
  • Fixed anchor() positioning in CSS Grid to correctly account for grid-area. (155823420)
  • Fixed the default computed value for text-emphasis-style: filled|open to be filled|open circle not filled|open dot in horizontal typographic modes. (155911820)
  • Fixed the text-decoration shorthand to cover all four longhand properties. (156011594)
  • Fixed an issue where @namespace rules that failed insertion could still affect the namespace node. (156651404)
  • Fixed incorrect handling of auto inline margins on grid items during track sizing that caused excessive vertical spacing in subgrids. (157638931)
  • Fixed automatic min-size handling for flex and grid items to correctly treat overflow: clip as non-scrollable, aligning with the CSS specifications. (158215991)
  • Fixed incorrect baseline alignment for <button> elements when contain: layout is applied by using the content box as the baseline. (159007878)
  • Fixed out-of-flow box with no sibling ignoring align-content. (159097576)
  • Fixed CSS anchor positioning to remember the last successful position option at ResizeObserver delivery time, aligning with the spec. (159225250)
  • Fixed handling of the ::first-line pseudo-element when floats prevent the initial line from containing inline content, ensuring correct styling is applied to the actual first formatted line. (159613287)
  • Fixed an issue where collapsed table rows subtracted border-spacing twice. (160542118)
  • Fixed ::view-transition pseudo-element to use position: absolute instead of fixed to align with the updated specification. (160622000)
  • Fixed container queries to allow container-name matching across the full flat tree, making container names tree-scoped in line with the CSS Conditional 5 specification. (160696378)
  • Fixed handling of ::first-letter pseudo-elements to always force inline display unless floated.(160710650)
  • Fixed the behavior of the nesting selector & directly inside @scope to correctly act like :where(:scope) for proper specificity handling. (160769736)
  • Fixed position-try-fallback resolution by treating names as tree-scoped references to properly search shadow DOM host scopes. (161081231)
  • Fixed an issue where a <select> element with long <option> text caused horizontal scrolling when nested inside a flex item. (161563289)
  • Fixed getComputedStyle to return numeric values for orphans and widows instead of the internal auto value, ensuring the computed values correctly reflect the CSS specification. (161566631)
  • Fixed column-count: 1 so that it now correctly creates a multi-column container per the CSS Multi-column Layout specification. (161611444)
  • Fixed the calculation of anchor positions in vertical-rl multi-column layouts by correctly flipping coordinates in fragmented flows. (161616545)
  • Fixed the order to try anchor position fallback options, such that the last successful position option is tried first, followed by the original style, and then the remaining options. (161714637)
  • Fixed position-area handling to include the in-flow scrollable area of the initial containing block. (161741583)
  • Fixed position-visibility: no-overflow to respond correctly to scrolling. (162173481)
  • Fixed: Renamed position-area keywords from x-self-start, x-self-end, y-self-start, and y-self-end to self-x-start, self-x-end, self-y-start, and self-y-end respectively to align with updated CSSWG specifications.(162214793)
  • Fixed auto margins by converting them to zero when position-area or anchor-center is applied in CSS Anchor Positioning. (162809291)
  • Fixed FontFace.family so that font family names with spaces are treated as plain strings without parsing or serializing aligning with other browsers. (163047573)
  • Fixed flex and grid layout to correctly handle padding and margins in all writing modes. (163048874)
  • Fixed an issue where underlines using text-underline-position: right appeared on top of the text in horizontal writing modes instead of under the line. (163506701)
  • Fixed an infinite style resolution loop when a position-try box was inside a display: none tree. (163691875)
  • Fixed position-area alignment so that when only one inset is set to auto, the element now aligns toward the opposite non-auto inset. (163691905)
  • Fixed text-decoration-thickness and text-underline-offset not working in vertical writing modes. (163727749)
  • Fixed an issue where scrollRectToVisible() did not scroll pages to bring fixed anchor-positioned boxes into view when navigating with the keyboard. (163764088)
  • Fixed an issue where anchor-positioned elements transitioning from display: block to display: none can not anchor themselves to the anchor. (163861918)
  • Fixed incorrect underline positioning for text-decoration when inline box sides are trimmed. (163909909)

DOM

  • Fixed an issue where command-clicking to open a link in a new tab navigates the current tab. (57216935)

Editing

  • Fixed jumbled text when copy/pasting bidirectional text starting with left-to-right. (152236717)
  • Fixed paste performance in textarea by skipping unnecessary layout calls and only removing unrendered text nodes in richly editable fields. (157813510)

Events

  • Fixed boundary pointer and mouse events not firing when the hit test target changed under a stationary pointer. (160147423)

Forms

  • Fixed an issue where some websites may sometimes fail to reveal the focused element when the keyboard appears. (50384887)
  • Fixed form controls to preserve legibility when using accent-color in both light and dark modes by adjusting luminance thresholds and updating submit button text handling. (99018889)
  • Fixed input fields with field-sizing: content so that larger placeholder text now correctly expands the height of the field by including the placeholder’s computed height. (123125836)
  • Fixed <select> element with long <option> text causing horizontal scrolling in grid or flex containers. (141633685)
  • Fixed an issue on iOS where backing out of the “Take a photo/video” file upload flow caused the upload button to stop working. (157789623)
  • Fixed painting for <input type="range"> sliders in right-to-left vertical block writing modes. (158567821)
  • Fixed an issue where tainted scripts were blocked from reading values of form fields they created, now allowing access if the field was not modified by user input. (163299988)

HTML

  • Fixed an issue where navigating to :~:text fragments on dynamically generated pages did not highlight or scroll to the fragment. (150880542)

Home Screen Web Apps

  • Fixed an issue where an audio element failed to play when re-opening a Home Screen Web App. (155336513)

Images

  • Fixed HDR images in CSS backgrounds, CSS borders and inside SVG images so they are now properly decoded and rendered in HDR mode. (158076668)

JavaScript

  • Fixed non-standard new Date(2024-12-3) yielding to an “Invalid Date” error. (141044926)
  • Fixed “text/json/json+json” to be considered an invalid JSON MIME type. (154912716)
  • Fixed compatibility issues with the timezone option in the Intl.DateTimeFormat constructor. (156148700)
  • Fixed Intl.Local#language to return "und" if the language subtag is "und". (156248659)
  • Fixed Intl to support non-continental timezones to align with the specification. (156424446)
  • Fixed exception check errors by adding a missing exception check for Array#flat. (157525399)
  • Fixed an issue where the module loader would incorrectly attempt to refetch a module after a failed fetch. (158084942)
  • Fixed Iterator.prototype.flatMap to properly handle iterators without a return method. (158783404)
  • Fixed poor error messages for destructing null or undefined values. (159340067)
  • Fixed TypeError messages to be clearer in for-of loops. (159814766)
  • Fixed TypeError messages when calling class or function constructors without new to include the constructor name. (161152354)

MathML

  • Fixed rendering of unknown MathML elements so they now behave like mrow as required by the MathML Core specification. (148593275)
  • Fixed mfenced elements to render like mrow. (161416576)

Media

  • Fixed western Arabic numbers being displayed in the video viewer instead of eastern Arabic numbers. (141281469)
  • Fixed WebVTT line-height to be normal by default, not 1. (156633220)
  • Fixed handling of null media accessibility caption profile. (159134245)
  • Fixed hiding and resuming a webm video that sometimes causes a decoding error. (159508950)
  • Fixed MediaRecorder to no longer fire erroneous error events when stopped immediately after track changes, aligning behavior with Chrome and closer to Firefox. (161124260)
  • Fixed an issue where custom WebVTT caption text size settings did not propagate to cue child elements by moving the font-size definition into the cue’s shared <style> block. (162547969)

Networking

  • Fixed an issue where rel=preload link headers with a nonce could trigger erroneous Content-Security-Policy-Report-Only violations due to the nonce not being copied into the fetch options. (75060055)
  • Fixed an issue where apps that are mistakenly calling the WKWebView API loadRequest from a background thread may end up crashing. (162070925)

PDF

  • Fixed an issue where the active PDF annotation hover effect would remain visible after moving the pointer away. (162951528)

Rendering

  • Fixed incorrect clipping of position: fixed and position: sticky content during view transitions. (154886047)
  • Fixed computing static position to correctly size and locate an inset modified containing block. (155650719)
  • Fixed alignment candidate to consider both first and last baseline item position. (155806707)
  • Fixed the cross axis direction in flexbox to properly consider text directionality when the cross axis aligns with the inline axis to handle direction property and flex-wrap: wrap-reverse interactions. (156540996)
  • Fixed <button> elements to use the last line as their baseline instead of the first line to ensure consistent alignment with <br> in the text. (157955703)
  • Fixed orthogonal table cells so their writing-mode is no longer forced to match the table, allowing proper vertical layout. (158221827)
  • Fixed an issue where exiting fullscreen could scroll to unscrollable areas. (158351089)
  • Fixed an issue where the padding end incorrectly contributed to scrollable overflow when the inline direction was flipped. (158529814)
  • Fixed word breaking so that a hyphen followed by a Latin-1 Supplement character (U+00C0–U+00FF) correctly allows line breaks. (158942361)
  • Fixed large inset box shadows to render correctly. (159888287)
  • Fixed an issue where sticky elements at the edge of the viewport could disappear during rubber band scrolling. (160385933)
  • Fixed an issue where selecting table cells could cause overlapping selections in flex and grid layouts. (160805174)
  • Fixed flickering of elements with slow-painting content during view transitions. (160886647)
  • Fixed an issue where elements with both opacity and CSS filter effects could render incorrectly. (161130683)
  • Fixed an issue where elements with background images were not counted as contentful for Paint Timing. (161456094)
  • Fixed scroll-to-text fragment highlights to automatically choose a contrasting foreground and background color to keep text readable on dark pages, while respecting custom ::target-text styles. (163166782)
  • Fixed an issue where fullscreen dialog backdrops did not properly extend below the address bar by extending the backdrop’s background into obscured inset areas. (163535684)
  • Fixed an issue where slotted text nodes could become hidden when adjacent elements in a flex container changed their display property. (163571747)

SVG

  • Fixed an issue where a dynamic change in a CSS property of an SVG element does not get reflected in the instances of the SVGElement. (98577657)
  • Fixed an issue where stop-color incorrectly accepted hashless hex color values like 1234 by treating them as invalid to follow the spec. (119166640)
  • Fixed SVGMarkerElement to correctly support the SVG_MARKER_ORIENT_AUTO_START_REVERSE value, aligning behavior with the spec and other browsers. (123453058)
  • Fixed absolutely positioned SVG elements to correctly account for the containing block’s padding. (127608838)
  • Fixed handling of word-spacing so that leading white space in SVG text correctly applies spacing at the start of a text box. (134941299)
  • Fixed an issue where SVGs with a 0px intrinsic width were ignored but now correctly respect degenerate aspect ratios and fall back to the viewBox aspect ratio. (156339128)
  • Fixed handling semicolons at end of a keySplines value. (156511711)
  • Fixed unnecessary rounding of viewportLocation in 'foreignObject' layout. (156740732)
  • Fixed <svg> elements to correctly calculate their intrinsic aspect ratio using currentViewBoxRect() when a <view> is referenced. (157445966)
  • Fixed SVGFETurbulenceElement to correctly fallback numOctaves to 1 for invalid or negative values, aligning with the specification and other browsers. (158988528)
  • Fixed an issue where SVG pattern tileImage could appear blurred or pixelated when zooming or printing. (159202567)
  • Fixed SVGStyleElement so that its type and media attributes now use pure attribute reflection, matching HTMLStyleElement. (159358585)
  • Fixed an issue where <view> element was not applied to the root element. (159705519)
  • Fixed SVGAElement so that its rel and relList attributes now affect navigation behavior, including proper handling of noopener, noreferrer, and the new opener value, aligning SVG links with HTMLAnchorElement behavior. (160724516)

Security

  • Fixed parsing of require-trusted-types-for in CSP to ensure 'script' is only valid when followed by whitespace or end of buffer. (147760089)

Service Worker

  • Fixed an issue where service worker downloads are not being saved to Downloads folder. (154501503)

Storage

  • Fixed WebSockets to correctly inherit storage access from the frame that created them. (147949918)
  • Fixed requestStorageAccess() should always grant access when called from a same-site iframe. (156545395)
  • Fixed Storage Access API to not be usable in insecure contexts. (157337423)
  • Fixed requestStorageAccess() to reject with a NotAllowedError. (157446015)
  • Fixed an issue where cross-origin navigations incorrectly preserved storage access. (158446697)
  • Fixed an issue where dedicated workers could inherit storage access from their parent document, preventing them from sending cross-site requests with cookies. (158814068)

Tables

  • Fixed collapsed table rows retaining nonzero height. (158276634)

Web API

  • Fixed an issue where the first pointerdown event was lost after triggering a context menu by right-clicking. (84787733)
  • Fixed window.opener being incorrectly set to null when a site-isolated iframe navigated to a new site, ensuring opener relationships persist across frame migrations. (117269418)
  • Fixed the ability to delete a cookie through Cookie Store API that was set through document.cookie. (142339417)
  • Fixed Trusted Types to only verify event handler attributes for elements in the XHTML, SVG, and MathML namespaces, preventing incorrect checks on other namespaces. (147763139)
  • Fixed reading the mutable field from the outer object instead of as a child of notification. (157475553)
  • Fixed location.protocol setter to be restricted to HTTP(S) schemes. (157607342)
  • Fixed scroll and scrollend events so they correctly fire on <input type="text"> elements instead of their inner elements. (157880733)
  • Fixed CookieStore methods to strip tabs and spaces from the names and values passed in. (157907393)
  • Fixed JSON modules to fetch with an application/json Accept header. (158176845)
  • Fixed an issue where click and auxclick event targeting does not follow pointer capture target override. (159477637)
  • Fixed the order of pointerup and boundary events so that pointerout and pointerover fire before pointerup when a child element is attached under the cursor. (160913756)
  • Fixed element.scrollTo and element.scrollBy so they correctly scroll text input fields by forwarding scroll operations to the inner text element. (160963921)
  • Fixed EventCounts interface was not maplike. Enables use of methods such as .forEach(), keys(), and entries(). (160968888)
  • Fixed an issue where mousemove events were still dispatched to removed mouseover targets instead of their parent element when the target was deleted. (161203639)
  • Fixed missing pointerenter and mouseenter events when a child element moved under the mouse. (161362257)
  • Fixed an issue where only one CSP violation report was sent for multiple enforced require-trusted-types-for directives. (161740298)
  • Fixed Trusted Types incorrectly treating null or undefined policy return values as null instead of empty strings during createHTML, createScript, and createScriptURL operations. (161837641)
  • Fixed attachShadow() to default to using the global custom element registry instead of the host’s registry when customElementRegistry is null. (161949419)
  • Fixed attachShadow() to use the global custom element registry by default when customElementRegistry is null, aligning with the specification. (161949493)

Web Extensions

  • Fixed an issue where onInstalled getting called after every launch of Safari when opening a profile window. (147491513)
  • Fixed sender.origin parameter to match window.location.origin. (155884667)
  • Fixed an issue where Safari extension popups could open scrolled down and some websites could flicker during scrolling. (155965298)
  • Fixed an issue that caused the web page to crash when navigating to certain URLs with an extension enabled. (158180410)

Web Inspector

  • Fixed syntax highlighting for JavaScript features like template literals, private class elements, optional chaining, and others. (107619553)
  • Fixed an issue where the Console truncated long string outputs. (124629101)
  • Fixed an issue where DOM elements represented in the Console could not be selected. (157015598)
  • Fixed an issue where newlines and indentation in HTML markup would show up in DOM node previews in the Console. (157225532)
  • Fixed an issue that prevented scrolling of the Media details sidebar from the Elements tab. (157768497)
  • Fixed an issue where accepting a completion suggestion for a shorthand property value would malform the combined value. (159107788)
  • Fixed an issue where navigating the DOM tree using the keyboard would get stuck in a loop within certain subtrees. (159841729)
  • Fixed an issue where the Sources tab won’t show contents of a script that contains a for statement with optional chaining in the test condition. (160617913)
  • Fixed an issue where adding DOM attributes or node siblings did not work correctly when using the actions from the context menu. (161577627)

WebDriver

  • Fixed the navigate endpoint in WebDriver to properly validate URLs against the current browsing context and set the default readiness state to Interactive to align with the specification. (157031091)
  • Fixed an issue where element references nested inside Array or Object arguments were not properly extracted when executing scripts. (162571946)

WebRTC

  • Fixed camera indicator staying enabled even after ending a meeting or removing access to the camera. (152962650)

Feedback

We love hearing from you. To share your thoughts, find us online: Jen Simmons on Bluesky / Mastodon, Saron Yitbarek on BlueSky / Mastodon, and Jon Davis on Bluesky / Mastodon. You can follow WebKit on LinkedIn. If you run into any issues, we welcome your feedback on Safari UI (learn more about filing Feedback), or your WebKit bug report about web technologies or Web Inspector. If you run into a website that isn’t working as expected, please file a report at webcompat.com or refresh the page and then select Report a Website Issue from Safari Page Menu to share feedback directly with Apple. Filing issues really does make a difference.

You can also find this information in the Safari release notes.

]]>
::target-text: An easy way to style text fragments https://webkit.org/blog/17628/target-text-an-easy-way-to-style-text-fragments/ Thu, 04 Dec 2025 19:21:31 +0000 https://webkit.org/?p=17628 You’re reading a great blog post. You want to share it with your friend but instead of getting them to read the whole thing, you really just want to highlight a few key sentences and have them go directly to that section of the page. That’s what text fragments are for.

As a user, you can highlight any section of text on a page and right click to make it a text fragment. In Safari, that means right clicking and selecting “Copy Link with Highlight” from the menu and getting a url that will highlight the text fragment when the page loads.

The default highlighting gives you a pale yellow highlight under the fragment text, like this:

Lorem ipsum blog post with pale yellow highlight for text fragment.

You can click on this link to see for yourself how it works.

That’s the user experience. But what about the developer experience? Is there something we developers can do to customize that experience for our users a bit more? Actually, there is! We’ll use the ::target-text pseudo-element to help us style our text fragment.

In your CSS file, use the ::target-text pseudo-element and style the text with whatever properties you wish, like this:

::target-text {
  background-color: blue;
  color: white;
}

That’ll get you this result:

Lorem ipsum blog post with white text on blue highlight for text fragment.

So if you want to decide how a text fragment looks to your users, take advantage of ::target-text and own the user’s text fragment experience. It’s fully supported in all browsers.

If you enjoyed this kind of bite-size content, let me know. You can reach me, Saron Yitbarek, on BlueSky, or reach out to our other evangelists — Jon Davis, on Bluesky / Mastodon, and Jen Simmons, on Bluesky / Mastodon. You can also follow WebKit on LinkedIn. If you find a bug or problem, please file a WebKit bug report.

]]>
Grid: how grid-template-areas offer a visual solution for your code https://webkit.org/blog/17620/grid-how-grid-template-areas-offer-a-visual-solution-for-your-code/ Fri, 21 Nov 2025 01:00:18 +0000 https://webkit.org/?p=17620 Using grid lines is a flexible and powerful way to place your elements on a grid, but, when looking at the code, it might be a bit hard to visualize. So Grid gives you another way to place your elements that might be easier to see called grid areas. There’s a bit more upfront work involved, but the pay off might be worth it.

The idea behind grid areas is that we name each element we want to place on our grid and then use a certain syntax to place them visually where we want them to go. To illustrate, let’s start with my product page.

Here’s the html I’m starting with:

<div class="card">
  <h1>Product 1</h1>
  <h2>$99</h2>
  <p>This is a description of the first option.</p>
  <ul><!-- product details here --></ul>
</div>

<div class="card">
  <h1>Product 2</h1>
  <h2>$99</h2>
  <p>This is a description of the first option.</p>
  <ul><!-- product details here --></ul>
</div>

<div class="card">
  <h1>Add-ons</h1>
  <h2>$149</h2>
  <p>This is another description.</p>
  <ul><!-- product details here --></ul>
</div>

<div class="card">
  <h1>Testimonial</h1>
  <h2>$299</h2>
  <p>This is a third description.</p>
  <ul><!-- product details here --></ul>
</div>

And here’s the CSS I’m starting with:

.pricing-options {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2em;
}
.card {
  border: 1px solid black;
  padding: 2em 5em;
  font-family: sans-serif;
  border-radius: 1em;
}

That will give me this result:

Four cards three on one row and the last on the second left spot.

We want our page to follow this design:

Black and white mockup of two products, add-ons on the right spanning two rows, and testimonial spanning two columns.

This means we want our Add-ons to span two rows and our Testimonial to span two columns. Here’s how we can accomplish that with grid-template-areas.

First, we need to label each element by assigning a value to the grid-area property. To do that, let’s give our elements classes to reference in our CSS.

<div class="card product-1">
  <h1>Product 1</h1>
  <!-- product details here -->
</div>

<div class="card product-2">
  <h1>Product 2</h1>
  <!-- product details here -->
</div>

<div class="card add-ons">
  <h1>Add-ons</h1>
  <!-- product details here -->
</div>

<div class="card testimonial">
  <h1>Testimonial</h1>
  <!-- product details here -->
</div>

Now let’s add those grid-area property values. You can name them anything you want, but since my class names are pretty descriptive, I’m going to name the grid-areas the same as my class names.

.product-1 {
  grid-area: product-1;
}
.product-2 {
  grid-area: product-2;
}
.add-ons {
  grid-area: add-ons;
}
.testimonial {
  grid-area: testimonial;
}

Now comes the visual part. In our CSS, we’re going to go back up to where our grid is defined and we’re going to assign a new property called grid-template-areas. I’m now going to visually assign each cell of my grid to an element in my html.

My grid is three columns across and an unspecified number of rows, which means it’ll be as many rows as needed. I’m going to assign product-1 to that first top cell and product-2 in my second top cell. Then my third top cell is going to be taken up by my add-ons element. And because my add-ons element is going to span two rows, the cell right beneath that is going to be assigned to add-ons too. And finally, we have the bottom left cell assigned to testimonial and because that element is taking up two columns across, the cell right next to it will be assigned to testimonial as well.

Here’s what the final code looks like:

.pricing-options {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 2em;
  grid-template-areas:
    "product-1 product-2 add-ons"
    "testimonial testimonial add-ons";
}

The beauty of grid-template-areas is that all of the decisions about where to place what element happen in a single property. You still have to do the upfront work of naming your elements, but once you’ve done that, you can visually see where everything is in relation to each other in a single place. Changing it is simpler too — just move the element name to a different “cell” and you’re done.

Using grid-template-areas , we get our desired layout.

Final layout of site with two products, add-ons on the right spanning two rows and testimonial at the bottom spanning two columns.

If you have any other questions about Grid and would like to see more content on this topic, let us know. You can share your feedback with me, Saron Yitbarek, on BlueSky, or reach out to our other evangelists — Jon Davis, on Bluesky / Mastodon, and Jen Simmons, on Bluesky / Mastodon. You can also follow WebKit on LinkedIn. If you find a bug or problem, please file a WebKit bug report.

]]>
WebKit Features for Safari 26.1 https://webkit.org/blog/17541/webkit-features-for-safari-26-1/ Mon, 03 Nov 2025 09:00:01 +0000 https://webkit.org/?p=17541 Today, Safari 26.1 is available with iOS 26.1, iPadOS 26.1, macOS Sequoia 26.1 and visionOS 26.1, as well as for macOS Sequoia and macOS Sonoma. It contains 2 new features and 36 improvements to existing features.

Relative units in SVG

As part of our most recent efforts on quality, WebKit for Safari 26.1 refactors the way the rendering engine handles CSS Units. This results in giving the SVG engine easier access to relative units, adding support for certain units inside SVG files for the first time. These units include rem; viewport units: vh, vw, vmin, vmax; typography-relative units: rlh, ic, cap, and container query units: cqw, cqi, cqmin, cqmax.

Anchor Positioning improvements

Safari 26.1 includes a dozen improvements to CSS Anchor Positioning. Now WebKit remembers the last successful position-try fallback in CSS anchor positioning to reduce layout jumps when styles change. See below for the full list of changes to Anchor Positioning.

Bug fixes and more

Along with the new features, WebKit for Safari 26.1 includes improvements to existing features.

Accessibility

  • Fixed hit testing for scrolled iframe content by adjusting for the frame’s scroll position, ensuring accurate element detection across assistive technologies. (158233884)
  • Fixed an issue where VoiceOver reports the wrong radio count with a dynamically inserted radio option. (159937173)
  • Fixed exposing content within dynamically expanded details elements in the accessibility tree. (159937257)
  • Fixed the target of aria-labelledby not updating its accessibility label after dynamic innerHTML change in the label. (160691619)

CSS Anchor Positioning

  • Fixed anchor positioning to handle fragmented multicolumn flows. (156958568)
  • Fixed anchor positioning fallbacks to respond to scrolling. (158451016)
  • Fixed an issue where container queries doesn’t work with position-try element. (158880410)
  • Fixed anchor positioning to account for a left-hand scrollbar in right-to-left and vertical-rl containing blocks. (160723993)
  • Fixed handling inline containing blocks for CSS Anchor Positioning. (160892829)
  • Fixed an issue where anchor-positioned elements failed to update their position when the default anchor changed. (160892850)
  • Fixed an issue where transitioning an element to display: none with transition-behavior: allow-discrete and CSS Anchor Positioning would repeatedly restart the transition. (161421046)
  • Fixed position-area for the initial containing block to include the in-flow scrollable area, improving alignment for typical overflow cases. (161997622)
  • Fixed position-visibility: anchors-visible visibility heuristic when anchor is clipped by an ancestor container. (160060564)

CSS

  • Fixed @media print styles to work when used inside a nested rule. (158608834)
  • Fixed: Improved the performance of :has(> .changed) .subject selectors. (159257003)
  • Fixed pseudo-class invalidation performance by creating separate RuleSets for attribute selectors like :has([attr=value]) to avoid using universal invalidation. (159257022)
  • Fixed an issue where changing the ruby-overhang property did not trigger a layout update, ensuring proper rendering when overhang values change. (159573050)
  • Fixed offsetParent to return the fixed-position element’s containing block when it is not the viewport, such as a transformed element. (160892685)
  • Fixed <select> fallback styling by removing the outdated background and updating the dropdown arrow. (161104364)

Forms

  • Fixed native text inputs so that their background colors update when autofilled. (159014135)
  • Fixed checkboxes and radio buttons missing borders in the filled state when “Increased Contrast” is enabled on macOS. (159379948)

PDF

  • Fixed VoiceOver not recognizing the password form in encrypted documents. (159240531)

Rendering

  • Fixed a bottom gap appearing on layouts with viewport-sized fixed containers on iOS. (158055568)
  • Fixed an issue on iOS where Safari extension popups and some websites could scroll or flicker unexpectedly. (160216319)
  • Fixed list markers overlapping text in certain situations. (160892820)
  • Fixed an issue that caused cropped flexbox elements to render incorrectly. (161218029)
  • Fixed string search freezing when subject has large number (>1000). (161421015)

SVG

  • Fixed absolutely positioned SVGs so that their size correctly accounts for the padding of the containing block when the SVG root is out-of-flow. (160727702)

Security

  • Fixed Safari ignoring the style-src-elem Content Security Policy directive ensuring it is checked before falling back to style-src, in line with CSP3 specifications. (157298407)

Web API

  • Fixed an issue on iOS 26 where pressing the B button on a gamepad could make a page appear to lose gamepad focus by bypassing the system’s automatic navigation behavior. (159125095)

Web Inspector

  • Fixed issue where searching on certain text fails to find matches. (159897282)

WebGPU

  • Fixed an issue where GPUQueue.copyExternalImageToTexture could not handle SVG images. (158442476)
  • Fixed an issue where video playback using the WebGPU renderer in WebCodecs could display a black screen. (158442539)
  • Fixed an issue where WebGPU video textures failed to load in Three.js panoramas. (159918934)

WebKit API

  • Fixed a crash when an app uses WKWebView::loadRequest API on background threads. (162225842)

WebRTC

  • Fixed getUserMedia() on iOS incorrectly firing devicechange events when there was no actual change to available microphones or default devices. (157693528)

Feedback

We love hearing from you. To share your thoughts, find our web evangelists online: Jen Simmons on Bluesky / Mastodon, Saron Yitbarek on Bluesky / Mastodon, and Jon Davis on Bluesky / Mastodon. You can follow WebKit on LinkedIn. If you run into any issues, we welcome your feedback on Safari UI (learn more about filing Feedback), or your WebKit bug report about web technologies or Web Inspector. If you run into a website that isn’t working as expected, please file a report at webcompat.com. Filing issues really does make a difference.

You can also find this information in the Safari release notes.

]]>
CSS Grid: A helpful mental model and the power of grid lines https://webkit.org/blog/17474/css-grid-a-helpful-mental-model-and-the-power-of-grid-lines/ Fri, 10 Oct 2025 01:13:45 +0000 https://webkit.org/?p=17474 Grid is a powerful, flexible tool that brings complex layouts to life. While it’s not new, and has been around for eight years, there’s so much to learn that it can still feel confusing and overwhelming to work with.

What’s the right mental model for thinking about Grid? What do all the new terms mean? What’s with that “/” anyway? If you have these questions and struggle to wrap your head around Grid, you’re not alone. There’s a lot of stuff to learn. Let’s see if we can unpack and explore it together, and make grid a little more comfortable to use.

When we think of laying out content on a webpage, we might start by listing out all of our elements in HTML. Then we use CSS to move and adjust them into place, changing their flow on the page, tweaking the space between them, until they’re finally in their right positions.

But with Grid, I want to try something different.

Instead of starting with that list of elements and shifting them around, we’re going to use a mental model to first focus on the container holding our elements.

Let’s think of our grid like we’re creating a brand new spreadsheet.

When you start a new document, depending on the software, you might have to first declare that it’s going to be a spreadsheet. Similarly, to use Grid we need to declare that the display for our container will be grid, like this:

.products {
  display: grid;
}

Before we put our data into a spreadsheet, we first think about what that spreadsheet will look like. We’ll probably start with the columns — what columns do we need to hold our data? If we’re working with a list of products, will the columns contain prices, discount codes, descriptions, launch dates?

Then we’ll think about the rows — how many rows of data do we need to contain everything? Once we have a sense of these columns and rows, we can decide where to place our data.

Similarly, our grid comes with columns and rows that we determine upfront. If I’m working on a grid of products, I might think about how many products I have and how that translates to columns and rows. I have six products, so I’m going to have three columns and two rows. And I’m going to throw in a grid-gap so I have some cushion. That should look good.

Black and white mockups of six product cards organized into two rows and three columns

Here’s what that code might look like:

.products {
   display: grid;
   grid-template-columns: 1fr 1fr 1fr;
   grid-template-rows: 1fr 1fr;
   grid-gap: 2em;
}

Let’s dissect this code a bit further.

Here, I’m using fr for my values, which stands for fractional unit, and tells my CSS to divide the space up into fractions. While I don’t know exactly how wide I want each column to be, and that width should change anyway when the viewport width changes, I know that I want three equal columns. So, using my fr, I can divide up the width into three equal fractional units: 1fr 1fr 1fr.

Let’s now move on to something that might not be immediately intuitive. Why is it called grid-template-columns anyway? Why not just grid-columns? What does “template” mean in this context?

This was one of the new vocabulary of Grid that tripped me up when I first saw it. I constantly had to look up the syntax for setting columns and rows.

When it comes to columns and rows, there are actually several Grid properties that reference them.

The first, grid-template-columns and grid-template-rows reference the columns and rows on the container, the top-level element of our little grid world. The word “template” is meant to reference a sort of blueprint we’re creating — at the highest level, we are defining a template that the children within our container will adhere to. That template outlines the structure and creates the rules of our grid.

The second pair of properties is grid-row and grid-column. Unlike our first properties, these don’t refer to our container. Instead, we drop down to the children. These properties allow us to place individual items into certain rows and columns. I’ll show you how a bit later.

And the third set of properties are the auto properties: grid-auto-rows and grid-auto-columns. These allow you to define the size of any extra rows and columns for content you might not have planned for. So in my products example, I may start with six products, but since my team is always working on new ones, I might want to prepare for a future where I add a few more products. In that case, if I wanted them to take the same 1fr of space, I would set that property to 1fr , like this:

.products {
   display: grid;
   grid-template-columns: 1fr 1fr 1fr;
   grid-template-rows: 1fr 1fr;
   grid-gap: 2em;
   grid-auto-rows: 1fr;
}

Now let’s get back to my grid.

Just like I would think about my rows and columns in my spreadsheet, I’ve thought about and determined the rows and columns of my grid. Let’s explore other elements of our mental model.

In my spreadsheet, my rows and columns are separated by lines. In Grid, these are called my grid lines. Separating my columns are column grid lines, and separating my rows are row grid lines.

While we know that the cells moving from left to right (or right to left) are my rows and the cells going up and down are my columns, rows and columns are more generically known as “tracks”.

And if I have multiple cells grouped together spanning different rows and columns, that’s a “grid area.”

That’s some of the introductory vocabulary to give you a foundation of how to think about grid. Now that you know what things are called, let’s try actually laying out come products and see what happens.

I started with six products, but I don’t think I want to display all six right now. Instead, I’m going to feature my two best sellers, have a section for add-ons, and include a testimonial at the bottom. The design I have in mind might look something like this:

Black and white mockup of two products, an add-on, and testimonials.

Just like how we start our spreadsheet by thinking about the columns and rows, I need to create my grid and start with considering the columns and rows I’ll need, creating a template that my individual elements will use.

Looking at this mock up, I can see that I have three columns and two rows. But there’s some merging going on. Just like a spreadsheet can have merged cells, I see that one of my “cells,” the Add-ons, actually spans two rows. And my other “cell,” the Testimonial, spans two columns.

But before we implement this design, let’s see what Grid does all on its own. If we just designate our template rows and columns and do nothing else, where do our elements end up?

Here’s the code we’re starting with:

.products {
   display: grid;
   grid-template-columns: 1fr 1fr 1fr;
   grid-template-rows: 1fr 1fr;
   grid-gap: 2em;
}

That’ll get us the following output:

Grid layout of three cards across and one on the second row in the first column.

Not too bad. The default behavior actually got us pretty far. Without us explicitly telling Grid where to put each element, it automatically placed the elements in the next available “cell” in our Grid, and when it ran out of column space, it wrapped around to the second row. Pretty close! This is one of the things that makes Grid so powerful — it offers a lot out of the box without us needed to be explicit.

Now we need to add the code to create the spanning action we have in our design.

This next step takes a little bit of upfront planning. Before I start merging and spanning things, I need to first establish my grid lines. But I’m going to take things a step further: I’m also going to number them.

Black and white mockup of two products, add-ons, and testimonial with pink and green gridlines.

This is where our grid and the mental model of a spreadsheet start to differ. If I were to describe where Product 1 is located in a spreadsheet, I would describe it as being in the first column and the first row. In fact, in a spreadsheet, it’s these rows and columns that have labels. But in Grid, the most common way to position elements actually isn’t by using the rows and columns at all. Instead, we use the numbered grid lines to dictate where an element goes. We don’t say “the first column,” we say “between the first and second column grid lines.”

If we compare our mockup with our output, there are only two elements whose placement we need to update: Add-ons and Testimonials. Let’s look at Add-ons first.

Here, we want to keep the default behavior of the columns — it should stay between the 3 and 4 column grid lines. But we want the height to span both rows. Put in grid line lingo, we want the element to start at row grid line 1 and end at row grid line 3. Let’s write the code to make that happen.

.add-on {
   grid-row: 1/3;
}

Let’s see what that looks like.

Grid layout of four cards with Add-ons taking two rows and placed in first column.

Something interesting happened! We got the spanning across rows we wanted, but now my Add-on section has jumped to first place. That’s because Grid prioritized explicitly positioned elements over implicitly positioned ones. Since right now, Add-on is the only element with any kind of explicit positioning, it gets priority positioning in my grid. But I don’t want that. So I need to add an explicit column positioning to get it back where I want it. Let’s do that now.

Since we’re positioning based on grid lines, we’re going to explicitly put our Add-on between the 3 and 4 column grid lines, like this:

.add-on {
   grid-row: 1/3;
   grid-column: 3/4;
}

That’ll get us this output:

Four cards laid out in a grid with Add-ons on the right spanning two rows

Wonderful. Three elements placed, one more to go.

Here, we’re going to use grid lines once again. We’re going to have my Testimonial section start at row grid line 1 and go all the way to row grid line 3. Let’s code that now:

.testimonial {
   grid-column: 1/3;
}

And we get this output:

Four cards laid out as a grid with Add-ons spanning two rows on the right and Testimonial spanning two columns at the bottom

And just like that, we have our elements laid out just like our mockup.

We spent a lot of time in this article laying the foundation for Grid, establishing some important vocabulary that we later used to implement our own grid design. The biggest takeaway here, and the concept that tripped me up the most when I first learned Grid, is the importance of using those grid lines to place and span elements.

But that isn’t the only way to place items. You can also use something called grid areas that might feel a little more intuitive. We’ll cover that next.

If you found this helpful or have more feedback, you can share your feedback with me, Saron Yitbarek, on BlueSky, or reach out to our other evangelists — Jon Davis, on Bluesky / Mastodon, and Jen Simmons, on Bluesky / Mastodon. You can also follow WebKit on LinkedIn. If you find a bug or problem, please file a WebKit bug report.

]]>
Position-area: Clear and explicit or short and sweet? https://webkit.org/blog/17417/position-area-clear-and-explicit-or-short-and-sweet/ Mon, 29 Sep 2025 18:42:52 +0000 https://webkit.org/?p=17417 When I first learned anchor positioning, I built a demo to help me figure out how it all worked. I had a goal of what I wanted and I was trying to figure out what properties I needed to make it happen. I had a profile picture, and, when you clicked on it, I wanted a menu to appear below it, but left aligned to the profile picture, like this:

Nav menu with profile picture and drop down menu right below it

I did some searching, and found that, using logical direction, the code to accomplish this looked like this:

.profile-menu {
  position-anchor: --profile-button;
  position: absolute;
  position-area: block-end span-inline-end;
}

Most of this code is good and fine, but there’s one bit that I found surprising and a bit unclear: span-inline-end. This property conveys a few things. The span tells me that I’m crossing columns and including more than one. Makes sense. The inline-end tells me that one of those columns is the inline-end . Great.

But there’s something missing.

If I’m spanning multiple columns, what’s the other column? Do we start all the way on the left and spanning three columns, or are we starting in the center and spanning just the two? Looking at this property, there’s no way to tell.

I’m wondering if there should be a change to how CSS works, so that, instead, developers would write center-span-inline-end. That spells it out clearly. You start at the center and you span over to inline-end. Every piece of the puzzle is there.

So the code above would be rewritten as this:

.profile-menu {
  position-anchor: --profile-button;
  position: absolute;
  position-area: block-end center-span-inline-end;
}

But with this new property, you get an extra word, making it a bit more verbose. So is that extra word worth the extra clarity to you? Or would you prefer to fill in the blank yourself and keep things concise?

This change to the spec is currently being considered, and we want to know if it’s a change you’d support or if you’d prefer things as they are.

Find me on BlueSky and let me know which you like better.

]]>
Release Notes for Safari Technology Preview 228 https://webkit.org/blog/17386/release-notes-for-safari-technology-preview-228/ Wed, 17 Sep 2025 21:20:52 +0000 https://webkit.org/?p=17386 Safari Technology Preview Release 228 is now available for download for macOS Tahoe and macOS Sequoia. If you already have Safari Technology Preview installed, you can update it in System Settings under General → Software Update.

This release includes WebKit changes between: 299100@main…299754@main.

Accessibility

New Features

  • Added support for auto-expanding details and hidden=”until-found” elements for text searches done via assistive technologies. (299649@main) (159913471)

Resolved Issues

  • Fixed an issue where VoiceOver reports the wrong radio count with a dynamically inserted radio option. (299585@main) (159221583)
  • Fixed exposing content within dynamically expanded details elements in the accessibility tree. (299601@main) (159291226)

CSS

New Features

  • Added support for :scope when the scoping root is :visited. (299560@main) (157588890)
  • Added support for using color-mix() without a color space, defaulting to oklab. (299440@main) (159039709)
  • Added support for display-p3-linear colors in CSS. (299381@main) (159579630)

Resolved Issues

  • Fixed -webkit-user-select: none disabling find-in-page in Safari. (299624@main) (8081660)
  • Fixed anchor position to only generate position options on base style. (299135@main) (158900076)
  • Fixed out-of-flow box with no sibling ignoring align-content. (299107@main) (159097576)
  • Fixed performance of :has(> .changed) .subject selectors. (299162@main) (159173631)
  • Fixed handling of the ::first-line pseudo-element when floats prevent the initial line from containing inline content, ensuring correct styling is applied to the actual first formatted line. (299402@main) (159613287)

DOM

Resolved Issues

  • Fixed an issue where command-clicking to open a link in a new tab navigates the current tab. (299537@main) (57216935)

Editing

Resolved Issues

  • Fixed jumbled text when copy/pasting bidirectional text starting with left-to-right. (299176@main) (152236717)

Forms

Resolved Issues

  • Fixed <select> element with long <option> text causing horizontal scrolling in grid or flex containers. (299631@main) (141633685)
  • Fixed checkboxes and radio buttons missing borders in the filled state when “Increased Contrast” is enabled on macOS. (299269@main) (159226308)
  • Fixed switch controls that may be sized incorrectly due to incorrect margins. (299543@main) (159729284)

JavaScript

New Features

  • Added support for Wasm Memory buffer APIs. (299236@main) (159305098)
  • Added support for Wasm JS String Builtins. (299455@main) (159679027)

Resolved Issues

  • Fixed non-standard new Date(2024-12-3) yielding to an “Invalid Date” error. (299182@main) (141044926)
  • Fixed poor error messages for destructing null or undefined values. (299244@main) (159340067)

Media

Resolved Issues

  • Fixed western Arabic numbers being displayed in the video viewer instead of eastern Arabic numbers. (299348@main) (141281469)
  • Fixed handling of null media accessibility caption profile. (299204@main) (159134245)
  • Fixed hiding and resuming a webm video that sometimes causes a decoding error. (299366@main) (159508950)

PDF

Resolved Issues

  • Fixed VoiceOver not recognizing the password form. (299180@main) (155907450)

Rendering

Resolved Issues

  • Fixed list markers overlapping text in certain situations. (299671@main) (157054277)
  • Fixed string search freezing when subject has large number (>1000). (292919@main) (159129919)
  • Fixed position-visibility: anchors-visible visibility heuristic in certain situations. (299554@main) (159790886)
  • Fixed buttons with box shadow being broken. (299603@main) (159888287)

SVG

Resolved Issues

  • Fixed an issue where a dynamic change in a CSS property of an SVG element does not get reflected in the instances of the SVGElement. (299112@main) (98577657)
  • Fixed an issue where <view> element was not applied to the root element. (299459@main) (159705519)

Service Worker

Resolved Issues

  • Fixed an issue where service worker downloads are not being saved to Downloads folder. (299564@main) (154501503)

Web API

Resolved Issues

  • Fixed preventing the javascript: protocol in navigation.navigate(). (299235@main) (158867866)
  • Fixed an issue where click and auxclick event targeting does not follow pointer capture target override. (299567@main) (159477637)

Web Extensions

Resolved Issues

  • Fixed an issue that caused the web page to crash when navigating to certain URLs with an extension enabled. (299173@main) (158180410)

Web Inspector

Resolved Issues

  • Fixed an issue where accepting a completion suggestion for a shorthand property value would malform the combined value. (299157@main) (159107788)
  • Fixed issue where searching on certain text fails to find matches. (299541@main) (159272725)

WebGPU

Resolved Issues

  • Fixed incorrect handling of some PNG pixel formats in WebGPU. (299404@main) (158797747)

WebRTC

New Features

  • Added encrypted field to RTCRtpHeaderExtensionParameters. (299356@main) (159279401)

Resolved Issues

  • Fixed camera indicator staying enabled even after ending a meeting/access to camera. (299161@main) (152962650)
]]>