├── .gitignore ├── img ├── calc.png ├── box01.png ├── box02.png ├── cube01.png ├── cube02.png ├── diagram.png ├── card-flip01.png ├── card-flip02.png ├── carousel01.png ├── david-desandro.jpg ├── perspective01.png ├── perspective02.png ├── pixelation01.png ├── transforms01.png ├── perspective-children01.png └── weather-app-transition.jpg ├── _config.yml ├── js ├── flip-card.js ├── switch-steps.js ├── rotate-box.js └── utils.js ├── _layouts ├── example.html └── doc.html ├── _includes ├── footer.html ├── docs-nav.html └── html-head.html ├── README.md ├── index.html ├── _posts ├── examples │ ├── 2010-12-02-transforms-02-pixelation.html │ ├── 2010-12-01-perspective-01.html │ ├── 2010-12-03-card-01.html │ ├── 2010-12-01-perspective-02-children.html │ ├── 2010-12-02-transforms-01-functions.html │ ├── 2010-12-03-card-02-slide-flip.html │ ├── 2010-12-03-card-03-slide-flip-2-ways.html │ ├── 2010-12-04-cube-01-steps.html │ ├── 2010-12-05-box-01-steps.html │ ├── 2010-12-04-cube-02-show-sides.html │ ├── 2010-12-06-carousel-01.html │ ├── 2010-12-05-box-02-show-sides.html │ ├── 2010-12-06-carousel-02-dynamic.html │ ├── 2010-12-02-transforms-03-origin.html │ └── 2010-12-01-perspective-03.html └── docs │ ├── 2010-12-08-conclusion.md │ ├── 2010-12-02-perspective.md │ ├── 2010-12-03-3d-transform-functions.md │ ├── 2010-12-06-rectangular-prism.md │ ├── 2010-12-01-introduction.md │ ├── 2010-12-04-card-flip.md │ ├── 2010-12-07-carousel.md │ └── 2010-12-05-cube.md └── css └── style.css /.gitignore: -------------------------------------------------------------------------------- 1 | _site -------------------------------------------------------------------------------- /img/calc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrummerHead/3dtransforms/gh-pages/img/calc.png -------------------------------------------------------------------------------- /img/box01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrummerHead/3dtransforms/gh-pages/img/box01.png -------------------------------------------------------------------------------- /img/box02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrummerHead/3dtransforms/gh-pages/img/box02.png -------------------------------------------------------------------------------- /img/cube01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrummerHead/3dtransforms/gh-pages/img/cube01.png -------------------------------------------------------------------------------- /img/cube02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrummerHead/3dtransforms/gh-pages/img/cube02.png -------------------------------------------------------------------------------- /img/diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrummerHead/3dtransforms/gh-pages/img/diagram.png -------------------------------------------------------------------------------- /img/card-flip01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrummerHead/3dtransforms/gh-pages/img/card-flip01.png -------------------------------------------------------------------------------- /img/card-flip02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrummerHead/3dtransforms/gh-pages/img/card-flip02.png -------------------------------------------------------------------------------- /img/carousel01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrummerHead/3dtransforms/gh-pages/img/carousel01.png -------------------------------------------------------------------------------- /img/david-desandro.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrummerHead/3dtransforms/gh-pages/img/david-desandro.jpg -------------------------------------------------------------------------------- /img/perspective01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrummerHead/3dtransforms/gh-pages/img/perspective01.png -------------------------------------------------------------------------------- /img/perspective02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrummerHead/3dtransforms/gh-pages/img/perspective02.png -------------------------------------------------------------------------------- /img/pixelation01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrummerHead/3dtransforms/gh-pages/img/pixelation01.png -------------------------------------------------------------------------------- /img/transforms01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrummerHead/3dtransforms/gh-pages/img/transforms01.png -------------------------------------------------------------------------------- /img/perspective-children01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrummerHead/3dtransforms/gh-pages/img/perspective-children01.png -------------------------------------------------------------------------------- /img/weather-app-transition.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrummerHead/3dtransforms/gh-pages/img/weather-app-transition.jpg -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | # auto: true 2 | pygments: true 3 | permalink: /:categories/:title.html 4 | 5 | # site-wide data 6 | site_name: Intro to CSS 3D transforms -------------------------------------------------------------------------------- /js/flip-card.js: -------------------------------------------------------------------------------- 1 | var init = function() { 2 | var card = document.getElementById('card'); 3 | 4 | document.getElementById('flip').addEventListener( 'click', function(){ 5 | card.toggleClassName('flipped'); 6 | }, false); 7 | }; 8 | 9 | window.addEventListener('DOMContentLoaded', init, false); -------------------------------------------------------------------------------- /_layouts/example.html: -------------------------------------------------------------------------------- 1 | {% assign section = 'Examples' %} 2 | {% assign root_path = '../' %} 3 | {% include html-head.html %} 4 | 5 | {{ content }} 6 | 7 |

Sorry, your browser does not support CSS 3D transforms. This example may be broken.

8 | 9 | {% include footer.html %} 10 | 11 | 12 | -------------------------------------------------------------------------------- /_layouts/doc.html: -------------------------------------------------------------------------------- 1 | {% assign root_path = '../' %} 2 | {% assign section = 'Docs' %} 3 | {% include html-head.html %} 4 | 5 | 6 | 7 | 8 | {% include docs-nav.html %} 9 | 10 |
11 | 12 |

{{ page.title }}

