Quantcast
Channel: Updates
Viewing all 599 articles
Browse latest View live

New In Chrome 54

$
0
0

New In Chrome 54

Note: I'm trying something new with the latest video release of New In Chrome, in addition to posting it on YouTube, I've posted a fully annoted version of the script. It includes all of the relevant links I mentioned, and a few other helpful links. Leave your thoughts in the comments and let me know if this is useful to you!

Watch on YouTube

I’m Pete LePage, let’s dive in and see what’s new for developers in Chrome 54!

Custom elements v1

Complex user interfaces often require a large amount of HTML. Most languages allow developers to create their own components built on top of language primitives to mitigate this kind of verbosity. But until now, creating reusable components on the web has been difficult.

Custom elements allow you to create your own custom HTML tags, and define the new element’s API and behavior in JavaScript. The result, a browser-native way to build reusable, interoperable components.

Chrome 54 provides support for the latest custom elements V1 spec, and will continue to support the V0 API until enough of you have moved to V1.

Check out our primer on custom elements to how you can use it to create reusable web components for your site or application.

BroadcastChannel API

It is not uncommon for desktop users to have multiple windows or tabs open simultaneously, and some sites even encourage this behavior, such as web editors that open documents in their own tabs.

Communicating between those tabs can be difficult. The BroadcastChannel API is a new one-to-many messaging API between windows, tabs, iframes, web workers, and service workers. It allows scripts to establish named channels to send messages between browsing contexts of the same origin.

Other BroadcastChannel resources

requestFullScreen

Media is an increasingly important part of the browsing experience.

In addition to a user gesture, you can now use Element.requestFullScreen() to trigger full screen mode after a screen orientation change - and allows you to create richer media experiences that include rotate to full screen.

Foreign fetch

Imagine if a commonly used origin like an API provider, web font service or other service had the ability to deploy its own service worker.

Instead of always going to the network, the provider could implement their own custom networking logic, and take advantage of a single, authoritative cache instance for storing its responses.

Now, thanks to foreign fetch, which is available in Chrome 54 as an origin trial, it’s a reality. Check out Jeffrey’s post linked in the comments below!

Closing

These are just a few of the changes in Chrome 54 for developers.

Check the description for more details and links the documentation and specifications.

Oh, and don't forget to check out the Chrome Dev Summit, we'll be streaming it on YouTube on November 10th and 11th.

If you want to stay up to date with Chrome and know what’s coming, click that Subscribe button up there.

I’m Pete LePage, and as soon as Chrome 55 is released, I’ll be right here to tell you -- what’s new in Chrome!

Subscribe to Chrome Developers on YouTube

Subscribe to our YouTube channel or our RSS feed


auxclick is Coming to Chrome 55

$
0
0

auxclick is Coming to Chrome 55

When is a click not a click? For a web developer working on a complex user interface, that's not an abstract philosophical question. If you're implementing custom mouse input behavior, it's crucial to keep user intent in mind. If a user clicks on a link with their mouse's middle button, for instance, then it's reasonable to assume that they wanted to open a new tab with that link's contents. If a user middle-clicks on a random UI element, then it you may want to assume that it was inadvertent, and ignore that input, while a primary button click would be expected to trigger a response from the UI.

It's possible, if a bit cumbersome, to model these nuanced interactions via a single click event listener. You would have to explicitly check the button property of the MouseEvent, to see whether it was set to 0, representing the primary button, versus anything else, with 1 usually representing the middle button, and so on. But not many developers go as far as explicitly checking the button property, leading to code that handles all clicks identically, regardless of which button was pressed.

Starting with Chrome 55, a new type of MouseEvent, called auxclick, is fired in response to any clicks made with a non-primary button. Accompanying this new event is a corresponding change in behavior of the click event: it will only fire when the primary mouse button is pressed. We hope that these changes will make it easier for web developers to write event handlers that respond to only the type of clicks that they care about, without having to specifically check the MouseEvent.button property.

Reduce false positives

As mentioned, one motivation for creating auxclick was to avoid deployment of custom click handlers that mistakenly override the "middle-click-opens-a-tab" behavior. For example, imagine that you've written a click event handler that uses the History API to rewrite the location bar, and implement custom single-page navigations. It might look something like:

document.querySelector('#my-link').addEventListener('click', event => {
  event.preventDefault();
  // ...call history.pushState(), use client-side rendering, etc....
});

Your custom logic might work as intended when triggered by a mouse's primary button, but if that code runs when a middle button is clicked, it's effectively a false positive. Prior to the new behavior, you'd end up preventing the default action of opening a new tab, which runs counter to your user's expectations. While you could explicitly check for event.button === 0 at the start of your handler, and only execute the code if that's the case, it's easy to forget, or never realize it's necessary to do that.

Only run the code you need

The flip side of fewer false positives is that auxclick callbacks will only run when there's actually a non-primary mouse button clicked. If you have code that needs to, for example, calculate an appropriate destination URL before opening a new tab, you can listen for auxclick and include that logic in your callback. It won't incur the overhead of being run when the primary mouse button is clicked.

Browser support and compatibility

This new behavior is currently only implemented in Chrome 55. As mentioned in the initial proposal, feedback (both positive and negative) from the web developer community is appreciated. Filing a GitHub issue is the best way to share that feedback with the folks who are working on the standardization process.

In the meantime, developers don't have to wait for auxclick to be widely available to follow some best practices for handling mouse events. If you take the time to check the value of the MouseEvent.button property at the start of your click event handler, you can ensure that you take appropriate action. The following pattern will handle primary and auxiliary clicks differently, whether or not there's native support for auxclick:

function handlePrimaryClick(event) {
  // ...code to handle the primary button click...
}

function handleAuxClick(event) {
  // ...code to handle the auxiliary button click….
}

document.querySelector('#my-link').addEventListener('click', event => {
  if (event.button === 0) {
    return handlePrimaryClick(event);
  }


  // This provides fallback behavior in browsers without auxclick.
  return handleAuxClick(event);
});

// Explicitly listen for auxclick in browsers that support it.
document.querySelector('#my-link').addEventListener('auxclick', handleAuxClick);

API Deprecations and Removals in Chrome 55

$
0
0

API Deprecations and Removals in Chrome 55

In nearly every version of Chrome, we see a significant number of updates and improvements to the product, its performance, and also capabilities of the Web Platform. This article describes the deprecations and removals in Chrome 55, which is in beta as of October 21. This list is subject to change at any time.

Resources with non-script MIME types can no longer be executed

Previous versions of Chrome allowed content to with several non-script MIME types to be executed as script. In addition to the obvious security vulnerability, this problem also reduces the value of content security policy settings like script-src 'self'.

For example, a site might lock down same-origin JavaScript, yet still allow users to upload images that are served from that origin. Malicious users might upload JavaScript embedded within a specially-crafted image file, and that JavaScript had the potential to be served from that origin and executed. As of Chrome 55 will no longer execute content loaded with the following MIME types:

  • audio/*
  • image/*
  • video/*
  • text/csv

Intent to Remove | Chromestatus Tracker | Chromium Bug

Remove SVGSVGElement.viewPort

The implementation of SVGSVGElement.viewPort has not worked in Chrome since 2012. The attribute is not present at all in other browsers and it has been removed from the specification. For these reasons the property was deprecated in Chrome 54 and has now been removed.

Intent to Remove | Chromestatus Tracker | Chromium Bug

Deprecation policy

To keep the platform healthy, we sometimes remove APIs from the Web Platform which have run their course. There can be many reasons why we would remove an API, such as: they are superseded by newer APIs, they are updated to reflect changes to specifications to bring alignment and consistency with other browsers, or they are early experiments that never came to fruition in other browsers and thus can increase the burden of support for web developers.

Some of these changes will have an effect on a very small number of sites. To mitigate issues ahead of time, we try to give developers advanced notice so that if needed, they can make the required changes to keep their sites running.

Chrome currently has a process for deprecations and removals of API's and the TL;DR is:

  • Announce on the blink-dev mailing list.
  • Set warnings and give time scales in the Chrome DevTools Console when usage is detected on a page.
  • Wait, monitor, and then remove feature as usage drops.

You can find a list of all deprecated features in chromestatus.com using the deprecated filter and removed features by applying the removed filter. We will also try to summarize some of the changes, reasoning, and migration paths in these posts. We will also try to summarize some of the changes, reasoning, and migration paths in these posts.

Capture a MediaStream From a Canvas, Video or Audio Element

$
0
0

Capture a MediaStream From a Canvas, Video or Audio Element

The captureStream() method makes it possible to capture a MediaStream from a <canvas>, <audio> or <video> element.

This enables a video or audio stream from any of these elements to be recorded, live-streamed via WebRTC, or combined with effects or other MediaStreams in a <canvas>. In other words, captureStream() enables MediaStream to pass media back and forth between canvas, audio or video elements — or to an RTCPeerConnection or MediaRecorder.

In the following demo (available from the WebRTC samples) a MediaStream captured from a canvas element on the left is streamed via a WebRTC peer connection to the video element on the right:

(There are links to more canvas and video examples below.)

The captureStream() code is simple.

For <canvas>:

var canvas = document.querySelector('canvas');
var video = document.querySelector('video');

// Optional frames per second argument.
var stream = canvas.captureStream(25);
// Set the source of the <video> element to be the stream from the <canvas>.
video.srcObject = stream;

For <video>:

var leftVideo = document.getElementById('leftVideo');
var rightVideo = document.getElementById('rightVideo');

leftVideo.onplay = function() {
  // Set the source of one <video> element to be a stream from another.
  var stream = leftVideo.captureStream();
  rightVideo.srcObject = stream;
};

Note: captureStream() can only be called after the video element is able to play video; that's the reason it's in the onplay handler here.

But why?

The captureStream() method makes it possible to record or live stream from canvas and media elements:

  • Record and stream game play from a <canvas>
  • Capture video from a camera, then add additional content or effects
  • Create picture-in-picture effects from multiple videos via a <canvas>
  • Combine video and images (from files or a camera or both) in a <canvas>
  • Live-stream video played from a file
  • Use a recorded audio or video message for a video or voice mail

Essentially, captureStream() enables JavaScript to construct and "inject stuff" into a MediaStream.

The small print

  • Attempting to use captureStream() with a media element that implements content protection via Encrypted Media Extensions will throw an exception.

  • When capturing from a <canvas>, the maximum frame rate is set when captureStream() is called. For example, canvas.captureStream(10) means that the canvas outputs between 0 and 10 fps. Nothing gets captured when nothing gets painted on the <canvas>, and 10 fps is captured even if the <canvas> gets painted at 30 fps. There is a bug with more discussion filed on the captureStream spec.

  • The dimensions of a captureStream() video match the <canvas> it was called on.

Demos

Canvas

Video

Support

  • Canvas captureStream(): Firefox 43 or above; Chrome 50 and above with chrome://flags/#enable-experimental-web-platform-features enabled, or Chrome 52 and above by default.
  • Video and audio captureStream(): Firefox 47; Chrome 52 and above with chrome://flags/#enable-experimental-web-platform-features enabled, or Chrome 53 and above by default.

Find out more

Introducing the Web Share API

$
0
0

Introducing the Web Share API

Good news, everybody! Matt Giuca on the Chrome team has been working on a simple API called Web Share that allows websites to invoke the native sharing capabilities of the host platform.

There have been a number of ways to invoke native sharing capabilities on the platform, but they all have significant drawbacks. There was Web Intents (dead), there is protocol handling via registerProtocolHandler but this has zero support on mobile, there is direct sharing to a well-known service URL such as Twitter's, and there is also the Android intent: URL syntax (which was, unfortunately, Android-only, and required apps to opt-in).

The Web Share API is important because it gives the user control of how and where the data is shared.

In Chrome 55 (Beta as of October 2016), we've enabled an Origin Trial that lets you integrate the Web Share API into your site. The origin trial means this API is not generally available to all sites; instead you need to register to get access during the trial phase. Over this time, the API will likely change and break in unexpected ways, which is why we are looking for as much feedback as possible.

The Web Share API is a promise -based, single method API that takes an object with properties named title, text and url.

navigator.share({
    title: document.title,
    text: "Hello World",
    url: window.location.href
}).then(() => console.log('Successful share'))
.catch(() => console.log('Error sharing:', error));

Once invoked it will bring up the native picker (see video) and allow you to share the data with the app chosen by the user.

This API has a few constraints:

  • You need to host your site in a secure context (typically https).
  • You only need to supply one of text or url, not both.
  • You can only invoke the API as a result of a user gesture. (For example, you can't call navigator.share() in an onload handler.)
  • The property values that you pass into the API must all be strings.

How to get this working

The process is pretty simple:

  1. Get the Chrome Beta Channel on Android (as of October 2016).
  2. Sign up for the Origin Trial.
  3. Integrate the Origin Trial tokens into your site (as long as it is on https).
  4. Call navigator.share() in response to a user gesture.
  5. Share!

Be progressive

The API is not available on all platforms, so you will have to gracefully handle the scenarios where you don't have the ability to call. I try to progressively enhance as much as possible, and the process that I follow on my blog is to:

  1. Use your preferred sharing service via a simple <a> (intent: URL with Twitter fallback is an example I use).
  2. Check the availability of the API (navigator.share !== undefined).
  3. Wait for the content to be available and then find the sharing element.
  4. Intercept and prevent the default behavior of the click.
  5. Call navigator.share().

Share the correct URL

You should also think about the URL that you want to share. In many cases the user will be on a mobile device and your site might have an "m." url, or a url that is custom to user's context. You can use the fact that there might be a canonical URL on your page to provide a better experience to the user. For example, you might do:

var url = document.location;
var canonicalElement = document.querySelector('link[rel=canonical]');
if(canonicalElement !== undefined) {
    url = canonicalElement.href;
}

Where can I get more information

You can get all the relevant information at ChromeStatus, but to save you a click, here are the important links:

Future work will also level the playing field for web apps, by allowing them to register to be a "share receiver", enabling web-to-app sharing, app-to-web sharing and web-to-web sharing. Personally, I am incredibly excited about this.

Once Upon an Event Listener

$
0
0

Once Upon an Event Listener

Pop quiz: what's the purpose of the third parameter passed to addEventListener()?

Don't be embarrassed if you thought that addEventListener() only took two parameters, or perhaps just always hardcode a value of false, with a vague understanding that it has something to do with… bubbles?

Note: The third parameter has historically been a boolean value, which defaulted to false, and which controlled whether the event listener was in capturing or bubbling mode.

A more configurable addEventListener()

The addEventListener() method has come a long way since the early days of the web, and its new functionality is configured via a supercharged version of that third parameter. Recent changes to the method's definition allow developers to provide additional options via a configuration object, while remaining backward compatible when there's a boolean parameter or when an option is not specified.

We're happy to announce that Chrome 55 adds support for the once option in that configuration object, alongside the passive (implemented in Chrome 51) and capture options (implemented in Chrome 49). For example:

element.addEventListener('click', myClickHandler, {
  once: true,
  passive: true,
  capture: true
});

You can mix and match those options as appropriate to your own use case.

The benefits of cleaning up after yourself

So that's the syntax for using the new once option, but what does that get you? In short, it gives you an event listener that's tailored to "one and done" use cases.

By default, event listeners persist after the first time they're called, which is what you want for some types of events—buttons that can be clicked multiple times, for example. For other uses, though, having an event listener stick around isn't necessary, and can lead to undesirable behavior if you have a callback that must only execute once. Hygienic developers have always had the option of using removeEventListener() to explicitly clean things up, following patterns like:

element.addEventListener('click', function(event) {
  // ...one-time handling of the click event...
  event.target.removeEventListener(event.type, arguments.callee);
});

The equivalent code, making use of the new once parameter, is cleaner, and doesn't force you to keep track of the name of the event (event.type, in the previous example) or a reference to the callback function (arguments.callee):

element.addEventListener('click', function(event) {
  // ...one-time handling of the click event...
}, {once: true});

Cleaning up your event handlers can also offer memory efficiencies by destroying the scope that's associated with the callback function, allowing any variables captured in that scope to be garbage collected. Here's one such example where it would make a difference:

function setUpListeners() {
  var data = ['one', 'two', '...etc.'];

  window.addEventListener('load', function() {
    doSomethingWithSomeData(data);
    // data is now part of the callback's scope.
  });
}

By default, the load event listener callback will remain in scope when it finishes running, even though it's never used again. Because the data variable is used inside the callback, it will also remain in scope, and never get garbage collected. If the callback were removed via the once parameter, though, both the function itself and anything that's kept alive via its scope will be candidates for garbage collection.

Browser support

Chrome 55+, Firefox 50+, and Safari's technology preview 7+ have native support for the once option.

Many JavaScript UI libraries provide convenience methods for creating event listeners, and some have shortcuts for defining one-time events—the most notable of which is jQuery's one() method.

Pointing the Way Forward

$
0
0

Pointing the Way Forward

Pointing at things on the web used to be simple. You had a mouse, you moved it around, sometimes you pushed buttons, and that was it. Everything that wasn’t a mouse was emulated as one, and developers knew exactly what to count on.

Simple doesn’t necessarily mean good, though. Over time, it became increasingly important that not everything was (or pretended to be) a mouse: you could have pressure-sensitive and tilt-aware pens, for amazing creative freedom; you could use your fingers, so all you needed was the device and your hand; and hey, why not use more than one finger while you’re at it?

We’ve had touch events for a while to help us with that, but they’re an entirely separate API specifically for touch, forcing you to code two separate event models if you want to support both mouse and touch. Chrome 55 ships with a newer standard that unifies both models: pointer events.

A single event model

Pointer events unify the pointer input model for the browser, bringing touch, pens, and mice together into a single set of events.

document.addEventListener('pointermove',
  ev => console.log('The pointer moved.'));
foo.addEventListener('pointerover',
  ev => console.log('The pointer is now over foo.'));

Here’s a list of all the available events, which should look pretty familiar if you’re familiar with mouse events:

pointerover The pointer has entered the bounding box of the element. This happens immediately for devices that support hover, or before a pointerdown event for devices that do not.
pointerenter Similar to pointerover, but does not bubble and handles descendants differently. Details on the spec.
pointerdown The pointer has entered the active button state, with either a button being pressed or contact being established, depending on the semantics of the input device.
pointermove The pointer has changed position.
pointerup The pointer has left the active button state.
pointercancel Something has happened that means it’s unlikely the pointer will emit any more events. This means you should cancel any in-progress actions and go back to a neutral input state.
pointerout The pointer has left the bounding box of the element or screen. Also after a pointerup, if the device does not support hover.
pointerleave Similar to pointerout, but does not bubble and handles descendants differently. Details on the spec.
gotpointercapture Element has received pointer capture.
lostpointercapture Pointer which was being captured has been released.

Note: Pointer events are confusingly unrelated to the pointer-events CSS property. Even worse, the two can be used together! The behaviour of pointer-events (the CSS property) with pointer events (the event model) is no different than with mouse events or touch events, though, so if you’ve used that CSS property before, you know what to expect.

Different input types

You’ll still have to handle the differences between input types, such as whether the concept of hover applies, but you can do so from within the same event handlers. You can tell device types apart with the deviceType property of the PointerEvent interface. For example, if you were coding a side navigation drawer, you could have the following logic on your pointermove event:

switch(ev.deviceType) {
  case 'mouse':
    // Do nothing.
    break;
  case 'finger':
    // Allow drag gesture.
    break;
  case 'pen':
    // Also allow drag gesture.
    break;
  default:
    // Getting an empty string means the browser doesn't know
    // what device type it is. Let's assume mouse and do nothing.
    break;
}

Default actions

Touch-enabled browsers often make special allowances for certain types of input, overriding certain gestures to make the page scroll, zoom, or refresh. With touch events, this happens more or less transparently, with browser actions happening after the touch events, unless cancelled. This leads to some potentially confusing behaviour for the end user, with both browser- and developer-defined actions taking place sequentially, based off of a single input.

With pointer events, whenever a default action like scroll or zoom is triggered, you’ll get a pointercancel event, to let you know that the browser has taken control of the pointer.

document.addEventListener('pointercancel',
  ev => console.log('Go home, the browser is in charge now.'));

Built-in speed: This model allows for better performance by default, compared to touch events, where you would need to use passive event listeners to achieve the same level of responsiveness.

You can stop the browser from taking control with the touch-action CSS property. Setting it to none on an element will disable all browser-defined actions started over that element, but there are a number of other values for finer-grained control, such as pan-x, for allowing the browser to react to movement on the x axis but not the y axis. Chrome 55 supports the following values:

auto Default; the browser can perform any default action.
none The browser isn’t allowed to perform any default actions.
pan-x The browser is only allowed to perform the horizontal scroll default action.
pan-y The browser is only allowed to perform the vertical scroll default action.
pan-left The browser is only allowed to perform the horizontal scroll default action, and only to pan the page to the left.
pan-right The browser is only allowed to perform the horizontal scroll default action, and only to pan the page to the right.
pan-up The browser is only allowed to perform the vertical scroll default action, and only to pan the page up.
pan-down The browser is only allowed to perform the vertical scroll default action, and only to pan the page down.
manipulation The browser is only allowed to perform scroll and zoom actions.

Pointer capture

Ever spent a frustrating hour debugging why you’re not getting a mouseup event, until you realised that it’s because the user is letting go of the button outside your click target? No? Okay, maybe it’s just me, then.

Still, until now there wasn’t a really good way of tackling this problem. Sure, you could set up the mouseup handler on the document, and save some state on your application to keep track of things. That’s not the cleanest solution, though, particularly if you’re building a web component and trying to keep everything nice and isolated.

With pointer events comes a much better solution: you can capture the pointer, so that you’re sure to get that pointerup event (or any other of its elusive friends).

const foo = document.querySelector('#foo');
foo.addEventListener('pointerdown', ev => {
  console.log('Button down, capturing!');
  // Every pointer has an ID, which you can read from the event.
  foo.setPointerCapture(ev.pointerId);
});

foo.addEventListener('pointerup',
  ev => console.log('Button up. Every time!'));

Browser support

At the time of writing, Pointer Events are supported in Internet Explorer 11, Microsoft Edge, Chrome and Opera, and partially supported in Firefox. You can find an up-to-date list at caniuse.com.

You can use the Pointer Events polyfill for filling in the gaps. Alternatively, checking for browser support in runtime is straightforward:

if (window.PointerEvent) {
  // Yay, we can use pointer events!
} else {
  // Back to mouse and touch events, I guess.
}

Pointer events are a fantastic candidate for progressive enhancement: just modify your initialization methods to make the check above, add pointer event handlers in the if block, and move your mouse/touch event handlers to the else block.

So go ahead, give them a spin and let us know what you think!

Touch Action Options

$
0
0

Touch Action Options

The touch-action CSS property allows a developer to restrict how a user can interact with an element which is especially helpful to prevent events being dispatched when it's not necessary.

Before version 55, Chrome supported pan-x and pan-y which restrict elements to scrolling in one direction.

The video below shows an example of an element without a touch-action defined (left), as well as pan-x and pan-y (middle and right).

The CSS for the the middle and right hand screen-casts being:

.pan-x {
  touch-action: pan-x;
}

.pan-y {
  touch-action: pan-y;
}

In Chrome 55, pan-left, pan-right, pan-up and pan-down were added. These properties have a subtle but important difference in behavior.

These properties force the user to start gestures in one direction before the element will respond. This is similar to the "pull-to-refresh" gesture which only responds when the user gestures downwards on the screen.

The following video demonstrates pan-right and pan-down which require gestures to start from right to left and bottom to top respectively. Once the gesture has started, you can actually pan back and forth. It's only the initial direction that is affected.

While the video demonstrates this behavior, you might find it easier to try yourself which you can by checking out the sample.

The CSS for this demo is:

.pan-right {
  touch-action: pan-right;
}

.pan-down {
  touch-action: pan-down;
}

The last thing that's happening in the world of touch-action is the pinch-zoom property. This is a new property in Chrome 55, behind a flag, that can be used with any of the pan options (i.e. pan-x, pan-y, pan-left, pan-right, pan-down, pan-up).

If you pinch on a website it'll generally zoom in on the pages content. Defining a touch-action will prevent this behavior, but adding pinch-zoom will re-enable this behavior.

This video shows the difference between touch-action: pan-x and touch-action: pan-x pinch-zoom;

All of these properties should simplify some of the logic that would otherwise need to implemented by developers using pointer-events.


DevTools Digest, October 2016

$
0
0

DevTools Digest, October 2016

Hey hey, Kayce here, back again for another digest to update you on what's new in DevTools since last month.

New features in the Console

In Chrome 56, which is currently in Canary, the DevTools Console is powered by CodeMirror. This enables a whole bunch of new features, like:

Syntax highlighting as you type. Previously, DevTools could only highlight syntax after a code block had been evaluated.

Matching parenthesis / bracket / brace highlighting. If you've got an extra parenthesis, bracket, or brace, DevTools highlights it red.

mismatched
parenthesis

Matching parentheses, brackets, or braces are highlighted grey when your cursor is next to one of them.

matched parentheses

Smart return. When you type out a multi-line code block, DevTools now knows whether to create a new line or execute your code each time you press Enter. For example, suppose you want to evaluate the following for loop in the Console:

for (var i = 0; i < 5; i++) {
  console.log(i);
}

In the past, hitting Enter after typing out the first line would have caused DevTools to evaluate the line, causing an error. To continue the code block to a new line, you would have had to held Shift before pressing Enter. In contrast, now DevTools just automatically continues the code block on a new line after you hit Enter, as you expect it would.

Multiple cursors. Hold Command (Mac) or Control+Alt (Windows, Linux) and then click.

multiple cursors

Canary now highlights non-top contexts red

If you've worked in the Console lately, you might have been bitten by a nasty little bug that was setting the execution context selector to values other than top.

That bug should be now be fixed in Stable, but, just to be safe, the DevTools in Canary (Chrome 56) now warns you that you're not in the top context by highlighting the selector red.

non-top context highlighted
red

New user agent: UC Browser

You can now select UC Browser for iOS, Android, or Windows Phone from the Network conditions drawer tab.

UC Browser user agent

Sharing is caring

As always, we'd love to hear your feedback or ideas on anything DevTools related.

  • Ping us at ChromeDevTools on Twitter for brief questions or feedback, or to share new ideas.
  • For longer discussions, the mailing list or Stack Overflow are your best bets.
  • For anything docs related, open an issue on our docs repo.
  • You can always go straight to the team to file a bug or request a feature on Crbug.

Until next month,

Kayce

Manage Hyphens with CSS

$
0
0

Manage Hyphens with CSS

In many written languages, it's possible to break lines between syllables as well as between words. This is often done so that more characters may be placed on a line of text with the goal of having fewer lines in a text area, and thus saving space. In such languages the break is indicated visually with a hyphen ('-').

The CSS Text Module Level 3 defines a hyphens property to control when hyphens are shown to users and how they behave when shown. Starting with version 55, Chrome implements the hyphens property. Per the specification, the hyphens property has three values: none, manual, and auto. To illustrate this we need to use a soft hyphen (&shy;) as in the following example.

Google ipsum dolor sit amet, consectetur adipiscing e&shy;lit.

A soft hyphen is one that will only be shown when it occurs at the trailing margin. How this hyphen renders in Chrome 55 or later depends on the value of the CSS hypens property.

-webkit-hyphens: manual;
hyphens: manual;

Combining these gives a result like this:

Notice that the soft hyphen isn't visible. In all cases, when a word containing the soft hyphen fits on a single line, the hypen will be invisible. Now, let's look at how all three values of hyphen behave.

Note: The following examples contain working CSS. But you won't be able to see it functioning unless you use a supporting browser. This same code is also available in a downloadable example.

Using none

In the first example, the hyphens property is set to none. This prevents the soft hyphen from ever being displayed. You can confirm this by adjusting the window size so that the word 'elit' will not fit in the visible line of text.

div.none { -webkit-hyphens: none; hyphens: none; }

Google ipsum dolor sit amet, consectetur adipiscing e­lit.

Using manual

In the second example, the hyphens property is set to manual meaning the soft hyphen will only appear when the margin breaks the word 'elit'. Again, you can confirm this by adjusting the window size.

div.manual { -webkit-hyphens: manual; hyphens: manual; }

Google ipsum dolor sit amet, consectetur adipiscing e­lit.

Using auto

In the third example, the hyphens property is set to auto. In this case, no soft hyphen is needed since the user agent will determine hyphen locations automatically. If you resize the window, you'll see that the browser hyphenates this example in the same place as in the second, though no soft hyphen is present. If you continue to shrink the window, you'll see that your browser is able to break lines between any two syllables in the text.

div.auto { -webkit-hyphens: auto; hyphens: auto; }

Google ipsum dolor sit amet, consectetur adipiscing elit.

Avoiding the Not Secure Warning in Chrome

$
0
0

Avoiding the Not Secure Warning in Chrome

As announced in September, Chrome will soon mark non-secure pages containing password and credit card input fields as Not Secure in the URL bar.

This document is intended to aid Web Developers in updating their sites to avoid this warning.

Enable warnings

Warnings will be enabled by default for everyone in Chrome 56, slated for release in January 2017.

To test the upcoming user experience before then, install the latest Google Chrome Canary build. At the time of this writing, Chrome Canary is version 56. Version 56.0.2895.0 is the first version to include detection of sensitive fields. You can see an example of the browser’s warning behavior on this page if you open it in Chrome 56.0.2895.0 or later, then view the console in DevTools.

When the Not Secure state is shown, the DevTools console shows the message In Chrome M56 (Jan 2017), this page will be marked as “not secure” in the URL bar. For more information, see [https://goo.gl/zmWq3m](https://security.googleblog.com/2016/09/moving-towards-more-secure-web.html).

An example console warning

Resolve warnings

To ensure that the Not Secure warning is not displayed for your pages, you must ensure that all forms containing <input type=password> elements and any inputs detected as credit card fields are present only on secure origins. This means that the top-level page must be HTTPS and, if the input is in an iframe, that iframe must also be served over HTTPS.

Warning: It is NOT sufficient to place an HTTPS iframe inside a HTTP page; the top-level page itself must be HTTPS as well.

If your site overlays an HTTPS login frame over HTTP pages...

An example HTTPS log in over HTTP

...you will need to change the site to either use HTTPS for the entire site (ideal) or redirect the browser window to an HTTPS page containing the login form:

An example HTTPS log in over HTTPS

Long term - Use HTTPS everywhere

Eventually, Chrome will show a Not Secure warning for all pages served over HTTP, regardless of whether or not the page contains sensitive input fields. Even if you adopt one of the more targeted resolutions above, you should plan to migrate your site to use HTTPS for all pages.

Get Ready for the Chrome Dev Summit 2016

$
0
0

Get Ready for the Chrome Dev Summit 2016

Chrome Dev Summit is almost here! We'll kick off live from San Francisco at the SFJAZZ Center, at 10:00 AM PT this coming Thursday, Nov 10th. This year's summit will focus on key themes that matter to you: Progressive, to build high quality web apps; Performance, to increase user engagement; and What's Next, a look at how the Chrome team is thinking about the future of the web.

While we're putting the finishing touches on the keynote, sessions, and code labs, we wanted to provide you with some tips to get ready to experience Chrome Dev Summit, either in-person or via the livestream.

To get the most out of Chrome Dev Summit, make sure to check out the schedule and set up notifications for the sessions you don't want to miss. These will help you plan your schedule whether you're in person or tuning in via the livestream.

Can't join us in person?

Don't worry, we've got you covered! Here are some ways you can connect with Chrome Dev Summit in real-time:

  • Tune in to the livestream at any time throughout the 2 day summit on . We will stream the keynote and all sessions over the course of the event. If you want us to send you a reminder to tune into the livestream, sign up here.
  • Subscribe to the Chrome Developers YouTube Channel to stay up to date as we'll be publishing all of the talks from the event.
  • Join the conversation and send us your web questions on Twitter that include the #ChromeDevSummit hashtag or join our Slack by signing up here and a team of onsite Googlers will do their best to track down an answer in real time for you.

We're looking forward to having you with us you for 2 days of web fun, soon!

Don't forget to join the social conversation at #ChromeDevSummit.

New In Chrome 55

$
0
0

New In Chrome 55

Watch on YouTube

  • async and await allows you to write promise-based code as if it were synchronous, but without blocking the main thread.
  • Pointer events provide a unified way of handling all input events.
  • Sites added to the home screen, are automatically granted the persistent storage permission.

And there’s plenty more.

I’m Pete LePage, here’s what’s new for developers in Chrome 55!

Pointer Events

Pointing at things on the web used to be simple. You had a mouse, you moved it around, sometimes you pushed buttons, and that was it. But this, doesn’t work so well on here.

Touch events are good, but to support touch and mouse, you had to support two event models:

elem.addEventListener('mousemove', mouseMoveEvent);
elem.addEventListener('touchmove', touchMoveEvent);

Chrome now enables unified input handling by dispatching PointerEvents:

elem.addEventListener('pointermove', pointerMoveEvent);

Pointer events unify the pointer input model for the browser, bringing touch, pens, and mice together into a single set of events. They’re supported in IE11, Edge, Chrome, Opera and partially supported in Firefox.

Check out Pointing the Way Forward for more details.

async and await

Asynchronous JavaScript can be difficult to reason about. Take this function with all it’s “lovely” callbacks:

function logFetch(url) {
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function (e) {
    if (xhr.readyState === 4) {
      if (xhr.status === 200) {
        console.log(xhr.responseText);
      } else {
        console.error('xhr failed', xhr.statusText);
      }
    }
  };
  xhr.onerror = function (e) {
    console.error(xhr.statusText);
  };
  xhr.open('GET', url);
  xhr.send();
}

Re-writing it with promises helps avoid the nesting problem:

function logFetch(url) {
  return fetch(url)
    .then(response => response.text())
    .then(text => {
      console.log(text);
    }).catch(err => {
      console.error('fetch failed', err);
    });
}

But, Promise-based code can still be difficult to read when there are long chains of asynchronous dependencies.

Chrome now supports the async and await JavaScript keywords, allowing you to write Promise-based JavaScript that can be as structured and readable as synchronous code.

Instead, our asynchronous function can be simplified to this:

async function logFetch(url) {
  try {
    const response = await fetch(url);
    console.log(await response.text());
  }
  catch (err) {
    console.log('fetch failed', err);
  }
}

Jake has a great post: Async Functions - making promises friendly with all the details.

Persistent Storage

The persistent storage origin trial is now over. You can now mark web storage as persistent, preventing Chrome from automatically clearing the storage for your site.

if (navigator.storage && navigator.storage.persist) {
  navigator.storage.persist().then(granted => {
    if (granted)
      alert("Storage will not be cleared except by explicit user action");
    else
      alert("Storage may be cleared by the UA under storage pressure.");
  });
}

In addition, sites that have high engagement, have been added to the home screen or have push notifications enabled are automatically granted the persistence permission.

Check out Chris Wilson’s Persistent Storage post for full details and how you can request persistent storage for your site.

CSS Automatic Hyphenation

CSS automatic hyphenation, one of Chrome’s most frequently requested layout features is now supported on Android and Mac.

Web Share API

And finally, it’s now easier to invoke native sharing capabilities with the new Web Share API, which is available as an origin trial. Paul (Mr. Web Intents) Kinlan has all the details in his Navigator Share post.

Closing

These are just a few of the changes in Chrome 55 for developers.

If you want to stay up to date with Chrome and know what’s coming, be sure to subscribe, and be sure to check out the videos from the Chrome Dev Summit for a deeper dive into some of the awesome things the Chrome team is working on.

I’m Pete LePage, and as soon as Chrome 56 is released, I’ll be right here to tell you what’s new in Chrome!

Subscribe to Chrome Developers on YouTube

Subscribe to our YouTube channel or our RSS feed

Performant Parallaxing

$
0
0

Performant Parallaxing

Love it or hate it, parallaxing is here to stay. When used judiciously it can add depth and subtlety to a web app. The problem, however, is that implementing parallaxing in a performant way can be challenging. In this article we’ll discuss a solution that is both performant and, just as importantly, works cross-browser.

TL;DR

  • Don’t use scroll events or background-position to create parallax animations.
  • Use CSS 3D transforms to create a more accurate parallax effect.
  • For Mobile Safari use position: sticky to ensure that the parallax effect gets propagated.

If you want the drop-in solution head over to the UI Element Samples GitHub repo and grab the Parallax helper JS! You can see a live demo of the parallax scroller in the GitHub repo.

Problem parallaxers

To begin with let’s take a look at two common ways of achieving a parallax effect, and in particular why they are unsuitable for our purposes.

Bad: using scroll events

The key requirement of parallaxing is that it should be scroll-coupled; for every single change in the page’s scroll position the parallaxing element's position should update. While that sounds simple, an important mechanism of modern browsers is their ability to work asynchronously. This applies, in our particular case, to scroll events. In most browsers scroll events are delivered as "best-effort" and are not guaranteed to be delivered on every frame of the scroll animation!

This important piece of information tells us why we need to avoid a JavaScript-based solution that moves elements based on scroll events: JavaScript doesn’t guarantee that parallaxing will keep in step with the page’s scroll position. In older versions of Mobile Safari scroll events were actually delivered at the end of the scroll, which made it impossible to make a JavaScript-based scroll effect. More recent versions do deliver scroll events during the animation, but, similarly to Chrome, on a "best-effort" basis. If the main thread is busy with any other work, scroll events will not get delivered immediately, meaning the parallax effect will be lost.

Bad: updating background-position

Another situation we’d like to avoid is painting on every frame. Many solutions attempt to change background-position to provide the parallax look, which causes the browser to repaint the affected parts of the page on scroll, and that can be costly enough to significantly jank the animation.

If we want to deliver on the promise of parallax motion, we want something that can be applied as an accelerated property (which today means sticking to transforms and opacity), and which doesn’t rely on scroll events.

CSS in 3D

Both Scott Kellum and Keith Clark have done significant work in the area of using CSS 3D to achieve parallax motion, and the technique they use is effectively this:

  • Set up a containing element to scroll with overflow-y: scroll (and probably overflow-x: hidden).
  • To that same element apply a perspective value, and a perspective-origin set to top left, or 0 0.
  • To the children of that element apply a translation in Z, and scale them back up to provide parallax motion without affecting their size on screen.

The CSS for this approach looks like so:

.container {
  width: 100%;
  height: 100%;
  overflow-x: hidden;
  overflow-y: scroll;
  perspective: 1px;
  perspective-origin: 0 0;
}

.parallax-child {
  transform-origin: 0 0;
  transform: translateZ(-2px) scale(3);
}

Which assumes a snippet of HTML like this:

<div class="container”>
  <div class="parallax-child”></div>
</div>

Adjusting scale for perspective

Pushing the child element back will cause it to get smaller proportional to the perspective value. You can calculate how much it will need to be scaled up with this equation: (perspective - distance) / perspective. Since we most likely want the parallaxing element to parallax but appear at the size we authored it it would need to be scaled up in this way, rather than being left as is.

In the case of the above code, perspective is 1px, and the parallax-child's Z distance is -2px. This means that the element will need to be scaled up by 3x, which you can see is the value plugged into the code: scale(3).

For any content that doesn’t have a translateZ value applied, you can substitute a value of zero. This means the scale is (perspective - 0) / perspective, which nets out at a value of 1, which means that it’s been scaled neither up or down. Quite handy, really.

How this approach works

It’s important to be clear why this works, since we’re going to use that knowledge shortly. Scrolling is effectively a transform, which is why it can be accelerated; it mostly involves shifting layers around with the GPU. In a typical scroll, which is one without any notion of perspective, scrolling happens in a 1:1 manner when comparing the scrolling element and its children. If you scroll an element down by 300px, then its children are transformed up by the same amount: 300px.

However, applying a perspective value to the scrolling element messes around with this process; it changes the matrices that underpin the scroll transform. Now a scroll of 300px may only move the children by 150px, depending on the perspective and translateZ values you chose. If an element has a translateZ value of 0 it will be scrolled at 1:1 (as it used to), but a child pushed in Z away from the perspective origin will be scrolled at a different rate! Net result: parallax motion. And, very importantly, this is handled as part of the browser’s internal scroll machinery automatically, meaning there’s no need to listen to scroll events or change background-position.

A fly in the ointment: Mobile Safari

There are caveats to every effect, and one important one for transforms is about the preservation of 3D effects to child elements. If there are elements in the hierarchy between the element with a perspective and its parallaxing children, the 3D perspective is "flattened", meaning the effect is lost.

<div class="container”>
  <div class="parallax-container”>
    <div class="parallax-child”></div>
  </div>
</div>

In the above HTML, the .parallax-container is new, and it will effectively flatten the perspective value and we lose the parallax effect. The solution, in most cases, is fairly straightforward: you add transform-style: preserve-3d to the element, causing it to propagate any 3D effects (like our perspective value) that have been applied further up the tree.

.parallax-container {
  transform-style: preserve-3d;
}

In the case of Mobile Safari, however, things are a little more convoluted. Applying overflow-y: scroll to the container element technically works, but at the cost of being able to fling the scrolling element. The solution is to add -webkit-overflow-scrolling: touch, but it will also flatten the perspective and we won’t get any parallaxing.

From a progressive enhancement point-of-view, this probably isn’t too much of an issue. If we can’t parallax in every situation our app will still work, but it would be nice to figure out a workaround.

position: sticky to the rescue!

There is, in fact, some help in the form of position: sticky, which exists to allow elements to "stick" to the top of the viewport or a given parent element during scroll. The spec, like most of them, is fairly hefty, but it contains a helpful little gem within:

A stickily positioned box is positioned similarly to a relatively positioned box, but the offset is computed with reference to the nearest ancestor with a scrolling box, or the viewport if no ancestor has a scrolling box. - CSS Positioned Layout Module Level 3

This may not appear to mean a great deal at first glance, but a key point in that sentence is when it refers to how, exactly, the stickiness of an element is calculated: "the offset is computed with reference to the nearest ancestor with a scrolling box". In other words, the distance to move the sticky element (in order for it to appear attached to another element or the viewport) is calculated before any other transforms are applied, not after. This means that, very much like the scrolling example earlier, if the offset was calculated at 300px, there’s a new opportunity to use perspectives (or any other transform) to manipulate that 300px offset value before it’s applied to any sticky elements.

By applying position: -webkit-sticky to the parallaxing element we can effectively "reverse" the flattening effect of -webkit-overflow-scrolling: touch. This ensures that the parallaxing element references the nearest ancestor with a scrolling box, which in this case is .container. Then, similarly to before, the .parallax-container applies a perspective value, which changes the calculated scroll offset and creates a parallax effect.

<div class="container”>
  <div class="parallax-container”>
    <div class="parallax-child”></div>
  </div>
</div>

.container {
  overflow-y: scroll;
  -webkit-overflow-scrolling: touch;
}

.parallax-container {
  perspective: 1px;
}

.parallax-child {
  position: -webkit-sticky;
  top: 0px;
  transform: translate(-2px) scale(3);
}

This restores the parallax effect for Mobile Safari, which is excellent news all round!

Sticky positioning caveats

There is a difference here, however: position: sticky does alter the parallax mechanics. Sticky positioning tries to, well, stick the element to the scrolling container, whereas a non-sticky version doesn’t. This means that the parallax with sticky ends up being the inverse of the one without:

  • With position: sticky, the nearer the element is to z=0 the less it moves.
  • Without position: sticky, the nearer the element is to z=0 the more it moves.

If that all seems a bit abstract, take a look at this demo by Robert Flack, which demonstrates how elements behave differently with and without sticky positioning. To see the difference you need Chrome Canary (which is version 56 at the time of writing) or Safari.

A demo by Robert Flack showing how position: sticky affects parallax scrolling.

Assorted bugs and workarounds

As with anything, though, there are still lumps and bumps that need to be smoothed over:

  • Sticky support is inconsistent. Support is still being implemented in Chrome, Edge lacks support entirely, and Firefox has painting bugs when sticky is combined with perspective transforms. In such cases it’s worth adding a little code to only add position: sticky (the -webkit- prefixed version) when it’s needed, which is for Mobile Safari only.
  • The effect doesn’t "just work" in Edge. Edge tries to handle scrolling at the OS level, which is generally a good thing, but in this case it prevents it from detecting the perspective changes during scroll. To fix this you can add a fixed position element, as this seems to switch Edge over to a non-OS scrolling method, and ensures that it accounts for perspective changes.
  • "The page’s content just got huge!" Many browsers account for the scale when deciding how big the page’s content is, but sadly Chrome and Safari don’t account for perspective. So if there’s — say — a scale of 3x applied to an element, you may well see scroll bars and the like, even if the element is at 1x after the perspective has been applied. It is possible to work around this issue by scaling elements from the bottom right corner (with transform-origin: bottom right), which works because it will cause oversized elements to grow into the “negative region” (typically the top left) of the scrollable area; scrollable regions never let you see or scroll to content in the negative region.

Conclusion

Parallaxing is a fun effect when used thoughtfully. As you can see it’s possible to implement it in a way that is performant, scroll-coupled, and cross-browser. Since it requires a little bit of mathematical wriggling, and a small amount of boilerplate to get the desired effect, we have wrapped up a small helper library and sample, which you can find in our UI Element Samples GitHub repo.

Have a play, and let us know how you get on.

Take Photos and Control Camera Settings

$
0
0

Take Photos and Control Camera Settings

Image Capture is an API to capture still images and configure camera hardware settings.

The API enables control over camera features such as zoom, focus mode, contrast, ISO and white balance. Best of all, Image Capture allows you to access the full resolution capabilities of any available device camera or webcam. Previous techniques for taking photos on the Web have used video snapshots, which are lower resolution than that available for still images.

Image Capture is available in Chrome 56 on Android and desktop as an Origin Trial, or in Chrome Canary on desktop and Android with Experimental Web Platform features enabled.

The API has four methods:

  • takePhoto() returns a Blob, the result of a single photographic exposure, which can be downloaded, stored by the browser or displayed in an img element. This method uses the highest available photographic camera resolution.
  • grabFrame() returns an ImageBitmap object, a snapshot of live video, which could (for example) be drawn on a canvas and then post-processed to selectively change color values. Note that the ImageBitmap will only have the resolution of the video source — which will be lower than the camera's still-image capabilities.
  • getPhotoCapabilities() returns a PhotoCapabilities object that provides access to available camera options and their current values.
  • setOptions() is used to configure camera settings such as zoom, white balance or focus mode.

The Image Capture API gets access to a camera via a MediaStream from getUserMedia():

navigator.mediaDevices.getUserMedia({video: true})
  .then(gotMedia)
  .catch(error => console.error('getUserMedia() error:', error));

function gotMedia(mediaStream) {
  const mediaStreamTrack = mediaStream.getVideoTracks()[0];
  const imageCapture = new ImageCapture(mediaStreamTrack);
  console.log(imageCapture);
}

You can try out this code from the DevTools console.

Note: To choose between different cameras, such as the front and back camera on a phone, get a list of available devices via the MediaDevices.enumerateDevices() method, then set deviceId in getUserMedia() constraints as per the demo here.

You can use takePhoto() to get a still image and then set it as the src of an <img>:

const img = document.querySelector('img');
// ...
imageCapture.takePhoto()
  .then(blob => {
    img.src = URL.createObjectURL(blob);
  })
  .catch(error => console.error('takePhoto() error:', error));

Use grabFrame() to get data for a frame of video and then draw it on a <canvas>:

const canvas = document.querySelector('canvas');
// ...
imageCapture.grabFrame()
  .then(imageBitmap => {
    canvas.width = imageBitmap.width;
    canvas.height = imageBitmap.height;
    canvas.getContext('2d').drawImage(imageBitmap, 0, 0);
  })
  .catch(error => console.error('grabFrame() error:', error));

Camera capabilities

If you run the code above, you'll notice a difference in dimensions between the grabFrame() and takePhoto() results.

The takePhoto() method gives access to the camera's maximum resolution.

grabFrame() just takes the next-available VideoFrame in the MediaStream inside the renderer process, whereas takePhoto() interrupts the MediaStream, reconfigures the camera, takes the photo (usually in a compressed format, hence the Blob) and then resumes the MediaStream. In essence, this means that takePhoto() gives access to the full still-image resolution capabilities of the camera. Previously, it was only possible to 'take a photo' by calling drawImage() on a canvas element, using a video as the source (as per the example here).

In this demo, the <canvas> dimensions are set to the resolution of the video stream, whereas the natural size of the <img> is the maximum still-image resolution of the camera. CSS, of course, is used to set the display size of both.

The full range of available camera resolutions for still images can be get and set using the MediaSettingsRange values for PhotoCapabilities.imageHeight and imageWidth. Note that the minimum and maximum width and height constraints for getUserMedia() are for video, which (as discussed) may be different from the camera capabilities for still images. In other words, you may not be able to access the full resolution capabilities of your device when saving from getUserMedia() to a canvas. The WebRTC resolution constraint demo shows how to set getUserMedia() constraints for resolution.

Anything else?

  • The Shape Detection API works well with Image Capture: call grabFrame() repeatedly to feed ImageBitmaps to a FaceDetector or BarcodeDetector. Find out more about the API from Paul Kinlan's blog post.

  • The Camera flash (device light) can be accessed via FillLightMode.

Demos and code samples

Support

  • Chrome 56 on Android and desktop as an Origin Trial.
  • Chrome Canary on Android and desktop with Experimental Web Platform features enabled.

Find out more


position:sticky is back in Chrome

$
0
0

position:sticky is back in Chrome

Four years ago Eric Bidelman created a rather awesome blog post about the fact that position: sticky landed in WebKit, which at the time was the engine that powered Chrome (as well as many other browsers including Safari). One year later, and much to the consternation of web developers we removed position:sticky from Chrome because "the current implementation isn't designed in a way that integrates well with the existing scrolling and compositing system".

We've always wanted to get it back in to Chrome as the bug stated, "Once we've got our scrolling and compositing house in order, we should return to position: sticky and implement the feature in a way that integrates well with the rest of the engine". The meta bug tracking the implementation has been worked on since 2013.

The great news is that as of Chrome 56 (currently beta as of December 2016, stable in Jan 2017) position: sticky is now back in Chrome.

What is position:sticky?

It's taken a little while to get here, so why am I excited about it?

position:sticky is a CSS positioning attribute that allows you to fix an element to the viewport (i.e, anchor it to the top of the screen) but only when its parent is visible in the viewport and it is within the threshold value. When it is not fixed to the viewport, the element will act like it is position: relative. It is a very nice and simple addition to the platform that removes the need to use JavaScript in an onscroll event handler just to lock an element to the top of the viewport.

This is what it looks like on my blog. It allows me to keep the current section's header at the top of the screen whilst you read my rather long and laborious articles :\

To implement this feature specify that the position attribute should have the value of sticky on the element that you want to be, er, stuck. Additionally, you can also add in the offset at where it needs to be stuck.

h3 {
  /* Element will be 'fixed' when it ... */
  position: sticky;
  /* ... is 10px from the top of the viewport */
  top: 10px;
}

The previous example will fix the <h3> element at 10px from the top of the viewport. To fix it directly to the top of the viewport you would set the top attribute as top: 0px.

Support for this feature is pretty strong. It is available on Chrome (yay), Firefox and Safari. Here are more details about position:sticky:

API Deprecations and Removals in Chrome 56

$
0
0

API Deprecations and Removals in Chrome 56

In nearly every version of Chrome, we see a significant number of updates and improvements to the product, its performance, and also capabilities of the Web Platform. This article describes the deprecations and removals in Chrome 56, which is in beta as of December 8. This list is subject to change at any time.

Remove CBC-mode ECDSA ciphers in TLS

TLS's CBC-mode construction is flawed, making it fragile and very difficult to implement securely. Although CBC-mode ciphers are still widely used with RSA, they are virtually nonexistent with ECDSA. Other browsers still support these ciphers, we believe the risk is low. Additionally, ECDSA in TLS is used by few organizations and usually with a more complex setup (some older clients only support RSA), so we expect ECDSA sites to be better maintained and more responsive in case of problems.

TLS 1.2 added new ciphers based on AEADs which avoids these problems, specifically AES_128_GCM, AES_256_GCM, or CHACHA20_POLY1305. Although we are only requiring this for ECDSA-based sites at this time, it is recommended for all administrators. AEAD-based ciphers not only improve security but also performance. AES-GCM has hardware support on recent CPUs and ChaCha20-Poly1305 admits fast software implementations. Meanwhile, CBC ciphers require slow complex mitigations and PRNG access on each outgoing record. AEAD-based ciphers are also a prerequisite for HTTP/2 and False Start optimizations.

