HTML5 Rocks

HTML5 Rocks

Introduction to Custom Filters (aka CSS Shaders)

By Paul Lewis at

TL;DR

Custom Filters, or CSS Shaders as they used to be called, allow you to use the power of WebGL's shaders with your DOM content. Since in the current implementation the shaders used are virtually the same as those in WebGL, you need to take a step back and understand some 3D terminology and a little bit of the graphics pipeline.

I've included a recorded version of a presentation I recently delivered to LondonJS. In the video I step through an overview of the 3D terminology you need to understand, what the different variable types are that you'll encounter, and how you can start playing with Custom Filters today. You should also grab the slides so you can play with the demos yourself.

Introduction to Shaders

I've previously written an introduction to shaders which will give you a good breakdown of what shaders are and how you can use them from a WebGL point of view. If you've never dealt with shaders it's something of a required read before you go much further, because many of the Custom Filters concepts and language hinges on the existing WebGL shader terminology.

So with that said, let's enable Custom Filters and plough on!

Enabling Custom Filters

Custom Filters are available in both Chrome and Canary as well as Chrome for Android. Simply head over to about:flags and search for "CSS Shaders", enable them and restart the browser. Now you're good to go!

The syntax

Custom Filters expands on the set of filters that you can already apply, like blur or sepia, to your DOM elements. Eric Bidelman wrote a great playground tool for those, which you should check out.

To apply a Custom Filter to a DOM element you use the following syntax:

.customShader {
  -webkit-filter:

    custom(
      url(vertexshader.vert)
      mix(url(fragment.frag) normal source-atop),

    /* Row, columns - the vertices are made automatically */
    4 5,

    /* We set uniforms; we can't set attributes */
    time 0)
}

You'll see from this that we declare our vertex and fragment shaders, the number of rows and columns we want our DOM element to get broken down into, and then any uniforms we want to pass through.

A final thing to point out here is that we use the mix() function around the fragment shader with a blend mode (normal), and a composite mode (source-atop). Let's take a look at the fragment shader itself to see why we even need a mix() function.

Pixel Pushing

If you're familiar with WebGL's shaders you'll notice that in Custom Filters things are a little different. For one we don't create the texture(s) that our fragment shader uses to fill in the pixels. Rather the DOM content that has the filter applied gets mapped to a texture automatically, and that means two things:

  1. For security reasons we can't query individual pixel color values of the DOM's texture
  2. We don't (at least in current implementations) set the final pixel color ourselves, i.e. gl_FragColor is off limits. Rather, it's assumed that you will want to render the DOM content, and what you get to do is manipulate its pixels indirectly through css_ColorMatrix and css_MixColor.

That means our Hello World of fragment shaders looks more like this:

void main() {
  css_ColorMatrix = mat4(1.0, 0.0, 0.0, 0.0,
                         0.0, 1.0, 0.0, 0.0,
                         0.0, 0.0, 1.0, 0.0,
                         0.0, 0.0, 0.0, 1.0);

  css_MixColor = vec4(0.0, 0.0, 0.0, 0.0);

  // umm, where did gl_FragColor go?
}

Each pixel of the DOM content is multiplied by the css_ColorMatrix, which in the above case does nothing as its the identity matrix and changes none of the RGBA values. If we did want to, say, just keep the red values we would use a css_ColorMatrix like this:

// keep only red and alpha
css_ColorMatrix = mat4(1.0, 0.0, 0.0, 0.0,
                       0.0, 0.0, 0.0, 0.0,
                       0.0, 0.0, 0.0, 0.0,
                       0.0, 0.0, 0.0, 1.0);

You can hopefully see that as you multiply the 4D (RGBA) pixel values by the matrix that you get a manipulated pixel value out of the other side, and in this case one that zeros out the green and blue components.

The css_MixColor is mainly used as a base color that you want to, well, mix in with your DOM content. The mixing is done through the blend modes that you'll be familiar with from art packages: overlay, screen, color dodge, hard light and so on.

There are plenty of ways that these two variables can manipulate the pixels, and included in my presentation is a demo that you can play around with. You should check out the Custom Filters specification to get a better handle on how the blend and composite modes interact.

Vertex Creation

In WebGL we take full responsibility for the creation of our mesh's 3D points, but in Custom Filters all you have to do is specify the number of rows and columns that you want and the browser will automatically break down your DOM content into a bunch of triangles:

Each one of those vertices then gets passed through to our vertex shader for manipulation, and that means we can start moving them around in 3D space as we need. It's not long before you can make some pretty crazy effects!

