Adobe
Products
Acrobat
Creative Cloud
Creative Suite
Digital Marketing Suite
Digital Publishing Suite
Elements
Photoshop
Touch Apps
Student and Teacher Editions
More products
Solutions
Digital marketing
Digital media
Education
Financial services
Government
Web Experience Management
More solutions
Learning Help Downloads Company
Buy
Home use for personal and home office
Education for students, educators, and staff
Business for small and medium businesses
Licensing programs for businesses, schools, and government
Special offers
Search
 
Info Sign in
Welcome,
My cart
My orders My Adobe
My Adobe
My orders
My information
My preferences
My products and services
Sign out
Why sign in? Sign in to manage your account and access trial downloads, product extensions, community areas, and more.
Adobe
Products Sections Buy   Search  
Solutions Company
Help Learning
Sign in Sign out My orders My Adobe
Preorder Estimated Availability Date. Your credit card will not be charged until the product is shipped. Estimated availability date is subject to change. Preorder Estimated Availability Date. Your credit card will not be charged until the product is ready to download. Estimated availability date is subject to change.
Qty:
Purchase requires verification of academic eligibility
Subtotal
Review and Checkout
Adobe Developer Connection / HTML5, CSS3, and JavaScript /

Introducing CSS shaders: Cinematic effects for the web

by Vincent Hardy

Vincent Hardy
  • Adobe

Content

  • Filter Effects 1.0
  • Custom filter effects with CSS shaders
  • What are shaders?
  • How do CSS shaders work?
  • Writing shaders
  • Comparison with WebGL
  • Where to go from here

Created

3 October 2011

Page tools

Share on Facebook
Share on Twitter
Share on LinkedIn
Bookmark
Print
animation CSS HTML5

Advances in HTML5 and CSS (for example transitions, animations, transforms, text shadows, box-shadows, gradients, SVG) have improved the graphical and interactive richness of HTML. SVG filter effects are now moving to Filter Effects 1.0 to become available in CSS and HTML, in addition to SVG, and will bring effects such as grayscale, sepia tone, or hue-rotate to all web content. More sophisticated effects, such as the chiseled effect shown in Figure 1, will also be possible.

Figure 1. Filter Effects applied to SVG content, from the svg-wow.org website.
Figure 1. Filter Effects applied to SVG content, from the svg-wow.org website.

The Adobe CSS shaders proposal has been brought to the W3C FX task force. CSS shaders define a filter effects extensibility mechanism and provide rich, easily animated visual effects to all HTML5 content. They work particularly well with CSS animations and CSS transitions.

The following videos show examples of CSS shaders in action on HTML content.

v1(flipbook) View demo

CSS shaders Flipbook demo (0:39)

v2(map) View demo

CSS shaders unfolding map demo (0:18)

v3(twitter) View demo

CSS shaders twitter feed demo (0:22)

This article describes what CSS shaders are and how they work, and includes code examples. It also covers how to use shaders to create custom effects and how to write your own custom shaders.

A few caveats: This is a work in progress. As we continue the discussion with the broader community, we will be making some changes. The syntax used in this article reflects the CSS shader's proposed syntax, but it will likely evolve as the discussions in the W3C FX Task Force and with the broader community continue. Note also that, in accordance with common practice, all the new proposed properties are prefixed with -webkit- in our WebKit prototype. For the sake of simplicity, I have omitted this prefix in the rest of the article.

Filter Effects 1.0

To understand CSS shaders, it is necessary to have a basic understanding of predefined filter effects. The following demo shows a simple filter effects example: on hover, a user gets a simple grayscale to color fade effect.

v4(grayscale) View demo

Grayscale filter effects demo (0:06)

Here is the code for the grayscale effect:

<html> <head> ... <style> #shaded { filter: grayscale(1); transition: filter ease-in 0.3s; } #shaded:hover { filter: grayscale(0); } </style> </head> <body> <div id="shaded"> <div id="multi-col"> <h2>The Creative Web</h2> <p>Lorem ipsum dolor ... </p> <img id="png-img" src="planes.jpg"/> <p>Mauris at ... </p> <img id="svg-img" src="picture.svg" /> <p>Morbi congue ....</p> <img id="css3-img" src="html5_css3_styling.svg" /> </div> </div> </body> </html>

Using filter effects is pretty straightforward: the filter property defines the filter (or chain of filters) that should be applied. As you can see, it is also very easy to integrate it with CSS transitions. The filter property is animatable.

In the example, the grayscale() filter function is animated to gradually fade out because the amount parameter in the filter function is animated from 1 (full grayscale) to 0 (no grayscale) when the user hovers on the shaded element.

The W3C Filter Effects 1.0 draft specification defines two things:

  • A general syntax for defining a filter by assembling filter primitives in a graph.
  • A CSS filter property that can reference a filter definition or use one or more filter functions.

The filter property can use a number of predefined filter functions: blur, drop-shadow, gamma, grayscale, hue-rotate, invert, opacity, saturate, sepia, and sharpen. Figure 2 illustrates the effect of each:

  1. blur(5, 5)
  2. drop-shadow(10, 5, 5)
  3. hue-rotate(328deg)
  4. saturate(5)
  5. invert(1)
  6. grayscale(1)
  7. opacity(0.5)
  8. gamma(1.1, 3.6, 0)
  9. sepia(0.5)
Figure 2. The filter effects functions.
Figure 2. The filter effects functions.

The beauty of Filter Effects is the simplicity of the syntax and the integration with CSS animations and CSS transitions.

However, some things are more difficult. For example, what if you want to have only a portion of the element turn to gray scale? Or what if you want the transition to happen differently, for example, as a swipe effect over the element? Or what if you want a filter effect that is not amongst the predefined set of filter functions or the default set of filter primitives? This is where CSS shaders come in.

The CSS shaders proposal offers to add a custom() filter function to Filter Effects that integrates with predefined filters and CSS animations and transitions. CSS shaders provide the flexibility and expressivity needed to create arbitrary effects—from the simplest ones to the most complex.

Custom filter effects with CSS shaders

I'll start with an example. The effect shown above (fading from grayscale to color) is nice, but it can be improved. The following video shows a more sophisticated effect: when transitioning from grayscale to color, the content "wobbles" for a short while and, simultaneously, a color-swipe goes across the content, bottom to top.

v5(wobble) View demo

Simple CSS shaders in action demo (0:10)

This demo uses a vertex shader for the wobble effect and a pixel shader for the color swipe effect. Both are simply referenced by the custom() filter function which also carries parameters for the shaders, as well as some configuration options. Here is the code:

<html> <head> ... <style> #shaded { filter: custom(url('wobble.vs') /* wobble effect */ url('color-swipe.fs'), /* swipe effect */ 40 40, /* mesh lines/cols */ amplitude 60, /* wobble strength */ amount 0.0); /* effect amount */ transition: filter ease-in-out 2s; ...; } #shaded:hover { filter: custom(url('wobble.vs') url('color-swipe.fs'), 40 40, amplitude 60, amount 1.0); } </style> </head> <body> <div id="shaded"> <div id="multi-col"> <h2>The Creative Web</h2> <!-- Same as previous example --> </div> </div> </body> </html>

Note how similar the code is to the earlier grayscale example. As for other filter effects, we use the filter property to define the effect. The difference is that instead of using one of the predefined filter functions, we use the custom() function and reference the two shaders. The specifics of shaders are discussed in more detail later on. For the time being, the important thing to understand is that each shader provides a specific effect and exposes parameters that can be set and animated from CSS.

In this example, the custom filter uses a wobble.vs vertex shader (for the distortion) and the color-swipe.fs fragment shader (for the grayscale to color swipe effect).

What are shaders?

Shaders are common in 3D graphics. They are (typically) small programs that process the vertices of 3D geometry (vertex shaders) and the color of pixels (fragment shaders).

For example, a vertex shader can create a waving flag effect on a surface, or a wobble effect, as in the previous example. A fragment shader (also called pixel shader) can make arbitrary computations to determine a pixel's color. CSS shaders harness the power of hardware-accelerated shader programs.

How do CSS shaders work?

With CSS shaders, you can turn your HTML or SVG element into a vertex mesh. This is illustrated in Figure 3, as step 1. That mesh is then processed by a vertex shader (in step 2) which makes any kinds of distortion, in 3D space, possible. In step 3, the mesh is rendered (or rasterized) into pixels which the fragment shader colors.

Figure 3. The CSS shaders processing model.
Figure 3. The CSS shaders processing model.

As authors, you can control the mesh's granularity, and you can specify parameters that control the shaders.

In the example, the element with the shaded id has its filter property set to:

custom(url('wobble.vs') /* wobble effect */ url('color-swipe.fs'), /* swipe effect */ 40 40, /* mesh lines/cols */ amplitude 60, /* wobble strength */ amount 0.0); /* effect amount */

The wobble.vs and color-swipe.fs shaders have been coded such that when the amount parameter is set to 0, there is no wobble and the pixel shader applies a uniform grayscale to the element.

