Menu

Chrome 73 Beta: Constructable stylesheets, a new RegExp function, and passive mouse events

February 8th, 2019

Unless otherwise noted, changes described below apply to the newest Chrome Beta channel release for Android, Chrome OS, Linux, macOS, and Windows. View a complete list of the features in Chrome 73 on ChromeStatus.com. Chrome 73 is beta as of February 8, 2019.

Constructable stylesheets

It’s long been possible to dynamically create a stylesheet by attaching it directly to a <style> element’s sheet property. This comes with problems including a flash of unstyled content and sometimes the bloat of duplicate CSS rules. New methods on the CSSStyleSheet interface add a programmatic way to add stylesheets, eliminating the old method’s problems.

Constructable stylesheets let you define shared CSS styles and apply them to multiple shadow roots or to the document object. This is referred to as adopting. Updates to a shared style sheet are applied everywhere it’s been adopted. Adopting a stylesheet is fast. Constructable stylesheets are useful in many use cases including theme sharing between components, preloading stylesheets without DOM injection, and more.
Chrome 73 Beta: Constructable stylesheets, a new RegExp function, and passive mouse events
Instead of a new API, stylesheets are constructed imperatively with the replace() and replaceSync() methods as shown below.

const sheet = new CSSStyleSheet();

// replace all styles synchronously:
sheet.replaceSync('a { color: red; }');

// replace all styles, allowing external resources:
sheet.replace('@import url("styles.css")')
    .then(sheet => {
        console.log('Styles loaded successfully');
    })
    .catch(err => {
        console.error('Failed to load:', err);
    });

To learn more, try out the sample.

String.prototype.matchAll()

A new regular expression matching method is being added to String.prototype. The matchAll() function provides a more complete set of matches than String.prototype.match() does. To understand the new function, first consider the following regular expression code:

const regex = /t(e)(st(\d?))/g;
const string = 'test1test2';

Calling string.match(regex) returns an array that contains only complete matches, in this case 'test1' and 'test2'. What about those capturing groups? I can get the first set, those related to 'test1' if I remove the g flag. Getting the rest currently requires writing additional code. It would be nice if I didn’t need to.

The specification authors reached the same conclusion and created matchAll(), which has just landed in Chrome. And instead of returning the limited results just described, matchAll() returns an iterable object and contains a few convenience properties.

To learn more about this method read our article on developers.google.com. For more about what’s new in JavaScript for Chrome, head over to v8.dev.

Passive Mousewheel listeners

Scrolling responsiveness is important enough to user engagement that Chrome has been working to improve scrolling through event behavior. A best practice for event listeners is that if they don’t call preventDefault(), then they need to be registered as passive (by passing {passive: true} to addEVentListener()). Non-passive events are blocking since the browser has to wait for them to finish in case preventDefault() was called.

Unnecessarily blocking event listeners happen often enough that in Chrome 56, we changed touchstart and touchmove that are registered on root targets to be passive by default. This allows the browser to safely perform scrolling and zooming without being blocked on listeners. Starting in Chrome 73, the wheel and mousewheel event listeners behave the same way, making the following lines of code equivalent:

window.addEventListener("wheel", func);
window.addEventListener("wheel", func, {passive: true} );

For more background and a few stats on change, read Making wheel events passive by default.

Other features in this release

Cross-Origin resource policy

Cross-Origin-Resource-Policy response header allows http servers to ask the browser to prevent cross-origin or cross-site embedding of the returned resource. This is complementary to the Cross-Origin Read Blocking feature and is especially valuable for resources not covered by CORB (which only protects HTML, XML and JSON).

Cross-Origin-Resource-Policy is currently the only way to protect images against Spectre attacks or against compromised renderers.
CSS redirects are cross-origin

To align with the specification, stylesheets that (a) failed to load due to network error, or (b) loaded via a redirect from cross-origin back to same-origin are considered cross-origin.

document.visibilityState set to “hidden” when WebContents is occluded