Animating with Shaders

Bringing in animations to your shaders is what makes them fun and engaging. To do that you simply use a transition (or animation) in your CSS to update uniform values:

.shader {
  /* transition on the filter property */
  -webkit-transition: -webkit-filter 2500ms ease-out;

  -webkit-filter: custom(
    url(vshader.vert)
    mix(url(fshader.frag) normal source-atop),
    1 1,
    time 0);
}

 .shader:hover {
  -webkit-filter: custom(
    url(vshader.vert)
    mix(url(fshader.frag) normal source-atop),
    1 1,
    time 1);
}

So the thing to notice in the code above is that time is going to ease from 0 to 1 during the transition. Inside the shader we can declare the uniform time and use whatever its current value is:

uniform float time;

uniform mat4 u_projectionMatrix;
attribute vec4 a_position;

void main() {
  // copy a_position to position - attributes are read only!
  vec4 position = a_position;

  // use our time uniform from the CSS declaration
  position.x += time;

  gl_Position = u_projectionMatrix * position;
}

Get Playing!

Custom Filters are great fun to play with, and the amazing effects you can create are difficult (and in some cases impossible) without them. It is still early days, and things are changing around, but adding them will add a little bit of showbiz to your projects, so why not give them a go?

Additional Resources

CSS Background shorthand coming to mobile WebKit browsers

By Pete LePage at

Earlier this year, WebKit updated the behavior of the CSS background shorthand property. With this change, the background shorthand property will reset the background-size to its default value of auto auto if it’s not set in the shorthand declaration. This change brings Chrome and other WebKit browsers in compliance with the specification and matches the behavior of Firefox, Opera and Internet Explorer.

With Chrome for Android moving forward to current revisions on WebKit, this change is now rolling out in Android. Because this was a fix to webkit, sites that tested in multiple browsers are likely not affected.

Old way of doing things

// background-size is reset to auto auto by the background shorthand 
.foo {  
  background-size: 50px 40px;
  background: url(foo.png) no-repeat;
}

The background shorthand property does not contain any size property and will therefore reset the background-size to its default value of auto auto.

Correct way to specifying image size

// background-size is specified after background
.fooA { background: url(foo.png) no-repeat; background-size: 50px 40px;
}

// background-size is specified inline after position
.fooB { background: url(foo.png) 0% / 50px 40px no-repeat;
}

In fooB, specifying a background-size in the background shorthand requires the position (0%) be specified first, followed by a forward slash then the background-size (50px 40px). |

Fixes for existing code

There are several options that will provide an easy fix for this:

  • Use background-image instead of the background shorthand property.
  • Set the background-size last, with a higher specificity than any other CSS rules that set background on that element, and don’t forget to check and :hover rules.
  • Apply the !important property to background-size.
  • Move the sizing information to the background shorthand property.

Bonus: background image offsets

In addition to this change, there’s now greater flexibility in positioning the image within the background. In the past, you could only specify the image position relative from the top left corner, now you can specify an offset from the edges of the container. For example setting background-position: right 5px bottom 5px; the image will be positioned 5px from the right edge and 5px from the bottom. Check out this sample on JSBin

Canvas-driven background images

By Eric Bidelman at

Programmatically animating background images

There are two primary ways people animate background images:

  1. Use CSS sprites to update a background-position in JS .
  2. Hacks with .toDataURL() .

The first works great if you have the image ahead of time, but what if your source needs to be programmatically generated, say, by a <canvas>? The solution to #1 is to use .toDataURL() on the canvas and set the background to the generated URL:

while(1) {
  var url = canvas.toDataURL('image/jpeg');
    el.style.background = 'url(' + url + ')';
 }

There are two problems with this:

  1. data: URLs add a ~33% size overhead to the resulting image.
  2. A ton of DOM touching (el.style).

Both of these methods are inefficient: unacceptable for an always-silky-smooth 60fps web app.

Using 2d canvas as a background

DEMO

Turns out, there's a non-standard API which WebKit has had for years that can take canvas as the source for a background. Sadly however, there's no published spec for this feature.

First, instead of specifying a URL for the back:

.bg {
  background: url(bg.png) no-repeat 50% 50%;
}

use -webkit-canvas(), referencing a string identifier to a canvas context:

.canvas-bg {
  background: -webkit-canvas(animation) no-repeat 50% 50%;
}

Next, we need to create the 2d context with a special version of .getContext():

var ctx = document.getCSSCanvasContext('2d', 'animation', 300, 300);