Intent to Remove | Chromestatus Tracker | Chromium Bug

Mouse on Android stops firing TouchEvents

Until version 55, Android low-level mouse events in Chrome primarily followed an event path designed for touch interactions. For example, mouse drag motion while a mouse button is pressed generates MotionEvents delivered through View.onTouchEvent.

However, since touch events cannot support hover, hovering mousemoves followed a separate path. The whole design had quite a few side-effects including mouse interactions firing TouchEvents, all moue buttons appearing as left mouse buttons, and MouseEvents being suppressed by TouchEvents.

Starting with Chrome 56, a mouse on Android M Or later will:

  • No longer fire TouchEvents.
  • Fire a consistent sequence of MouseEvents with appropriate buttons and other properties.

Intent to Remove | Chromestatus Tracker | Chromium Bug

Remove user gestures from touch scroll

We've seen multiple examples of poorly written or malicious ads that trigger navigation for touch scrolls either on touchstart or all touchend events. If a 'wheel' event can't open a pop-up, then touch scrolling shouldn't either. This may break some scenarios, for example, media not playing on touch, or pop-ups not opening on touch. Safari already silently fails to open pop-ups in all of these scenarios.

Intent to Remove | Chromestatus Tracker | Chromium Bug

Disallow all fetches for scripts with invalid type/language attributes

