Meaningful preset values when autocompleting CSS functions
Some CSS properties, like filter,
take functions for values. For example, filter: blur(1px) adds a 1-pixel blur to a node.
When autocompleting properties like filter, DevTools now populates the property with a meaningful
value so that you can preview what kind of change the value will have on the node.
Clearing site data has been available from Application > Clear Storage for a while.
The new feature in Chrome 75 is being able to run the command from the Command Menu.
If you don't want to delete all site data, you can control what data gets deleted from
Application > Clear Storage.
Previously Application > IndexedDB only allowed you to inspect IndexedDB databases from the
main origin. For example, if you had an <iframe> on your page, and that <iframe> was using IndexedDB,
you wouldn't be able to see its database(s). As of Chrome 75, DevTools shows IndexedDB databases for all origins.
Suppose that you're inspecting network activity.
Your site uses text compression to reduce
the transfer size of resources. You want to see how large the page's resources are after the
browser uncompresses them. Previously this information was only available when using
large request rows. Now you can
access this information by hovering over the Size column.
For a while now DevTools has enabled you to specify when exactly it should pause on a breakpoint like this: at the
beginning of the line, before document.querySelector('#dante') is called, or before addEventListener('click', logWarning)
is called. If you enable all 3, you're essentially creating 3 breakpoints. Previously the Breakpoints pane did not
give you the ability to manage these 3 breakpoints individually. As of Chrome 75 each inline breakpoint gets its
own entry in the Breakpoints pane.
Setting for toggling tab indentation in the Sources panel editor
Accessibility testing revealed that there was a tab trap in the Editor. Once a keyboard user tabbed
into the Editor, they had no way to tab out of it because the Tab key was used for indentation.
To override the default behavior and use Tab to move focus, enable Settings >
Preferences > Sources > Enable Tab Moves Focus.
Feedback
To discuss the new features and changes in this post, or anything else related to DevTools:
File definite bug reports and feature requests at Chromium Bugs.
Discuss possible features, changes, and bugs on the Mailing List.
If you're on Mac or Windows, consider using Chrome Canary as your default
development browser. Canary gives you access to the latest DevTools features.
Note: Canary is released as soon as its built, without testing. This means that Canary
breaks about once-a-month. It's usually fixed within a day. You can go back to using Chrome
Stable while Canary is broken.
Class fields simplify class syntax by avoiding the need for constructor
functions just to define instance properties. In Chrome 72, we added support for
public class fields.
class IncreasingCounter {
// Public class field
_publicValue = 0;
get value() {
return this._publicValue;
}
increment() {
this._publicValue++;
}
}
And I said private class fields were in the works. I’m happy to say that
private class fields have landed in Chrome 74. The new private fields syntax is
similar to public fields, except you mark the field as being private by using a
# (pound sign). Think of the # as being part of the field name.
class IncreasingCounter {
// Private class field
#privateValue = 0;
get value() {
return this.#privateValue;
}
increment() {
this.#privateValue++;
}
}
Remember, private fields are just that, private. They’re accessible
inside the class, but not available outside the class body.
To read more about public and private classes, check out Mathias’s post on
class fields.
prefers-reduced-motion
Some users have reported getting motion sick when viewing parallax scrolling,
zooming, and other motion effects. To address this, many operating systems
provide an option to reduce motion whenever possible.
Chrome now provides a media query, prefers-reduced-motion - part of
Media Queries Level 5 spec, that allows you to detect when this
option is turned on.
@media (prefers-reduced-motion: reduce)
Imagine I have a sign-up button that draws attention to itself with a slight
motion. The new query lets me shut off the motion for just the button.
The CSS Transitions specification requires that
transition events are sent when a transition is enqueued,
starts, ends, or is canceled. These events have been supported in other
browsers for a while…
But, until now, they weren’t supported in Chrome. In Chrome 74 you can now
listen for:
transitionrun
transitionstart
transitionend
transitioncancel
By listening for these events, its possible to track or change behavior when a
transition is run.
Feature policy API updates
Feature policies, allow you to selectively enable, disable, and modify the
behavior of APIs and other web features. This is done either through the
Feature-Policy header or through the allow attribute on an iframe.
HTTP Header:Feature-Policy: geolocation 'self'
<iframe ... allow="geolocation self">
</iframe>
Chrome 74 introduces a new set of APIs to check which features are enabled:
You can get a list of features allowed with
document.featurePolicy.allowedFeatures().
You can check if a specific feature is allowed with
document.featurePolicy.allowsFeature(...).
And, you can get a list of domains used on the current page that allow a
specified feature with document.featurePolicy.getAllowlistForFeature().
These are just a few of the changes in Chrome 74 for developers, of course,
there’s plenty more. Personally, I’m pretty excited about
KV Storage, a super fast, async,
key/value storage service, available as an origin trial.
Google I/O is happening soon!
And don’t forget - Google I/O is just a few
weeks away (May 7th to 9th) and we’ll have lots of great new stuff for you.
If you can't make it, all of the sessions will be live streamed, and will be
available on our
Chrome Developers YouTube channel
afterwards.
Subscribe
Want to stay up to date with our videos, then subscribe
to our Chrome Developers YouTube channel,
and you’ll get an email notification whenever we launch a new video, or add our
RSS feed to your feed reader.
I’m Pete LePage, and as soon as Chrome 75 is released, I’ll be right
here to tell you -- what’s new in Chrome!
Over the last few years, we've been working to bring native sharing capabilities
to the web. The
Web Share API
allows web apps to invoke the same share dialog box that a native app user would
see. The
Web Share Target API
allows web apps to receive data from a share.
The only resource previously supported by these APIs was links. Chrome 75 adds
support for Web Web Share API - Level
2, making it easy for web apps to
share files to other apps using the system provided picker.In the
future, you'll also be
able to use web apps as a share target. For now, your web app can share files
with other web share targets registered on your device.
This article assumes some familiarity with the web share APIs. If this is new to
you, check out the links above or the demo.
The canShare() method
If you're familiar with the earlier API, you're used to doing feature detection
by testing for navigator.share(). With files it's more complicated. You need
to know whether the file a user is sharing is sharable on the current system. To
find out, you test for the presence of canShare(), then pass it a reference to
the files you want to share.
const shareData = { files: filesArray };
if (navigator.canShare && navigator.canShare(shareData)) {
// Share the data.
} else {
console.log('Your system doesn't support sharing files.');
}
Take note of what's not in shareData. When calling canShare() for files,
shareData cannot contain other members. If you need title, text, or url you'll
need to add them afterwards.
Image, video, audio and text files can be shared (see
permitted extensions).
More file types may be permitted in the future.
You're now ready to share:
if (navigator.canShare && navigator.canShare( { files: filesArray } )) {
navigator.share({
files: files,
title: 'Vacation Pictures',
text: 'Barb\nHere are the pictures from our vacation.\n\nJoe', })
.then(() => console.log('Share was successful.'))
.catch((error) => console.log('Sharing failed', error));
} else {
console.log('Your system doesn't support sharing files.');
}
It may seem odd to include other data members when sharing files. Allowing these
members explands the flexibility of use cases. Imagine if after running the code
above, the user chose an email application as the target. The title parameter
might become an email subject, the text, the body of the message, and the
files, attachments.
Note: The shareData argument is required for both canShare() and share()
even though the specification labels it as optional in both cases. As the
specification itself states, this is because of a quirk of the Web IDL rules.
Low-latency rendering with the desynchronized hint
Stylus-based drawing applications built for the web have long suffered from
latency issues because a web page has to synchronize graphics updates with the
DOM. In any drawing application, latencies longer than 50 milliseconds can
interfere with a user's hand-eye coordination, making applications difficult to
use.
The desynchronized hint for canvas.getContext() invokes a different code
path that bypasses the usual DOM update
mechanism.
Instead the hint tells the underlying system to skip as much compositing as it
is able and in some cases, the canvas's underlying buffer is sent directly to
the screen's display controller. This eliminates the latency that would be
caused by using the renderer compositor queue.
How good is it?
If you want to get to the code, scroll ahead. To see it in action, you need a
device with a touch screen, and preferably a stylus. (Fingers work too.) If you
have one, try the 2d or
webgl samples. For the rest of you
check out this demo by Miguel Casas,
one of the engineers who implemented this feature. Open the demo, press play,
then move the slider back and forth randomly and quickly.
This example uses a one-minute, twenty-one second clip from the short film
Sintel by Durian, the Blender open movie
project. In this example, the movie is played in a <video> element whose
contents are simultaneously rendered to a <canvas> element. Many devices can
do this without tearing, though devices with front buffer rendering such as
Chrome OS for example may have tearing. (The movie is great, but heartbreaking.
I was useless for an hour after I saw it. Consider yourself warned.)
Using the hint
There's more to using low latency than adding desynchronized to
canvas.getContext(). I'll go over the issues one at a time.
Create the canvas
On another API I'd discuss feature detection first. For the desynchronized
hint you must create the canvas first. Call canvas.getContext() and pass it
the new desynchronized hint with a value of true.
const canvas = document.querySelector('myCanvas');
const ctx = canvas.getContext('2d', {
desynchronized: true,
// Other options. See below.
});
Feature detection
Next, call getContextAttributes(). If the returned attributes object has a
desynchronized property, then test it.
if (ctx.getContextAttributes().desynchronized) {
console.log('Low latency canvas supported. Yay!');
} else {
console.log('Low latency canvas not supported. Boo!');
}
Avoiding flicker
There are two instances where you can cause flicker if you don't code correctly.
Some browsers including Chrome clear WebGL canvases between frames. It's
possible for the display controller to read the buffer while it's empty causing
the image being drawn to flicker. To avoid this is to set
preserveDrawingBuffer to true.
Flicker can also occur when you clear the screen context in your own drawing
code. If you must clear, draw to an offscreen framebuffer then copy that to the
screen.
Alpha channels
A translucent canvas element, one where alpha is set to true, can still be
desynchronized, but it must not have any other DOM elements above it.
There can be only one
You cannot change the context attributes after the first call to
canvas.getContext(). This has always been true, but repeating it might save
you some frustration if you're unaware or have forgotten .
For example, let's say that I get a context and specify alpha as false, then
somewhere later in my code I call canvas.getContext() a second time with alpha
set to true as shown below.
const canvas = document.querySelector('myCanvas');
const ctx1 = canvas.getContext('2d', {
alpha: false,
desynchronized: true,
});
//Some time later, in another corner of code.
const ctx2 = canvas.getContext('2d', {
alpha: true,
desynchronized: true,
});
It's not obvious that ctx1 and ctx2 are the same object. Alpha is still false and a
context with alpha equal to true is never created.
Supported canvas types
The first parameter passed to getContext() is the contextType. If you're
already familliar with getContext() you're no doubt wondering if anything
other than '2d' context types are supported. The table below shows the context
types that support desynchronized.
contextType
Context type object
'2d'
CanvasRenderingContext2D
'webgl'
WebGLRenderingContext
'webgl2'
WebGL2RenderingContext
Conclusion
If you want to see more of this, check out the samples. In addition to
the video example already described
there are examples showing both '2d'
and 'webgl' contexts.
Remove overflow: -webkit-paged-x and overflow: -webkit-paged-y
These are old webkit-specific properties that allowed developers to fragment
content over columns inside a scrollable region. They are now removed.
Practically speaking these aren't used. Most developers use them accidentally,
and typically when they are they force a new formatting context similar to
setting overflow: hidden.
Paint Holding - reducing the flash of white on same-origin navigations
For a while now, Chrome has eagerly cleared the screen when transitioning to a
new page to give users the reassurance that the page is loading. This "flash of
white" is this brief moment during which the browser shows a white paint while
loading a page. This can be distracting in-between navigations, especially when
the page is reasonably fast in reaching a more interesting state.
But for pages that load lightning fast, this approach is actually detrimental
to the user experience. In the following animation, you see an example of what
this looks like today.
We are big fans of this website and it kills us that their quality experience
has a flash of white, and we wanted to fix it. We did so with a new behavior
that were calling Paint Holding, where the browser waits briefly before
starting to paint, especially if the page is fast enough. This ensures that the
page renders as a whole delivering a truly instant experience.
The way this works is that we defer compositor commits until a given page load
signal (PLS) (e.g. first contentful paint / fixed timeout) is reached. We
distinguish between main-thread rendering work and commit to the impl thread
(only the latter is deferred). Waiting until a PLS occurs reduces likelihood of
flashes of white/solid-color.
Our goal with this work was for navigations in Chrome between two pages that
are of the same origin should have a seamless and fast default navigation
experience with no flashes of white/solid-color background between old and new
content.
Try Paint Holding in Chrome Canary (Chrome 76) and let us know what you think.
Developers shouldn't have to worry about making any modifications to their
pages to take advantage of it.
In February, we introduced the <model-viewer> web
component,
which let you declaratively add a 3D model to a web page, while hosting the
model on your own site. One thing it didn't support was augmented reality. That
is, you could not render the component's source image on top of a device's
camera feed.
To do that, we've since added support for Magic Leap, and Quick Look on iOS. Now
we're announcing support for AR on Android with the addition of the ar
attribute. This attribute is built on a new ARCore feature called Scene Viewer,
and external app for viewing 3D models. To learn more about Scene Viewer,
check out Viewing 3D models in AR from an Android browser.
Let's see how to do augmented reality with <model-viewer>.
The attribute
A web component, you may recall, requires no special knowledge to use. It
behaves like a standard HTML element, having a unique tag as well as properties
and methods. After
installing it with a <script> tag,
use it like any HTML element.
<model-viewer alt="A 3D model of an astronaut." src="Astronaut.gltf" ios-src="Astronaut.usdz" magic-leap ar>
This looks much the same as what I had in my earlier article. Notice the thing
I've highlighted at the very end. That's the new attribute.
Installing the new version
If you're using <model-viewer> already, you're probably importing the component
using the <script> tags exactly
as shown in the documentation.
We're continually making improvements. If you want to test new features before
deliberately upgrading and deploying, you'll want to install a specific version
of <model-viewer>. To do this add the version number to the file URLs as shown
below. Then watch
the releases page
for updates.
In Chrome 76 you can hide the Add to Home screen mini-infobar
Background on Progressive Web Apps and the mini-infobar
Progressive Web Apps (PWA) are a pattern for
creating app-like, instant loading, reliable and installable websites.
When your PWA passes the
installability checklist on
Android, a Chrome system dialog called the mini-infobar will appear at the
bottom of the browser window.
Today the Add to Home screen mini-infobar is shown at the same time as the
beforeinstallprompt
event.
Changes in Chrome 76
We’ve been listening to our community and what we heard was that developers
want more control over when to ask users to install a PWA. We heard you!
Starting in Chrome 76, you can prevent the mini-infobar by calling
preventDefault() on the beforeinstallprompt event.
The beforeinstallprompt event can help you promote the installation of your
progressive web app, making it easy for users to add it to their home screen.
Our community has shared that users who install a PWA to the home screen are
highly engaged, with more repeat visits, time spent in the app and when
applicable, higher conversion rates.
To promote your web app without the mini-infobar, listen for the
beforeinstallprompt event, then, save the event. Next, update your user
interface to indicate your PWA can be installed, for example by adding an
install button, showing an install banner, using in-feed promotions, or a
menu option. When the user clicks on the install element, call prompt() on
the saved beforeinstallprompt event to show the add to home screen modal
dialog.
Future of the Add to Home screen mini-infobar
The use of the add to home screen infobar is still a temporary measure.
We’re experimenting with new UI patterns that will continue to give Progressive
Web App users the ability to install, and do this in a way that reduces
clutter in the browsing experience.
Flaky tests are a common problem in Chrome. They
impact the productivity of other developers, and get disabled over time.
Disabled tests mean diminishing test coverage.
Triaging Stage
The OWNERS of directories are responsible for fixing their flaky tests.
If you received a bug about a flaky test, spend a few minutes and
comment what went wrong on the bug. If you have an old flaky test and
it's unclear what went wrong, try to simply re-enable the test.
Reassign the bug ASAP if it's clearly a problem in another component.
The owners of that component should have better judgement about the failure,
Debugging Stage
A number of command-line flags are useful for
fixing flaky tests. For example, --enable-pixel-output-in-tests
will render the actual browser UI.
Have fallback tools if the debugger makes flakiness disappear. It's
possible that, under debugger, the test is never flaky. In that case, log
statements or base::debug::StackTrace can be handy.
Keep in mind common reasons for EXPECT__* failures besides bugs in production
code:
Incorrect expectations (e.g. secure page means HTTPS; it can be a localhost instead).
Race conditions due to tests not waiting for the proper event.
// It takes 2 round trips between the UI and the background thread to complete.
SyncWithTheStore();
SyncWithTheStore();
CheckTheStore();
The two round trips may change into three in the future, making the test flaky.
However, only the store state is relevant. Instead, use an observer for the
store.
Beware of common patterns such as the following:
Submit TestPasswordForm();
// Wait until things settle down.
RunLoop().RunUntilIdle();
CheckCredentialPromptVisible();
A snippet like the above from a browser test is almost surely incorrect.
There are many events that should happen in different processes and
threads before some UI appears.
The fix above is correct under the assumption that
WaitUntilCredentialPromptVisible() doesn’t actually check the UI.
The browser tests should not depend on external UI events like "focus lost"
or “window became foreground”. Imagine an implementation where the prompt
appears only when the browser window is active. Such an implementation
would be correct; however, checking for the actual window makes the test flaky.
Post-fix Stage
Once the test is fixed, run it hundreds of times locally. Keep an eye on the
Flakiness Portal.
When adding style declarations to a DOM node sometimes the declaration value is easier to
remember than the declaration name. For example, when making a <p> node bold, the value
bold might be easier to remember than the name font-weight. The Style pane's autocomplete UI now
supports CSS values. If you remember what keyword value you want, but can't remember the property
name, try typing the value and autocomplete should help you find the name you're looking
for.
The Network panel previously had a usability issue where options like the throttling
menu were unreachable when the DevTools window was narrow. To fix this issue and
de-clutter the Network panel, a few lesser-used options have been moved behind the new
Network Settings pane.
The following options have moved to Network Settings: Use Large Request Rows, Group By Frame,
Show Overview, Capture Screenshots. Figure 3 maps the old locations to the new ones.
When exporting a HAR file from the Network panel to share network logs with your
colleagues, your HAR file now includes WebSocket messages. The _webSocketMessages
property begins with an underscore to indicate that it's a custom field.
Share network logs with colleagues more easily with the new Export All As HAR With Content
buttons. HAR importing and exporting have existed in DevTools for a while. The more
discoverable buttons are the new change.
Puppeteer for Firefox is a new experimental project that enables you to automate Firefox with the
Puppeteer API. In other words, you can now automate Firefox and Chromium with the same Node API,
as demonstrated in the video below.
After running node example.js, Firefox opens and the text page is inserted into the
search box on Puppeteer's documentation site. Then the same task is repeated in Chromium.
Check out the Puppeteer talk by Joel and
Andrey from Google I/O 2019 to learn more about Puppeteer
and Puppeteer for Firefox. The Firefox announcement happens around 4:05.
Feedback
To discuss the new features and changes in this post, or anything else related to DevTools:
File definite bug reports and feature requests at Chromium Bugs.
Discuss possible features, changes, and bugs on the Mailing List.
If you're on Mac or Windows, consider using Chrome Canary as your default
development browser. Canary gives you access to the latest DevTools features.
Note: Canary is released as soon as its built, without testing. This means that Canary
breaks about once-a-month. It's usually fixed within a day. You can go back to using Chrome
Stable while Canary is broken.
Drawing on screen with the canvas element requires the page to synchronize
graphics updates with the DOM. This synchronization can sometimes cause latency.
For example, in a drawing app, latencies longer than 50 milliseconds can
interfere with hand-eye coordination, making them difficult to use.
The desynchronized hint, when creating a canvas context, uses a different
code path, that bypasses the usual DOM update mechanism. The hint, tells the
system to skip as much compositing as it can. In some cases, the canvas's
underlying buffer is sent directly to the screen's display controller. This
eliminates the latency that would be caused by using the renderer compositor
queue.
Using the desynchronized hint is simple, just add desynchronized: true to
the options object when creating the canvas.
The web share API allows you to plug
into the share service provided by the OS, making it easy to share web pages
and apps with other installed apps on the users device.
In Chrome 75, the Web Share API now supports the sharing file of files! I’m
particularly excited about this because it makes it way easier for apps to
share photos, videos and more. Squoosh is adding support for this to share a
file once you’ve finished compressing it. The Web Share API currently supports
the sharing of audio files, images, videos, and text documents.
It’s best to use feature detection to see if the web share API is supported,
and fallback to your traditional mechanism if it’s not. And you can use
navigator.canShare to check if file sharing is supported.
const webShareAvailable = {
links: 'share' in navigator,
files: 'canShare' in navigator,
};
If navigator.canShare returns true, sharing of those files is supported,
so you can call navigator.share, and pass an object with the array of files
you want to share. Chrome will open the system share sheet and give you a
list of installed apps that you can share the files to.
if (webShareAvailable.files) {
const shareData = { files: filesArray };
if (navigator.canShare(shareData)) {
shareData.title = 'Squooshed files.';
navigator.share(shareData)
.then(...)
.catch(...);
} else {
// File sharing not supported
}
}
Numeric literals now allow underscores (_, U+005F) as
separators to make them more readable. For example, 1_000_000_000 will be
interpreted by mathematical operations as equivalent to 1000000000.
Underscores can only appear between digits, and consecutive underscores are
not allowed. So literals such as 3._14, _2.71 or 1.6__2 are illegal.
Want to stay up to date with our videos, then subscribe
to our Chrome Developers YouTube channel,
and you’ll get an email notification whenever we launch a new video, or add our
RSS feed to your feed reader.
I’m Pete LePage, and as soon as Chrome 76 is released, I’ll be right
here to tell you -- what’s new in Chrome!
If your PWA has use cases where it’s helpful for a user to install your app,
for example if you have users who use your app more than once a week, you
should be promoting the installation of your PWA within the web UI of your app.
But how should you notify the user that your PWA can be installed?
Check out Patterns for Promoting PWA Installation, a series
of recommended patterns and best practices that you can use to promote the
installation of your Progressive Web App.
It includes patterns for notifying users within the core UI of your app,
within your app's content, or just letting the browser notify the user. And,
it includes recommendations on how to place the notification for different
types of apps.
Scheduled to be released in Chrome 76, LayoutNG is a new layout engine exiting a
multi-year effort. There are several exciting immediate improvements,
and additional performance gains and advanced layout features will be coming.
What's new?
Improves performance isolation.
Better support for scripts other than Latin
Fixes many issues around floats and margins
Fixes a large number of web compatibility issues
Please note that LayoutNG will be launched in stages. In Chrome 76, LayoutNG
is used for inline and block layout. Other layout primitives
(such as table, flexbox, grid, and block fragmentation) will be replaced in subsequent releases.
Developer visible changes
Although the user visible impact should be minimal, LayoutNG changes some behavior
in very subtle ways, fixes hundreds of tests, and improves compatibility
with other browsers. Despite our best efforts, it is likely that this
will cause some sites and applications to render or behave slightly differently.
The performance characteristics are also quite different; although performance on
a whole is similar or slightly better than before, certain use
cases are likely to see performance improvements, while others are expected to
regress somewhat, at least short-term.
Floats
LayoutNG reimplements support for floating elements (float: left; and float: right;)
fixing a number of correctness issues around placement
of floats in relation to other content.
Superimposed content
The legacy float implementation didn’t correctly account for margins when placing
content around a floating element, resulting in the content
partially or fully overlapping the float itself. The most common manifestation of
this bug appears when an image is positioned beside a paragraph
where the avoidance logic fails to account for the height of a line.
(See Chromium bug #861540.)
Fig 1a, Legacy layout engine
Text overlaps the floating image to the right
Fig 1b, LayoutNG
Text is positioned beside the floating image to the right
The same problem may occur within a single line. The example below shows
a block element with a negative margin following a floating element
(#895962). The text should not overlap with the float.
Fig 2a, Legacy layout engine
Text overlaps the floating orange element
Fig 2b, LayoutNG
Text is positioned beside the floating orange element
Formatting context positioning
When an element forming a block formatting context is sized next to floats,
the legacy layout engine would try to size the block a fixed number
of times before giving up. This approach led to unpredictable and unstable
behavior and didn't match other implementations. In LayoutNG all
floats are taken into account when sizing the block.
(See Chromium bug #548033.)
Absolute and fixed positioning are now more compliant with W3C specifications
and better match the behavior in other browsers. The differences
between the two are most visible in two cases:
Multi-line inline containing blocks If an absolutely positioned
containing block spanned multiple lines, the legacy engine might
incorrectly use only a subset of the lines to compute the containing block bounds.
Vertical writing modes The legacy engine had many problems placing
out-of-flow elements in the default position in vertical writing modes.
See the next section for more details about improved writing mode support.
Right-to-left (RTL) languages and vertical writing modes
LayoutNG was designed from the ground up to support vertical writing modes
and RTL languages, including bidirectional content.
Bidirectional text
LayoutNG supports the most up-to-date bidirectional algorithm defined by
The Unicode Standard.
Not only does this update fix various rendering errors, but it also includes
missing features such as paired bracket support
(See Chromium bug #302469.)
Orthogonal flows
LayoutNG improves the accuracy of vertical flow layout, including, for example,
placement of absolutely positioned objects and sizing of orthogonal
flow boxes (especially when percent is used). Of the 1,258 tests in the
W3C test suites, 103 tests that failed in the old layout engine pass in LayoutNG.
Intrinsic sizing
Intrinsic sizes are now calculated correctly when a block contains children
in an orthogonal writing mode.
Text layout & line breaking
The legacy Chromium layout engine laid out text element-by-element and line-by-line.
This approach worked well in most cases but required a lot of e
xtra complexity to support scripts and achieve good performance. It was also
prone to measurement inconsistencies, which led to subtle differences
in the sizing of size-to-content containers and their content or unnecessary line breaks.
In LayoutNG, text is laid out at the paragraph level and then split into lines.
This allows for better performance, higher quality text rendering,
and more consistent line breaking. The most notable differences are detailed below.
Joining across element boundaries
In some scripts, certain characters can be visually joined when they're adjacent.
Check out this example from Arabic:
In LayoutNG joining now works even if the characters are in different elements.
Joins will even be preserved when different styling is applied
(See Chromium bug #6122.)
A grapheme is the smallest unit of a language's writing system. For example,
in English and other languages that use the Latin alphabet, each letter is a grapheme.
The images below show the rendering of the following HTML in the legacy
layout engine and LayoutNG, respectively:
Fig 3a, Legacy layout engine
Note how the form of the second letter changes
Fig 3b, LayoutNG
The two versions are now identical
Chinese, Japanese, and Korean (CJK) ligatures
Although Chromium already supports ligatures and enables them by default,
there are some limitations: ligatures involving multiple CJK codepoints
are not supported in the legacy layout engine due to a rendering optimization.
LayoutNG removes these restrictions and supports ligatures regardless of script.
The example below shows the rendering of three discretionary ligatures
using the Adobe SourceHanSansJP font:
Fig 4a, Legacy layout engine
MHz correctly forms a ligature
but マンション and 10点 do not
Fig 4b, LayoutNG
All three groups form ligatures as expected
Size-to-content elements
For elements that size-to-content (such as inline blocks) the current layout
engine computes the size of the block first and then performs
layout on the content. In some cases, such as when a font kerns aggressively,
this may result in a mismatch between the size of the content
and the block. In LayoutNG this failure mode has been eliminated as the block
is sized based on the actual content.
The example below shows a yellow block sized to content. It uses the Lato font
which uses kerning to adjust the spacing between T and -.
The bounds of the yellow box should match the bounds of the text.
Line wrapping
Similar to the problem described above, if the content of a size-to-content
block is larger (wider) than the block, content can sometimes
wrap unnecessarily. This is quite rare but sometimes happens for mixed directionality content.
Fig 6b, LayoutNG
Note how the left and right edges of the box match the bounds of the text
For more detailed information about the specific compatibility issues and bugs
fixed by LayoutNG, please see the issues linked above
or search the Chromium bug database for bugs marked
Fixed-In-LayoutNG.
If you suspect that LayoutNG may have caused a website to break, please
file a bug report,
and we'll investigate.
Address Bar Install for Progressive Web Apps on the Desktop
On desktop, there's typically no indication to a user that a Progressive Web
App is installable, and if it is, the install flow is hidden within the three
dot menu.
In Chrome 76 (beta mid-June 2019), we're making it easier for users to install
Progressive Web Apps on the desktop by adding an install button to the address
bar (omnibox). If a site meets the
Progressive Web App installability criteria,
Chrome will automatically show an install icon in the address bar. Clicking the
button prompts the user to install the PWA.
Like other install events, you can listen for the appinstalled
event to detect if the user installed your PWA.
Adding your own install prompt
If your PWA has use cases where it’s helpful for a user to install your app,
for example if you have users who use your app more than once a week, you
should be promoting the installation of your PWA within the web UI of your app.
To add your own custom install button, listen for the
beforeinstallprompt event. When it’s fired,
save a reference to the event, and update your user interface to let the user
know they can install your Progressive Web App.
Patterns for promoting the installation of your PWA
There are three key ways you can promote the installation of your PWA:
Automatic browser promotion, like the address bar install button.
Application UI promotion, where UI elements appear in the application
interface, such as banners, buttons in the header or navigation menu, etc.
Inline promotional patterns interweave promotions within the site content.
Check out Patterns for Promoting PWA Installation (mobile)
for more details. It’s focus is mobile, but many of the patterns are applicable
for desktop, or can be easily modified to work for mobile experiences.
When a Progressive Web App is installed on Android, Chrome automatically
requests and installs a WebAPK of your app. Being installed via an
APK makes it possible for your app to show up in the app launcher, in
Android's app settings and to register a set of intent filters.
Chrome 76 and later
Chrome checks for updates either every 1 day or every 30 days. Checking for
updates every day happens the large majority of the time. It switches to
the 30 day interval in unlikely cases where the update server cannot provide
an update.
Hypothetical update check for Chrome 76 and later
January 1: Install WebAPK
January 1: Launch WebAPK → No update check (0 days have passed)
January 2: Launch WebAPK → Check whether update is needed (1 day has passed)
January 4: Launch Chrome → No update check (Launching Chrome has no effect)
January 4: Launch WebAPK → Check whether update is needed (1+ days have passed)
January 6: Clear Chrome's data in Android settings
January 9: Launch WebAPK → No update check (From Chrome's perspective this
is the first WebAPK launch)
January 10: Launch WebAPK → Check whether update is needed (1 day has passed)
Chrome 75 and earlier
Chrome checks for updates either every 3 days or every 30 days. Checking for
updates every 3 days happens the large majority of the time. It switches to
the 30 day interval in unlikely cases where the update server cannot provide
an update.
Hypothetical update check for Chrome 75 and earlier
January 1: Install WebAPK
January 1: Launch WebAPK → No update check (0 days have passed)
January 2: Launch WebAPK → No update check (1 day has passed)
January 4: Launch Chrome → No update check (Launching Chrome has no effect)
January 4: Launch WebAPK → Check whether update is needed (3+ days have passed)
January 6: Clear Chrome's data in Android settings
January 9: Launch WebAPK → No update check (From Chrome's perspective this
is the first WebAPK launch)
January 12: Launch WebAPK → Check whether update is needed (3+ days have passed)
Further reading
For complete details, including additional triggers that cause Chrome to check
the manifest, and potentially request and install a new WebAPK, refer to the
Updating the WebAPK section of the WebAPK
docs.
The lazyload feature policy was intended to allow developers to selectively
control the lazyload attribute on the <iframe> and <img> tags to provide more
control over loading delay for embedded contents and images on a per origin
basis.
The policy is removed in favor of a newer feature policy for loading, namely
loading-frame-default-eager which is more aligned with how the loading
attribute will be used. The removal applies to both the Feature-Policy header
and the <iframe>allow attribute.
Remove outputs from MediaStreamAudioDestinationNode
According to the specification, the MediaStreamAudioDestinationNode in the Web
Audio API should have no outputs. Chrome's implementation has a single output
which has been removed.
Chromium has been showing deprecation warnings since 2015 whenever the API is
used in a non-secure browsing context. Chrome now restricts the API to secure
browsing contexts. This change brings Chromium’s implementations in line with
the privacy and security recommendations in the specification, and is aligned
with the overarching effort to deprecate powerful features on insecure origins.
Chromium has been showing deprecation warnings since 2015 whenever the API is
used in a non-secure browsing context. Chrome now restricts the API to secure
browsing contexts. This change brings Chromium’s implementations in line with
the privacy and security recommendations in the specification, and is aligned
with the overarching effort to deprecate powerful features on insecure origins.
Tests are critical because they find bugs and regressions, enforce better
designs and make code easier to maintain. Code coverage helps you ensure
your tests are thorough.
Chromium CLs can show a line-by-line breakdown of test coverage. You can
use the code coverage trybot to ensure you only submit well-tested code.
To see code coverage for a Chromium CL, trigger the code coverage trybot
linux-coverage-rel:
Once the build finishes and code coverage data is processed successfully,
look at the right column of the side by side diff view to see coverage
information:
The code coverage tool currently supports C/C++ code for Chrome on Linux;
support for more platforms and more languages is in progress.
The code coverage trybot has been rolled out to a 10% experiment, and once
we’re more comfortable in its stability, we plan to enable it by default and
expand it to more platforms.
Learn More
Want to learn more? Check out the coverage in Gerrit demo CL
and play around with code coverage in Gerrit, or see the full
codebase coverage dashboard, broken down by directories and components.
In Chrome 66, we shipped the text portion
of the Asynchronous Clipboard API.
Now in Chrome 76, adding support for images to the Asynchronous
Clipboard API, making it easy to programmatically copy and paste
image/png images.
Before we dive in, let’s take a brief look at how the Asynchronous Clipboard
API works. If you remember the details, skip ahead to the
image section.
Recap of the Asynchronous Clipboard API
Copy: Writing text to the clipboard
Text can be copied to the clipboard by calling navigator.clipboard.writeText().
Since this API is asynchronous, the writeText() function returns a Promise
that will be resolved or rejected depending on whether the passed text is
copied successfully:
async function copyPageURL() {
try {
await navigator.clipboard.writeText(location.href);
console.log('Page URL copied to clipboard');
} catch (err) {
console.error('Failed to copy: ', err);
}
}
Paste: Reading text from the clipboard
Much like copy, text can be read from the clipboard by calling
navigator.clipboard.readText() and waiting for the returned Promise to
resolve with the text:
async function getClipboardText() {
try {
const text = await navigator.clipboard.readText();
console.log('Clipboard contents: ', text);
} catch (err) {
console.error('Failed to read clipboard contents: ', err);
}
}
Handling paste events
Paste events can be handled by listening for the (surprise) paste event.
It works nicely with the new asynchronous methods for reading clipboard text:
The navigator.clipboard API is only supported for pages served over HTTPS,
and to help prevent abuse, clipboard access is only allowed when a page is
the active tab. Pages in active tabs can write to the clipboard without
requesting permission, but reading from the clipboard always requires
permission.
When the Asynchronous Clipboard API was introduced,
two new permissions for copy and paste were added to the
Permissions API:
The clipboard-write permission is granted automatically to pages when they
are the active tab.
The clipboard-read permission must be requested, which you can do by
trying to read data from the clipboard.
const queryOpts = { name: 'clipboard-read' };
const permissionStatus = await navigator.permissions.query(queryOpts);
// Will be 'granted', 'denied' or 'prompt':
console.log(permissionStatus.state);
// Listen for changes to the permission state
permissionStatus.onchange = () => {
console.log(permissionStatus.state);
};
🆕 The new image-focused portion of the Asynchronous Clipboard API
Copy: Writing an image to the clipboard
The new navigator.clipboard.write() method can be used for copying images
to the clipboard. Like writeText(), it is asynchronous, and
Promise-based. Actually, writeText() is just a convenience method for the
generic write() method.
In order to write an image to the clipboard, you need the image as a
Blob. One way to
achieve this is by fetching (or XMLHttpRequesting) the image from a
server and getting the response body as a Blob (or for XHR,
by setting the responseType to 'blob').
Another method to Blobify an image is to write the image to a canvas, then
call the canvas’s toBlob() method.
Next, pass an array of ClipboardItems as a parameter to the write() method.
Currently you can only pass one image at a time, but we plan to add support for
multiple images in the future.
The ClipboardItem takes an object with the MIME type of the image as the key,
and the actual blob as the value. The sample code below shows a future-proof
way to do this by leveraging the Object.defineProperty()
method. Using this approach will ensure your code will be ready for future
image types as well as other MIME types that the Asynchronous Clipboard API
may support.
The navigator.clipboard.read() method reads data from the clipboard. It is
also asynchronous, and Promise-based.
To read an image from the clipboard, we need to obtain a list of
ClipboardItems, then iterate over them. Since everything is asynchronous,
use the for ... of iterator, since it handles async/await code
nicely.
Each ClipboardItem can hold its contents in different types, so you'll
need to iterate over the list of types, again using a for ... of loop.
For each type, call the getType() method with the current type as an argument
to obtain the corresponding image Blob. As before, this code is is not tied
to images, and will work with other future file types.
async function getClipboardContents() {
try {
const clipboardItems = await navigator.clipboard.read();
for (const clipboardItem of clipboardItems) {
try {
for (const type of clipboardItem.types) {
const blob = await clipboardItem.getType(type);
console.log(URL.createObjectURL(blob));
}
} catch (e) {
console.error(e, e.message);
}
}
} catch (e) {
console.error(e, e.message);
}
}
Custom paste handler
If you want to dynamically handle paste events, you can listen for the paste
event, prevent the default behavior, then use the code above
to read the contents from the clipboard, and handle it in whatever way your
app needs.
The copy event includes a clipboardData
property with the items already in the right format, eliminating the need to
manually create a blob. Like before, don't forget to prevent the default
behavior.
Opening up the Asynchronous Clipboard API for images comes with certain
risks that need to be carefully evaluated.
One new challenge are so-called image compression bombs,
that is, image files that appear to be innocent, but—once decompressed—turn out to be huge.
Even more serious than large images are specifically crafted malicious images
that are designed to exploit known vulnerabilities in the native operating system.
This is why we can’t just copy the image directly to the native clipboard,
and why in Chrome we require that the image be transcoded.
The specification
therefore also explicitly mentions transcoding as a mitigation method:
“To prevent malicious image data from being placed on the clipboard, the image data may be
transcoded to produce a safe version of the image.”
There is ongoing discussion happening in the
W3C Technical Architecture Group review
on whether, and how the transcoding details should be specified.
Next Steps
We are actively working on expanding the Asynchronous Clipboard API to add
support a larger number of data types. But, due to the potential risks, we
will tread carefully. You can star the bug to be notified about
changes.
For now, image support has landed and can be used as of Chrome 76.
The Asynchronous Clipboard API was implemented by
Darwin Huang
and Gary Kačmarčík.
Darwin also provided the demo.
My introduction of this article is inspired by
Jason Miller’s
original text.
Thanks to Kyarik and again Gary Kačmarčík for reviewing this article.
Web Components update: more time to upgrade to v1 APIs
The Web Components v1 APIs are a web platform standard that has shipped in Chrome, Safari, Firefox,
and (soon) Edge. The v1 APIs are used by literally millions of sites, reaching billions of users
daily. Developers using the draft v0 APIs provided valuable feedback that influenced the
specifications. But the v0 APIs were only supported by Chrome. In order to ensure interoperability,
late last year, we
announced
that these draft APIs were deprecated and were scheduled for removal as of Chrome 73.
Because enough developers requested more time to migrate, the APIs have not yet been removed
from Chrome. The v0 draft APIs are now targeted for removal in Chrome 80, around February 2020.
Here's what you need to know if you believe you might be using the v0 APIs:
Test your site with the v0 APIs disabled. If your site works as expected, congratulations!
You're done. See Back to the future: disabling the v0 APIs
for instructions.
You'll need to exit Chrome before starting it from the command line. If you have Chrome Canary
installed, you can run the test in Canary while keeping this page loaded in Chrome.
To test your site with v0 APIs disabled:
If you're on Mac OS, browse to chrome://version to find the executable path for Chrome.
You'll need the path in step 3.
To double check that you have started the browser correctly, open a new tab, open the DevTools
console, and run the following command:
console.log(
"Native HTML Imports?", 'import' in document.createElement('link'),
"Native Custom Elements v0?", 'registerElement' in document,
"Native Shadow DOM v0?", 'createShadowRoot' in document.createElement('div'));
If everything is working as expected, you should see:
Native HTML Imports? false Native Custom Elements v0? false Native Shadow DOM v0? false
If the browser reports true for any or all of these features, something's wrong. Make sure
you've fully quit Chrome before restarting with the flags.
Finally, load your app and run through the features. If everything works as expected, you're
done.
Use the v0 polyfills {#use-the-v0-polyfills}
The Web Components v0 polyfills provide support for the v0 APIs on browsers that don't
provide native support. If your site isn't working on Chrome with the v0 APIs disabled,
you probably aren't loading the polyfills. There are several possibilities:
You're not loading the polyfills at all. In this case, your site should fail on other browsers,
like Firefox and Safari.
You're loading the polyfills conditionally based on browser sniffing. In this case, your site
should work on other browsers. Skip ahead to [Load the polyfills]{#load-the-v0-polyfills).
In the past, the Polymer Project team and others have recommended loading the polyfills conditionally
based on feature detection. This approach should work fine with the v0 APIs disabled.
Install the v0 polyfills {#install-the-v0-polyfills}
The Web Components v0 polyfills were never published to the npm registry. You can install
the polyfills using Bower, if your project is already using Bower. Or you can install from a zip file.
If you install from a zip file, you'll have to manually update the polyfills if another
version comes out. You'll probably want to check the polyfills in with your code.
Load the v0 polyfills {#load-the-v0-polyfills}
The Web Components v0 polyfills are provided as two separate bundles:
webcomponents-min.js
Includes all of the polyfills. This bundle includes the shadow DOM polyfill, which is much
larger than the other polyfills, and has greater performance impact. Only use this bundle if
you need shadow DOM support.
webcomponents-lite-min.js
Includes all polyfills except for shadow DOM.
Note: Polymer 1.x users should choose this bundle, since Shadow DOM emulation was included directly
in the Polymer library. Polymer 2.x users need a different version of the polyfills. See
the Polymer
Project blog post for details.
There are also individual polyfills available as part of the Web Components polyfill package. Using
individual polyfills separately is an advanced topic, not covered here.
If you installed the polyfills directly from GitHub, you'll need to supply the path where you
installed the polyfills.
If you conditionally load the polyfills based on feature detection, your site should continue to
work when v0 support is removed.
If you conditionally load the polyfills using browser sniffing (that is, loading the polyfills on
non-Chrome browsers), your site will fail when v0 support is removed from Chrome.
Help! I don't know what APIs I'm using! {#help-i-don't-know-what-apis-i'm-using}
If you don't know whether you're using any of the v0 APIs—or which APIs you're
using—you can check the console output in Chrome.
If you previously started Chrome with the flags to disable the v0 APIs, close Chrome and restart
it normally.
Open a new Chrome tab and load your site.
Press Control+Shift+J (Windows, Linux, Chrome OS) or Command+Option+J (Mac) to open the DevTools
Console.
Check the console output for deprecation messages. If there's a lot of console output, enter
"Deprecation" in the Filter box.
You should see deprecation messages for each v0 API you're using. The output above shows messages
for HTML Imports, custom elements v0, and shadow DOM v0.
Next steps: moving off of v0 {#next-steps-moving-off-of-v0}
Making sure the v0 polyfills are getting loaded should ensure your site keeps working when the v0
APIs are removed. We recommend moving to the Web Components v1 APIs, which are broadly supported.
If you're using a Web Components library, like the Polymer library, X-Tag, or SkateJS, the first
step is to check whether newer versions of the library are available that support the v1 APIs.
If you have your own library, or wrote custom elements without a library, you'll need to update to
the new APIs. These resources might help:
Right-click a node in the DOM Tree to copy that DOM node's CSS to your clipboard.
Visualize layout shifts
Supposing you're reading a news article on your favorite website. As you're reading the page, you
keep losing your place because the content is jumping around. This problem is called layout
shifting. It usually happens when images and ads finish loading. The page hasn't reserved any
space for the images and ads, so the browser has to shift all the other content down to
make room for them. The solution is to use placeholders.
Keep request counts and file sizes low. Reports
the total number of network requests and file sizes for various categories, such as
documents, scripts, stylesheets, images, and so on.
Maximum Potential First Input Delay. Measures the maximum potential time between a user's
first page interaction and the browser's response to that interaction. Note that this metric
replaces the Estimated Input Latency metric. Maximum Potential First Input Delay does not
factor into your Performance category score.
The Node and CLI versions of Lighthouse 5.1 have 3 new major features worth checking out:
Performance Budgets. Prevent your site from regressing
over time by specifying request counts and file sizes that pages should not exceed.
Plugins. Extend
Lighthouse with your own custom audits.
Stack Packs. Add audits tailored
to specific technology stacks. The WordPress Stack Pack shipped first. React and AMP Stack
Packs are in development.
OS theme syncing
If you're using the dark theme of your OS, DevTools now switches to its own dark theme
automatically.
Keyboard shortcut for opening the Breakpoint Editor
Press Control+Alt+B or
Command+Option+B (Mac) when focused in the Sources panel's
Editor to open the Breakpoint Editor. Use the Breakpoint Editor to create
Logpoints and Conditional Breakpoints.
Prefetch cache in Network panel
The Size column of the Network panel now says (prefetch cache) when a resource was loaded from
the prefetch cache. Prefetch is a new-ish web platform feature for speeding up subsequent
page loads. Can I use... reports that it's supported in 83.33% of global browsers as of July 2019.
Notifications and push messages in the Application panel
The Background Services section of the Application panel now supports Push Messages and
Notifications. Push Messages occur when a server sends information to a service worker.
Notifications occur when a service worker or page script shows information to the user.
If you're on Mac or Windows, consider using Chrome Canary as your default
development browser. Canary gives you access to the latest DevTools features.
Note: Canary is released as soon as its built, without testing. This means that Canary
breaks about once-a-month. It's usually fixed within a day. You can go back to using Chrome
Stable while Canary is broken.