CSS 3D Clouds Retake

This post is going to cover my experience following through the tutorial on making CSS 3D clouds posted here: http://www.clicktorelease.com/tutorials/css3dclouds/. I didn’t make the original code, but I did run into several issues while I went through and I wanted to share my experience, work-arounds, and pieces of code that were missing from the original tutorial.

All the questions that came up and fixes changes here were done on the Chrome Beta (v20.0.1132.41 beta-m to be exact)

1. Creating the world and a camera

CSS 3D Clouds Step 1

In this step, you create two div’s in the body of your HTML 5 page, the outer <div> gets an id of viewport and the inner <div> gets an id of world. From there you setup some structural styling (viewport spans entire screen via absolute positioning, world is centered in the middle)

Initial Page Setup

Some initial styling needs to be done to make it look like the demo, here’s what I have:

  1. * {
  2. box-sizing: border-box;
  3. margin: 0;
  4. padding: 0;
  5. }
  6.  
  7. body {
  8. overflow: hidden;
  9. }
  10.  
  11. #viewport {
  12. background-image: linear-gradient(bottom, rgb(69, 132, 180) 28%, rgb( 31, 71, 120 ) 64%);
  13. background-image: -o-linear-gradient(bottom, rgb(69, 132, 180) 28%, rgb( 31, 71, 120 ) 64%);
  14. background-image: -moz-linear-gradient(bottom, rgb(69, 132, 180) 28%, rgb( 31, 71, 120 ) 64%);
  15. background-image: -webkit-linear-gradient(bottom, rgb(69, 132, 180) 28%, rgb( 31, 71, 120 ) 64%);
  16. background-image: -ms-linear-gradient(bottom, rgb(69, 132, 180) 28%, rgb( 31, 71, 120 ) 64%);
  17. }
  18.  
  19. #world {
  20. background-color: rgba(255, 0, 0, .2);
  21. }

Vendor prefixes

I’m so used to Chrome being the “latest and greatest” that I honestly expected to be able to use non-prefixed CSS properties and have the code “just work”. That’s NOT the case. As of this writing you will need to use prefixed properties, so add the following prefixes into the appropriate rules:

  1. #viewport {
  2. perspective: 400;
  3. -webkit-perspective: 400;
  4. -moz-perspective: 400;
  5. -o-perspective: 400;
  6. }
  7.  
  8. #world {
  9. transform-style: preserve-3d;
  10. -webkit-transform-style: preserve-3d;
  11. -moz-transform-style: preserve-3d;
  12. -o-transform-style: preserve-3d;
  13. }

Help, my javascript code doesn’t work!

You probably put your javascript in the <head> tag, which means that

  1. document.getElementById( 'world' )

will not work because the elements don’t exist yet. Put the script at the end right before the </body> tag and it should work if everything else is correct.

Besides, it’s just good practice to put your javascript last.

Help, my javascript code doesn’t work! (pt 2)

This just shows my ignorance of javascript, but if something still isn’t working, you might have this problem:

Javascript uses the \ character in your strings to tell the parser to treat the next line as if the string continued:

  1. 'translateZ( ' + d + 'px ) \
  2. rotateX( ' + worldXAngle + 'deg) \
  3. rotateY( ' + worldYAngle + 'deg)';

Is the same as:

  1. 'translateZ( ' + d + 'px ) rotateX( ' + worldXAngle + 'deg) rotateY( ' + worldYAngle + 'deg)';

Zooming javascript

The code samples in the original tutorial omit the code to zoom in and out with the mouse wheel. Here it is in all it’s javascripty wonderfulness:

  1. window.addEventListener( 'mousewheel', onContainerMouseWheel );
  2. window.addEventListener( 'DOMMouseScroll', onContainerMouseWheel );
  3.  
  4. function onContainerMouseWheel( event ) {
  5. event = event ? event : window.event;
  6. d = d - (event.detail ? event.detail * -5 : event.wheelDelta / 8);
  7. updateView();
  8. }

2. Adding objects to our world

CSS 3D Clouds Step 2
E.g. .cloudBase.

Create cloud base code is incorrect

