Web Platform Team Blog

Making the web awesome

CSS Shapes Editor for Brackets

CSS Shapes open a lot of design possibilities with the ability to wrap content inside and around custom paths.

However, creating the actual shapes used to be a cumbersome process. You’d use an image authoring tool to create paths, export them, maybe adjust them to conform to CSS shapes syntax, import them into your stylesheet, then check in the browser to see how the result interacts with content on the page. Even minor adjustments become too painful to do with this workflow. A better approach was needed.

CSS Shapes are meant to be used in the browser. Why not create them there?


Today, we are announcing the release of the CSS Shapes Editor extension for Brackets. It is a tool which you use to edit, scale and transform CSS Shapes values right in the browser when using the LivePreview mode in Brackets. Authoring shapes this way gives you instant visual feedback for your changes, so you get to see how the shapes interact with other elements on the page.

Head over to the Brackets blog to find out how to get the CSS Shapes Editor extension.

We are also making it easy for web developers inspect CSS Shapes with the Webkit WebInspector. You can see the shape outline by hovering your mouse over the element which uses it.


April 2014 Extensible Web Summit

Last week, W3C TAG (Technical Architecture Group) held an “Extensible Web Summit” hosted by the PhoneGap team at the Adobe offices in San Francisco. The summit brought together TAG members, people from the Extensible Web Community Group, browser implementers, JavaScript library authors, and web developers to talk about the future of the web platform. I believe the consensus of the people who participated was that the TAG should host more summits like these on a regular basis.

The conversations at the summit were informed by the Extensible Web Manifesto, which lays out a few ideas on how to add new features to the web. What makes the most sense to me in the manifesto is the idea of exposing lower-level capabilities that high-level features can be built upon. It’s an easy trap to build constrained high-level features that can’t be extended past a narrow set of use cases. It’s somewhat harder — but more rewarding — to find lower-level primitives that expose the inner workings of a feature and allow for extensions to new use cases.

The summit was organized barcamp style, with topics suggested by the attendees. A list of sessions with links to the conversation minutes can be found on the summit’s Lanyrd site. Topics ranged over the whole web stack, from exploring the levels below the browser through how web applications get packaged.

In the introductory talks, Tab Atkins from Google acknowledged that CSS is one of the least-extensible parts of the web stack. If a CSS declaration isn’t understood, it generally gets thrown out with no way to retrieve the information. This makes it difficult to write JavaScript libraries that extend CSS capabilities, as you have to reconstruct all the CSS parsing and cascading you require.

Custom properties help with some of these problems. Once they are widely supported, CSS polyfills can avoid re-inventing CSS parsing and cascading. The summit had a session on what else might be useful for extending CSS. One of the suggestions was some way for script to hook in to when styles change — perhaps something like a style mutation observer.

We have DOM MutationObservers to watch for DOM changes. But style changes aren’t exposed in this way:  if a script needs to react to a style change, all sorts of hacks are needed to find out when something changed and what that change might be. A standardized style mutation observer would be a big help for these problems.

So one result of the extensible Web Summit is renewed interest in exposing style changes. There’s already a thread on www-style following up on the summit session, and I’m planning on pushing forward on the idea as much as I can. If you are interested, please join the discussion there.

And if you find anything else interesting in the summit notes, please follow up on the topics that interest you. Part of the Extensible Web Manifesto is about getting more feedback from web developers in choosing how we move the web forward. Hopefully we can have more events like this summit where we can draw upon ideas from a larger and larger set of people who want to make the web awesome.

Bear talks about filters on CSS-Tricks

Some time ago, we got a facelift at our Baker-Hamilton building in San Francisco. For a while, all of the conference rooms were floor-to-ceiling clear glass. The masses were horrified to think that we’d be on display during meetings, like goldfish in a goldfish bowl. So when the frosted glass was applied to the windows, it was the “talk of the town,” as they say. As all good memes do, it spread: before we knew it, several folks had said, “We should really do something around frosted-glass effect in web design.” About that time, Chris Coyier invited Bear Travis to write a guest article on CSS-Tricks. The subject that came to mind? Frosting Glass with CSS Filters. Hmmm…


Then again, Jacob just told me that it all started with Arno trying to do a frosted-glass effect on his photos. Where do memes originate?

Enjoy Frosting Glass with CSS Filters.

New canvas features

A number of Canvas 2D features features recently landed in WebKit, Chrome and Firefox. Though they were proposed and drafted some time ago, no one was yet actively working on implementing them and polishing the spec. This was a great opportunity for the Adobe Web platform team to clarify those features and work with the various browser vendors to get them implemented.

Most of these features are cutting edge, so to see the running examples below, you need nightly WebKit, daily Chromium, Opera developer or Firefox Nightly. To turn on experimental canvas features in Chrome or Opera, browse to “chrome://flags“, turn on “Enable experimental canvas features” and relaunch. Firefox has individual flags for each feature. They are accessed by going to “about:config“, clicking on “I’ll be careful, I promise” and setting the flag to true. For this article, turn on turn on “canvas.path.enabled” and “canvas.focusring.enabled“. Most of the time, you need to re-launch for the setting to take effect. For features that are marked as ‘shipping‘, you don’t have to use experimental browsers; the latest version of that browser will do.

Path2D objects

The Path2D object lets you cache drawing commands. Previously, if you had a series of drawing commands, you had to repeat them for each frame of your animation. Using Path2D you can record those calls and play them back quickly. This simplifies your code and could increase the performance of your application dramatically. You can even initialize the path with SVG path data. This is faster and you could even store the path data in an SVG path element that is part of your markup.

Path2D can be constructed with the following interface:

  path = new Path2D(); // Creates a new empty Path2D object
  path = new Path2D(path); // Creates a new Path2D object that is a copy
  path = new Path2D(d); // Creates a new path with a string interpreted
                        // as SVG path data

The object also exposes the canvaspathmethods so all the path drawing APIs from canvas – such as lineTo, arc and rect – are available.

Canvas 2D context APIs for Path2D

To actually use this new object, the 2D canvas context was extended with the following API’s:

  void fill(Path2D path, optional CanvasFillRule fillRule = "nonzero");
  void stroke(Path2D path);
  void clip(Path2D path, optional CanvasFillRule fillRule = "nonzero");
  boolean isPointInPath(Path2D path, double x, double y,
                        optional CanvasFillRule fillRule = "nonzero");
  boolean isPointInStroke(Path2D path, double x, double y);

These methods use the passed-in path object as opposed to the current default path of the existing APIs. Here’s an example that draws a lot of fish bones:;
      ctx.fill(p); // fill the path
Check out this Pen!

If you profile this CodePen in Chrome, Safari or Firefox, little time is spent in Javascript. If you use individual draw calls, most of the time is spent running scripts. As a result, the performance is much slower.

This example also shows how you can use SVG as a source of path data:

var pathstring = document.getElementById("p").attributes.d.value;
var p = new Path2D(pathstring);

This API is enabled on WebKit and Firefox Nightly. It is experimental in Chrome Canary.

ImageData constructors

If you ever use a JavaScript routine or web workers to create a buffer of image data, you know that there was no convenient way to pass that to a canvas putImageData call.

It seems that you should be able to do the following:

var buffer = new Uint8ClampedArray(256*256);
... // populate the image data
ctx.putImageData({width: 256, height: 256, data: buffer}, 0,0);

However, because of the way browsers are implemented, you get an exception when executing putImageData. Browsers expect that you pass in a browser created object as opposed to one with the same signature that you created yourself.

The workaround was to call getImageData on a context to create a ‘dummy’ Imagedata object and then update it with your data.

With the new ImageData constructor this is no longer necessary and you can write the following code:

var data = new Uint8ClampedArray(256*256);
... // populate the image data
ctx.drawImage(new ImageData(data, 256), 0,0);

ImageData is now also in the global space for web workers. It’s not a transferable object yet like in Internet Explorer 11 so the members of ImageData still have to be transferred individually. This API is available on WebKit and Firefox, and is planned for Chrome.

Opaque canvas

The canvas constructor was extended so you can set its initial color to opaque black.

Because the browser now knows that the backdrop for drawing is always opaque, it can make certain assumptions that speed up drawing of transparent content and images. It also helps performance when the canvas context is drawn into the web page since it can assume the everything underneath the canvas pixels can be removed.

An additional benefit is that the browser can now draw text with sub-pixel anti-aliasing. You can trigger this behavior by passing a JSON object during the canvas context creation:

var ctx = canvas.getContext("2d", {alpha: false});

Once you create a context for a canvas element, there is no way to change it back from opaque to non-opaque and vice versa.

For example:

Check out this Pen!

This example draws some text in the small canvas on the left (under “Input canvas”) and then enlarges it in the canvas on the right (under “zoomed in”). Note how the anti-aliasing on the text is colored. This is a trick to give your monitor more horizontal resolution. For more info see this Wikipedia article. This feature improves the readability of text, especially on low-DPI devices. You need to take care to match the resolution of the canvas backing with the screen and don’t do transformations on anti-aliased text. Otherwise, you see the colored edges of the glyphs.

This API is shipping in Chrome and Nightly Firefox. In Safari you can trigger this behavior by filling the entire canvas with a constant color right after construction of the 2D context.

Focus rings

This new API gives you the ability to draw a focus region on your canvas context. To use this feature, you need to provide a sub-DOM to the canvas object in your markup. This could something like this:

<canvas width="750" height="220">  <input id="showA" type="checkbox" /></canvas><label for="showA">Show As</label>
<canvas width="750" height="220">  <input id="showB" type="checkbox" /></canvas><label for="showB">Show Bs</label>

The sub-DOM needs to contain elements that can get the focus. These elements (also known as fallback content) should have a pixel representation in the canvas bitmap. When the user uses the tab key, elements in the sub-DOM get the focus. To draw a focus ring for a selectedelement, you use the following API:

...; // path around the focus area

drawFocusIfNeeded checks if the element has focus. If it has, it draws a focus ring with the correct style around the path. Here is an example:

   context.rect(x-7, y-7, 12 + metrics.width+2, 14);
   if(context.drawFocusIfNeeded) // for older browsers
Check out this Pen!

To try it out, click on one of the checkboxes and notice the focus ring. You can also move the ring by using the Tab key.

To enable this feature in Firefox, turn on “canvas.focusring.enabled” in about:config. This API is also about to land in Chrome as an experimental feature.


As you can tell, there are a lot of small improvements being made to Canvas 2D. We are also looking into support for hit regions that help you route mouse events and provide accessibility features.

These features are brand new so it’s likely you will find bugs. If so, please tell us about them so we can address them before they ship. Let us know what you think!

5/4/2013 Update 1
– Firefox enabled Path2D by default so no runtime flags are needed
– Mathias Bynens pointed out that the demos are working in Opera Developer as well.

CSS Shapes Level 1 is ready for your feedback!

CSS Shapes Level 1 describes how content can be wrapped around geometric shapes. As of last week, the specification is a candidate recommendation. Also, both Blink and WebKit now have the latest syntax that matches this latest spec. This means the spec draft is stable enough for you to try out the features in your designs and to provide feedback.

To help you get started, here are some resources:

So, try it out and do provide feedback!

CSS animations and transitions performance: looking inside the browser

You’ve probably used CSS Animations or CSS Transitions in a project. (If not, check out CSS-Trick’s almanac entries on animations and transitions.) Some of your animations might have performed smoothly. Other might have appeared choppy. Do you wonder why?

In this article, we’ll explore how browsers handle CSS Animations and CSS Transitions, so you can develop intuition around whether an animation is likely to perform well — before writing any code! With this intuition, you’ll be able to make design decisions that play well with the browser and result in silky smooth user experiences.

Browser Internals

Let’s pop the hood of the browser, and look around. Once we understand how it works, we can drive it better.

Modern browsers typically have two important threads of execution. These threads work together to render a web page:

  • The main thread
  • The compositor thread

Typically, the main thread is responsible for:

  • Running your JavaScript.
  • Calculating your HTML elements’ CSS styles.
  • Laying out your page.
  • Painting your elements into one or more bitmaps.
  • Handing these bitmaps over to the compositor thread.

Typically, the compositor thread is responsible for:

  • Drawing bitmaps to the screen via the GPU.
  • Asking the main thread to update bitmaps for visible or soon-to-be-visible parts of the page.
  • Figuring out which parts of the page are visible.
  • Figuring out which parts are soon-to-be-visible when you’re scrolling.
  • Moving parts of the page when you scroll.