Thanks to the WebContents Occlusion feature in Chromium, the Page Visibility API will now accurately reflect the visibility state of web pages, especially when they are occluded. In other words, the document.visibilityState value will be “hidden” when the browser tab or window is covered by one or more window.

The WebContents Occlusion feature is supported only on Chrome OS and macOS at this time. Windows support is in progress.

DOMMatrixReadOnly.scaleNonUniform()

The scaleNonUniform() function post-multiplies a non-uniform scale transformation on the current matrix and returns the resulting matrix. It is being re-added to support legacy compatibility with SVGMatrix. Non-uniform scaling is a transformation in which at least one of the scaling factors is different from the others. For example, non-uniform scaling might turn a rectangle into a square or a parallelogram.

EME extension: HDCP policy check

Applications now have the ability to query whether a certain HDCP policy can be enforced so that playback can be started at the optimum resolution for the best user experience. A sample is available for developers who want to try it.

GamePad API: GamepadButton touched attribute

The GamePad API now provides the touched state of a gamepad button, which indicates whether a finger is on a button independent of whether it’s being pressed.

imagesrcset and imagesizes attributes on link rel=preload

The <link> element now supports imagesrcset and imagesizes properties to correspond to srcset and sizes attributes of HTMLImageElement. To use them, the <link> element must include the preload and image keywords as shown below.

<link rel="preload" as="image" href="pic400.jpg" imagesizes="100vw"
imagesrcset="pic400.jpg 400w, pic800.jpg 800w, pic1600.jpg 1600w">

Implicit root scroller

Implicit root scroller allows viewport-filling scrollers (iframes, divs) to perform document-level scrolling, i.e. show/hide URL bar, overscroll glow, rotation anchoring, etc.. This feature doesn’t have an API so it’s not on a standards track. Chrome will try to determine if a page is mainly contained in a non-document scroller and attempt to delegate its document-scrolling-UX to that scroller.

This is an implicit version of the previously proposed rootScrollers API.

::part pseudo element on shadow hosts

Chrome now supports the ::part() pseudo-element on shadow hosts, allowing shadow hosts to selectively expose chosen elements from their shadow tree to the outside page for styling purposes.

PerformanceObserver.supportedEntryTypes

PerformanceObserver.supportedEntryTypes provides a way to feature-detect the PerformanceEntry types that are implemented in a web browser. For example, a developer running this in Chrome could get something like this in the console:

["longtask", "mark", "measure", "navigation", "paint", "resource"]

Use the response URL as the base URL for CSS and XSLT stylesheets

On the web, URLs are usually relative to the document’s base URL. That means, if the page is /hello/ and contains <img src="world.jpg">, the image is loaded from /hello/world.jpg.

There are a couple of exceptions to this, the most common of which is CSS. Within stylesheets, URLs (e.g. for background images) are relative to the stylesheet’s “response URL”.

The “response” distinction is important. If the page contains <link rel="stylesheet" href="/styles.css">, and /styles.css redirects to /foo/styles.css, URLs in the stylesheet will be relative to /foo/styles.css. In this case the request URL is different to the response URL, and it’s the response URL that’s used as the base URL.

With a service worker in the middle, Chrome didn’t handle this correctly. It would use the request URL as the base URL for CSS. This is fixed in Chrome 73. Chrome will correctly use the response URL.

This change applies to the following resource types:

XHR: Use the response URL for responseURL and documents

XHR’s responseURL property should provide the URL of the response.

In many cases, the request and response URLs are the same, but service workers can choose to return a response from elsewhere. Redirects also cause the request and response URLs to be different.

If the XHR request was intercepted by a service worker, Chrome would incorrectly set responseURL to the request URL. This is fixed in Chrome 73. Chrome will correctly set responseURL to the response URL.

WebRTC updates

RTCConfiguration.offerExtmapAllowMixed

A boolean property has been added to RTCConfiguration.offerExtmapAllowMixed() to enable the extmap-allow-mixed attribute in a session description protocol (SDP) offer.