Instead of:

  1. for( var j = 0; j <<; 5; j++ ) {

the correct line is:

  1. for( var j = 0; j < 5; j++ ) {

Actual random numbers and prefixed transforms

The random numbers for createCloud():

  1. var random_x = 256 - ( Math.random() * 512 );
  2. var random_y = 256 - ( Math.random() * 512 );
  3. var random_z = 256 - ( Math.random() * 512 );

The transform styles for createCloud()

  1. div.style.transform = t;
  2. div.style.webkitTransform = t;
  3. div.style.MozTransform = t;
  4. div.style.oTransform = t;

3. Adding layers to our objects

CSS 3D Clouds Step 3
There were a couple of things in this section that cause me to scratch my head and go whyyyyy?

Code for random generation and transforms.

Random variables:

  1. var random_x = 256 - ( Math.random() * 512 );
  2. var random_y = 256 - ( Math.random() * 512 );
  3. var random_z = 100 - ( Math.random() * 200 );
  4. var random_a = Math.random() * 360;
  5. var random_s = .25 + Math.random();
  6. random_x *= .2; random_y *= .2;

Vendor transforms:

  1. cloud.style.transform = t;
  2. cloud.style.webkitTransform = t;
  3. cloud.style.MozTransform = t;
  4. cloud.style.oTransform = t;

Why don’t I see the new squares?

You have to add in the style for .cloudLayer into your CSS:

  1. .cloudLayer {
  2. position: absolute;
  3. left: 50%;
  4. top: 50%;
  5. width: 256px;
  6. height: 256px;
  7. margin-left: -128px;
  8. margin-top: -128px;
  9. background-color: rgba( 0, 255, 255, .1 );
  10. -webkit-transition: opacity .5s ease-out;
  11. -moz-transition: opacity .5s ease-out;
  12. -o-transition: opacity .5s ease-out;
  13. }

I see the cloud layers, but why are they are all flat?

Yeah, this got me too, the parent div’s need to have preserve-3d, so add this into your CSS:

  1. #world div {
  2. transform-style: preserve-3d;
  3. -webkit-transform-style: preserve-3d;
  4. -moz-transform-style: preserve-3d;
  5. -o-transform-style: preserve-3d;
  6. }

4. Making the 3D effect work

CSS 3D Clouds Step 4

This section is essentially “make the layers point at the camera”. You still want them projected into the same locations, but you want them to always face the camera, giving you that sense of “volume” effect.

Vendor Transforms and Update()

First, here’s all the vendor transforms:

  1. layer.style.transform = t;
  2. layer.style.webkitTransform = t;
  3. layer.style.MozTransform = t;
  4. layer.style.oTransform = t;

Now, you also need to call this update manually once right before the end of your script. So right before the closing script tag, make sure you call this:

  1. update();

Render Loop

Finally, even if you do this, you’ll notice that your layers still don’t point at the camera. You need to add in a function that loops and updates the layers in the #viewport at regular intervals. You could add a call to the update function inside your mouse move event, but we’ll need the loop to get the rotation to work in the next step, so it’s better if you just do this now.

  1. (function() {
  2. var lastTime = 0;
  3. var vendors = ['ms', 'moz', 'webkit', 'o'];
  4. for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
  5. window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
  6. window.cancelRequestAnimationFrame = window[vendors[x]+
  7. 'CancelRequestAnimationFrame'];
  8. }
  9.  
  10. if (!window.requestAnimationFrame)
  11. window.requestAnimationFrame = function(callback, element) {
  12. var currTime = new Date().getTime();
  13. var timeToCall = Math.max(0, 16 - (currTime - lastTime));
  14. var id = window.setTimeout(function() { callback(currTime + timeToCall); },
  15. timeToCall);
  16. lastTime = currTime + timeToCall;
  17. return id;
  18. };
  19.  
  20. if (!window.cancelAnimationFrame)
  21. window.cancelAnimationFrame = function(id) {
  22. clearTimeout(id);
  23. };
  24. }())

Lets break this down. I discovered that this function is a polyfill for the browser animation spec here one Paul Irish’s awesome blog http://paulirish.com/2011/requestanimationframe-for-smart-animating/. Previously, when you would animate something, you would set a timer, and every few milliseconds go and update move something from point A to point B on the screen with a small increment. In order to get smoother animations, the browsers are starting to support this requestAnimationFrame function that allows several changes to be made, and update everything with a single reflow / redraw of the screen. This becomes especially handy when you are updating multiple elements on the screen and you want a clean responsive display. It also means that the browser can stop animating when you switch tabs, which means that you don’t eat up battery when someone isn’t looking at your page :)

All you really need to know is that this creates a function on the javascript window object that tells the browser to “please render an animation frame, and call back to this function when you are done and ready to render the next frame”.

5. Final words

CSS 3D Clouds Step 5

Subtle Rotating

Not mentioned, but if you want the clouds to slowly rotate like the demo, you need to add in the rotate z component into the transform update of your layers like so:

  1. 'rotateZ( ' + layer.data.a + 'deg ) /

And, you need to add in a speed property into your cloud layers when you create them:

  1. speed: .2 * Math.random() - .1

Adding Cloud Images

Instead of this:

  1. var cloud = document.createElement( 'div' );