Currently, Chrome's preload scanner fetches items in <scripts> elements regardless of the value of the type or language attribute, though the script will not be executed when parsed. By deprecating the fetch, the preload scanner and the parser will have the same semantics, and we will not be initiating fetches for scripts we will not use. This is intended to save data for users who navigate to sites with a lot of custom script tags that are post-processed (like type=”text/template”, for example).

The use case of using invalid scripts to ping servers is adequately covered by the sendBeacon API.

This change aligns Chrome with Safari, though FireFox still requests scripts regardless of type or language.

Intent to Remove | Chromestatus Tracker | Chromium Bug

Remove MediaStreamTrack.getSources()

This method is no longer part of the spec and is not supported by any other major browser. It has been replaced by MediaDevices.enumerateDevices(), which Blink has supported without flags since version 47 and which is also supported by other browsers. An example of this is shown below. This hypothetical getCameras() function first uses feature detection to find and use enumerateDevices(). If the feature detection fails, it looks for getSources() in MediaStreamTrack. Finally, if there is no API support of any kind return the empty cameras array.

function getCameras(camerasCallback) {
  var cameras = [];
  if('enumerateDevices' in navigator.mediaDevices) {
     navigator.mediaDevices.enumerateDevices()
      .then(function(sources) {
        return sources.filter(function(source) {
          return source.kind == 'videoinput'
        });
      })
      .then(function(sources) {
        sources.forEach(function(source) {
          if(source.label.indexOf('facing back') >= 0) {
            // move front facing to the front.
            cameras.unshift(source);
          }
          else {
            cameras.push(source);
          }
        });
        camerasCallback(cameras);
      });
  }
  else if('getSources' in MediaStreamTrack) {
    MediaStreamTrack.getSources(function(sources) {

      for(var i = 0; i < sources.length; i++) {
        var source = sources[i];
        if(source.kind === 'video') {

          if(source.facing === 'environment') {
            // cameras facing the environment are pushed to the front of the page
            cameras.unshift(source);
          }
          else {
            cameras.push(source);
          }
        }
      }
      camerasCallback(cameras);
    });
  }
  else {
    // We can't pick the correct camera because the API doesn't support it.
    camerasCallback(cameras);
  }
};