When the user hovers on the shaded element, its filter property is set to:

custom(url('wobble.vs') url('color-swipe.fs'), 40 40, amplitude 60, amount 1)

Again, remember the meaning of the parameters is shader specific. In this example, the author of the shader has designed it so that at amount 0.5, the wobble has its maximum effect, and it settles back to stillness at amount 1.0. The color-swipe shader is such that between amount 0.0 and amount 1.0 it creates a bottom to top color swipe along with a shine effect, done by adding white to the pixel values at the same location as the swipe's horizontal divide. Watching the above video is the best way to understand the visual effect.

As with the grayscale filter effect earlier, the integration with CSS transition makes it very easy to set the effect in motion and is done the same way, using the transition property.

Writing shaders

In practice, it seems likely many people will use great custom effects provided by shaders that will expose easily configured parameters, as in the previous example.

Writing shaders, while taking some practice is not that difficult. Also, and this is a little known secret, they are a lot of fun to author.

Shaders are written in the OpenGL ES shading language , the same language used for WebGL shaders. Here is the vertex shader example that creates the wobble effect from the previous example.

For those not familiar with shaders, the following terminology definitions should help read the examples:

  • Vertex: A coordinate on the geometry processed by the shaders.
  • Texture: A raster image (offscreen image). CSS shaders turn an element's rendering into a texture that is used and processed by the vertex and fragment shaders.
  • Attributes: Per-vertex parameters, passed to the vertex shader
  • Uniform: Global parameters that have the same value for all vertices and pixels. They are passed from the custom() function to the shaders.
  • Projection Matrix: A matrix converting coordinates from the normalized vertex coordinate range ([-0.5, +0.5] along each axis) back to the actual viewport coordinate system. Typically used in the vertex shader.
precision mediump float; /* required */ // ================= Per-vertex attributes =================== // attribute vec3 a_position; /* The vertex's coordinates */ attribute vec2 a_texCoord; /* The vertext's texture coordinate */ // Uniform parameters are available to shaders and have the // same value for all vertex or pixel. uniform mat4 u_projectionMatrix; /* The projection matrix */ // ================ Shader parameters ======================== // uniform float amplitude; uniform float amount; // ============== End shader parameters ====================== // const float rotate = 20.0; /* could be made a uniform */ /* to allow control form CSS */ const float PI = 3.14...; varying vec2 v_texCoord; mat4 rotateX(float f) {...} mat4 rotateY(float f) {...} mat4 rotateZ(float f) {...} void main() { v_texCoord = a_texCoord.xy; vec4 pos = vec4(a_position, 1.0); float r = 1.0 - abs((amount - 0.5) / 0.5); float a = r * rotate * PI / 180.0; mat4 rotX = rotateX(a); mat4 rotY = rotateY(a / 4.0); mat4 rotZ = rotateZ(a / 8.0); float dx = 0.01 * cos(3.0 * PI * (pos.x + amount)) * r; float dy = 0.01 * cos(3.0 * PI * (pos.y + amount)) * r; float dz = 0.1 * cos(3.0 * PI * (pos.x + pos.y + amount)) * r; pos.x += dx; pos.y += dy; pos.z += dz; gl_Position = u_projectionMatrix * rotZ * rotY * rotX * pos; }

And here is the color-swipe fragment shader from the example:

precision mediump float; /* required */ // The 'original' content rendering in a texture. uniform sampler2D s_texture; // ================ Shader parameters ======================== // uniform float amplitude; /* unused in this fragment shader */ uniform float amount; // ============== End shader parameters ====================== // varying vec2 v_texCoord; // The desired 'color swipe' color. const vec4 swipeColor = vec4(1.0, 1.0, 1.0, 1.0); vec4 grayscale(vec4 color) { ...; return gray; } void main() { vec4 color = texture2D(s_texture, v_texCoord); vec4 gray = grayscale(color); vec2 pos = v_texCoord; float p = 1.0 - pos.y; /* progress from bottom to top */ vec4 sc = swipeColor * color.a; float threshold = amount * 1.2; if (p < threshold) { float a = min(abs(threshold - p) / 0.2, 1.0); gl_FragColor = mix(sc, color, a); } else { float a = min(abs(threshold - p) / 0.005, 1.0); gl_FragColor = mix(sc, gray, a); } }

There are many good resources on the Web to learn how to write shaders or some libraries that contain excellent sets of shaders (see references at the end).

Shading languages, such as the OpenGL ES shading language, are designed to make programming visual effects easy. CSS shaders offer a way to tie this expressivity into the CSS syntax and make it easy to use and animate these effects.