13 | 14 | {{ content }} 15 | 16 |
17 | 18 | {% include footer.html %} 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /_includes/footer.html: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /_includes/docs-nav.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 11 |
12 |
-------------------------------------------------------------------------------- /_includes/html-head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {% if page.title %}{{ page.title }} · {% endif %}{{ site.site_name }}{% if section %} › {{ section }}{% endif %} 10 | 11 | 12 | -------------------------------------------------------------------------------- /js/switch-steps.js: -------------------------------------------------------------------------------- 1 | var init = function() { 2 | var container = document.querySelector('.container'), 3 | buttons = document.querySelectorAll('#options button'), 4 | containerClass = 'step1', 5 | 6 | onButtonClick = function(event) { 7 | container.removeClassName( containerClass ); 8 | containerClass = event.target.className; 9 | container.addClassName( containerClass ); 10 | }; 11 | 12 | for ( var i=0, len = buttons.length; i < len; i++ ) { 13 | buttons[i].addEventListener( 'click', onButtonClick, false ); 14 | } 15 | 16 | }; 17 | 18 | window.addEventListener('DOMContentLoaded', init, false); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Intro to CSS 3D transforms 2 | 3 | By [David DeSandro](http://desandro.com) 4 | 5 | [desandro.github.io/3dtransforms](http://desandro.github.io/3dtransforms) 6 | 7 | Tutorial, examples, and discussion all about CSS 3D transforms. 8 | 9 | Originally written for [24 ways 2010](http://24ways.org/2010/intro-to-css-3d-transforms). 10 | 11 | ## Viewing this project locally 12 | 13 | This project is built with [Jekyll](https://jekyllrb.com). 14 | 15 | git clone https://github.com/desandro/3dtransforms.git 16 | cd 3dtransforms/ 17 | jekyll serve 18 | 19 | ## License 20 | 21 | Written content is licensed under a [Creative Commons Attribution License](http://creativecommons.org/licenses/by/4.0/). 22 | 23 | Example code is licensed under the [MIT license](http://desandro.mit-license.org). Have at it. 24 | -------------------------------------------------------------------------------- /js/rotate-box.js: -------------------------------------------------------------------------------- 1 | var init = function() { 2 | var box = document.querySelector('.container').children[0], 3 | showPanelButtons = document.querySelectorAll('#show-buttons button'), 4 | panelClassName = 'show-front', 5 | 6 | onButtonClick = function( event ){ 7 | box.removeClassName( panelClassName ); 8 | panelClassName = event.target.className; 9 | box.addClassName( panelClassName ); 10 | }; 11 | 12 | for (var i=0, len = showPanelButtons.length; i < len; i++) { 13 | showPanelButtons[i].addEventListener( 'click', onButtonClick, false); 14 | } 15 | 16 | document.getElementById('toggle-backface-visibility').addEventListener( 'click', function(){ 17 | box.toggleClassName('panels-backface-invisible'); 18 | }, false); 19 | 20 | }; 21 | 22 | window.addEventListener( 'DOMContentLoaded', init, false); -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: nil 3 | title: Intro to CSS 3D transforms 4 | --- 5 | {% assign root_path = '' %} 6 | {% include html-head.html %} 7 | 8 | 9 | 10 | 11 |

{{ site.site_name }}

12 | 13 |

By David DeSandro

14 | 15 | 23 | 24 | 32 | 33 |

Project home: github.com/desandro/3dtransforms

34 | 35 | 36 | -------------------------------------------------------------------------------- /_posts/examples/2010-12-02-transforms-02-pixelation.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: example 3 | title: Transforms 2 - pixelation 4 | category: examples 5 | --- 6 | 7 | 33 | 34 | 35 | 36 | 37 |

{{ page.title }}

38 | 39 |

font-size: 2.5em

40 |

transform: scale(2.5);

41 |

transform: perspective(1200) translateZ(700px);

42 | 43 | 44 | -------------------------------------------------------------------------------- /_posts/docs/2010-12-08-conclusion.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: Conclusion 4 | layout: doc 5 | category: docs 6 | 7 | --- 8 | 9 | 10 | 3D transforms change the way we think about the blank canvas of web design. Better yet, they change canvas itself, trading in the flat surface for an voluminous installation. 11 | 12 | My hope is that you took at least one peak a demo and were intrigued. We web designers, who have rejoiced for border-radius, box-shadow, and background gradient, now have an incredible tool at our disposal in 3D transforms. They deserve just the same enthusiasm, research, and experimentation we have spent on the previous browser features. Now is the perfect time to figuratively take the plunge and start thinking about how leveraging three dimensions can elevate our craft. I'm enthralled to witness what's to come. 13 | 14 | See you on the flip side. 15 | 16 | * * * 17 | 18 | ## About the author 19 | 20 | If the Web were a coloring book, [**David DeSandro**](http://desandro.com) would be the kid manically scribbling outside the lines of every page, whittling away his front-end development crayons to wee nubs. Lucky for him, he's paid to do the thing he loves, creating engaging, innovative interfaces at [nclud](http://nclud.com). Come nightfall, he dons a cape, develops [resources](http://github.com/desandro), journals his [discoveries](http://dropshado.ws), and fights crime around Washington DC. -------------------------------------------------------------------------------- /_posts/examples/2010-12-01-perspective-01.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: example 3 | title: Perspective 1 4 | category: examples 5 | --- 6 | 7 | 44 | 45 | 46 | 47 | 48 |

{{ page.title }}

49 | 50 | {% highlight css %} 51 | 52 | #red .box { 53 | background-color: red; 54 | transform: perspective( 600px ) rotateY( 45deg ); 55 | } 56 | 57 | {% endhighlight %} 58 | 59 |
60 |
61 |
62 | 63 | {% highlight css %} 64 | 65 | #blue { 66 | perspective: 600px; 67 | } 68 | 69 | #blue .box { 70 | background-color: blue; 71 | transform: rotateY( 45deg ); 72 | } 73 | 74 | {% endhighlight %} 75 | 76 |
77 |
78 |
79 | 80 | 81 | -------------------------------------------------------------------------------- /_posts/examples/2010-12-03-card-01.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: example 3 | title: Card 1 4 | category: examples 5 | --- 6 | 7 | 69 | 70 | 71 | 72 | 73 |

{{ page.title }}

74 | 75 |
76 |
77 |
1
78 |
2
79 |
80 |
81 | 82 |
83 |

84 |
85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /_posts/examples/2010-12-01-perspective-02-children.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: example 3 | title: Perspective 2 - children 4 | category: examples 5 | --- 6 | 7 | 48 | 49 | 50 | 51 | 52 |

{{ page.title }}

53 | 54 | {% highlight css %} 55 | 56 | #red figure { 57 | background: red; 58 | transform: perspective( 400px ) rotateY(45deg); 59 | } 60 | 61 | {% endhighlight %} 62 | 63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | 75 | {% highlight css %} 76 | 77 | #blue { 78 | perspective: 400px; 79 | } 80 | 81 | #blue figure { 82 | background: blue; 83 | transform: rotateY( 45deg ); 84 | } 85 | 86 | {% endhighlight %} 87 | 88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | 100 | 101 | -------------------------------------------------------------------------------- /_posts/examples/2010-12-02-transforms-01-functions.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: example 3 | title: Transforms 1 - functions 4 | category: examples 5 | --- 6 | 7 | 8 | 67 | 68 | 69 | 70 | 71 |

{{ page.title }}

72 | 73 |
74 |
translateZ( -200px )
75 |
76 | 77 |
78 |
translateZ( 200px )
79 |
80 | 81 |
82 |
rotateX( 45deg )
83 |
84 | 85 |
86 |
rotateY( 45deg )
87 |
88 | 89 |
90 |
rotateZ( 45deg )
91 |
92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /_posts/docs/2010-12-02-perspective.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: Perspective 4 | layout: doc 5 | category: docs 6 | 7 | --- 8 | 9 | 10 | To activate 3D space, an element needs perspective. This can be applied in two ways: using the `transform` property, with the perspective as a functional notation. 11 | 12 | 13 | {% highlight css %} 14 | 15 | transform: perspective( 600px ); 16 | 17 | {% endhighlight %} 18 | 19 | or using the `perspective` property: 20 | 21 | {% highlight css %} 22 | 23 | perspective: 600px; 24 | 25 | {% endhighlight %} 26 | 27 | **NOTE**: for the sake of brevity in the example code, I am using the un-prefixed CSS properties, i.e. `perspective`. In actual use, you'll have to use vendor-prefixed versions: `-webkit-perspective`, `-moz-perspective`, etc. 28 | 29 | [**See Example: Perspective 1**](../examples/perspective-01.html) 30 | 31 | [![Perspective property at work](../img/perspective01.png)](../examples/perspective-01.html) 32 | 33 | These two formats both trigger a 3D space, but there is a difference. The functional notation is convenient for directly applying a 3D transform on a single element (in [the previous example](../examples/perspective-01.html), I use it in conjunction with a `rotateY` transform). But when used on multiple elements, the transformed elements don't line up as expected. If you use the same transform across elements with different positions, each element will have its own vanishing point. To remedy this, use the `perspective` property on a parent element, so each child may share the same 3D space. 34 | 35 | [**See Example: Perspective 2**](../examples/perspective-02-children.html) 36 | 37 | [![Perspective differences when used with child elements](../img/perspective-children01.png)](../examples/perspective-02-children.html) 38 | 39 | The value of `perspective` determines the intensity of the 3D effect. Think of it as a distance from the viewer to the object. The greater the value, the further the distance, the less intense the visual effect. `perspective: 2000px;` yields a subtle 3D effect, as if we are viewing an object from far away through binoculars. `perspective: 100px;` produces a tremendous 3D effect, like a tiny insect viewing a massive object. 40 | 41 | By default, the vanishing point for a 3D space is positioned at the center. You can change the position of the vanishing point with `perspective-origin` property. 42 | 43 | 44 | {% highlight css %} 45 | 46 | perspective-origin: 25% 75%; 47 | 48 | {% endhighlight %} 49 | 50 | [**See Example: Perspective 3**](../examples/perspective-03.html) 51 | 52 | [![Intense perspective value, with vanishing point modified](../img/perspective02.png)](../examples/perspective-03.html) 53 | 54 | * * * 55 | 56 | [**Next: 3D transform functions »**](3d-transform-functions.html) 57 | -------------------------------------------------------------------------------- /_posts/examples/2010-12-03-card-02-slide-flip.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: example 3 | title: Card 2 - slide flip 4 | category: examples 5 | --- 6 | 7 | 73 | 74 | 75 | 76 | 77 |

{{ page.title }}

78 | 79 |
80 |
81 |
1
82 |
2
83 |
84 |
85 | 86 |
87 |

88 |
89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /_posts/docs/2010-12-03-3d-transform-functions.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: 3D transform functions 4 | layout: doc 5 | category: docs 6 | 7 | --- 8 | 9 | As a web designer, you're probably well acquainted with working in two dimensions, X and Y, positioning items horizontally and vertically. With a 3D space initialized with `perspective`, we can now transform elements in all three glorious spatial dimensions, including the third Z dimension. 10 | 11 | 3D transforms use the same `transform` property used for 2D transforms. If you're familiar with 2D transforms, you'll find the basic [3D transform functions](http://www.w3.org/TR/css3-3d-transforms/#transform-functions) fairly similar. 12 | 13 | * `rotateX( angle )` 14 | * `rotateY( angle )` 15 | * `rotateZ( angle )` 16 | * `translateZ( tz )` 17 | * `scaleZ( sz )` 18 | 19 | Whereas `translateX()` positions an element along the horizontal X axis, `translateZ()` positions it along the Z axis, which runs front to back in 3D space. Positive values position the element closer to the viewer, negative values further away. 20 | 21 | The `rotate` functions rotate the element around the corresponding axis. This is a bit counter-intuitive at first as you might imagine that `rotateX` will spin an object left to right. Instead, using `rotateX( 45deg )` rotates an element _around_ the horizontal X axis, so the top of the element angles back and away, and the bottom angles near. 22 | 23 | [**See Example: Transforms 1**](../examples/transforms-01-functions.html) 24 | 25 | [![CSS 3D transform functions](../img/transforms01.png)](../examples/transforms-01-functions.html) 26 | 27 | There's also several shorthand transform functions that require values for all three dimensions: 28 | 29 | * `translate3d( tx, ty, tz )` 30 | * `scale3d( sx, sy, sz )` 31 | * `rotate3d( rx, ry, rz, angle )` 32 | 33 | **Pro-tip:** These `foo3d()` transform functions also have the benefit of triggering hardware acceleration in Safari. Dean Jackson, CSS 3D transform spec author and main WebKit dude, writes (by way of [Thomas Fuchs](http://mir.aculo.us/2010/08/05/html5-buzzwords-in-action/)): 34 | 35 | > In essence, any transform that has a 3D operation as one of its functions will trigger hardware compositing, even when the actual transform is 2D, or not doing anything at all (such as `translate3d(0,0,0)`). Note this is just current behaviour, and could change in the future (which is why we don't document or encourage it). But it is very helpful in some situations and can significantly improve redraw performance. 36 | 37 | For the sake of simplicity, these demos will use the basic transform functions, but if you're writing production-ready CSS for iOS or Safari-only, **make sure to use the `foo3d()` functions to get the best rendering performance.** 38 | 39 | * * * 40 | 41 | [**Next: Card flip »**](card-flip.html) 42 | -------------------------------------------------------------------------------- /_posts/docs/2010-12-06-rectangular-prism.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: Rectangular prism 4 | layout: doc 5 | category: docs 6 | 7 | --- 8 | 9 | Cube objects are easy enough to generate as we only have to worry about one measurement. But how would we handle a non-regular rectangular prism? Let's try to make one 300px wide, 200px high, and 100px deep. 10 | 11 | The markup remains the same as the `#cube`'s version, but switch the `#cube` id for `#box`. The container styles remain mostly the same. 12 | 13 | {% highlight css %} 14 | 15 | .container { 16 | width: 300px; 17 | height: 200px; 18 | position: relative; 19 | perspective: 1000px; 20 | } 21 | 22 | #box { 23 | width: 100%; 24 | height: 100%; 25 | position: absolute; 26 | transform-style: preserve-3d; 27 | } 28 | 29 | {% endhighlight %} 30 | 31 | Now, to position the faces. Each set of faces will need their own sizes. The smaller faces (left, right, top and bottom) need to be positioned in the center of the container, where they can be easily rotated and then shifted outward. The thinner left and right faces get positioned `left: 100px` ( (300 - 100) / 2 ), The stouter top and bottom faces get positioned `top: 50px` ( (200 - 100) / 2 ). 32 | 33 | {% highlight css %} 34 | 35 | #box figure { 36 | margin: 0; 37 | display: block; 38 | position: absolute; 39 | border: 2px solid black; 40 | } 41 | 42 | #box .front, 43 | #box .back { 44 | width: 296px; 45 | height: 196px; 46 | } 47 | 48 | #box .right, 49 | #box .left { 50 | width: 96px; 51 | height: 196px; 52 | left: 100px; 53 | } 54 | 55 | #box .top, 56 | #box .bottom { 57 | width: 296px; 58 | height: 96px; 59 | top: 50px; 60 | } 61 | 62 | {% endhighlight %} 63 | 64 | The rotate values all can remain the same as in the cube example, but for this rectangular prism, the translate values do differ. The front and back faces each are shifted out `50px` since the `#box` is 100px deep. Left and right faces translate is `150px` for 300px width. Top and bottom panels go `100px` for the 200px height. 65 | 66 | {% highlight css %} 67 | 68 | #box .front { transform: rotateY( 0deg ) translateZ( 50px ); } 69 | #box .back { transform: rotateX( 180deg ) translateZ( 50px ); } 70 | #box .right { transform: rotateY( 90deg ) translateZ( 150px ); } 71 | #box .left { transform: rotateY( -90deg ) translateZ( 150px ); } 72 | #box .top { transform: rotateX( 90deg ) translateZ( 100px ); } 73 | #box .bottom { transform: rotateX( -90deg ) translateZ( 100px ); } 74 | 75 | {% endhighlight %} 76 | 77 | [**See Example: Box 1**](../examples/box-01-steps.html) 78 | 79 | [![3D CSS box object](../img/box01.png)](../examples/box-01-steps.html) 80 | 81 | Just like the cube example, to expose a face, the `#box` needs to have a style to reverse its face's transform. Both the `translateZ` and `rotate` values are the opposites of the corresponding face. 82 | 83 | {% highlight css %} 84 | 85 | #box.show-front { transform: translateZ( -50px ) rotateY( 0deg ); } 86 | #box.show-back { transform: translateZ( -50px ) rotateX( -180deg ); } 87 | #box.show-right { transform: translateZ( -150px ) rotateY( -90deg ); } 88 | #box.show-left { transform: translateZ( -150px ) rotateY( 90deg ); } 89 | #box.show-top { transform: translateZ( -100px ) rotateX( -90deg ); } 90 | #box.show-bottom { transform: translateZ( -100px ) rotateX( 90deg ); } 91 | 92 | {% endhighlight %} 93 | 94 | [**See Example: Box 2**](../examples/box-02-show-sides.html) 95 | 96 | [![3D CSS box object rotating](../img/box02.png)](../examples/box-02-show-sides.html) 97 | 98 | * * * 99 | 100 | [**Next: Carousel »**](carousel.html) 101 | -------------------------------------------------------------------------------- /_posts/examples/2010-12-03-card-03-slide-flip-2-ways.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: example 3 | title: Card 3 - slide flip two ways 4 | category: examples 5 | --- 6 | 7 | 89 | 90 | 91 | 92 | 93 |

{{ page.title }}

94 | 95 |
96 |
97 |
1
98 |
2
99 |
100 |
101 | 102 |
103 |

104 | 105 | 106 |

107 |
108 | 109 | 110 | 124 | 125 | -------------------------------------------------------------------------------- /_posts/docs/2010-12-01-introduction.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | layout: doc 4 | category: docs 5 | 6 | --- 7 | 8 | Ladies and gentlemen, it is the second decade of the second millennium and we are still kicking around the same 2D interface we got three decades ago. Sure, Apple debuted a few apps for OSX 10.7 that have a couple more 3D flourishes, and Microsoft has had that [Flip 3D](http://windows.microsoft.com/en-US/windows-vista/Using-Windows-Flip-3D) for a while. But c'mon, 2011 is right around the corner. That's _Twenty Eleven_ folks. Where is our 3D virtual reality? By now, we should be zipping around the [Metaverse in super-sonic motorbikes](http://en.wikipedia.org/wiki/Snow_Crash). 9 | 10 | Granted, the capability of rendering complex 3D environments has been present for years. On the Web, there already are number of solutions -- [Flash](http://www.adobe.com/devnet/flash/3d_animation.html), [three.js](https://github.com/mrdoob/three.js/) in canvas, and eventually WebGL. And finally, we meager front-end developers have our own three-dimensional jewel: CSS 3D Transforms! 11 | 12 | ## Rationale 13 | 14 | Like a beautiful jewel, 3D transform can be dazzling, a true spectacle to behold. But before we start tacking 3D diamonds and rubies to our compositions like Liberace's tailor, we owe it to our users to ask what can they benefit from this awesome feature. 15 | 16 | The entire application does not, and should not, take advantage of 3D. CSS was built to style documents, not generate explorable environments. I fail to find a benefit to filling out a web form that can be accessed by swiveling my viewport to the Sign-Up Room (although there have been proposals to make the Web just that). However, there is plenty of opportunity to use 3D transforms _in between_ the interface, via transitions. 17 | 18 | Take for instance the Weather App on the iPhone. The application uses two views: a details view and an options view. Switching between these two views is done with a 3D flip transition. This affords the user that the interface has two and only two views, as they can only exist on either side of the same plane. 19 | 20 | ![iPhone Weather App 3D flip transition](../img/weather-app-transition.jpg) 21 | 22 | Also consider slide cycle plugins. When you're at the last slide, what cues tip-off the user that the advancing will re-start the cycle at the first? A better paradigm can be used with a 3D transform, where the slides are placed side by side one another in a circle in 3D space. In that arrangement, the last slide logically comes before the first. 23 | 24 | 3D transforms are more than just eye candy. We can also use them to solve dilemmas and make our applications more intuitive. 25 | 26 | ## Current Support Environment 27 | 28 | [The CSS 3D transforms module](http://dev.w3.org/csswg/css3-3d-transforms/) has been out in the wild for several year now. While only Apple-produced browsers like Safari and Mobile Safari originally supported it, support has been added by Google Chrome and Mozilla Firefox. View the chart on [caniuse.com/#feat=transforms3d](http://caniuse.com/#feat=transforms3d) to check the latest support environment across the browser landscape. 29 | 30 | This all adds up to a bit of a challenge for those of us excited for 3D transforms. I'll give it to you straight: missing that dimension of depth can make degradation a bit ungraceful. Unless the transform is relatively simple and holds up in non-3D-supporting browsers, you'll most likely have to design another solution. But what's another hurdle in a steeplechase? We web folk have had our mettle tested for years. We're galvanized for devising multiple solutions. 31 | 32 | Here's the part of the article where I mention [Modernizr](http://modernizr.com), and you brush over it because you've read this part of an article a hundreds of times before. But seriously, it's the best way to test for CSS 3D transform support. Use it. 33 | 34 | Even with these difficulties mounted up, trying out 3D transforms today is the right move. The CSS 3D transforms module was developed by the same team at Apple who produced the [CSS 2D transforms](http://www.w3.org/TR/css3-2d-transforms/) and [animation](http://www.w3.org/TR/css3-animations/modules). Both specifications have since been adopted by Mozilla and Opera. Transforming three-dimensionally now will guarantee you'll be ahead of the game when the other browsers catch up. 35 | 36 | The choice is yours. You can make excuses and poo-poo 3D transforms because they're too hard and only snobby Apple fans will see them today. Or, with a [tip of the fedora to Mr. Andy Clarke](http://hardboiledwebdesign.com/), you can get hardboiled and start designing with the best features out there right this instant. 37 | 38 | So I bid you, [in the words of the eternal Optimus Prime](http://tfwiki.net/wiki/Roll_out)... 39 | 40 | > Transform and roll out. 41 | 42 | Let's get coding. 43 | 44 | * * * 45 | 46 | [**Next: Perspective »**](perspective.html) 47 | -------------------------------------------------------------------------------- /_posts/docs/2010-12-04-card-flip.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: Card Flip 4 | layout: doc 5 | category: docs 6 | 7 | --- 8 | 9 | We now have all the tools to start making 3D objects. Let's get started with the basics, flipping a card. 10 | 11 | Here's the basic markup we'll need: 12 | 13 | {% highlight html %} 14 | 15 |
16 |
17 |
1
18 |
2
19 |
20 |
21 | 22 | {% endhighlight %} 23 | 24 | The `.container` will house the 3D space. The `#card` acts as a wrapper for the 3D object. Two separate elements for both faces of the card, `.front` and `.back`. Even for such a simple object, I recommend using this same pattern for any 3D transform. Keeping the 3D space element and the object separate element establishes a paradigm that is simple to understand and easier to style. 25 | 26 | We're ready for some 3D stylin'. First, apply necessary `perspective` to the parent 3D space, along with any size or positioning styles. 27 | 28 | {% highlight css %} 29 | 30 | .container { 31 | width: 200px; 32 | height: 260px; 33 | position: relative; 34 | perspective: 800px; 35 | } 36 | 37 | {% endhighlight %} 38 | 39 | Now the `#card` element can be transformed in its parent's 3D space. We're using absolute/relative positioning so the 3D object is removed from the flow of the document. We'll also add @width: 100%;` and `height: 100%;@. This ensures the object's `transform-origin` will occur in the center of container. More on `transform-origin` later. 40 | 41 | Let's add a CSS3 transition so users can see the transform take effect. 42 | 43 | {% highlight css %} 44 | 45 | #card { 46 | width: 100%; 47 | height: 100%; 48 | position: absolute; 49 | transform-style: preserve-3d; 50 | transition: transform 1s; 51 | } 52 | 53 | {% endhighlight %} 54 | 55 | The `.container`'s `perspective` only applies to direct descendant children, in this case `#card`. In order for subsequent children to inherit a parent's perspective, and live in the same 3D space, the parent can pass along its perspective with `transform-style: preserve-3d`. Without 3D `transform-style`, the faces of the card would be flattened with its parents and the back face's rotation would be nullified. 56 | 57 | To position the faces in 3D space, we'll need to reset their positions in 2D with `position: absolute`. In order to hide the back-side of the faces when they are faced away from the viewer, we use `backface-visibility: hidden`. 58 | 59 | {% highlight css %} 60 | 61 | #card figure { 62 | margin: 0; 63 | display: block; 64 | position: absolute; 65 | width: 100%; 66 | height: 100%; 67 | backface-visibility: hidden; 68 | } 69 | 70 | {% endhighlight %} 71 | 72 | To flip the `.back` face, we add a basic 3D transform of `rotateY( 180deg )`. 73 | 74 | {% highlight css %} 75 | 76 | #card .front { 77 | background: red; 78 | } 79 | #card .back { 80 | background: blue; 81 | transform: rotateY( 180deg ); 82 | } 83 | 84 | {% endhighlight %} 85 | 86 | With the faces in place, the `#card` requires a corresponding style for when it is flipped. 87 | 88 | {% highlight css %} 89 | 90 | #card.flipped { 91 | transform: rotateY( 180deg ); 92 | } 93 | 94 | {% endhighlight %} 95 | 96 | Now we have a working 3D object. To flip the card, we can toggle the `flipped` class. When `.flipped`, the `#card` will rotate 180 degrees, thus exposing the `.back` face. 97 | 98 | [**See Example: Card 1**](../examples/card-01.html) 99 | 100 | [![3D card flip transition](../img/card-flip01.png)](../examples/card-01.html) 101 | 102 | ## Slide-flip 103 | 104 | Take another look at the Weather App 3D transition. You'll notice that it's not quite the same effect as our [previous demo](../examples/card-01.html). If you follow the right edge of the card, you'll find that it stays flush with the container. Instead of pivoting from the horizontal center, it pivots on that right edge. But the transition is not just a rotation -- the edge moves horizontally from right to left. We can reproduce this transition just by modifying a couple lines of CSS from our original card flip demo. 105 | 106 | The pivot point for the rotation occurs at the right side of the card. By default, the `transform-origin` of an element is at its horizontal and vertical center (`50% 50%` or `center center`). Let's change it to the right side: 107 | 108 | {% highlight css %} 109 | 110 | #card { transform-origin: right center; } 111 | 112 | {% endhighlight %} 113 | 114 | That flip now needs some horizontal movement with `translateX`. We'll set the rotation to `-180deg` so it flips right side out. 115 | 116 | {% highlight css %} 117 | 118 | #card.flipped { 119 | transform: translateX( -100% ) rotateY( -180deg ); 120 | } 121 | 122 | {% endhighlight %} 123 | 124 | [**See Example: Card 2**](../examples/card-02-slide-flip.html) 125 | 126 | [![3D card slide-flip transition](../img/card-flip02.png)](../examples/card-02-slide-flip.html) 127 | 128 | * * * 129 | 130 | [**Next: Cube »**](cube.html) 131 | -------------------------------------------------------------------------------- /_posts/docs/2010-12-07-carousel.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: Carousel 4 | layout: doc 5 | category: docs 6 | 7 | --- 8 | 9 | Front-end developers have a myriad of choices when it comes to content carousels. Now that we have 3D capabilities in our browsers, why not give a shot at creating an actual 3D carousel? 10 | 11 | The markup for this demo takes the same form as the box, cube, and card. Let's make it interesting and have a carousel with 9 panels. 12 | 13 | {% highlight html %} 14 | 15 |
16 | 27 |
28 | 29 | {% endhighlight %} 30 | 31 | Now apply basic layout styles. Let's give each panel of the `#carousel` 20px gaps between one another, done here with `left: 10px;` and `top: 10px;`. The effective width of each panel remains 210px. 32 | 33 | {% highlight css %} 34 | 35 | .container { 36 | width: 210px; 37 | height: 140px; 38 | position: relative; 39 | perspective: 1000px; 40 | } 41 | 42 | #carousel { 43 | width: 100%; 44 | height: 100%; 45 | position: absolute; 46 | transform-style: preserve-3d; 47 | } 48 | 49 | #carousel figure { 50 | margin: 0; 51 | display: block; 52 | position: absolute; 53 | width: 186px; 54 | height: 116px; 55 | left: 10px; 56 | top: 10px; 57 | border: 2px solid black; 58 | } 59 | 60 | {% endhighlight %} 61 | 62 | Next up: rotating the faces. This `#carousel` has 9 panels. If each panel gets an equal distribution on the carousel, each panel would be rotated 40 degrees from the next ( 360 / 9 ). 63 | 64 | {% highlight css %} 65 | 66 | #carousel figure:nth-child(1) { transform: rotateY( 0deg ); } 67 | #carousel figure:nth-child(2) { transform: rotateY( 40deg ); } 68 | #carousel figure:nth-child(3) { transform: rotateY( 80deg ); } 69 | #carousel figure:nth-child(4) { transform: rotateY( 120deg ); } 70 | #carousel figure:nth-child(5) { transform: rotateY( 160deg ); } 71 | #carousel figure:nth-child(6) { transform: rotateY( 200deg ); } 72 | #carousel figure:nth-child(7) { transform: rotateY( 240deg ); } 73 | #carousel figure:nth-child(8) { transform: rotateY( 280deg ); } 74 | #carousel figure:nth-child(9) { transform: rotateY( 320deg ); } 75 | 76 | {% endhighlight %} 77 | 78 | Now the outward shift. Back when we were creating cube and boxes, the `translate` value was simple to calculate, as it was equal to one half the width, height, or depth of the object. Now with a carousel, there is no size we can immediately reference. We'll have calculate the distance for the shift by other means. 79 | 80 | Drawing out a diagram of the carousel, we see that we only know two things: the width of each panel is 210px and the each panel is rotated 40 degrees from the next. If we split one of these triangles down its center, we get a right triangle, prime for some trigonometry. 81 | 82 | ![Geometric diagram of carousel](../img/diagram.png) 83 | 84 | We can determine the length of _r_ in this diagram with a basic tangent equation. 85 | 86 | ![Trigonometric calculation](../img/calc.png) 87 | 88 | There you have it, `288px` is the distance to translate the panels out in 3D space. 89 | 90 | {% highlight css %} 91 | 92 | #carousel figure:nth-child(1) { transform: rotateY( 0deg ) translateZ( 288px ); } 93 | #carousel figure:nth-child(2) { transform: rotateY( 40deg ) translateZ( 288px ); } 94 | #carousel figure:nth-child(3) { transform: rotateY( 80deg ) translateZ( 288px ); } 95 | #carousel figure:nth-child(4) { transform: rotateY( 120deg ) translateZ( 288px ); } 96 | #carousel figure:nth-child(5) { transform: rotateY( 160deg ) translateZ( 288px ); } 97 | #carousel figure:nth-child(6) { transform: rotateY( 200deg ) translateZ( 288px ); } 98 | #carousel figure:nth-child(7) { transform: rotateY( 240deg ) translateZ( 288px ); } 99 | #carousel figure:nth-child(8) { transform: rotateY( 280deg ) translateZ( 288px ); } 100 | #carousel figure:nth-child(9) { transform: rotateY( 320deg ) translateZ( 288px ); } 101 | 102 | {% endhighlight %} 103 | 104 | If we decide on changing the width of the panel or the number of panels, we only need to plug in those two variables into our equation to get the appropriate translateZ value. In JS terms, that equation would be: 105 | 106 | {% highlight javascript %} 107 | 108 | var tz = Math.round( ( panelSize / 2 ) / 109 | Math.tan( ( ( Math.PI * 2 ) / numberOfPanels ) / 2 ) ); 110 | // or simplified to 111 | var tz = Math.round( ( panelSize / 2 ) / 112 | Math.tan( Math.PI / numberOfPanels ) ); 113 | 114 | {% endhighlight %} 115 | 116 | Just like our previous 3D objects, to show any one panel, we need only to apply the reverse transform on the carousel. Here's the style to show the fifth panel: 117 | 118 | {% highlight css %} 119 | 120 | transform: translateZ( -288px ) rotateY( -160deg ); 121 | 122 | {% endhighlight %} 123 | 124 | [**See Example: Carousel 1**](../examples/carousel-01.html) 125 | 126 | [![3D CSS carousel](../img/carousel01.png)](../examples/carousel-01.html) 127 | 128 | By now, you probably have two thoughts: 129 | 130 | 1. Re-writing transform styles for each panel looks to be tedious. 131 | 2. Why bother doing high school math -- Aren't robots supposed to be doing all this work for us? 132 | 133 | And you're absolutely right. The repetitive nature of 3D objects lend themselves to scripting. We can offload all the monotonous transform styles to our dynamic script, which, if done right, will be more flexible than the hard-coded version. 134 | 135 | [**See Example: Carousel 2**](../examples/carousel-02-dynamic.html) 136 | 137 | * * * 138 | 139 | [**Next: Conclusion »**](conclusion.html) 140 | -------------------------------------------------------------------------------- /_posts/docs/2010-12-05-cube.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: Cube 4 | layout: doc 5 | category: docs 6 | 7 | --- 8 | 9 | Creating 3D card objects is a good way to get started with 3D transform. But once you've mastered them, you'll be hungry to push it further and create some true 3D objects: prisms. We'll start out by making a cube. 10 | 11 | The markup for the cube is similar to the card. This time we need 6 child elements for all 6 faces of the cube. 12 | 13 | {% highlight html %} 14 | 15 |
16 |
17 |
1
18 |
2
19 |
3
20 |
4
21 |
5
22 |
6
23 |
24 |
25 | 26 | {% endhighlight %} 27 | 28 | Basic position and size styles set the 6 faces on top of one another in the container. 29 | 30 | {% highlight css %} 31 | 32 | .container { 33 | width: 200px; 34 | height: 200px; 35 | position: relative; 36 | perspective: 1000px; 37 | } 38 | 39 | #cube { 40 | width: 100%; 41 | height: 100%; 42 | position: absolute; 43 | transform-style: preserve-3d; 44 | } 45 | 46 | #cube figure { 47 | margin: 0; 48 | width: 196px; 49 | height: 196px; 50 | display: block; 51 | position: absolute; 52 | border: 2px solid black; 53 | } 54 | 55 | {% endhighlight %} 56 | 57 | With the card, we only had to rotate its back face. The cube, however, requires that 5 of the 6 faces to be rotated. Faces 1 and 2 will be the front and back. Faces 3 and 4 will be the sides. Faces 5 and 6 will be the top and bottom. 58 | 59 | {% highlight css %} 60 | 61 | #cube .front { transform: rotateY( 0deg ); } 62 | #cube .back { transform: rotateX( 180deg ); } 63 | #cube .right { transform: rotateY( 90deg ); } 64 | #cube .left { transform: rotateY( -90deg ); } 65 | #cube .top { transform: rotateX( 90deg ); } 66 | #cube .bottom { transform: rotateX( -90deg ); } 67 | 68 | {% endhighlight %} 69 | 70 | We could remove the `#cube .front` style declaration, as this transform has no effect, but let's leave it in to keep our code consistent. 71 | 72 | Now each face is rotated, and only the front face is visible. The 4 side faces are all perpendicular to the viewer, so they appear invisible. To push them out to their appropriate sides, they need to be translated out from the center of their positions. Each side of the cube is 200px wide. From the cube's center they'll need to be translated out half that distance, `100px`. 73 | 74 | {% highlight css %} 75 | 76 | #cube .front { transform: rotateY( 0deg ) translateZ( 100px ); } 77 | #cube .back { transform: rotateX( 180deg ) translateZ( 100px ); } 78 | #cube .right { transform: rotateY( 90deg ) translateZ( 100px ); } 79 | #cube .left { transform: rotateY( -90deg ) translateZ( 100px ); } 80 | #cube .top { transform: rotateX( 90deg ) translateZ( 100px ); } 81 | #cube .bottom { transform: rotateX( -90deg ) translateZ( 100px ); } 82 | 83 | {% endhighlight %} 84 | 85 | Note here that the `translateZ` function comes _after_ the `rotate`. The order of transform functions is important. Take a moment and soak this in. Each face is first rotated towards its position, then translated outward in a separate vector. 86 | 87 | We have a working cube, but we're not done yet. 88 | 89 | ## Returning to the Z origin plane 90 | 91 | For the sake of our users, our 3D transforms should not distort the interface when the active panel is at its resting position. But once we start pushing elements out of the Z origin plane, distortion is inevitable. 92 | 93 | In order to keep 3D transforms snappy, Safari composites the element then applies the transform. Consequently, anti-aliasing on text will remain whatever it was before the transform was applied. When transformed forward in 3D space, significant pixelation can occur. 94 | 95 | [**See Example: Transforms 2**](../examples/transforms-02-pixelation.html) 96 | 97 | [![Using 3D transforms can pixelate text](../img/pixelation01.png)](../examples/transforms-02-pixelation.html) 98 | 99 | Looking at back at the [Perspective 3 demo](../examples/perspective-03.html), note that no matter how small the perspective value is, or where ever the transform origin may be, the 1 panel always returns to its original position, as if all those funky 3D transforms didn't even matter. 100 | 101 | To resolve the distortion and restore pixel perfection on our `#cube`, we can push back the 3D object, so that the front face will be positioned back at the Z origin. 102 | 103 | {% highlight css %} 104 | 105 | #cube { transform: translateZ( -100px ); } 106 | 107 | {% endhighlight %} 108 | 109 | [**See Example: Cube 1**](../examples/cube-01-steps.html) 110 | 111 | [![CSS 3D cube object](../img/cube01.png)](../examples/cube-01-steps.html) 112 | 113 | To expose any face of the cube, we'll need a style that rotates the cube to expose any face. The transform is the opposite of the corresponding face. We toggle the necessary class on the `#box` to apply the appropriate transform. 114 | 115 | {% highlight css %} 116 | 117 | #cube.show-front { transform: translateZ( -100px ) rotateY( 0deg ); } 118 | #cube.show-back { transform: translateZ( -100px ) rotateX( -180deg ); } 119 | #cube.show-right { transform: translateZ( -100px ) rotateY( -90deg ); } 120 | #cube.show-left { transform: translateZ( -100px ) rotateY( 90deg ); } 121 | #cube.show-top { transform: translateZ( -100px ) rotateX( -90deg ); } 122 | #cube.show-bottom { transform: translateZ( -100px ) rotateX( 90deg ); } 123 | 124 | {% endhighlight %} 125 | 126 | Notice how the order of the transform functions has reversed. First we push the object back with `translateZ`, then we rotate it. 127 | 128 | Finishing up, we can add a transition to animate the rotation between states. 129 | 130 | {% highlight css %} 131 | 132 | #cube { transition: transform 1s; } 133 | 134 | {% endhighlight %} 135 | 136 | [**See Example: Cube 2**](../examples/cube-02-show-sides.html) 137 | 138 | [![CSS 3D cube object changing sides](../img/cube02.png)](../examples/cube-02-show-sides.html) 139 | 140 | * * * 141 | 142 | [**Next: Rectangular prism »**](rectangular-prism.html) 143 | -------------------------------------------------------------------------------- /_posts/examples/2010-12-04-cube-01-steps.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: example 3 | title: Cube 1 - steps 4 | category: examples 5 | --- 6 | 7 | 146 | 147 | 148 | 149 | 150 |

{{ page.title }}

151 | 152 |
153 |
154 |
1
155 |
2
156 |
3
157 |
4
158 |
5
159 |
6
160 |
161 |
162 | 163 |
164 |

165 | 166 | 167 | 168 | 169 |

170 |
171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | section, footer, nav { 2 | display: block; 3 | } 4 | 5 | body { 6 | font-family: 'Helvetica Neue', Arial, sans-serif; 7 | -webkit-text-size-adjust: none; 8 | color: #333; 9 | max-width: 720px; 10 | margin: 0 auto; 11 | padding: 10px; 12 | } 13 | 14 | a { 15 | color: blue; 16 | color: hsl( 220, 90%, 40% ); 17 | text-decoration: none; 18 | } 19 | 20 | a:hover { 21 | background-color: blue; 22 | background-color: hsl( 220, 90%, 50% ); 23 | color: white; 24 | } 25 | 26 | #options { 27 | position: relative; 28 | z-index: 100; 29 | margin-bottom: 40px; 30 | } 31 | 32 | button { 33 | font-size: 16px; 34 | -webkit-appearance: push-button; 35 | } 36 | 37 | footer { 38 | border-top: 1px solid #CCC; 39 | font-size: 0.8em; 40 | position: relative; 41 | z-index: 100; 42 | } 43 | 44 | #disclaimer { 45 | color: red; 46 | font-weight: bold; 47 | display: none; 48 | } 49 | .no-csstransforms3d #disclaimer { display: block; } 50 | 51 | hr { 52 | border: none; 53 | border-top: 1px solid #CCC; 54 | } 55 | 56 | figure { 57 | margin: 0; 58 | } 59 | 60 | code { 61 | font-family: 'Monaco', 'Menlo', monospace; 62 | } 63 | 64 | /* index navigation */ 65 | 66 | .index nav ul { 67 | list-style: none; 68 | margin: 0 0 3.0em 0; 69 | padding: 0; 70 | } 71 | 72 | .index nav ul a { 73 | display: block; 74 | font-size: 18px; 75 | font-weight: bold; 76 | line-height: 24px; 77 | padding: 10px; 78 | border: 1px solid #CCC; 79 | border-bottom: none; 80 | } 81 | 82 | .index nav ul li:first-child a { 83 | border-radius: 10px 10px 0 0; 84 | } 85 | 86 | .index nav ul li:last-child a { 87 | border-radius: 0 0 10px 10px; 88 | border-bottom: 1px solid #CCC; 89 | } 90 | 91 | /**** Docs ****/ 92 | 93 | body.doc { max-width: 900px; } 94 | 95 | .doc #content { 96 | font-size: 14px; 97 | line-height: 1.5em; 98 | } 99 | 100 | .doc #content blockquote { 101 | margin-left: 0; 102 | padding: 0.8em; 103 | background: #EEE; 104 | background: hsla( 0, 0%, 0%, 0.04 ); 105 | } 106 | 107 | .doc #content img { 108 | border: 1px solid #CCC; 109 | display: inline-block; 110 | } 111 | 112 | .doc #content pre { 113 | font-size: 12px; 114 | line-height: 1.5em; 115 | } 116 | 117 | .doc nav h1 { 118 | font-size: 20px; 119 | } 120 | 121 | .doc nav ul { 122 | margin: 0; 123 | padding: 0; 124 | list-style: none; 125 | } 126 | 127 | .doc nav li a { 128 | display: block; 129 | padding: 0.3em 0; 130 | } 131 | 132 | .doc nav li.current a { 133 | font-weight: bold; 134 | color: #333; 135 | } 136 | .doc nav li.current a:hover { color: white; } 137 | 138 | 139 | 140 | @media screen and (min-width: 768px) { 141 | 142 | body.doc #content { 143 | padding-left: 220px; 144 | } 145 | 146 | .doc #doc-nav-wrapper { 147 | position: fixed; 148 | left: 0; 149 | top: 0; 150 | width: 100%; 151 | } 152 | 153 | .doc .doc-nav-positioner { 154 | max-width: 900px; 155 | margin: 0 auto; 156 | position: relative; 157 | } 158 | 159 | .doc nav { 160 | width: 200px; 161 | font-size: 14px; 162 | position: absolute; 163 | top: 10px; 164 | left: 10px; 165 | } 166 | 167 | .doc nav h1 { 168 | margin-top: 0; 169 | } 170 | 171 | } 172 | 173 | /* proxy range */ 174 | 175 | .proxy-range { 176 | display: inline-block; 177 | position: relative; 178 | height: 30px; 179 | width: 200px; 180 | border: 1px solid hsla( 0, 0%, 0%, 0.15 ); 181 | background-color: hsla( 0, 0%, 0%, 0.02 ); 182 | border-radius: 15px; 183 | box-shadow: inset 0 1px 7px hsla( 0, 0%, 0%, 0.3 ); 184 | } 185 | 186 | .proxy-range.highlighted { 187 | background-color: hsla( 220, 90%, 50%, 0.15 ); 188 | } 189 | 190 | .proxy-range .handle { 191 | width: 38px; 192 | height: 38px; 193 | border-radius: 20px; 194 | border: 1px solid hsla(0, 0%, 0%, 0.3); 195 | position: absolute; 196 | top: -5px; 197 | left: -20px; 198 | background-color: hsla( 220, 70%, 60%, 1.0 ); 199 | background-image: -webkit-gradient(radial, center 15%, 0, center 30%, 30, 200 | from( hsla( 0, 0%, 100%, 0.6 ) ), 201 | color-stop( 50%, hsla( 0, 0%, 100%, 0.0 ) ), 202 | color-stop( 50%, hsla( 0, 0%, 0%, 0.0 ) ), 203 | to( hsla( 0, 0%, 0%, 0.5 ) ) 204 | ); 205 | background-image: -moz-radial-gradient(center 30%, cover, 206 | hsla( 0, 0%, 100%, 0.5 ), 207 | hsla( 0, 0%, 100%, 0.0 ) 50%, 208 | hsla( 0, 0%, 0%, 0.0 ) 50%, 209 | hsla( 0, 0%, 0%, 0.5 ) 210 | ); 211 | box-shadow: 212 | 0 2px 0px -1px hsla( 0, 0%, 100%, 0.7 ) inset, 213 | 0 -4px 2px -1px hsla( 0, 0%, 0%, 0.1 ) inset, 214 | 0 1px 2px 0px hsla( 0, 0%, 0%, 0.3 ) 215 | ; 216 | -webkit-transition-property: width, height, top, left, -webkit-border-radius; 217 | -moz-transition-property: width, height, top, left, -moz-border-radius; 218 | -webkit-transition-duration: 0.1s; 219 | -moz-transition-duration: 0.1s; 220 | } 221 | 222 | .proxy-range.highlighted .handle { 223 | height: 98px; 224 | top: -35px; 225 | width: 4px; 226 | left: -3px; 227 | background-image: -webkit-gradient(linear, 0 top, 0 bottom, 228 | from( hsla( 0, 0%, 100%, 0.6 ) ), 229 | color-stop( 50%, hsla( 0, 0%, 100%, 0.0 ) ), 230 | color-stop( 50%, hsla( 0, 0%, 0%, 0.0 ) ), 231 | to( hsla( 0, 0%, 0%, 0.5 ) ) 232 | ); 233 | border-radius: 3px; 234 | } 235 | 236 | 237 | 238 | 239 | /******* Pygments *******/ 240 | 241 | 242 | 243 | pre { 244 | background: #111; 245 | color: white; 246 | padding: 0.8em; 247 | white-space: pre-wrap; 248 | } 249 | 250 | 251 | code .s1, 252 | code .s { color: #78BD55; } /* string */ 253 | code .mi, /* integer */ 254 | code .cp { color: #5298D4; } /* doctype */ 255 | code .k { color: #E39B79; } /* keyword */ 256 | code .kd, /* storage */ 257 | code .na { color: #A9D866; } /* markup attribute */ 258 | code .p { color: #EDB; } /* punctuation */ 259 | code .o { color: #F63; } /* operator */ 260 | code .nb { color: #AA97AC;} /* support */ 261 | 262 | /* comment */ 263 | code .c, 264 | code .c1 { color: #666; font-style: italic; } 265 | 266 | code .nt { color: #A0C8FC; } /* Markup open tag */ 267 | 268 | code .nf { color: #9EA8B8; } /* css id */ 269 | code .nc { color: #A78352; } /* CSS class */ 270 | code .m { color: #DE8E50; } /* CSS value */ 271 | code .nd { color: #9FAD7E; } /* CSS pseudo selector */ 272 | -------------------------------------------------------------------------------- /_posts/examples/2010-12-05-box-01-steps.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: example 3 | title: Box 1 - steps 4 | category: examples 5 | --- 6 | 7 | 165 | 166 | 167 | 168 | 169 |

{{ page.title }}

170 | 171 |
172 |
173 |
1
174 |
2
175 |
3
176 |
4
177 |
5
178 |
6
179 |
180 |
181 | 182 |
183 |

184 | 185 | 186 | 187 | 188 |

189 |
190 | 191 | 192 | 193 | -------------------------------------------------------------------------------- /_posts/examples/2010-12-04-cube-02-show-sides.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: example 3 | title: Cube 2 - show sides 4 | category: examples 5 | --- 6 | 7 | 137 | 138 | 139 | 140 | 141 |

{{ page.title }}

142 | 143 |
144 |
145 |
1
146 |
2
147 |
3
148 |
4
149 |
5
150 |
6
151 |
152 |
153 | 154 |
155 | 156 |

157 | 158 | 159 | 160 | 161 | 162 | 163 |

164 | 165 |

166 | 167 |

168 | 169 | 170 |
171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /_posts/examples/2010-12-06-carousel-01.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: example 3 | title: Carousel 1 4 | category: examples 5 | --- 6 | 7 | 120 | 121 | 122 | 123 | 124 |

{{ page.title }}

125 | 126 |
127 | 138 |
139 | 140 |
141 | 145 | 146 |
147 | 148 | 149 | 171 | -------------------------------------------------------------------------------- /_posts/examples/2010-12-05-box-02-show-sides.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: example 3 | title: Box 2 - show sides 4 | category: examples 5 | --- 6 | 7 | 160 | 161 | 162 | 163 | 164 |

{{ page.title }}

165 | 166 |
167 |
168 |
1
169 |
2
170 |
3
171 |
4
172 |
5
173 |
6
174 |
175 |
176 | 177 |
178 | 179 |

180 | 181 | 182 | 183 | 184 | 185 | 186 |

187 | 188 |

189 | 190 |

191 | 192 |
193 | 194 | 195 | 196 | -------------------------------------------------------------------------------- /_posts/examples/2010-12-06-carousel-02-dynamic.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: example 3 | title: Carousel 2 - dynamic 4 | category: examples 5 | --- 6 | 7 | 69 | 70 | 71 | 72 | 73 |

{{ page.title }}

74 | 75 |
76 | 98 |
99 | 100 |
101 |

102 | 103 | 104 |

105 | 106 | 110 | 111 |

112 | 113 |

114 | 115 |

116 | 117 |

118 | 119 |
120 | 121 | 122 | 225 | -------------------------------------------------------------------------------- /_posts/examples/2010-12-02-transforms-03-origin.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: example 3 | title: Transforms 3 - transform origin 4 | category: examples 5 | --- 6 | 7 | 141 | 142 | 143 | 144 | 145 |

{{ page.title }}

146 | 147 |
148 |
149 |
150 |
1
151 |
2
152 |
3
153 |
4
154 |
5
155 |
6
156 |
157 |
158 | 159 | 160 |
161 | 162 |
163 |

164 | 165 | 166 |

167 |

168 | 169 | 170 |

171 | 175 |
176 | 177 | 180 | 181 | 182 |
183 | 184 | 185 | 215 | 216 | -------------------------------------------------------------------------------- /_posts/examples/2010-12-01-perspective-03.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: example 3 | title: Perspective 3 4 | category: examples 5 | --- 6 | 7 | 122 | 123 | 124 | 125 | 126 |

{{ page.title }}

127 | 128 |
129 |
130 |
1
131 |
2
132 |
3
133 |
4
134 |
5
135 |
6
136 |
137 |
138 | 139 | 140 |
141 | 142 |

143 | 144 | 145 |

146 | 147 |

148 | 149 | 150 |

151 | 152 |

153 | 154 | 155 |

156 | 157 |

158 | 159 |

160 | 161 |

162 | 163 |

164 | 165 |
166 | 167 | 168 | 209 | -------------------------------------------------------------------------------- /js/utils.js: -------------------------------------------------------------------------------- 1 | // ======================= DOM Utility Functions from PastryKit =============================== // 2 | 3 | // Sure, we could use jQuery or XUI for these, 4 | // but these are concise and will work with plain vanilla JS 5 | 6 | Element.prototype.hasClassName = function (a) { 7 | return new RegExp("(?:^|\\s+)" + a + "(?:\\s+|$)").test(this.className); 8 | }; 9 | 10 | Element.prototype.addClassName = function (a) { 11 | if (!this.hasClassName(a)) { 12 | this.className = [this.className, a].join(" "); 13 | } 14 | }; 15 | 16 | Element.prototype.removeClassName = function (b) { 17 | if (this.hasClassName(b)) { 18 | var a = this.className; 19 | this.className = a.replace(new RegExp("(?:^|\\s+)" + b + "(?:\\s+|$)", "g"), " "); 20 | } 21 | }; 22 | 23 | Element.prototype.toggleClassName = function (a) { 24 | this[this.hasClassName(a) ? "removeClassName" : "addClassName"](a); 25 | }; 26 | 27 | // ======================= Modernizr =============================== // 28 | 29 | /* Modernizr 2.0.6 (Custom Build) | MIT & BSD 30 | * Build: http://www.modernizr.com/download/#-csstransforms3d-iepp-cssclasses-prefixed-teststyles-testprop-testallprops-prefixes-domprefixes-load 31 | */ 32 | ;window.Modernizr=function(a,b,c){function C(a,b){var c=a.charAt(0).toUpperCase()+a.substr(1),d=(a+" "+o.join(c+" ")+c).split(" ");return B(d,b)}function B(a,b){for(var d in a)if(k[a[d]]!==c)return b=="pfx"?a[d]:!0;return!1}function A(a,b){return!!~(""+a).indexOf(b)}function z(a,b){return typeof a===b}function y(a,b){return x(n.join(a+";")+(b||""))}function x(a){k.cssText=a}var d="2.0.6",e={},f=!0,g=b.documentElement,h=b.head||b.getElementsByTagName("head")[0],i="modernizr",j=b.createElement(i),k=j.style,l,m=Object.prototype.toString,n=" -webkit- -moz- -o- -ms- -khtml- ".split(" "),o="Webkit Moz O ms Khtml".split(" "),p={},q={},r={},s=[],t=function(a,c,d,e){var f,h,j,k=b.createElement("div");if(parseInt(d,10))while(d--)j=b.createElement("div"),j.id=e?e[d]:i+(d+1),k.appendChild(j);f=["­",""].join(""),k.id=i,k.innerHTML+=f,g.appendChild(k),h=c(k,a),k.parentNode.removeChild(k);return!!h},u,v={}.hasOwnProperty,w;!z(v,c)&&!z(v.call,c)?w=function(a,b){return v.call(a,b)}:w=function(a,b){return b in a&&z(a.constructor.prototype[b],c)};var D=function(a,c){var d=a.join(""),f=c.length;t(d,function(a,c){var d=b.styleSheets[b.styleSheets.length-1],g=d.cssRules&&d.cssRules[0]?d.cssRules[0].cssText:d.cssText||"",h=a.childNodes,i={};while(f--)i[h[f].id]=h[f];e.csstransforms3d=i.csstransforms3d.offsetLeft===9},f,c)}([,["@media (",n.join("transform-3d),("),i,")","{#csstransforms3d{left:9px;position:absolute}}"].join("")],[,"csstransforms3d"]);p.csstransforms3d=function(){var a=!!B(["perspectiveProperty","WebkitPerspective","MozPerspective","OPerspective","msPerspective"]);a&&"webkitPerspective"in g.style&&(a=e.csstransforms3d);return a};for(var E in p)w(p,E)&&(u=E.toLowerCase(),e[u]=p[E](),s.push((e[u]?"":"no-")+u));x(""),j=l=null,a.attachEvent&&function(){var a=b.createElement("div");a.innerHTML="";return a.childNodes.length!==1}()&&function(a,b){function s(a){var b=-1;while(++b Thanks Faruk Ates, Paul Irish, and Mike Taylor http://modernizr.com 220 | var isRangeSupported = (function() { 221 | var isSupported = ranges[0].type !== 'text'; 222 | if ( isSupported ) { 223 | var appearanceProp = Modernizr.prefixed('appearance'); 224 | isSupported = getComputedStyle( ranges[0] )[ appearanceProp ] !== 'textfield'; 225 | } 226 | return isSupported; 227 | })(); 228 | 229 | // create range inputs for iOS 230 | if ( !isRangeSupported ) { 231 | for ( i=0; i < rangesLen; i++ ) { 232 | new DDD.ProxyRange( ranges[i] ); 233 | } 234 | } 235 | 236 | } 237 | 238 | }; 239 | 240 | 241 | window.addEventListener( 'DOMContentLoaded', DDD.init, false); 242 | 243 | // put in global namespace 244 | window.DDD = DDD; 245 | 246 | })(); 247 | --------------------------------------------------------------------------------