Intent to Remove | Chromestatus Tracker | Chromium Bug

Remove reflected-xss CSP directive

Early drafts of the Content Security Policy Level 2 spec contained a reflected-xss directive which offered nothing more than the X-XSS-Protection header other than a different syntax. This directive was removed from the spec in 2015, but not before it was implemented in Chrome. Support for this directive is now being removed.

Intent to Remove | Chromestatus Tracker | Chromium Bug

Replace CSP 'referrer' directive

The CSP referrer directive allowed site owners to set a referrer policy from an HTTP header. Not only does this feature have very low usage, it has also no longer part of any W3C spec.

Sites that still need this functionality should use <meta name="referrer"> or the new Referrer-Policy header.

Intent to Remove | Chromestatus Tracker | Chromium Bug

Remove PaymentAddress.careOf field

The PaymentAddress interface has a careOf field which is non-standard (no well-known address standards support it). The careOf field is also unnecessary, the recipient and organization fields sufficiently support all necessary use cases. Adding careOf poses significant issues in terms of interoperability with existing postal address schemas and APIs. For a fuller discussion, read the spec removal proposal on GitHub.

Intent to Remove | Chromium Bug

Remove SVGViewElement.viewTarget

The SVGViewElement.viewTarget attribute is not part of the SVG2.0 specification and it's usage is small or nonexistent. This attribute was deprecated in Chrome 54 and has now been removed.