Comparison with WebGL

WebGL provides an implementation for the HTML5 canvas element. WebGL offers a 3D context for canvas and, within that context, pixel shaders are available (and so are vertex shaders and all the other 3D features WebGL has to offer). WebGL operates within the bounds of the canvas for which it provides a context.

By contrast, CSS shaders provide a way to apply arbitrary shaders to arbitrary Web content.

Where to go from here

Adobe is bringing CSS shaders to the W3C as part of the FX task force and our goal is to start contributing this code to WebKit as soon as the work is accepted by W3C so that web developers can start enjoying this powerful new set of filter effects soon.

In the meantime, you may want to refer to the following resources to learn more about CSS animations and effects:

  • FX Task Force
  • CSS Animations
  • CSS Transitions
  • Filter Effects 1.0
  • CSS 2D Transforms
  • CSS 3D Transforms
  • OpenGL ES 2.0
  • OpenGL ES Shading Language (PDF)
  • WebGL
  • WebGL Wiki
  • GLFX.js

Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License+Adobe Commercial Rights

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License. Permissions beyond the scope of this license, pertaining to the examples of code included within this work are available at Adobe.

More Like This

  • Real-time data exchange in HTML5 with WebSockets
  • Introducing the HTML5 storage APIs
  • Introducing theexpressiveweb.com beta
  • Adobe, standards, and HTML5
  • Developing HTML5 games with Impact JavaScript game engine and Dreamweaver CS5.5
  • Using the Geolocation API
  • CSS3 basics
  • Backbone.js Wine Cellar tutorial – Part 1: Getting started
  • JavaScript object creation: Learning to live without "new"
  • Object types in JavaScript

Products

  • Acrobat
  • Creative Cloud
  • Creative Suite
  • Digital Marketing Suite
  • Digital Publishing Suite
  • Elements
  • Mobile Apps
  • Photoshop
  • Touch Apps
  • Student and Teacher Editions

Solutions

  • Digital marketing
  • Digital media
  • Web Experience Management

Industries

  • Education
  • Financial services
  • Government

Help

  • Product help centers
  • Orders and returns
  • Downloading and installing
  • My Adobe

Learning

  • Adobe Developer Connection
  • Adobe TV
  • Training and certification
  • Forums
  • Design Center

Ways to buy

  • For personal and home office
  • For students, educators, and staff
  • For small and medium businesses
  • For businesses, schools, and government
  • Special offers

Downloads

  • Adobe Reader
  • Adobe Flash Player
  • Adobe AIR
  • Adobe Shockwave Player

Company

  • News room
  • Partner programs
  • Corporate social responsibility
  • Career opportunities
  • Investor Relations
  • Events
  • Legal
  • Security
  • Contact Adobe
Choose your region United States (Change)
Choose your region Close

North America

Europe, Middle East and Africa

Asia Pacific

  • Canada - English
  • Canada - Français
  • Latinoamérica
  • México
  • United States

South America

  • Brasil
  • Africa - English
  • Österreich - Deutsch
  • Belgium - English
  • Belgique - Français
  • België - Nederlands
  • България
  • Hrvatska
  • Česká republika
  • Danmark
  • Eastern Europe - English
  • Eesti
  • Suomi
  • France
  • Deutschland
  • Magyarország
  • Ireland
  • Israel - English
  • ישראל - עברית
  • Italia
  • Latvija
  • Lietuva
  • Luxembourg - Deutsch
  • Luxembourg - English
  • Luxembourg - Français
  • الشرق الأوسط وشمال أفريقيا - اللغة العربية
  • Middle East and North Africa - English
  • Moyen-Orient et Afrique du Nord - Français
  • Nederland
  • Norge
  • Polska
  • Portugal
  • România
  • Россия
  • Srbija
  • Slovensko
  • Slovenija
  • España
  • Sverige
  • Schweiz - Deutsch
  • Suisse - Français
  • Svizzera - Italiano
  • Türkiye
  • Україна
  • United Kingdom
  • Australia
  • 中国
  • 中國香港特別行政區
  • Hong Kong S.A.R. of China
  • India - English
  • 日本
  • 한국
  • New Zealand
  • 台灣

Southeast Asia

  • Includes Indonesia, Malaysia, Philippines, Singapore, Thailand, and Vietnam - English

Copyright © 2012 Adobe Systems Incorporated. All rights reserved.

Terms of Use | Privacy Policy and Cookies (Updated)

Ad Choices

Reviewed by TRUSTe: site privacy statement