Use this (or find your own cloud .png, it should be transparent to work properly)

  1. var cloud = document.createElement( 'img' );
  2. cloud.style.opacity = 0;
  3. var src = 'http://www.clicktorelease.com/tutorials/css3dclouds/cloud.png';
  4. ( function( img ) {
  5. img.addEventListener( 'load', function() {
  6. img.style.opacity = .8;
  7. } )
  8. } )( cloud );
  9. cloud.setAttribute( 'src', src );

And finally to remove all the debug styles remove the following lines out of your CSS:

From #world remove:

  1. background-color: rgba(255, 0, 0, .2);

From .cloudBase remove:

  1. background-color: rgba( 255, 0, 255, .5 );

From .cloudLayer remove:

  1. background-color: rgba( 0, 255, 255, .1 );

That should cover it! Now go make some happy clouds.

Credits

Everything here was completely taken from the Click To Release CSS 3D Clouds tutorial and expanded to include the missing parts.

Releasing: Comatose WordPress Theme

This has been in the pipe a long time, it started simply as a set of experiments playing with HTML 5, layouts, responsive design, page structure, typeography, displaying images on mobile screens, the mobile web, minimalism, and my own dislike with the previous design(s) of my site. Finally, I decided to turn it into a full fledged WordPress theme. This is the result. It powers my site, and the InterKnowlogy development blogs where I work.

So here is the low down:

  • HTML 5 layout with CSS 3 styling
  • Responsive Layout
  • Clean, minimalist design
  • Print style
  • Clean, readable, and consistent text styling.
  • Clean and readable typography.
  • Clean display of code.
  • Beautiful images
  • Images display at native resolution on Regular and High Density screens
  • Widget enabled sidebar support
  • Nested comment support
  • Gravatar image integration for comments (High resolution images for High Density screens)
  • Custom menu support
  • Nested sub-sub-sub menu support
  • Graceful degradation in older browsers

But don’t take my word for it. Download links, versions and release notes are all on the project page:
http://www.paulrohde.com/development/comatose/

And all of the source code is hosted on GitHub.

Desktop Screenshots

Comatose Windows with Chrome showing Sidebar

iPad Retina Screenshots

Menu

Comatose iPad Retina Menu

See more screenshots

Folding The Web

I’ve got a bone to pick, and maybe it’s not even worth picking but here it is: Most of the responsive grids on the web today suck. Responsive grids are hard to do right. A responsive site has to be well planned out, is difficult to implement, and are usually prone to an overabundance of excess styling to get it to work right and a lack of re-usability. That’s where a framework comes in, and although most of them help a little in some form or another, they don’t meet the overly high expectations I have for them. Of the better ones I’ve seen over the last several months, the best one I’ve looked at so far is the one in the twitter bootstrap framework:

http://twitter.github.com/bootstrap/index.html – (See the scaffolding section for more about the Grid)

As much as these frameworks are getting closer to what I want, most of them still suffer from one big problem: They only have two modes. If you look closely as you size down your browser on the bootstrap site, the sites snaps, then snaps again, and finally the content re-arranges down to a single column. What I really dislike about this, is that there are no intermediate steps between desktop and mobile. Yes, the size is different, and it helps a LOT, but the layout doesn’t change.

One of the more obvious, and disturbingly annoying, examples of this two mode thinking is Zurb Foundation, because not only do they lack the intermediary step sizing, but the way it’s done causes some pieces of content to MASSIVLY increase in size in mobile layout. You’ll probably notice it most when it causes images to get resized into pixelated, oversampled, Web 1.0 stock image nastiness that makes graphic designers cry. Seriously. In mobile layout, your content should never be larger than it is in a wide, full width desktop environment:


*sob*

So. Do I have a solution? Not completely. But I do have a demo of something cool I’ve been working on as I’ve been refining my ideas on how a responsive grid I would want to work with would behave. Take a look at it here:

http://www.paulrohde.com/demo/foldr/tests.html

It includes nesting grids and has a fully fluid layout. I’m still working on how I can make the grid more robust and get it to work in situations where the container itself is centered or fixed. I also want to include and make more complicated layout re-arrangement behaviors (like inlining a sidebar below your main content, or expanding a menu, and so on like you might have seen with the theme on my site) easier to do.

(Obligatory Screenshot)

Finally, I can’t rightly write a post like this without pointing out some great sources of inspiration: First, the Golden Grid System by Joni Korpi, which is a great example of a responsive site, even though I always feel like it’s overdone on a big monitor. Another really good article that I feel really marked the start of people thinking about a responsive web is an article on A List Apart on responsive web design by Ethan Marcotte. Finally, this post by Paul Irish on why you should only build and serve one layout of your site, and why you should be designing towards the modern web.

Happy Folding. Look for more posts on this in the nearish future.

Font Hybridization in HTML 5