Intent to Remove | Chromestatus Tracker | Chromium Bug

Deprecation policy

To keep the platform healthy, we sometimes remove APIs from the Web Platform which have run their course. There can be many reasons why we would remove an API, such as: they are superseded by newer APIs, they are updated to reflect changes to specifications to bring alignment and consistency with other browsers, or they are early experiments that never came to fruition in other browsers and thus can increase the burden of support for web developers.

Some of these changes will have an effect on a very small number of sites. To mitigate issues ahead of time, we try to give developers advanced notice so that if needed, they can make the required changes to keep their sites running.

Chrome currently has a process for deprecations and removals of API's and the TL;DR is:

  • Announce on the blink-dev mailing list.
  • Set warnings and give time scales in the Chrome DevTools Console when usage is detected on a page.
  • Wait, monitor, and then remove feature as usage drops.

You can find a list of all deprecated features in chromestatus.com using the deprecated filter and removed features by applying the removed filter. We will also try to summarize some of the changes, reasoning, and migration paths in these posts. We will also try to summarize some of the changes, reasoning, and migration paths in these posts.

Chrome DevTools: JavaScript CPU Profiling in Chrome 57

$
0
0

Chrome DevTools: JavaScript CPU Profiling in Chrome 57

In Chrome 57, which is currently Canary, the Timeline panel has been renamed to the Performance panel, the Profiles panel has been renamed to the Memory panel, and the Record JavaScript CPU Profile feature on the Profiles panel has been removed.