The SDP attribute extmap-allow-mixed, as defined in RFC8285, will be included in the SDP offer if this property is set to true. The SDP attribute extmap-allow-mixed is supported from Chrome 71, but due to backwards compatibility problems it was not included in the SDP offer by default.

This property is purely transitional. Initially it will be off by default. We hope to change the default to on when enough clients have updated their code. We hope that eventually backwards compatibility will not be needed and we can remove it completely.

RTCRtpReceiver.getParameters()

The new RTCRtpReceiver.getParameters() method returns the RTCRtpReceiver object’s track decoding parameters, which includes the codec and RTP header lists negotiated for the call, the RTCP information, and the layer count.

This method is an analog to RTCRtpSender.getParameters() and presents similar information for a call, but on the receiver side. It does not allow modification of the call’s parameters.

RTCRtpReceiver.getSynchronizationSources()

The new RTCRtpReceiver.getSynchronizationSources() method returns the latest playout timestamps of RTP packets for audio and video receivers. This is useful for determining in real time which streams are active, such as for the use case of audio meters or prioritizing displaying active participant streams in the UI.

Turn RTCRtpContributingSource from an interface into a dictionary

The specification requires RTCRtpContributingSource to be a dictionary, but it was previously shipped as an interface. With this change RTCRtpContributingSource will no longer have a prototype and getContributingSources() will create a new set of objects with each call.

Rename Atomics.wake() to Atomics.notify()

The Atomics.wake() method is being renamed Atomics.notify(). This is a low-level function to wake a Worker that has been suspended via Atomics.wait(). This conforms to a specification change made to alleviate confusion created by the similarity of the names wait and wake.

Transform list interpolation

Chrome has improved how CSS transforms are handled to reduce cases where a matrix interpolation fallback is used. An interpolation is an intermediate transformation. Sometimes interpretation of the CSS rule requires falling back to a matrix to accomplish the interpolation, and this can produce visual results other than what the web developer intends. To mitigate this, the specification was changed to reduce the number of situations when this can occur.

Interoperability improvements

Spec-compliant shadow blur-radius

Historically, Blink’s blur-radius interpretation has been at odds with both the CSS and Canvas2D specifications in that Blink shadows cover about half the expected area.

With this change Gaussian blur sigma is now computed as one-half the blur-radius, as mandated by the specification. Blink’s shadow implementation now matches FireFox and Safari.

Remove isomorphic decoding of URL fragment identifier

When Chrome opens a URL with a fragment id, it decodes %xx and applies isomorphic-decode to it, then tries to find an element with the decoding result as an ID in some cases. For example, if a user opens example.com/#%F8%C0, Chrome does the following:

  1. It searches the page for an element with id="%F8%C0".
  2. If it’s not found, it searches the page for an element with id="&#xF8;&#xC0;".

No other browsers do this, and it’s not defined by the standard. Starting in version 73, Chrome no longer does this either.

Deprecations, and Removals

Remove EXPLAIN and REINDEX support in WebSQL

The output ofEXPLAIN is not guaranteed to be stable over SQLite versions, so developers cannot rely on it. REINDEX is only useful when collation sequence definitions change, and Chrome only uses the built-in collation sequences. Both features are now removed.

Deprecate ‘drive-by downloads’ in sandboxed iframes

Chrome has deprecated downloads in sandboxed iframes that lack a user gesture (‘drive-by downloads’), though this restriction could be lifted via an allow-downloads-without-user-activation keyword in the sandbox attribute list. This allows content providers to restrict malicious or abusive downloads.

Downloads can bring security vulnerabilities to a system. Even though additional security checks are done in Chrome and the operating system, we feel blocking downloads in sandboxed iframes also fits the general thought behind the sandbox. Apart from security concerns, it would be a more pleasant user experience for a click to trigger a download on the same page, compared with downloads started automatically when landing at a new page, or started non-spontaneously after the click.

Removal is expected in Chrome 74.