The main thread can be busy for long periods of time running your JavaScript or painting a large element. While it’s busy, it’s not responsive to user input.

On the other hand, the compositor thread tries to stay extremely responsive to user input. The compositor tries to redraw the page 60 times per second when the page is changing, even if the page is incomplete.

For example, when the user scrolls a page, the compositor thread asks the main thread to update the bitmaps for newly visible parts of the page. However, if the main thread doesn’t respond quickly enough, the compositor doesn’t wait. The compositor draws the parts of the page it has so far and draws white elsewhere.


I mentioned the compositor thread draws bitmaps to the screen using the GPU. Let’s quickly go over the GPU.

The GPU is a chip found in most phones, tablets, and computers today. It’s extremely specialized, meaning it’s really good at certain things, and it’s not that great at others.

GPUs are really fast at:

  1. Drawing to the screen.
  2. Drawing the same bitmap over and over again.
  3. Drawing the same bitmap in a different position, rotation, or scale.

GPUs are relatively slow at:

  1. Loading bitmaps into their memory.

transition: height

Now that we have a rough idea of the software and hardware running our page, let’s look at how the browser’s main thread and compositor thread work together to perform a CSS Transition.

Suppose we’re transitioning an element’s height from 100px to 200px, like so:

div {
    height: 100px;
    transition: height 1s linear;

div:hover {
    height: 200px;

The main thread and the compositor thread will perform operations according to the timeline diagram below. Note that operations in orange boxes are potentially time-consuming. Operations in blue boxes are quick.


As you can see, there are lots of orange boxes, meaning the browser has to work pretty hard! This means the transition might be choppy.

In every frame of the transition, the browser has to perform layout, painting, and uploading new bitmaps to the GPU. As we learned, loading bitmaps into GPU memory can be a relatively slow operation.

The reason the browser has to work so hard every frame is because the contents of the element keep changing. Changing an element’s height may cause its child elements to also change in size, so the browser has to perform layout. After layout, the main thread has to regenerate the bitmap for the element.

transition: transform

So, height can be somewhat expensive to transition. Is there something cheaper?

Suppose we’re scaling an element from half size to full size. Also suppose we’re using the CSS transform property to scale it and the CSS transition property to animate the scaling, like so:

div {
    transform: scale(0.5);
    transition: transform 1s linear;

div:hover {
    transform: scale(1.0);

Let’s look at the timeline diagram for this case:


We see a lot less orange this time, meaning the animation will probably be smooth! So, how is animating an element’s transform different than animating its height?

By definition, the CSS transform property does not change the layout of an element or the elements around it. It affects the element as a whole- it scales the whole element or rotates the whole element or moves the whole element.

This is great news for the browser! The browser only has to generate the bitmap for the element and upload it to the GPU at the start of the animation. After that, the browser doesn’t have to do any more layout, painting, or bitmap uploading. Instead, the browser can leverage the GPU’s special ability to draw the same bitmap in a different position, rotation, or scale quickly.

Design Decisions

So, does this mean we shouldn’t animate an element’s height? No. Sometimes it’s exactly what your design warrants, and the animation could be fast enough. Maybe your element is isolated, and doesn’t cause other parts of the page to be laid out again. Maybe your element is simple to repaint, and the browser can do it quickly. Maybe your element is small, and the browser only has to upload a small bitmap to the GPU.

Of course, if you can animate a “cheaper” property like CSS transform instead of a more expensive property like CSS height, and there is no impact on your design vision, do that. For example, lets say your design involves a button that reveals a menu when tapped. Instead of animating the menu’s CSS top or height properties to reveal it, try animating the element’s CSS transform property for a similar or identical effect.

The CSS properties that are particularly fast to animate include:

This list is somewhat limited today, but as browsers advance, you’ll see more and more CSS properties becoming fast to animate. Also, don’t discount the current list. You might be surprised at just how many rich effects you can create by combining these properties. Get creative!

CSS Shapes geometry: discussed and demo’d

Flowing text around shapes shouldn’t be burdensome. If you have one continuous string of text, why not wrap it like a ribbon that can smoothly conform to a shape? The engineers who are implementing the CSS Shapes Module Level 1 spec are bringing that capability to the web platform.

Sara Soueidan experiments with creating non-rectangular layouts with CSS Shapes. Her articles spark ideas for creating magazine-like layouts and the creativity of taking shapes further with animation.

Hans Muller’s latest blog on the subject, A Simpler Algorithm for CSS Shapes Level 1, takes the time to break down what is happening on the implementation level.

The shape-margin property expands the polygon by the specified radial distance.

How does the shape-outside property flow content around a shape? Hans explains the fundamental geometry involved, and provides a demo that makes these concepts come to life.

Happy birthday, web, and many more

The web is 25 years old today. In its short existence it has transformed the way we play, learn, work and connect with each other. And yet, this is just the beginning. The web has the potential to transform the creative process.

Sir Tim Berners-Lee used his creativity when on March 12, 1989 he submitted his proposal for the World Wide Web and gifted it to the world as an open and free standard.

Today, two people in five have access to the web. That’s amazing, but we need the whole world to have equal, uncensored access. We must safeguard our privacy and personal freedom. We need to make sure that the web avoids fragmentation and remain a truly global resource. We all have a role to play in making sure we get the web we want and the web we deserve. As Sir Tim said, “This is for everyone.”

The web has made our planet more connected than ever. It has helped spread information, knowledge and ideas that can make the world a better place.

Within us all is the power to make a difference through our imagination and creativity.

We are all born creative. We all start as fearless explorers banging on pots and pans. We are all artists who have created masterpieces with our fingers dipped in paint.

More than ever we need creativity to solve our most challenging problems. And the web can eliminate the friction in the creative process.

The creative process is fundamentally collaborative and the web can enable connected creativity. The web can make it easier to be inspired by discovering and building on ideas from your neighbor next door or from across the world.

You can do truly remarkable things today on the web. And yet, it needs to be an even more expressive canvas. We’ve barely scratched the surface.

At Adobe, we’re passionate about building the best tools in the world for creative people. We believe in the potential for the web to transform the creative process. We’re looking forward to continue contributing to this grand enterprise.

The web has come a long way in its short existence, but there is so much more to do.

Let’s make it happen.

Add Shape and Depth to Your Layout with Photoshop and CSS Shapes

In the current Webkit implementation of the CSS Shapes specification, we’ve added support for shape-outside  using an image as a value. In this case, rather than defining the shape with a basic-shape function, the shape is computed from the image’s alpha channel, with the opacity threshold being configurable with shape-image-threshold. By using an image with a transparent background, you can use CSS Shapes to flow text around the arbitrary shape defined by your image.

The default behavior is to define the shape as the area(s) of the image greater than 0% opacity so even semi-transparent areas, such as drop shadows, will be part of the shape. In this article, I’ll walk you through creating an image and defining a drop shadow in its alpha channel using Photoshop and then how to use it with CSS Shapes to create depth & contour to this simple encyclopedia layout.


 Defining a Shape in the Alpha Channel with Photoshop

We’ll start by opening this simple image in Photoshop.

1. Create a new layer and name it ‘shadow’. We’ll be creating the drop shadow on this layer, so move it beneath the main image.

Create a New Layer

2. Fill the layer with black and set the fill opacity to 50%

Set Layer Fill & Opacity

3. With the shadow layer selected in the Layers panel, select the image with the Quick Selection tool. Click the Refine Edge button and set the Feather to 5px.

Soften the edges of the selection

4. Create a new Layer Mask. With the Move tool, adjust the shadow layer down and to the right.

Switch to the Channels panel and see the new alpha channel that has been created from the layer mask. This will be the shape around which text will flow when used with CSS Shapes.

Alpha Channel

Save the image as a PNG.

Wrapping Text Around Images with CSS Shapes

First, we’ll take our original page layout and modify to wrap around the unshadowed image.

    float: left;
    shape-outside: url("gears.png");

Since the original image had a transparent background, the shape is defined as the outline of the gears. Using shape-outside, we see the text wrap around the gears like this:

Using shape-margin, you can specify how close you want the text to wrap next to your image.

By default, the shape-margin is none, which in this case, wraps the text a little too close to the gears. We can adjust this accordingly:

    float: left;
    shape-outside: url("gears.png");
    shape-margin: 10px;

Much better:

But rather than setting a shape-margin: 10px;, I’d like to use the drop shadowed image we create above and allow the shadow in the alpha channel to define the contour of the shape.

    float: left;
    shape-outside: url("gears-dropshadow.png");

Resulting in this:

That’s it. In just a few simple steps, we added depth and richness to an otherwise flat and boxy layout using this cool new CSS feature.

If you’re curious about how exactly we calculate the shape from images, read about the algorithm for determining the first fit location for an image shape in Hans Muller’s blog.

The text in this example was excerpted from Wikipedia:
Gear. (2014, March 9). In Wikipedia, The Free Encyclopedia. Retrieved 20:41, March 10, 2014, from

CSS Regions polyfill – better, smarter, fuller

We first started work on a CSS Regions prototype to give designers and developers a seamless and flexible way to flow content inside a chain of boxes. As the feature gained visibility, it became clear that people wanted to experiment outside the WebKit-based browsers. So about one year ago, we created a rather simple polyfill supporting only basic functionality. Today, we would like to introduce a much-improved CSS Regions polyfill library, created by Francois Remy.

What’s new

What’s new? Basically everything the new polyfill was re-written from scratch to make it more flexible and feature rich. Under the hood, it is based on a general-purpose CSS parser. This means it’s more robust and less likely to produce unexpected results if your CSS is odd-looking (minified, uglyfied and so on).

The most readily apparent difference from the old polyfill is that it drops the support for the −adobe− prefix and instead only supports the standard, non-prefixed form of the properties and APIs. If your stylesheets are future-proofed with the standard, non-prefixed syntax, the new polyfill is essentially a drop-in replacement: you don’t need to do anything else! :) Also, all CSS properties are supported: along with flow−from and flow−into, region−fragment, break−before and break−after are supported (Keep in mind, Safari uses the old syntax for forced breaks inside regions, −webkit−region−break−before and −webkit−region−break−after).

Another notable addition is the support for the Regions CSSOM. This covers the NamedFlow interface, additions to the Element interface corresponding to the Region interface and support for the NamedFlow events (regionoversetchange and regionfragmentchange).

Unlike the old polyfill that required the Regions-specific code to be inlined within the HTML, the new polyfill fully supports external stylesheets. It also automatically updates the layout when the DOM is changed through JavaScript or when the viewport size changes through resizing or device rotation.

Also, unlike the old polyfill, the new polyfill doesn’t require the regions to have their size explicitly set.

What’s the catch?

This is a polyfill. It’s not the real deal and has some gotchas you should be aware of.

First of all, interactive content like form elements, contentEditable elements or user-interaction pseudo-classes (for example, :active, :hover) and JavaScript event listeners are something of a shot in the dark. The polyfill actually clones the contents of the named flow to move them through regions. This will likely cause interactive content to work in unexpected ways. Another effect of the content cloning is with the CSS cascade. The new DOM structure could make some selectors not apply anymore or new selectors to apply where they wouldn’t before.

This polyfill is doing the layout asynchronously. So, the user may experience content flickering, especially if scrolling before the page layout is complete. Especially with more complex layouts, auto-sizing can behave differently than a browser-native implementation.

Another missing piece is support for region styling – neither the standard ::region() pseudo-functional syntax nor the old and no longer standard @region syntax.

In terms of CSSOM, the NamedFlow.getRegionFlowRanges() is not implemented. Furthermore, the timing of the NamedFlow events is not guaranteed to be the same as a native, standards-compliant implementation. This means some events could be fired more often or with a delay when compared to a native, standard-compliant implementation.

Demo time

If you want to see the new polyfill in action you can check out the Regions samples hosted on CodePen. Where possible, we’ve converted the samples to render with the polyfill if the browser doesn’t support CSS Regions natively. Also, two important demos showing some of the major use cases of CSS Regions – the National Geographic Orphan Elephants demo and the Adaptive UI demo – are now polyfill-enabled so you can enjoy them on any browser, not just Safari.

How to get it

You can grab a copy from Francois Remy’s GitHub repository. There you will also find extensive documentation of what the polyfill does and how it does it.

Feel free to grab a copy, give it a run and, if something bugs you, don’t hesitate to file an issue or send out a pull request.