CSS Shaders

Introduction

One of the more exciting features for the web which I've been looking forward to some time now are CSS shaders. You might remember when 3D transforms were new and hot, CSS shaders will bring content transformations to a whole new level. The ability to perform any sort of transformations up-to single pixel precision allows developers to create and present content in ways that have not been possible before.

Differences between WebGL and CSS shaders

If you are familiar with shaders from WebGL, CSS shaders are almost identical with a few differences. As described by Vincent Hardy:

"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".

This very much applies to my implementation of CSS shaders through WebGL, but there are some more differences to WebGL and CSS shaders than that.

The biggest and most notable difference between the CSS shader specification and my implementation is that my implementation does not actually perform the rendering through CSS, but through JavaScript/WebGL instead. To accomplish this, the script performs a snapshot of the content in its current state which it sends to the WebGL program as the texture. In short, this means that any DOM changes that occur do not reflect on the shaders unless the snapshot is refreshed. This obviously is a major downside for my implementation, but when taken into account, it can still be used in many powerful ways. It is also noteworty, that at least with the computers I've tested with, my implementation has noticably higher framerate than the same application running on the native CSS shaders, which I'd presume is due to my implementation using a static snapshop where as the CSS shaders using the actual web content. Hopefully the performance issues are addressed, as even with the sample demos from Adobe, there is still noticable framerate dropping.

Security issues

The other major difference is the fact that with the current proposal and implementation of CSS shaders, the fragment shader does not have access to the texture color at all. Instead, the modifications to the colors are to be done through blending using css_ColorMatrix and css_BlendColor. With my implementation, those two variables can be used, but the fragment shaders can also read and write the color of the texture directly as it has full access to the texture. The reason CSS shaders do not have access to the texture color is due to security issues and I gave my views on the current approach here. As my implementation does have access to read the texture, it shouldn't come as a surprise that my implementation is not able to read cross-origin content (without proxy), distinguish :visited links, display OS-specific forms, and a whole lot of CSS properties that html2canvas still doesn't support.

As my implementation runs on WebGL, it can run on all browsers that support WebGL. As such, the samples should work with current stable versions of both Firefox and Chrome (sorry Opera, feel free to add prefixes etc.). My implementation also allows you to define shader attributes through JavaScript, so you can for example access the mouse coordinates within the shaders.

Samples

Most of these samples are by Adobe, slightly modified to include my CSS shader implementation to them.

Simple

Advanced

Conclusion

Personally, I think CSS shaders are the biggest thing that CSS has ever had coming for it, so I certainly hope the support for it won't end with webkit browsers. However, as Microsoft currently has no intentions to implement WebGL into Internet Explorer, I certainly don't see them implementing CSS shaders (which really has more security issues than just WebGL). I'd like to also note that this implementation is just a prototype experiment and as such still consists of many bugs and I wouldn't recommend using it in any production environment. If you would like to see how the native CSS shaders currently work in Chrome, you can either download the webkit prototype by Adobe or enable them with the command flag --enable-css-shaders.

Credits

The script uses the following libraries: