For the complete experience, please enable JavaScript in your browser. Thank you!

  • Creative Cloud
  • Photoshop
  • Illustrator
  • InDesign
  • Premiere Pro
  • After Effects
  • Lightroom
  • See all
  • See plans for: businesses photographers students
  • Document Cloud
  • Acrobat DC
  • eSign
  • Stock
  • Elements
  • Marketing Cloud
  • Analytics
  • Audience Manager
  • Campaign
  • Experience Manager
  • Media Optimizer
  • Target
  • See all
  • Acrobat Reader DC
  • Adobe Flash Player
  • Adobe AIR
  • Adobe Shockwave Player
  • All products
  • Creative Cloud
  • Individuals
  • Photographers
  • Students and Teachers
  • Business
  • Schools and Universities
  • Marketing Cloud
  • Document Cloud
  • Stock
  • Elements
  • All products
  • Get Support
    Find answers quickly. Contact us if you need to.
    Start now >
  • Learn the apps
    Get started or learn new ways to work.
    Learn now >
  • Ask the community
    Post questions and get answers from experts.
    Start now >
    • About Us
    • Careers At Adobe
    • Investor Relations
    • Privacy  |  Security
    • Corporate Responsibility
    • Customer Showcase
    • Events
    • Contact Us
News
    • 2/16/2016
      Adobe Announces New ColdFusion for Creating High-Performing Web and Mobile Apps
    • 2/10/2016
      Adobe Data Science Symposium and Grants Bring Big Ideas to Big Data
    • 2/3/2016
      Media Alert: Adobe to Unveil Next Generation Marketing Cloud at Summit
    • 1/21/2016
      Adobe Video Tools Get Rave Reviews at Sundance 2016
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:
vat included
Purchase requires verification of academic eligibility
Subtotal
Promotions
Estimated shipping
Tax
Calculated at checkout
Total
Review and Checkout
Adobe Developer Connection /

Introducing CSS shaders: Cinematic effects for the web

by Vincent Hardy

Vincent Hardy
  • html.adobe.com
  • Web Platform Blog
  • Adobe and the web
  • @vincent_hardy
  • @AdobeWebPlatfrm

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

Modified

29 August 2012

Page tools

Share on Facebook
Share on Twitter
Share on LinkedIn
Bookmark
Print
animationCSSHTML5
Was this helpful?
Yes   No

By clicking Submit, you accept the Adobe Terms of Use.

 
Thanks for your feedback.

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.

Note: Since CSS Shaders became a part of the CSS Filter Effects specification, CSS Shaders are now known as "CSS custom filters".

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.

Adobe proposed the CSS shaders proposal to the W3C FX task force in October 2011 and the proposed feature is now part of the CSS Filter Effect draft. This article uses the syntax of the latest CSS Filter effects draft. 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 */ mix(url('color-swipe.fs') normal source-atop), /* 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') mix(url('color-swipe.fs') normal source-atop), 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 author, 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 */ mix(url('color-swipe.fs') normal source-atop), /* 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') mix(url('color-swipe.fs') normal source-atop), 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. // ===== Built-in Per-vertex Attributes ===== attribute vec3 a_position; // The vertex's coordinates. attribute vec2 a_texCoord; // The vertex's texture coordinate. // ===== Built-in Parameters ===== // Uniform parameters are available to shaders and have the // same value for each vertex and fragment. uniform mat4 u_projectionMatrix; // The projection matrix. // ===== CSS Parameters ===== uniform float amplitude; uniform float amount; // ===== Varyings ===== // Varying are set in the vertex shader and available in the // fragment shader. // A fragment's value for a varying is a weighted average based // on its distance from the three vertices surrounding it. varying vec2 v_texCoord; // ===== Constants ====== const float rotate = 20.0; const float PI = 3.1415926; // ===== Helper Functions ====== mat4 rotateX(float a) {...} mat4 rotateY(float a) {...} mat4 rotateZ(float a) {...} // ===== Shader Entry Point ===== // 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. // ===== CSS Parameters ===== uniform float amplitude; // Unused in the fragment shader. uniform float amount; // ===== Varyings ====== varying vec2 v_texCoord; // ===== Constants ====== const vec3 scanlineColor = vec3(1.0, 1.0, 1.0); const float gradientHeight = 0.1; const mat4 grayscaleMatrix = mat4( … ); // ==== Shader Entry Point ===== void main() { // The scanline goes from the bottom of the element (1.0) to // just above the top of the element (-gradientHeight). // This makes sure the gradient is out of view at amount = 1.0. float scanlineTravelDistance = 1.0 + gradientHeight; // Scale amount from [0,1] to [0,scanlineTravelDistance]. float scanlineAmount = amount * scanlineTravelDistance; // Make the scanline start at the bottom and progress upward. // Its position goes from [1.0, -gradientHeight]. float scanlinePosition = 1.0 - scanlineAmount; if (v_texCoord.y < scanlinePosition) { // Make the element grayscale above the scanline. css_ColorMatrix = grayscaleMatrix; } else { // Apply a gradient below the scanline. float distanceFromScanline = v_texCoord.y - scanlinePosition; float gradientStrength = (gradientHeight - min(distanceFromScanline, gradientHeight)) / gradientHeight; css_MixColor = vec4(scanlineColor, gradientStrength); } }

Note: There are some differences in the way fragment shaders compute pixel color values in CSS Shaders due to the security constraints.

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

  • Developing HTML5 games with Impact JavaScript game engine and Dreamweaver CS5.5
  • Yeoman at your service: Tooling and frameworks for beautiful web applications
  • AngularJS directives and the computer science of JavaScript
  • Getting started with AngularJS
  • Ten things you need to know about responsive design
  • CSS: Everything is global and how to deal with it
  • Creating native-like user experiences in PhoneGap with App-UI
  • Introducing CSS blending
  • Using CSS3 transitions: A comprehensive guide
  • The pursuit of simplicity
Choose your region United States (Change)   Products   Downloads   Learn & Support   Company
Choose your region Close

Americas

Europe, Middle East and Africa

Asia Pacific

  • Brasil
  • Canada - English
  • Canada - Français
  • Latinoamérica
  • México
  • United States
  • Africa - English
  • Österreich - Deutsch
  • Belgium - English
  • Belgique - Français
  • België - Nederlands
  • България
  • Hrvatska
  • Cyprus - English
  • Česká republika
  • Danmark
  • Eesti
  • Suomi
  • France
  • Deutschland
  • Greece - English
  • Magyarország
  • Ireland
  • Israel - English
  • ישראל - עברית
  • Italia
  • Latvija
  • Lietuva
  • Luxembourg - Deutsch
  • Luxembourg - English
  • Luxembourg - Français
  • Malta - English
  • الشرق الأوسط وشمال أفريقيا - اللغة العربية
  • 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
  • 台灣

Commonwealth of Independent States

  • Includes Armenia, Azerbaijan, Belarus, Georgia, Moldova, Kazakhstan, Kyrgyzstan, Tajikistan, Turkmenistan, Ukraine, Uzbekistan

Copyright © 2016 Adobe Systems Incorporated. All rights reserved.

Terms of Use | Privacy | Cookies

AdChoices