Have no fear, you can still profile your JavaScript from the Performance panel. In fact, that's why the Record JavaScript CPU Profile feature was removed. The workflows and layouts are a little different, but the Performance panel provides all of the same information as the old workflow, and then some.

This little migration guide shows you how to record a JS profile in the Performance panel, and how the Performance panel's UI maps to the old workflow that you're used to.

How to record a JS profile

  1. Open DevTools.
  2. Click the Performance tab.
  3. Set the performance profile to JavaScript.

    JS Performance Profile

You can record in two ways:

  • To profile a page load, press Command+R (Mac) or Control+R (Windows, Linux) to reload the page. DevTools automatically starts the recording and then automatically stops when it detects that the page has finished loading.
  • To profile a running page, press Record Record, perform the actions that you want to profile, and then click Record again when you're finished.

How the old workflow maps to the new

From the Chart view of the old workflow, the screenshot below shows you the position of the CPU usage overview chart (top arrow) and the flame chart (bottom arrow) in the new workflow.

Chart view mapping

The Heavy (Bottom Up) view is available in the Bottom-Up tab:

Bottom-up view mapping

And the Tree (Top Down) view is available in the Call Tree tab:

Tree view mapping

Feedback

How was this article? Great? Terrible? Let us know by answering the questions below.

Did this article adequately explain how the old workflow maps to the new workflow?

Are there any features from the old workflow missing in this article?

Ping @ChromeDevTools on Twitter or open a GitHub issue on our docs repo if we missed any features, or if you have any other questions about this article.

Building a Better Web with Lighthouse

$
0
0

Building a Better Web with Lighthouse

Lighthouse is an open-source, automated tool for improving the quality of your web apps. You can install it as a Chrome Extension or run it as a Node command line tool. When you give Lighthouse a URL, it runs a barrage of tests against the page and then generates a report explaining how well the page did and indicating areas for improvement.

Lighthouse Logo

Since Google I/O, we've been hard at work making Lighthouse an awesome companion for building great Progressive Web Apps:

Today, we're happy to announce the 1.3 release of Lighthouse. Lighthouse 1.3 includes a bunch of big new features, audits, and the usual bug fixes. You can install it from npm (npm i -g lighthouse) or download the extension from the Chrome Web Store.

So what's new?

New look and feel

If you've used an earlier version of Lighthouse, you may have noticed that the logo is new! The HTML report and Chrome Extension have also undergone a complete refresh, with a cleaner presentation of scoring and more consistency across audit results. We've also added helpful debug information when you fail a test and include pointers to recommended workarounds.

Lighthouse Report

New Best Practices

To date, Lighthouse has focused on performance metrics and the quality of PWAs. However, an overarching goal of the project is to provide a guidebook for all of web development. This includes guidance on general best practices, performance and accessibility tips, and end-to-end help on making quality apps.

"Do Better Web" is an effort within the Lighthouse project to help developers do better on the web. In other words, help them modernize and optimize their web applications. Oftentimes, web devs use outdated practices, anti-patterns, or hit known performance pitfalls without realizing it. For example, it is widely known that JS-based animations should be done with requestAnimationFrame() instead of setInterval(). However, if the developer is unaware of the newer API, their web app needlessly suffers.

Lighthouse 1.3 includes 20+ new best practice suggestions ranging from tips for modernizing CSS & JavaScript features to performance recommendations like: "Reduce the number of render-blocking assets", "Use passive event listeners to improve scrolling performance".

Do Better Web Best Practices

We'll continue to add more recommendations over time. If you have suggestions for best practices or want to help us write an audit, file an issue on Github.

Report Viewer

Last but not least, we're excited to announce a new web viewer for Lighthouse results. Visit googlechrome.github.io/lighthouse/viewer, drag and drop the output of a Lighthouse run (or click to upload your file), and voila. "Insta" Lighthouse HTML report.

Report Viewer
Report Viewer

Lighthouse Viewer also lets you share reports with others. Clicking the share icon will sign you in to Github. We stash reports as secret gist in your account so you can easily delete a shared report or update it later on. Using Github for data storage also means you get version control for free!

Viewer Architecture
Viewer Architecture

Existing reports can be reloaded by Lighthouse Viewer by adding ?gist=GIST_ID to the URL:

Viewer Architecture 2
Viewer Architecture 2

For all the details on the latest in Lighthouse, see the full release notes over on Github. As always, hit us up to report bugs, file feature requests, or brainstorm ideas on what you'd like to see next.

URL Bar Resizing

$
0
0

URL Bar Resizing

The resizing behavior of the URL bar is changing in Chrome on Android starting in version 56. Here's what you should know:

Lengths defined in viewport units (i.e. vh) will not resize in response to the URL bar being shown or hidden. Instead, vh units will be sized to the viewport height as if the URL bar is always hidden. That is, vh units will be sized to the "largest possible viewport". This means 100vh will be larger than the visible height when the URL bar is shown.

The Initial Containing Block (ICB) is the root containing block used when sizing elements relative to their parents. For example, giving the <html> element a style of width: 100%; height: 100% will make it the same size as the ICB. With this change, the ICB will not resize when the URL bar is hidden. Instead, it will remain the same height, as if the URL bar were always showing ("smallest possible viewport"). This means an Element sized to the ICB height will not completely fill the visible height while the URL bar is hidden.

There is one exception to the above changes and that is for elements that are position: fixed. Their behavior remains unchanged. That is, a position: fixed element whose containing block is the ICB will resize in response to the URL bar showing or hiding. For example, if its height is 100% it will always fill exactly the visible height, whether or not the URL bar is shown. Similarly for vh lengths, they will also resize to match the visible height taking the URL bar position into account.

There are a few reasons for this change:

  • Usable vh units on mobile. Prior to this, using vh units meant a page would reflow jarringly everytime the user changed scroll direction.

  • Improved user experience. If a page reflows while the user is reading they may lose their relative location in the document. This is frustrating but also incurs additional processor usage and battery drain to relayout and repaint the page.

  • Improved interoperability with Safari on iOS. The new model should match how Safari behaves, making life easier for web developers. The unintuitive choice of making vh units the largest possible viewport but the ICB the smallest possible is to match Safari's behavior.

Demo

  • Here's a demonstration. The four bars on the right of the page are all possible combinations of 99%, 99vh, position:fixed and position:absolute provided on a scrollable page. Hiding the URL bar shows how it affects each. Resize events are printed down the page.

Support

  • Chrome 56 on Android.
Viewing all 599 articles
Browse latest View live