Over this Christmas break, I was over at a friends house and got to sit down and tinker with my friends Mac. I’d forgotten how good fonts look, and I suddenly realized why so many sites are now using custom web fonts. Since I primarily use Windows at work and at home, I get annoyed by fonts that are difficult to read or that don’t render well on the screen. Somehow, I’ve never been 100% happy with font rendering on windows. It’s been getting better, but it’s still not as good as a Mac is. Maybe its the screen, maybe its the OS, maybe its the app, maybe its a combination of all of the above. Because I’ve been on this HTML kick, and I’m on windows, I’ve tended toward Cufon as my font replacement tool of choice when building sites since it’s the only one that produces a “more-reasonable” output on my machine.

But Cufon by it’s nature has several drawbacks. First, you can’t copy and paste text rendered with Cufon. With most of the newer browsers you can select it, but there’s not much more you can do beyond that. So, I usually limit Cufon usage to titles, headers, and the more “design-ery” aspects of a page. Second, because Cufon is image based, if someone zooms in on your text beyond 100% Cufon rendered text gets all fuzzy the same way it would if you zoomed in on an image. And finally, because Cufon renders with javascript on the client, there’s no way to cache the text. Javascript is fast, but when you’re rendering a large amount of text on a phone, there’s usually not a good way around a flash of unstyled content. And it happens each time you go to a new page because it can’t be cached.

Web fonts on the other hand, allow you to use fonts in a very similar manner as if you had them installed on your device with native rendering by the OS. You can select, copy, paste, and use it as you would any other piece of text. Web fonts are cacheable, so although you could get a flash of unstyled content when you first visit a page, subsequent visits should render immediately. The disadvantage however, is the OS. On windows, the rendering of fonts just… Sucks. So people don’t use it.

But what if there was a way to do a hybrid between Cufon and Web Fonts?

Besides the rendering issue, Web Fonts are the best option. They’re the most flexible and the most future proof. But they still suffer on Windows, some phones, and on older browsers that don’t support the new @font-face CSS syntax. So what if we did a hybrid? Use @font-face, then fall back on Cufon for older browsers, and for windows. The advantage is that on a new browser the@font-face‘s will be cached, used for the initial rendering of the page, and then cleaned up with Cufon later.

Using Modernizr and a little custom javascript to do user agent testing I put together a page to test out the hybrid font idea:

http://www.paulrohde.com/demo/cufon-hybrid/demo.html

It’s a rough draft. I have some screen shots below from both Mac and PC’s (click for full size versions).

Mac


PC


For simplicity, the javascript code to test and load Cufon and my custom cufon polyfill looks like this:

  1.  
  2. function rendersNiceFontface() {
  3. result = navigator.appVersion.indexOf("Win") != -1
  4. || navigator.appVersion.indexOf("Android") != -1;
  5. return result;
  6. }
  7.  
  8. var supportsNiceFontface = !rendersNiceFontface();
  9.  
  10. Modernizr.load([
  11. {
  12. test : Modernizr.fontface && Modernizr.canvas && supportsNiceFontface,
  13.  
  14. nope : [ 'cufon-yui.js', 'BebasNeueRegular_400.font.js', 'cufon-polyfill.js' ]
  15. }
  16. ])
  17.  

Using the Modernizr yepnope.js, I’m able to completely skip loading Cufon at all if the browser supports good @font-face rules. There’s more that I’d have to do to clean it up before I’d use it in a real setting, but it demonstrate the concept, and is something I could definitely use later as a @font-face polyfill. It does have some drawbacks though, you have to maintain both your CSS rules and your Cufon replacement calls, and Cufon doesn’t work well with a large amount of body text, so if you don’t support @font-face, I’d fall back to a good secondary font and forgo Cufon in those cases.

I hope this got some gears turning, I’m looking forward to some comments.

Tip: Using zoom to target images to high density displays

I found this several days ago when I was looking for a way to scale images on an iPhone inside of a fluid layout such that they would display at a 1:1 pixel ratio. If you didn’t already know, the iPhone 4 and 4S displays everything as if the screen was the same size as a normal iPhone when it measures and does the layout. The result is that all the text looks extremely crisp, and any sites already designed for the original iPhone don’t break or look weird. With images this means that a 300 x 300 pixel image displays the correct size in the layout, but is essentially scaled up to fit over 600×600 “physical pixels”. As I was poking around I found an old CSS zoom property here: http://reference.sitepoint.com/css/zoom that for some reason works on mobile safari. Add a media query for 2x density screens, and viola! Your images now display at physical pixel dimensions on the iPhone 4 and 4S.

Here’s what the CSS looks like:

@media screen and (-webkit-min-device-pixel-ratio: 2) {
     img {
          zoom: 50%;
     }
}

Awesome hacks.

Happy img scaling.