- Knowledge needed: CSS, Intermediate JavaScript
- Requires: Text editor, browser that supports CSS3 transforms
This article reveals how to use CSS transforms to create a zoomable user interface similar to that of 2011.beercamp.com. In this, you’ll also learn how to use JavaScript to hijack scrolling to manipulate the zoom
With CSS3 transforms now supported in most major browsers, we have the delightful opportunity to create innovative layouts and interfaces. No longer are we shackled in our one-dimensional prisons, bound to the tyranny of vertically-scrolling sites.
With the site for BeerCamp at SXSW 2011, we at nclud recognised an ideal opportunity to bend some rules and try something new. I got the idea to leverage CSS transforms for the layout. Instead of the typical vertical scrolling site, where you traversed it downwards, this would could be traversed inwards. This is sort of design pattern has been categorised as a zoomable user interface or ZUI.
The BeerCamp at SXSW 2011 was an experiment in using CSS transforms to create a new interface design pattern. In this tutorial, we’ll build a zoomable user interface into a simple page. You’ll learn how to use CSS transforms to create a zoomable layout. You’ll also learn how to use JavaScript to hijack scrolling to manipulate the zoom.
Our example page lists the services of a web development shop. The services listed range from the broad to the specific. This content is well suited for a zoomable layout, as the subsequent sections are smaller segments of the previous sections. By placing one visual element inside another, you’re visually communicating the relationship between pieces of content.
- Knowledge needed: CSS, Intermediate JavaScript
- Requires: Text editor, browser that supports CSS3 transforms
David DeSandro reveals how to use CSS transforms to create a zoomable user interface similar to that of 2011.beercamp.com. In this tutorial, you’ll also learn how to use JavaScript to hijack scrolling to manipulate the zoom
With CSS3 transforms now supported in most major browsers, we have the delightful opportunity to create innovative layouts and interfaces. No longer are we shackled in our one-dimensional prisons, bound to the tyranny of vertically-scrolling sites.
With the site for BeerCamp at SXSW 2011, we at nclud recognised an ideal opportunity to bend some rules and try something new. I got the idea to leverage CSS transforms for the layout. Instead of the typical vertical scrolling site, where you traversed it downwards, this would could be traversed inwards. This is sort of design pattern has been categorised as a zoomable user interface or ZUI.
The BeerCamp at SXSW 2011 was an experiment in using CSS transforms to create a new interface design pattern. In this tutorial, we’ll build a zoomable user interface into a simple page. You’ll learn how to use CSS transforms to create a zoomable layout. You’ll also learn how to use JavaScript to hijack scrolling to manipulate the zoom.
Our example page lists the services of a web development shop. The services listed range from the broad to the specific. This content is well suited for a zoomable layout, as the subsequent sections are smaller segments of the previous sections. By placing one visual element inside another, you’re visually communicating the relationship between pieces of content.
Advertisement
Basic layout
Prior to the ZUI layout, the basic layout is designed for browsers that don’t support CSS transforms or have JavaScript disabled. The markup looks like this:- <div id="wrap">
- <div id="container">
- <ul id="nav">
- <li><a href="#web-dev">Web development</a></li>
- <li><a href="#front-end">Front-end development</a></li>
- <li><a href="#css">CSS</a></li>
- <li><a href="#css3">CSS3</a></li>
- <li><a href="#transforms">Transforms</a></li>
- </ul>
- <div id="content">
- <section id="web-dev">...</section>
- <section id="front-end">...</section>
- <section id="css">...</section>
- <section id="css3">...</section>
- <section id="transforms">...</section>
- </div> <!-- #content -->
- </div> <!-- #container -->
- </div> <!-- #wrap -->
For the zoomable layout, we need to consider how each section fits inside one another. I’ve chosen a ratio of 3:1 for the proportion between the current section and its subsequent section. This means the parent will have enough room for content, and the child container will still be visible.
Each section will be 900px x 540px so it fits within most browser windows. Subsequent sections will appear to be one-third the full size, 300px x 180px. You’ll notice this space in the centre of each section has been reserved for the subsequent sections to fit inside once CSS transforms are put in place. (See Demo 1: Basic layout.)
Now we can start adding CSS transforms. First let’s add Modernizr so we have more control over how browsers will inherit their styles. I’ve opted to use a custom build from the Modernizr 2.0 beta preview that only tests for CSS 2D transforms and CSS transitions. After adding the Modernizr code to our scripts, we can target browsers that support transforms with .csstransforms in our CSS. To scale each section inside one another, they first need to occupy the same space. This can be done with absolute positioning.
- /* absolute positioning */
- .csstransforms #container { position: relative; }
- .csstransforms #content { position: absolute; }
- .csstransforms section { position: absolute; }
- zoomScale = inverse ratio ^ zero-based-level
- /* level index 1: (1/3) ^ 1 = 1/3 = 0.3333 */
- .csstransforms #front-end {
- -webkit-transform: scale(0.3333);
- -moz-transform: scale(0.3333);
- -o-transform: scale(0.3333);
- transform: scale(0.3333);
- }
- /* level index 2: (1/3) ^ 2 ) = 1/9 = 0.1111 */
- .csstransforms #css {
- -webkit-transform: scale(0.1111);
- -moz-transform: scale(0.1111);
- -o-transform: scale(0.1111);
- transform: scale(0.1111);
- }
- /* level index 3: (1/3) ^ 3 = 1/27 = 0.0370 */
- .csstransforms #css3 {
- -webkit-transform: scale(0.037);
- -moz-transform: scale(0.037);
- -o-transform: scale(0.037);
- transform: scale(0.037);
- }
- /* level index 4: (1/3) ^ 4 = 1/81 = 0.0123456 */
- .csstransforms #transforms {
- -webkit-transform: scale(0.0123456);
- -moz-transform: scale(0.0123456);
- -o-transform: scale(0.0123456);
- transform: scale(0.0123456);
- }
Each section is positioned inside one another using CSS scale transforms. You can see the second section within the first and the others deeper within. Now we need to build a mechanism to let the user zoom in.
To zoom in to a section, we only need to apply its reciprocal scale to the sections’ parent #content. All child sections will scale up accordingly. The scale is equal to the ratio to the exponent of level’s zero-base index. The second section #front-end has a scale of 1/3, so it needs to be scaled 3x to bring it to 100% size.
- zoomScale = ratio ^ zero-based-level
- /* view #css3, level index 3 = 3 ^ 3 = 27 */
- .csstransforms #content {
- -webkit-transform: scale(27);
- -moz-transform: scale(27);
- -o-transform: scale(27);
- transform: scale(27);
- }
Scroll
Leveraging window scrolling is a natural convenient interaction to hook zooming into. Along side clicking and pointing, scrolling is a natural interaction that anyone with a mouse or keyboard uses. Currently there isn’t anything to scroll, since the entire page is self-contained in that 900 x 540 area. But we can fake it by adding an empty element that has height, which will serve as our proxy. The markup will be added after #wrap.- </div> <!-- #wrap -->
- <div id="scroller"></div>
- .csstransforms #scroller { height: 4000px; }
- /* prevent content from scrolling */
- #wrap {
- position: fixed;
- width: 100%;
- }
JavaScript
The basic idea is that we are going to hijack the scroll event and do something with it.As all this script will only need to run if the browser supports CSS transforms, we can encapsulate our entire script in a self-executing function, which will only proceed if CSS transforms are supported.
- (function(){
- // only proceed if CSS transforms are supported
- if ( !Modernizr.csstransforms ) {
- return;
- }
- // CSS transforms supported, continue...
- })();
- // the constructor that will do all the work
- function Zoomer( content ) {
- // keep track of DOM
- this.content = content;
- // position of vertical scroll
- this.scrolled = 0;
- // zero-based number of sections
- this.levels = 4;
- // height of document
- this.docHeight = document.documentElement.offsetHeight;
- // bind Zoomer to scroll event
- window.addEventListener( 'scroll', this, false);
- }
- // enables constructor to be used within event listener
- // like obj.addEventListener( eventName, this, false )
- Zoomer.prototype.handleEvent = function( event ) {
- if ( this[event.type] ) {
- this[event.type](event);
- }
- };
this.scrolled is a normalised decimal value, from 0 to 1, that represents the position of the scrolled page.
- // triggered every time window scrolls
- Zoomer.prototype.scroll = function( event ) {
- // normalize scroll value from 0 to 1
- this.scrolled = window.scrollY / ( this.docHeight - window.innerHeight );
- };
Its value goes from 0 to 1, so we need to multiply it by the zero-based number of sections.
- <code>zoomScale = ratio ^ ( percentage * levels )</code>
- // triggered every time window scrolls
- Zoomer.prototype.scroll = function( event ) {
- // normalize scroll value from 0 to 1
- this.scrolled = window.scrollY / ( this.docHeight - window.innerHeight );
- var scale = Math.pow( 3, this.scrolled * this.levels ),
- transformValue = 'scale('+scale+')';
- this.content.style.WebkitTransform = transformValue;
- this.content.style.MozTransform = transformValue;
- this.content.style.OTransform = transformValue;
- this.content.style.transform = transformValue;
- };
- function init() {
- var content = document.getElementById('content'),
- // init Zoomer constructor
- ZUI = new Zoomer( content );
- }
- window.addEventListener( 'DOMContentLoaded', init, false );
If done correctly, when you scroll to the bottom of the page, you’ll zoom in perfectly to the last section.
No comments:
Post a Comment