Note: this method is on the document object and not the canvas. The second argument is the same name used in -webkit-canvas().

Further information from Dave Hyatt:

There is only one CSS canvas for a given global identifier per document. When you obtain the drawing context you also specify the size. The canvas will not be cleared as long as you repeatedly request the same size. Specifying a new size is equivalent to the kind of behavior you’d expect if you resized a <canvas> element, and so the canvas buffer will be cleared.

All objects that observe a CSS canvas of the same name are sharing that canvas. This means that (similar to how animated GIFs work), you can do animations and have them happen in lockstep on all the clients of the canvas. Drawing changes will be propagated to all clients automatically.

Animations

As seen in the demo, we can reuse requestAnimationFrame() to drive an animation. This is great, because once things are hooked up, the association between CSS and the canvas element is preserved. There's no need to fiddle with the DOM.

Demo not animated in Chrome?

The current stable channel of Chrome (version 23) has crbug.com/161699, which prevents a requestAnimationFrame() animation from updating the background properly. This has been fixed in Chrome 25 (currently Canary). The demo also should work well in the current Safari.

Performance benefits

We're talking canvas here. Hardware accelerated animations are now fully in play (at least for the browsers this feature works in). And just to reiterate, there's no need to molest the DOM from JS.

Using webgl as a background

Hold on a sec. Does this mean we can power a CSS background using webgl? Of course it does! WebGL is merely a 3d context for canvas. Just swap in "experimental-webgl" instead of "2d", and voila.

var gl = document.getCSSCanvasContext('experimental-webgl', 'animation', 300, 150);

Here's a proof of concept that contains a div with it's background drawn using vertext and fragment shaders: DEMO

Other approaches

It's worth noting that Mozilla has had -moz-element() (MDN) for quite some time. This is part of the CSS Image Values and Replaced Content Module Level 4 spec and allows you to create an image generated from arbitrary HTML: videos, canvas, DOM content,...you name it. However, there are security concerns with having full access to snapshot images of the DOM. This is primarily why other browsers have not adopted said feature.

Interactive Globe with CSS shaders & Google Maps

By Paul Irish at

Recently, I have read news on Webmonkey that Adobe’s CSS Shaders proposal, which will bring high-quality cinematic effects to the web through some new CSS tools, has been accepted by the W3C. If you haven't seen it yet, watch the video below:

Google Chrome's latest Canary added support for CSS shaders, so I decided to experiment with them.

In this experiment, I used custom vertex shader (spherify.vs) and fragment shader (spherify.fs) to create a globe with Google Maps.

<iframe
  class="globe"
  src="http://maps.google.com/?ie=UTF8&amp;ll=14.597042,-15.625&amp;spn=158.47027,316.054688&amp;t=h&amp;z=2&amp;output=embed"
  scrolling="no"></iframe>
.globe {
  width: 550px;
  height: 550px;
  border: 0;
  -webkit-filter: contrast(1.4) custom(url(shaders/spherify.vs) mix(url(shaders/spherify.fs) multiply source-atop),
    50 50 border-box,
    amount 1,
    sphereRadius 0.5,
    sphereAxis -0.41 1 0.19,
    sphereRotation 43.5,
    ambientLight 0.15,
    lightPosition 1 0.87 0.25,
    lightColor 1 1 1 1,
    transform perspective(500));
}

Here, we're applying a vertex shader (spherify.vs) which will operate on a mesh that has 50 lines and 50 columns (50 50 border-box). Feel free to read the source of the vertex shader: spherify.vs. It's written in GLSL but you can probably follow along.

The mix() function provides basic functionalities for color manipulation like blending and alpha compositing on a fragment shader.

We can change the shere's radius, axis, rotation right in the CSS. In this example we set the value of the sphereRadius: 0.5 and it gives original sphere size.

Enjoy the demo!

Below is a video of the effect. If you've got shaders enabled you can play with the real thing right below!

If you just see a flat google maps above, you can enable it with the instructions below

Browsers support: CSS shaders

This is currently cutting-edge, so it's only available in the latest Google Chrome Canary and WebKit nightly. To enjoy the full experience you'll need to turn a few knobs.

Chrome Canary steps:

  • Type about:flags in the browser's navigation bar
  • Find "Enable CSS Shaders". Enable it
  • Relaunch the browser

WebKit nightly steps

  • Download and install WebKit nightly for Mac OSX
  • Open the browser's preferences panel. Go to Advanced tab and tick to show Develop > Enable WebGL menu in the menu bar.
  • In the browser's menu bar select Develop

Stacking Changes Coming to position:fixed elements

By Tom Wiltzius at

In Chrome 22 the layout behavior of position:fixed elements is slightly different than previous versions. All position:fixed elements now form new stacking contexts. This will change the stacking order of some pages, which has the potential to break page layouts. The new behavior matches the behavior of WebKit browsers on mobile devices (iOS Safari and Chrome for Android).

Stacking Whats?

Everyone knows and loves the z-index for determining depth ordering of elements on a page. Not all z-indexes are created equal, however: an element's z-index only determines its ordering relative to other elements in the same stacking context. Most elements on a page are in a single, root stacking context, but absolutely or relatively positioned elements with non-auto z-index values form their own stacking contexts (that is, all of their children will be z-ordered within the parent and not be interleaved with content from outside the parent). As of Chrome 22, position:fixed elements will also create their own stacking contexts.

For a general overview of stacking contexts this MDN article is a great read.

Compare position:fixed to the new position:sticky attribute: for reference, position:sticky always creates a new stacking context.

Motivation

Mobile browsers (Mobile Safari, Android browser, Qt-based browsers) put position:fixed elements in their own stacking contexts and have for some time (since iOS5, Android Gingerbread, etc) because it allows for certain scrolling optimizations, making web pages much more responsive to touch. The change is being brought to desktop for three reasons:

  1. Having different rendering behavior on "mobile" and "desktop" browsers is a stumbling block for web authors; CSS should work the same everywhere when possible.
  2. With tablets it isn’t clear which of the "mobile" or "desktop" stacking context creation algorithms is more appropriate.
  3. Bringing the scrolling performance optimizations from mobile to desktop is good for both users and authors.

Specifics of the Change

Here's an example showing the different layout behaviors: http://codepen.io/paulirish/pen/CgAof

With the change, both versions will render like the right-hand version.

In this example, the green box has a z-index: 1, the pink box has a z-index: 3, and the orange box has a z-index: 2. The blue box is an ancestor of the orange box, and has position:fixed.

If the blue box gets its own stacking context, the orange box's z-index is computed relative to the blue box’s stacking context. Since the blue box has a z-index of auto, giving it a stacking level of zero in the root stacking context, this means the orange box ends up behind the green and pink boxes, which have z-indexes of 1 and 3 (respectively) in the root context.

If the blue box does not get its own stacking context, the orange box's z-index is computed relative to the root stacking context (along with the green and pink boxes). Hence, the orange box ends up interleaved with the pink and green boxes.

For more detail about criteria for stacking context creation (and how stacking contexts behave in general), again refer to this MDN article. In the example the right-hand side version always gave the blue box its own stacking context because its opacity is less than 1. The behavior change being made effectively adds another criterion for creating a separate stacking context, namely an element being position:fixed.

Testing & The Future

To test if your page is going to change, go to Chrome's about:flags and turn on/off "fixed position elements create stacking contexts". If your layout behaves the same in both cases, you're set. If not, make sure it looks acceptable to you with that flag enabled, as that will be the default in Chrome 22.

This change removes one capability - the ability to interleave content within a position:fixed subtree with non-scrolling content from outside. It's unlikely that any web developers are doing this on purpose, and the same effect can be created by giving multiple position:fixed elements the different portions of DOM. As an example, consider these two examples:

http://codepen.io/wiltzius/pen/gcjCk

This page attempts to take two child divs (overlayA and overlayB) of a position:fixed element and place one above a separate content div and one below that same separate content div. It’s now impossible to do this because the position:fixed element is its own stacking context, and it (along with all of its children) will be either entirely above or entirely below the content div. Note that this example works in Chrome 21 and earlier but no longer in Chrome 22.

To fix this, the two overlays can be broken up into their own position:fixed elements. Each is its own stacking context, one of which can go above the content div and one of which can go below the content div. See the fixed example, which works in Chrome 21 and 22:

http://codepen.io/wiltzius/pen/vhFzG

Credit for the genesis of this example goes to the inimitable hixie.

Chrome is the first desktop browser to cause position:fixed elements to create their own stacking contexts. The relevant standard is the CSS z-index specification (see e.g. http://www.w3.org/TR/CSS21/zindex.html). There's not yet consensus over what to do about the difference between mobile and desktop browsers here, but given the confusion of having two different behaviors on mobile and desktop, Chrome has chosen to move to this single behavior on both platforms for the time being.

Updated Oct 1, 2012: The original version of this article suggested that the CSS z-index specification had already been changed to reflect the new behavior of position: fixed elements. This is inaccurate; it has been discussed on the www-style list but as of yet no change has been taken into the spec.

Stick your landings! position: sticky lands in WebKit

By Eric Bidelman at

position: sticky is a new way to position elements and is conceptually similar to position: fixed. The difference is that an element with position: sticky behaves like position: relative within its parent, until a given offset threshold is met in the viewport.

Use cases

Paraphrasing from Edward O’Connor's original proposal of this feature:

Many web sites have elements that alternate between being in-flow and having position: fixed, depending on the user's scroll position. This is often done for elements in a sidebar that the page author wants to be always visible as the user scrolls, but which slot into a space on the page when scrolled to the top. Good examples are news.google.com (the "Top Stories" sidebar) and yelp.com (search results map).

Introducing sticky positioning

LAUNCH DEMO

By simply adding position: sticky (vendor prefixed), we can tell an element to be position: relative until the user scrolls the item (or its parent) to be 15px from the top:

.sticky {
  position: -webkit-sticky;
  position: -moz-sticky;
  position: -ms-sticky;
  position: -o-sticky;
  top: 15px;
}

At top: 15px, the element becomes fixed.

To illustrate this feature in a practical setting, I've put together a DEMO which sticks blog titles as you scroll.

Old approach: scroll events

Until now, to achieve the sticky effect, sites setup scroll event listeners in JS. We actually use this technique as well on html5rocks tutorials. On screens smaller than 1200px, our table of contents sidebar changes to position: fixed after a certain amount of scrolling.

Here's the (now old way) to have a header that sticks to the top of the viewport when the user scrolls down, and falls back into place when the user scrolls up:

<style>
.sticky {
  position: fixed;
  top: 0;
}
.header {
  width: 100%;
  background: #F6D565;
  padding: 25px 0;
}
</style>

<div class="header"></div>

<script>
var header = document.querySelector('.header');
var origOffsetY = header.offsetTop;

function onScroll(e) {
  window.scrollY >= origOffsetY ? header.classList.add('sticky') :
                                  header.classList.remove('sticky');
}

document.addEventListener('scroll', onScroll);
</script>

Try it: http://jsbin.com/omanut/2/

This is easy enough, but this model quickly breaks down if you want to do this for a bunch of DOM nodes, say, every <h1> title of a blog as the user scrolls.

Why JS is not ideal

In general, scroll handlers are never a good idea. Folks tend to do too much work and wonder why their UI is janky.

Something else to consider is that more and more browsers are implementing hardware accelerated scrolling to improve performance. The problem with this is that on JS scroll handlers are in play, browsers may fall back into a slower (software) mode. Now we're no longer running on the GPU. Instead, we're back on the CPU. The result? User's perceive more jank when scrolling your page.

Thus, it makes a lot of sense to have such feature be declarative in CSS.

Support

Unfortunately, there isn't a spec for this one. It was proposed on www-style back in June and just landed in WebKit. That means there's no good documentation to point to. One thing to note however, according to this bug, if both left and right are specified, left wins. Likewise, if top and bottom are used at the same time, top wins.

Support right now is Chrome 23.0.1247.0+ (current Canary) and WebKit nightly.

Writing a flippable book using CSS Regions and 3D transforms

By Ilmari Heikkinen at

So. The day has come. You have finally grown bored of long scrolls of text and are looking for a new format. Something elegant. Something compact. Something that takes the long scroll, cuts it into neat little rectangles and binds them together. I call this invention the “book”.

With the power of CSS regions (CanIUse, go to chrome://flags and enable CSS Regions) and CSS 3D transformations, cutting-edge book technology is finally available on modern browsers. All you need is a few lines of JavaScript and a whole lot of CSS.

Let’s start off by defining our book structure. The book consists of pages and the pages consists of two sides. The sides contain the book content:

<div class="book">
        <div> <!-- first page -->
          <div> <!-- front cover -->
            <h1>My Fancy Book</h1>
          </div>
          <div> <!-- backside of cover -->
            <h1>By Me I. Myself</h1>
            <h2>2012 Bogus HTML Publishing Ltd</h2>
          </div>
        </div>
        <!-- content pages -->        
        <div>
          <!-- front side of page -->
          <div class="book-pages"></div>
          <!-- back side of page -->
          <div class="book-pages"></div>
        </div>
       <div>
          <div class="book-pages"></div>
          <div class="book-pages"></div>
        </div>
        <div>
          <div class="book-pages"></div>
          <div class="book-pages"></div>
        </div>
</div>

We’re going to use CSS regions to flow the book text into the book pages. But first we need the book text.

<span id="book-content">
  blah blah blah ...
</span>

Now that we have written our book, let’s define the flow CSS. I’m using the + character as a vendor prefix placeholder, replace it with -webkit- for WebKit browsers, -moz- for Firefox, and so on:

#book-content {
  +flow-into: book-text-flow;
}
.book-pages {
  +flow-from: book-text-flow;
}

Now the content from the #book-content span will go into the .book-pages divs instead. This is a rather poor book though. For a more bookish book we must embark on a quest. Our journey shall lead over the rainbow bridge of CSS transforms to the clockwork kingdom of JavaScript. In the halls of the mechanist fairylords we shall unleash epic transition magicks and obtain the fabled three keys that control the overworld interface.

The guardian of the rainbow bridge imparts on us the wisdom of stylish structural selectors so that we may turn our HTML book structure into a more book-shaped form:

html {
  width: 100%;
  height: 100%;
}
body {
  /* The entire body is clickable area. Let the visitor know that. */
  cursor: pointer;
  width: 100%;
  height: 100%;
  /* Set the perspective transform for the page so that our book looks 3D. */
  +perspective: 800px;
  /* Use 3D for body, the book itself and the page containers. */
  +transform-style: preserve-3d;
}
.book {
  +transform-style: preserve-3d;
  position: absolute;
}
/* Page containers, contain the two sides of the page as children. */
.book > div {
  +transform-style: preserve-3d;
  position: absolute;
}
/* Both sides of a page. These are flat inside the page container, so no preserve-3d. */
.book > div > div {
  /* Fake some lighting with a gradient. */
  background: +linear-gradient(-45deg, #ffffff 0%, #e5e5e5 100%);
  width: 600px;
  height: 400px;
  overflow: hidden;
  /* Pad the page text a bit. */
  padding: 30px;
  padding-bottom: 80px;
}
/* Front of a page */
.book > div > div:first-child {
  /* The front side of a page should be slightly above the back of the page. */
  +transform: translate3d(0px, 0px, 0.02px);
  /* Add some extra padding for the gutter. */
  padding-left: 40px;
  /* Stylish border in the gutter for visual effect. */
  border-left: 2px solid #000;
}
/* Back of a page */
.book > div > div:last-child {
  /* The back side of a page is flipped. */
  +transform: rotateY(180deg);
  padding-right: 40px;
  border-right: 2px solid #000;
}
/* Front cover of the book */
.book > div:first-child > div:first-child {
  /* The covers have a different color. */
  background: +linear-gradient(-45deg, #8c9ccc 0%, #080f40 100%);
  /* Put a border around the cover to make it cover the pages. */
  border: 2px solid #000;
  /* And center the cover. */
  margin-left: -1px;
  margin-top: -1px;
}
/* Back cover of the book */
.book > div:last-child > div:last-child {
  background: +linear-gradient(-45deg, #8c9ccc 0%, #080f40 100%);
  border: 2px solid #000;
  margin-left: -1px;
  margin-top: -1px;
}

In thus creating a somewhat paper-shaped style for our HTML, we arrive at the trillion-geared gates of the JavaScript kingdom. To pass through the gate, we must turn our flat book into a proper volume. To add some volume to the book, we offset each page slightly on the z-axis.

(function() {
var books = document.querySelectorAll('.book');
for (var i = 0; i < books.length; i++) {
  var book = books[i];
  var pages = book.childNodes;
  for (var j = 0; j < pages.length; j++) {
    if (pages[j].tagName == "DIV") {
      setTransform(pages[j], 'translate3d(0px, 0px, ' + (-j) + 'px)');
    }
  }
}
})();

Casting transition magic to impress the fairylords is not the most difficult of invocations. Yet, the results make the pages of our book animate their turning in a smooth fashion.

.book > div {
  +transition: 1s ease-in-out;
}

Finally, to make the pages actually turn, we need to bind the events themselves to our cause.

(function(){
	// Get all the pages.
	var pages = document.querySelectorAll('.book > div');
	var currentPage = 0;
	// Go to previous page when clicking on left side of window.
	// Go to the next page when clicking on the right side.
	window.onclick = function(ev) {
	  if (ev.clientX < window.innerWidth/2) {
	    previousPage();
	  } else {
	    nextPage();
	  }
	  ev.preventDefault();
	};
	var previousPage = function() {
	  if (currentPage > 0) {
	    currentPage--;
            // Rotate the page to closed position and move it to its place in the closed page stack.
	    setTransform(pages[currentPage], 'translate3d(0px,0px,' + (-currentPage) + 'px) rotateY(0deg)');
	  }
	};
	var nextPage = function() {
	  if (currentPage < pages.length) {
            // Rotate the page to open position and move it to its place in the opened stack.
	    setTransform(pages[currentPage], 'translate3d(0px,0px,' + currentPage + 'px) rotateY(-150deg)');
	    currentPage++;
	  }
	};
})();

With that, we have acquired the “book” technology and can evacuate the overworld crystal towers and leave behind their blinding glare and the fierce nuclear fires of Achenar, the great blue star of the overworld nexus. We triumphantly return to our homes, brandishing our books high above our heads, ready for the inevitable cascade of parades and celebrations in our honor.

You can see an example online here and get the full source for the examples. If you don’t have CSS Regions in your browser, the example will look quite broken. In which case you can try this example instead.

The amazing powers of CSS

By Ilmari Heikkinen at

Yesterday at the office, we were coming up with strange and magical CSS tricks. Take this one for instance, it makes empty links very visible:


a[href = ""] {
  background: red;
  color: white;
  font-size: x-large;
}

Check out the live example at jsFiddle

You can also style absolute links differently from relative links:


a[href ^= http] {
  display: inline-block;
  color: red;
  transform: rotate(180deg);
}

Check out the live example at jsFiddle

If you want to have a different style for links pointing out of your domain, you can use the :not() selector. This is actually how we do the little arrows next to external links at HTML5Rocks.


a[href ^= 'http']:not([href *= 'html5rocks.']) {
  background: transparent url(arrow.png) no-repeat center right;
  padding-right: 16px;
}

Check out the live example at jsFiddle

Just to remind you that you’re not limited to styling links, here’s how to make all PNG images inverted:


img[src $= .png] {
  filter: invert(100%);
}

Moving on from attribute selectors, did you know that you can make the document head visible, along with the other elements there?


head {
  display: block;
  border-bottom: 5px solid red;
}
script, style, link {
  display: block;
  white-space: pre;
  font-family: monospace;
}

Or that you can use the awesome power of CSS attr-function to fill in the :after and :before content?


script:before { content: “<script src=\”“ attr(src) “\” type=\”“ attr(type) “\”>”;
}
script:after { content: “</script>”;
}

style:before { content: “<style type=\”“ attr(type) “\”>”;
}
style:after { content: “< /style>”;
}

/* And for a finish, */
link:before { content: “<link rel=\”“ attr(rel) “\” type=\”“ attr(type) “\” href=\”“ attr(href) “\” />”;
}


Check out the live example at jsFiddle

Note that attr() reads in the attribute values of the matching element, so if you use it for #foo:before, it reads the attributes from #foo.

CSS layout gets smarter with calc()

By Alex Danilo at

Creating a nice CSS layout starts with assigning sizes for all the things being placed in a web application. One highly requested feature has always been the ability to specify sizes using a mixture of sizing units. For example, it’d be nice to be able to reserve 50% of an area plus a fixed amount of space, say 10px. Well you can do that right now using the calc() property. You can use this feature anywhere a length or number is used, so you can use it for positioning things, or in rgb() color values as well, so it has lots of great uses in a style sheet.

What you can do with calc()?

The calc() property can be used anywhere there’s a CSS length or number in your stylesheet.

It gives you two main features to make layout more flexible:

  1. Mixing percentages and absolute values.
  2. Mixing sizing units.

Mixing percentages with absolute units

Let’s take a look at an example of mixing percentages with absolute units. Say we’d like to allocate 50% of the available area less a fixed amount of pixels, then we could write it as so:

#foo {
  width: calc(50% - 100px); 
}
<div id=”foo”>Always 100 pixels less than half the available area</div>

If it had a background color of green it’d look like:

and if you shrunk the parent size, it would look like:

The nice thing here is we always know the right hand edge of the content will be 100px to the left of the middle of the containing area. Being able to combine different value types this way allows your web application to handle layout on different size devices with far greater control than before.

Mixing units

Another great thing is the ability to combine units with different measurements to get a resulting size. For example you could set sizes relative to the current font size by mixing 'em’ and 'px’ units.

#bar {
  height: calc(10em + 3px); 
}

You can find some great examples of combining values here and here.

Try it out

With calc() you can use +, -, * and / to add, subtract, multiply and divide values, allowing all sorts of possibilities. You can use calc() anywhere a CSS length or number can be used. We’re also working on adding calc() for angle and frequency properties soon. The calc() property for lengths is available now in Chrome 19 (Dev channel build) by use of the '-webkit-calc’ property, in Firefox since version 8 using the '-moz-calc’ property and in Internet Explorer since version 9 unprefixed. Let us know what you think by leaving a comment below.

A New Experimental Feature: scoped stylesheets

By Alex Danilo at

Chromium recently implemented a new feature from HTML5: scoped stylesheets, aka. <style scoped>. A web author can limit style rules to only apply to a part of a page by setting the ‘scoped’ attribute on a <style> element that is the direct child of the root element of the subtree you want the styles to be applied to. This limits the styles to affect just the element that is the parent of the <style> element and all of its descendants.

Example

Here’s a simple document that uses standard styling:

<html>
<body>
  <div>a div! <span>a span!</span></div>
    <div>
      <style>
        div { color: red; }
        span { color: green; }
      </style>
      a div! <span>a span!</span></div>
  <div>a div! <span>a span!</span></div>
</body>
</html>

The style rules specified will color text within any <div> red, and within any <span> green:

a div! a span!
a div! a span!
a div! a span!

However, if we set scoped on the <style> element:

<html>
<body>
  <div>a div! <span>a span!</span></div>
    <div>
      <style scoped>
        div { color: red; }
        span { color: green; }
      </style>
      a div! <span>a span!</span></div>
  <div>a div! <span>a span!</span></div>
</body>
</html>

then it restricts the style rules so that they’re applied to the enclosing <div> that is the parent of the <style scoped> element and anything inside just that <div>. We call this ‘scoped’ and the result looks like:

a div! a span!
a div! a span!
a div! a span!

This of course can be done anywhere in the markup. So if you’re adventurous, you could nest scoped styles within other scoped parts of the markup as much as you like to get fine-grained control over where styles get applied.

Use cases

Now what is this good for?

A common use case is syndicated content: when you as a web author would like to incorporate content from a third party, including all its styles, but do not want to risk those styles “polluting” other, unrelated parts of the page. A great advantage here is the ability to combine content from other sites like yelp, twitter, ebay, etc. into a single page without needing to isolate them using an <iframe> or on-the-fly editing the external content.

If you’re using a content management system (CMS) that sends you snippets of markup that are all mashed together into a final page display then this is a great feature to make sure each snippet gets styled in isolation from anything else on the page. This can be just as useful for a wiki as well.

When you want to author some nice demo code on a page, it’s easy to limit the styles to just the demo content. That lets you go wild with the CSS on the demo, yet nothing else on the page will get affected.

Another use case is simply encapsulation: for example, if your web page has a side menu, it makes sense to put styles that are specific to that menu into a <style scoped> section in that part of the markup. Those style rules won’t have any effect when rendering other parts of the page, which keeps them nicely separated from the main content!

Possibly one of the most compelling use cases is for the web component model. Web components are going to be a great way to build things like sliders, menus, date pickers, tab widgets, etc. By providing the scoped styles, a designer can build a widget and package it with their styles as a self-contained unit that others can grab and combine into a rich web application. We plan to use <style scoped> heavily with web components and the shadow DOM (that can already be enabled by setting the experimental “shadow DOM” flag in chrome://flags). Right now there’s no really good way to make sure that styles are limited to web components without resorting to bad practices like inline styling, so scoped styles are a perfect fit for this.

Why include the parent element?

The most natural way is to include the parent element so that the <style scoped> rules could, for example, set a common background color for the entire scope. It also allows scoped style sheets to be written “defensively” for browsers that don’t yet support <style scoped>, by prefixing rules with an ID or class selector as a fallback:

<div id=”menu”>
  <style scoped>
    #menu .main { … }
    #menu .sub { … }
  …

This mimics the effect of using styles when ‘scoped’ is implemented but with some run-time performance penalty due to the more complex selector. The nice thing about this approach is that it allows for a graceful fallback approach until the day when <style scoped> is widely supported and the ID selectors could simply be dropped.

Status

Given that the implementation of scoped style sheets is still new, they are currently hidden behind a run-time flag in Chrome. To enable them you need to get a version of Chrome that has a version number of 19 or higher (Chrome Canary right now), then locate the ‘Enable <style scoped>’ entry in chrome://flags (towards the end), click ‘Enable’ and then restart the browser.

There are currently no known bugs, but @global and scoped versions of @keyframes and @-webkit-region and are stil in the process of being implemented. Also, @font-face is ignored for the time being since there is a good chance that the spec will change.

We would like to encourage everyone interested in the feature to try it out and let us know about your experiences: the good, the bad and (maybe) the buggy.