Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Site updated at 2012-10-22 02:45:03 UTC

  • Loading branch information...
commit 4775bf9478eb1546312d207b4ef5b0886ac9056c 1 parent 11bd794
@tjvantoll authored
Showing with 2,678 additions and 15 deletions.
  1. +1 −1  atom.xml
  2. +1 −1  blog/categories/browsers/atom.xml
  3. +1 −1  blog/categories/css/atom.xml
  4. +1 −1  blog/categories/forms/atom.xml
  5. +1 −1  blog/categories/git/atom.xml
  6. +1 −1  blog/categories/html5/atom.xml
  7. +1 −1  blog/categories/java/atom.xml
  8. +1 −1  blog/categories/javascript/atom.xml
  9. +1 −1  blog/categories/jquery-ui/atom.xml
  10. +1 −1  blog/categories/less/atom.xml
  11. +1 −1  blog/categories/mobile/atom.xml
  12. +1 −1  blog/categories/qunit/atom.xml
  13. +1 −1  blog/categories/unit-testing/atom.xml
  14. +1 −1  sitemap.xml
  15. +15 −1 speaking/index.html
  16. +703 −0 speaking/slides/2012/Efficiency-Top-Ten/css/impress-demo.css
  17. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/asleep.jpg
  18. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/bust.jpg
  19. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/chase.jpg
  20. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/chaseConfused.jpg
  21. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/combine.jpg
  22. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/complex.png
  23. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/compress.jpg
  24. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/delegation.jpg
  25. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/dom.jpg
  26. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/domResults.png
  27. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/flashlight.jpg
  28. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/googleMaps.png
  29. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/gzip.png
  30. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/httpInspector.png
  31. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/httpRequests.png
  32. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/littleThings.jpg
  33. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/max.jpg
  34. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/mobile.jpg
  35. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/surprised.jpg
  36. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/together.jpg
  37. BIN  speaking/slides/2012/Efficiency-Top-Ten/img/usersHappy.jpg
  38. +635 −0 speaking/slides/2012/Efficiency-Top-Ten/index.html
  39. +800 −0 speaking/slides/2012/Efficiency-Top-Ten/js/impress.js
  40. +9 −0 speaking/slides/2012/Efficiency-Top-Ten/js/less-1.3.0.min.js
  41. +150 −0 speaking/slides/2012/Efficiency-Top-Ten/less/style.less
  42. +2 −0  speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-apollo.js
  43. +18 −0 speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-clj.js
  44. +2 −0  speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-css.js
  45. +1 −0  speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-go.js
  46. +2 −0  speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-hs.js
  47. +3 −0  speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-lisp.js
  48. +2 −0  speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-lua.js
  49. +2 −0  speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-ml.js
  50. +4 −0 speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-n.js
  51. +1 −0  speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-proto.js
  52. +2 −0  speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-scala.js
  53. +2 −0  speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-sql.js
  54. +1 −0  speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-tex.js
  55. +2 −0  speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-vb.js
  56. +3 −0  speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-vhdl.js
  57. +2 −0  speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-wiki.js
  58. +3 −0  speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-xq.js
  59. +2 −0  speaking/slides/2012/Efficiency-Top-Ten/prettify/lang-yaml.js
  60. +110 −0 speaking/slides/2012/Efficiency-Top-Ten/prettify/prettify.css
  61. +188 −0 speaking/slides/2012/Efficiency-Top-Ten/prettify/prettify.js
View
2  atom.xml
@@ -4,7 +4,7 @@
<title><![CDATA[TJ VanToll]]></title>
<link href="http://tjvantoll.com/atom.xml" rel="self"/>
<link href="http://tjvantoll.com/"/>
- <updated>2012-10-21T15:03:27-04:00</updated>
+ <updated>2012-10-21T22:44:53-04:00</updated>
<id>http://tjvantoll.com/</id>
<author>
<name><![CDATA[TJ VanToll]]></name>
View
2  blog/categories/browsers/atom.xml
@@ -4,7 +4,7 @@
<title><![CDATA[Category: Browsers | TJ VanToll]]></title>
<link href="http://tjvantoll.com/blog/categories/browsers/atom.xml" rel="self"/>
<link href="http://tjvantoll.com/"/>
- <updated>2012-10-21T15:03:27-04:00</updated>
+ <updated>2012-10-21T22:44:53-04:00</updated>
<id>http://tjvantoll.com/</id>
<author>
<name><![CDATA[TJ VanToll]]></name>
View
2  blog/categories/css/atom.xml
@@ -4,7 +4,7 @@
<title><![CDATA[Category: CSS | TJ VanToll]]></title>
<link href="http://tjvantoll.com/blog/categories/css/atom.xml" rel="self"/>
<link href="http://tjvantoll.com/"/>
- <updated>2012-10-21T15:03:27-04:00</updated>
+ <updated>2012-10-21T22:44:53-04:00</updated>
<id>http://tjvantoll.com/</id>
<author>
<name><![CDATA[TJ VanToll]]></name>
View
2  blog/categories/forms/atom.xml
@@ -4,7 +4,7 @@
<title><![CDATA[Category: Forms | TJ VanToll]]></title>
<link href="http://tjvantoll.com/blog/categories/forms/atom.xml" rel="self"/>
<link href="http://tjvantoll.com/"/>
- <updated>2012-10-21T15:03:27-04:00</updated>
+ <updated>2012-10-21T22:44:53-04:00</updated>
<id>http://tjvantoll.com/</id>
<author>
<name><![CDATA[TJ VanToll]]></name>
View
2  blog/categories/git/atom.xml
@@ -4,7 +4,7 @@
<title><![CDATA[Category: git | TJ VanToll]]></title>
<link href="http://tjvantoll.com/blog/categories/git/atom.xml" rel="self"/>
<link href="http://tjvantoll.com/"/>
- <updated>2012-10-21T15:03:27-04:00</updated>
+ <updated>2012-10-21T22:44:53-04:00</updated>
<id>http://tjvantoll.com/</id>
<author>
<name><![CDATA[TJ VanToll]]></name>
View
2  blog/categories/html5/atom.xml
@@ -4,7 +4,7 @@
<title><![CDATA[Category: HTML5 | TJ VanToll]]></title>
<link href="http://tjvantoll.com/blog/categories/html5/atom.xml" rel="self"/>
<link href="http://tjvantoll.com/"/>
- <updated>2012-10-21T15:03:27-04:00</updated>
+ <updated>2012-10-21T22:44:53-04:00</updated>
<id>http://tjvantoll.com/</id>
<author>
<name><![CDATA[TJ VanToll]]></name>
View
2  blog/categories/java/atom.xml
@@ -4,7 +4,7 @@
<title><![CDATA[Category: Java | TJ VanToll]]></title>
<link href="http://tjvantoll.com/blog/categories/java/atom.xml" rel="self"/>
<link href="http://tjvantoll.com/"/>
- <updated>2012-10-21T15:03:27-04:00</updated>
+ <updated>2012-10-21T22:44:53-04:00</updated>
<id>http://tjvantoll.com/</id>
<author>
<name><![CDATA[TJ VanToll]]></name>
View
2  blog/categories/javascript/atom.xml
@@ -4,7 +4,7 @@
<title><![CDATA[Category: JavaScript | TJ VanToll]]></title>
<link href="http://tjvantoll.com/blog/categories/javascript/atom.xml" rel="self"/>
<link href="http://tjvantoll.com/"/>
- <updated>2012-10-21T15:03:27-04:00</updated>
+ <updated>2012-10-21T22:44:53-04:00</updated>
<id>http://tjvantoll.com/</id>
<author>
<name><![CDATA[TJ VanToll]]></name>
View
2  blog/categories/jquery-ui/atom.xml
@@ -4,7 +4,7 @@
<title><![CDATA[Category: jQuery UI | TJ VanToll]]></title>
<link href="http://tjvantoll.com/blog/categories/jquery-ui/atom.xml" rel="self"/>
<link href="http://tjvantoll.com/"/>
- <updated>2012-10-21T15:03:27-04:00</updated>
+ <updated>2012-10-21T22:44:53-04:00</updated>
<id>http://tjvantoll.com/</id>
<author>
<name><![CDATA[TJ VanToll]]></name>
View
2  blog/categories/less/atom.xml
@@ -4,7 +4,7 @@
<title><![CDATA[Category: LESS | TJ VanToll]]></title>
<link href="http://tjvantoll.com/blog/categories/less/atom.xml" rel="self"/>
<link href="http://tjvantoll.com/"/>
- <updated>2012-10-21T15:03:27-04:00</updated>
+ <updated>2012-10-21T22:44:53-04:00</updated>
<id>http://tjvantoll.com/</id>
<author>
<name><![CDATA[TJ VanToll]]></name>
View
2  blog/categories/mobile/atom.xml
@@ -4,7 +4,7 @@
<title><![CDATA[Category: Mobile | TJ VanToll]]></title>
<link href="http://tjvantoll.com/blog/categories/mobile/atom.xml" rel="self"/>
<link href="http://tjvantoll.com/"/>
- <updated>2012-10-21T15:03:27-04:00</updated>
+ <updated>2012-10-21T22:44:53-04:00</updated>
<id>http://tjvantoll.com/</id>
<author>
<name><![CDATA[TJ VanToll]]></name>
View
2  blog/categories/qunit/atom.xml
@@ -4,7 +4,7 @@
<title><![CDATA[Category: QUnit | TJ VanToll]]></title>
<link href="http://tjvantoll.com/blog/categories/qunit/atom.xml" rel="self"/>
<link href="http://tjvantoll.com/"/>
- <updated>2012-10-21T15:03:27-04:00</updated>
+ <updated>2012-10-21T22:44:53-04:00</updated>
<id>http://tjvantoll.com/</id>
<author>
<name><![CDATA[TJ VanToll]]></name>
View
2  blog/categories/unit-testing/atom.xml
@@ -4,7 +4,7 @@
<title><![CDATA[Category: Unit Testing | TJ VanToll]]></title>
<link href="http://tjvantoll.com/blog/categories/unit-testing/atom.xml" rel="self"/>
<link href="http://tjvantoll.com/"/>
- <updated>2012-10-21T15:03:27-04:00</updated>
+ <updated>2012-10-21T22:44:53-04:00</updated>
<id>http://tjvantoll.com/</id>
<author>
<name><![CDATA[TJ VanToll]]></name>
View
2  sitemap.xml
@@ -130,6 +130,6 @@
</url>
<url>
<loc>http://tjvantoll.com/speaking/</loc>
- <lastmod>2012-08-28T22:31:19-04:00</lastmod>
+ <lastmod>2012-10-21T22:43:19-04:00</lastmod>
</url>
</urlset>
View
16 speaking/index.html
@@ -9,7 +9,7 @@
<meta name="author" content="TJ VanToll">
- <meta name="description" content="Speaking On certain occasions I&#8217;ve been known to talk to people in real life. 2012 LESS 101 Aug 09 2012 Liquid Web - Slides JavaScript for the &hellip;">
+ <meta name="description" content="Speaking On certain occasions I&#8217;ve been known to talk to people in real life. 2012 Front End Web Efficiency - The Top Ten Oct 23 2012 Lansing &hellip;">
<!-- http://t.co/dKP3o1e -->
@@ -106,6 +106,20 @@ <h1 class="entry-title">Speaking</h1>
<h2>2012</h2>
<article>
+ <h1>Front End Web Efficiency - The Top Ten</h1>
+ <time datetime="2012-10-23">
+ <span class="month">Oct</span>
+ <span class="day">23</span>
+ <span class="year">2012</span>
+ </time>
+ <footer>
+ <span class="categories">
+ Lansing Java Users Group - <a href="/speaking/slides/2012/Efficiency-Top-Ten">Slides</a>
+ </span>
+ </footer>
+ </article>
+
+ <article>
<h1>LESS 101</h1>
<time datetime="2012-08-09">
<span class="month">Aug</span>
View
703 speaking/slides/2012/Efficiency-Top-Ten/css/impress-demo.css
@@ -0,0 +1,703 @@
+/*
+ So you like the style of impress.js demo?
+ Or maybe you are just curious how it was done?
+
+ You couldn't find a better place to find out!
+
+ Welcome to the stylesheet impress.js demo presentation.
+
+ Please remember that it is not meant to be a part of impress.js and is
+ not required by impress.js.
+ I expect that anyone creating a presentation for impress.js would create
+ their own set of styles.
+
+ But feel free to read through it and learn how to get the most of what
+ impress.js provides.
+
+ And let me be your guide.
+
+ Shall we begin?
+*/
+
+
+/*
+ We start with a good ol' reset.
+ That's the one by Eric Meyer http://meyerweb.com/eric/tools/css/reset/
+
+ You can probably argue if it is needed here, or not, but for sure it
+ doesn't do any harm and gives us a fresh start.
+*/
+
+html, body, div, span, applet, object, iframe,
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,
+a, abbr, acronym, address, big, cite, code,
+del, dfn, em, img, ins, kbd, q, s, samp,
+small, strike, strong, sub, sup, tt, var,
+b, u, i, center,
+dl, dt, dd, ol, ul, li,
+fieldset, form, label, legend,
+table, caption, tbody, tfoot, thead, tr, th, td,
+article, aside, canvas, details, embed,
+figure, figcaption, footer, header, hgroup,
+menu, nav, output, ruby, section, summary,
+time, mark, audio, video {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-size: 100%;
+ font: inherit;
+ vertical-align: baseline;
+}
+
+/* HTML5 display-role reset for older browsers */
+article, aside, details, figcaption, figure,
+footer, header, hgroup, menu, nav, section {
+ display: block;
+}
+body {
+ line-height: 1;
+}
+ol, ul {
+ list-style: none;
+}
+blockquote, q {
+ quotes: none;
+}
+blockquote:before, blockquote:after,
+q:before, q:after {
+ content: '';
+ content: none;
+}
+
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+}
+
+/*
+ Now here is when interesting things start to appear.
+
+ We set up <body> styles with default font and nice gradient in the background.
+ And yes, there is a lot of repetition there because of -prefixes but we don't
+ want to leave anybody behind.
+*/
+body {
+ font-family: 'PT Sans', sans-serif;
+ min-height: 740px;
+
+ background: rgb(215, 215, 215);
+ background: -webkit-gradient(radial, 50% 50%, 0, 50% 50%, 500, from(rgb(240, 240, 240)), to(rgb(190, 190, 190)));
+ background: -webkit-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
+ background: -moz-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
+ background: -ms-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
+ background: -o-radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
+ background: radial-gradient(rgb(240, 240, 240), rgb(190, 190, 190));
+}
+
+/*
+ Now let's bring some text styles back ...
+*/
+b, strong { font-weight: bold }
+i, em { font-style: italic }
+
+/*
+ ... and give links a nice look.
+*/
+a {
+ color: inherit;
+ text-decoration: none;
+ padding: 0 0.1em;
+ background: rgba(255,255,255,0.5);
+ text-shadow: -1px -1px 2px rgba(100,100,100,0.9);
+ border-radius: 0.2em;
+
+ -webkit-transition: 0.5s;
+ -moz-transition: 0.5s;
+ -ms-transition: 0.5s;
+ -o-transition: 0.5s;
+ transition: 0.5s;
+}
+
+a:hover,
+a:focus {
+ background: rgba(255,255,255,1);
+ text-shadow: -1px -1px 2px rgba(100,100,100,0.5);
+}
+
+/*
+ Because the main point behind the impress.js demo is to demo impress.js
+ we display a fallback message for users with browsers that don't support
+ all the features required by it.
+
+ All of the content will be still fully accessible for them, but I want
+ them to know that they are missing something - that's what the demo is
+ about, isn't it?
+
+ And then we hide the message, when support is detected in the browser.
+*/
+
+.fallback-message {
+ font-family: sans-serif;
+ line-height: 1.3;
+
+ width: 780px;
+ padding: 10px 10px 0;
+ margin: 20px auto;
+
+ border: 1px solid #E4C652;
+ border-radius: 10px;
+ background: #EEDC94;
+}
+
+.fallback-message p {
+ margin-bottom: 10px;
+}
+
+.impress-supported .fallback-message {
+ display: none;
+}
+
+/*
+ Now let's style the presentation steps.
+
+ We start with basics to make sure it displays correctly in everywhere ...
+*/
+
+.step {
+ position: relative;
+ width: 900px;
+ padding: 40px;
+ margin: 20px auto;
+
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ -ms-box-sizing: border-box;
+ -o-box-sizing: border-box;
+ box-sizing: border-box;
+
+ font-family: 'PT Serif', georgia, serif;
+ font-size: 48px;
+ line-height: 1.5;
+}
+
+/*
+ ... and we enhance the styles for impress.js.
+
+ Basically we remove the margin and make inactive steps a little bit transparent.
+*/
+.impress-enabled .step {
+ margin: 0;
+ opacity: 0.3;
+
+ -webkit-transition: opacity 1s;
+ -moz-transition: opacity 1s;
+ -ms-transition: opacity 1s;
+ -o-transition: opacity 1s;
+ transition: opacity 1s;
+}
+
+.impress-enabled .step.active { opacity: 1 }
+
+/*
+ These 'slide' step styles were heavily inspired by HTML5 Slides:
+ http://html5slides.googlecode.com/svn/trunk/styles.css
+
+ ;)
+
+ They cover everything what you see on first three steps of the demo.
+*/
+.slide {
+ display: block;
+
+ width: 900px;
+ height: 700px;
+ padding: 40px 60px;
+
+ background-color: white;
+ border: 1px solid rgba(0, 0, 0, .3);
+ border-radius: 10px;
+ box-shadow: 0 2px 6px rgba(0, 0, 0, .1);
+
+ color: rgb(102, 102, 102);
+ text-shadow: 0 2px 2px rgba(0, 0, 0, .1);
+
+ font-family: 'Open Sans', Arial, sans-serif;
+ font-size: 30px;
+ line-height: 36px;
+ letter-spacing: -1px;
+}
+
+.slide q {
+ display: block;
+ font-size: 50px;
+ line-height: 72px;
+
+ margin-top: 100px;
+}
+
+.slide q strong {
+ white-space: nowrap;
+}
+
+/*
+ And now we start to style each step separately.
+
+ I agree that this may be not the most efficient, object-oriented and
+ scalable way of styling, but most of steps have quite a custom look
+ and typography tricks here and there, so they had to be styles separately.
+
+ First is the title step with a big <h1> (no room for padding) and some
+ 3D positioning along Z axis.
+*/
+
+#title {
+ padding: 0;
+}
+
+#title .try {
+ font-size: 64px;
+ position: absolute;
+ top: -0.5em;
+ left: 1.5em;
+
+ -webkit-transform: translateZ(20px);
+ -moz-transform: translateZ(20px);
+ -ms-transform: translateZ(20px);
+ -o-transform: translateZ(20px);
+ transform: translateZ(20px);
+}
+
+#title h1 {
+ font-size: 190px;
+
+ -webkit-transform: translateZ(50px);
+ -moz-transform: translateZ(50px);
+ -ms-transform: translateZ(50px);
+ -o-transform: translateZ(50px);
+ transform: translateZ(50px);
+}
+
+#title .footnote {
+ font-size: 32px;
+}
+
+/*
+ Second step is nothing special, just a text with a link, so it doesn't need
+ any special styling.
+
+ Let's move to 'big thoughts' with centered text and custom font sizes.
+*/
+#big {
+ width: 600px;
+ text-align: center;
+ font-size: 60px;
+ line-height: 1;
+}
+
+#big b {
+ display: block;
+ font-size: 250px;
+ line-height: 250px;
+}
+
+#big .thoughts {
+ font-size: 90px;
+ line-height: 150px;
+}
+
+/*
+ 'Tiny ideas' just need some tiny styling.
+*/
+#tiny {
+ width: 500px;
+ text-align: center;
+}
+
+/*
+ This step has some animated text ...
+*/
+#ing { width: 500px }
+
+/*
+ ... so we define display to `inline-block` to enable transforms and
+ transition duration to 0.5s ...
+*/
+#ing b {
+ display: inline-block;
+ -webkit-transition: 0.5s;
+ -moz-transition: 0.5s;
+ -ms-transition: 0.5s;
+ -o-transition: 0.5s;
+ transition: 0.5s;
+}
+
+/*
+ ... and we want 'positioning` word to move up a bit when the step gets
+ `present` class ...
+*/
+#ing.present .positioning {
+ -webkit-transform: translateY(-10px);
+ -moz-transform: translateY(-10px);
+ -ms-transform: translateY(-10px);
+ -o-transform: translateY(-10px);
+ transform: translateY(-10px);
+}
+
+/*
+ ... 'rotating' to rotate quater of a second later ...
+*/
+#ing.present .rotating {
+ -webkit-transform: rotate(-10deg);
+ -moz-transform: rotate(-10deg);
+ -ms-transform: rotate(-10deg);
+ -o-transform: rotate(-10deg);
+ transform: rotate(-10deg);
+
+ -webkit-transition-delay: 0.25s;
+ -moz-transition-delay: 0.25s;
+ -ms-transition-delay: 0.25s;
+ -o-transition-delay: 0.25s;
+ transition-delay: 0.25s;
+}
+
+/*
+ ... and 'scaling' to scale down after another quater of a second.
+*/
+#ing.present .scaling {
+ -webkit-transform: scale(0.7);
+ -moz-transform: scale(0.7);
+ -ms-transform: scale(0.7);
+ -o-transform: scale(0.7);
+ transform: scale(0.7);
+
+ -webkit-transition-delay: 0.5s;
+ -moz-transition-delay: 0.5s;
+ -ms-transition-delay: 0.5s;
+ -o-transition-delay: 0.5s;
+ transition-delay: 0.5s;
+}
+
+/*
+ The 'imagination' step is again some boring font-sizing.
+*/
+
+#imagination {
+ width: 600px;
+}
+
+#imagination .imagination {
+ font-size: 78px;
+}
+
+/*
+ There is nothing really special about 'use the source, Luke' step, too,
+ except maybe of the Yoda background.
+
+ As you can see below I've 'hard-coded' it in data URL.
+ That's not the best way to serve images, but because that's just this one
+ I decided it will be OK to have it this way.
+
+ Just make sure you don't blindly copy this approach.
+*/
+#source {
+ width: 700px;
+ padding-bottom: 300px;
+
+ /* Yoda Icon :: Pixel Art from Star Wars http://www.pixeljoint.com/pixelart/1423.htm */
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAARgAAAEYCAMAAACwUBm+AAAAAXNSR0IArs4c6QAAAKtQTFRFsAAAvbWSLUUrLEQqY1s8UYJMqJ1vNTEgOiIdIzYhjIFVLhsXZ6lgSEIsP2U8JhcCVzMsSXZEgXdOO145XJdWOl03LzAYMk4vSXNExr+hwcuxRTs1Qmk+RW9Am49eFRANQz4pUoNMQWc+OSMDTz0wLBsCNVMxa2NBOyUDUoNNSnlEWo9VRGxAVzYFl6tXCggHbLNmMUIcHhwTXkk5f3VNRT8wUT8xAAAACQocRBWFFwAAAAF0Uk5TAEDm2GYAAAPCSURBVHja7d3JctNAFIZRMwRCCGEmzPM8z/D+T8bu/ptbXXJFdij5fMt2Wuo+2UgqxVmtttq5WVotLzBgwIABAwYMGDCn0qVqbo69psPqVpWx+1XG5iaavF8wYMCAAQMGDBgwi4DJ6Y6qkxB1HNlcN3a92gbR5P2CAQMGDBgwYMCAWSxMlrU+UY5yu2l9okfV4bAxUVbf7TJnAwMGDBgwYMCAAbMLMHeqbGR82Zy+VR1Ht81nVca6R+UdTLaU24Ruzd3qM/e4yjnAgAEDBgwYMGDA7AJMd1l/3NRdVGcj3eX/2WEhCmDGxnM7yqygu8XIPjJj8iN/MGDAgAEDBgwYMAuDGb8q0RGlLCHLv1t9qDKWn3vdNHVuEI6HPaxO9Jo3GDBgwIABAwYMmIXBdC9ShGgMk+XnkXUeuGcsP/e1+lhNnZsL/G5Vs3OAAQMGDBgwYMCAWSxMR3SzOmraG5atdy9wZKzb+vg16qyqe2FltbnAgAEDBgwYMGDALAxmTJSuN3WA76rnVca6GTnemGN1WoEBAwYMGDBgwIBZGMxUomy4+xO899V4LAg5Xnc2MGDAgAEDBgwYMGA218Wq+2K1LDqvY9xZu8zN8fICdM6btYABAwYMGDBgwIABMzfH0+pGU5afze2tXebmeAfVz+p8BQYMGDBgwIABAwbMPBzZ+oWmfJrln1273FhkbHzee9WWbw7AgAEDBgwYMGDALAKm43hcdctKgblcPamOhuXnXlY5Xs6bsW4FGyQCAwYMGDBgwIABswiYMceZKgvMo+h8mrHLTdn676rj+FEFoTtHd8MwOxEYMGDAgAEDBgyYRcBM5UhXqiymW3R3c9ARhWO/OmjqfjVZy+xEYMCAAQMGDBgwYBYG073OnCV0RFNhMhaOa9WfKmOB6XjHMN1tQmaAAQMGDBgwYMCA2VWY7vXjz1U4croAzgPztwIDBgwYMGDAgAEDZhswh035NBw59Dww3RgYMGDAgAEDBgwYMJuD6f4tXT7NUqfCdBvZLkxXdgQGDBgwYMCAAQNmt2DGj8WzwAfV/w7T/aq7mxwwYMCAAQMGDBgwuwqTOo7uTwTngflSzQ3TdaJvAwEDBgwYMGDAgAED5gSvgbyo5oHZ4Pc+gwEDBgwYMGDAgAEzhOm+5G0qTGaAAQMGDBgwYMCAAXNaMOcnls3tNwWm+zRzp54NDBgwYMCAAQMGDJh5YNL36k1TLuGvVq+qnKMbS5n7tulT9asCAwYMGDBgwIABA2ZumKuztLnjgQEDBgwYMGDAgNl5mH/4/ltKA6vBNAAAAABJRU5ErkJggg==);
+ background-position: bottom right;
+ background-repeat: no-repeat;
+}
+
+#source q {
+ font-size: 60px;
+}
+
+/*
+ And the "it's in 3D" step again brings some 3D typography - just for fun.
+
+ Because we want to position <span> elements in 3D we set transform-style to
+ `preserve-3d` on the paragraph.
+ It is not needed by webkit browsers, but it is in Firefox. It's hard to say
+ which behaviour is correct as 3D transforms spec is not very clear about it.
+*/
+#its-in-3d p {
+ -webkit-transform-style: preserve-3d;
+ -moz-transform-style: preserve-3d; /* Y U need this Firefox?! */
+ -ms-transform-style: preserve-3d;
+ -o-transform-style: preserve-3d;
+ transform-style: preserve-3d;
+}
+
+/*
+ Below we position each word separately along Z axis and we want it to transition
+ to default position in 0.5s when the step gets `present` class.
+
+ Quite a simple idea, but lot's of styles and prefixes.
+*/
+#its-in-3d span,
+#its-in-3d b {
+ display: inline-block;
+ -webkit-transform: translateZ(40px);
+ -moz-transform: translateZ(40px);
+ -ms-transform: translateZ(40px);
+ -o-transform: translateZ(40px);
+ transform: translateZ(40px);
+
+ -webkit-transition: 0.5s;
+ -moz-transition: 0.5s;
+ -ms-transition: 0.5s;
+ -o-transition: 0.5s;
+ transition: 0.5s;
+}
+
+#its-in-3d .have {
+ -webkit-transform: translateZ(-40px);
+ -moz-transform: translateZ(-40px);
+ -ms-transform: translateZ(-40px);
+ -o-transform: translateZ(-40px);
+ transform: translateZ(-40px);
+}
+
+#its-in-3d .you {
+ -webkit-transform: translateZ(20px);
+ -moz-transform: translateZ(20px);
+ -ms-transform: translateZ(20px);
+ -o-transform: translateZ(20px);
+ transform: translateZ(20px);
+}
+
+#its-in-3d .noticed {
+ -webkit-transform: translateZ(-40px);
+ -moz-transform: translateZ(-40px);
+ -ms-transform: translateZ(-40px);
+ -o-transform: translateZ(-40px);
+ transform: translateZ(-40px);
+}
+
+#its-in-3d .its {
+ -webkit-transform: translateZ(60px);
+ -moz-transform: translateZ(60px);
+ -ms-transform: translateZ(60px);
+ -o-transform: translateZ(60px);
+ transform: translateZ(60px);
+}
+
+#its-in-3d .in {
+ -webkit-transform: translateZ(-10px);
+ -moz-transform: translateZ(-10px);
+ -ms-transform: translateZ(-10px);
+ -o-transform: translateZ(-10px);
+ transform: translateZ(-10px);
+}
+
+#its-in-3d .footnote {
+ font-size: 32px;
+
+ -webkit-transform: translateZ(-10px);
+ -moz-transform: translateZ(-10px);
+ -ms-transform: translateZ(-10px);
+ -o-transform: translateZ(-10px);
+ transform: translateZ(-10px);
+}
+
+#its-in-3d.present span,
+#its-in-3d.present b {
+ -webkit-transform: translateZ(0px);
+ -moz-transform: translateZ(0px);
+ -ms-transform: translateZ(0px);
+ -o-transform: translateZ(0px);
+ transform: translateZ(0px);
+}
+
+/*
+ The last step is an overview.
+ There is no content in it, so we make sure it's not visible because we want
+ to be able to click on other steps.
+
+*/
+#overview { display: none }
+
+/*
+ We also make other steps visible and give them a pointer cursor using the
+ `impress-on-` class.
+*/
+.impress-on-overview .step {
+ opacity: 1;
+ cursor: pointer;
+}
+
+
+/*
+ Now, when we have all the steps styled let's give users a hint how to navigate
+ around the presentation.
+
+ The best way to do this would be to use JavaScript, show a delayed hint for a
+ first time users, then hide it and store a status in cookie or localStorage...
+
+ But I wanted to have some CSS fun and avoid additional scripting...
+
+ Let me explain it first, so maybe the transition magic will be more readable
+ when you read the code.
+
+ First of all I wanted the hint to appear only when user is idle for a while.
+ You can't detect the 'idle' state in CSS, but I delayed a appearing of the
+ hint by 5s using transition-delay.
+
+ You also can't detect in CSS if the user is a first-time visitor, so I had to
+ make an assumption that I'll only show the hint on the first step. And when
+ the step is changed hide the hint, because I can assume that user already
+ knows how to navigate.
+
+ To summarize it - hint is shown when the user is on the first step for longer
+ than 5 seconds.
+
+ The other problem I had was caused by the fact that I wanted the hint to fade
+ in and out. It can be easily achieved by transitioning the opacity property.
+ But that also meant that the hint was always on the screen, even if totally
+ transparent. It covered part of the screen and you couldn't correctly clicked
+ through it.
+ Unfortunately you cannot transition between display `block` and `none` in pure
+ CSS, so I needed a way to not only fade out the hint but also move it out of
+ the screen.
+
+ I solved this problem by positioning the hint below the bottom of the screen
+ with CSS transform and moving it up to show it. But I also didn't want this move
+ to be visible. I wanted the hint only to fade in and out visually, so I delayed
+ the fade in transition, so it starts when the hint is already in its correct
+ position on the screen.
+
+ I know, it sounds complicated ... maybe it would be easier with the code?
+*/
+
+.hint {
+ /*
+ We hide the hint until presentation is started and from browsers not supporting
+ impress.js, as they will have a linear scrollable view ...
+ */
+ display: none;
+
+ /*
+ ... and give it some fixed position and nice styles.
+ */
+ position: fixed;
+ left: 0;
+ right: 0;
+ bottom: 200px;
+
+ background: rgba(0,0,0,0.5);
+ color: #EEE;
+ text-align: center;
+
+ font-size: 50px;
+ padding: 20px;
+
+ z-index: 100;
+
+ /*
+ By default we don't want the hint to be visible, so we make it transparent ...
+ */
+ opacity: 0;
+
+ /*
+ ... and position it below the bottom of the screen (relative to it's fixed position)
+ */
+ -webkit-transform: translateY(400px);
+ -moz-transform: translateY(400px);
+ -ms-transform: translateY(400px);
+ -o-transform: translateY(400px);
+ transform: translateY(400px);
+
+ /*
+ Now let's imagine that the hint is visible and we want to fade it out and move out
+ of the screen.
+
+ So we define the transition on the opacity property with 1s duration and another
+ transition on transform property delayed by 1s so it will happen after the fade out
+ on opacity finished.
+
+ This way user will not see the hint moving down.
+ */
+ -webkit-transition: opacity 1s, -webkit-transform 0.5s 1s;
+ -moz-transition: opacity 1s, -moz-transform 0.5s 1s;
+ -ms-transition: opacity 1s, -ms-transform 0.5s 1s;
+ -o-transition: opacity 1s, -o-transform 0.5s 1s;
+ transition: opacity 1s, transform 0.5s 1s;
+}
+
+/*
+ Now we 'enable' the hint when presentation is initialized ...
+*/
+.impress-enabled .hint { display: block }
+
+/*
+ ... and we will show it when the first step (with id 'bored') is active.
+*/
+.impress-on-bored .hint {
+ /*
+ We remove the transparency and position the hint in its default fixed
+ position.
+ */
+ opacity: 1;
+
+ -webkit-transform: translateY(0px);
+ -moz-transform: translateY(0px);
+ -ms-transform: translateY(0px);
+ -o-transform: translateY(0px);
+ transform: translateY(0px);
+
+ /*
+ Now for fade in transition we have the oposite situation from the one
+ above.
+
+ First after 4.5s delay we animate the transform property to move the hint
+ into its correct position and after that we fade it in with opacity
+ transition.
+ */
+ -webkit-transition: opacity 1s 5s, -webkit-transform 0.5s 4.5s;
+ -moz-transition: opacity 1s 5s, -moz-transform 0.5s 4.5s;
+ -ms-transition: opacity 1s 5s, -ms-transform 0.5s 4.5s;
+ -o-transition: opacity 1s 5s, -o-transform 0.5s 4.5s;
+ transition: opacity 1s 5s, transform 0.5s 4.5s;
+}
+
+/*
+ And as the last thing there is a workaround for quite strange bug.
+ It happens a lot in Chrome. I don't remember if I've seen it in Firefox.
+
+ Sometimes the element positioned in 3D (especially when it's moved back
+ along Z axis) is not clickable, because it falls 'behind' the <body>
+ element.
+
+ To prevent this, I decided to make <body> non clickable by setting
+ pointer-events property to `none` value.
+ Value if this property is inherited, so to make everything else clickable
+ I bring it back on the #impress element.
+
+ If you want to know more about `pointer-events` here are some docs:
+ https://developer.mozilla.org/en/CSS/pointer-events
+
+ There is one very important thing to notice about this workaround - it makes
+ everything 'unclickable' except what's in #impress element.
+
+ So use it wisely ... or don't use at all.
+*/
+.impress-enabled { pointer-events: none }
+.impress-enabled #impress { pointer-events: auto }
+
+/*
+ There is one funny thing I just realized.
+
+ Thanks to this workaround above everything except #impress element is invisible
+ for click events. That means that the hint element is also not clickable.
+ So basically all of this transforms and delayed transitions trickery was probably
+ not needed at all...
+
+ But it was fun to learn about it, wasn't it?
+*/
+
+/*
+ That's all I have for you in this file.
+ Thanks for reading. I hope you enjoyed it at least as much as I enjoyed writing it
+ for you.
+*/
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/asleep.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/bust.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/chase.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/chaseConfused.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/combine.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/complex.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/compress.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/delegation.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/dom.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/domResults.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/flashlight.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/googleMaps.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/gzip.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/httpInspector.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/httpRequests.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/littleThings.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/max.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/mobile.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/surprised.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/together.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  speaking/slides/2012/Efficiency-Top-Ten/img/usersHappy.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
635 speaking/slides/2012/Efficiency-Top-Ten/index.html
@@ -0,0 +1,635 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=1024" />
+ <meta name="apple-mobile-web-app-capable" content="yes" />
+ <title>Front End Web Efficiency - The Top Ten | TJ VanToll</title>
+
+ <meta name="description" content="Front End Web Efficiency - Discussion of the 10 key techniques to make responsive and efficient web applications." />
+ <meta name="author" content="TJ VanToll - tj.vantoll@gmail.com - tjvantoll.com" />
+
+ <link href="http://fonts.googleapis.com/css?family=Open+Sans:regular,semibold,italic,italicsemibold|PT+Sans:400,700,400italic,700italic|PT+Serif:400,700,400italic,700italic" rel="stylesheet" />
+
+ <script src="prettify/prettify.js"></script>
+ <link rel="stylesheet/less" href="less/style.less" />
+ <script src="js/less-1.3.0.min.js"></script>
+</head>
+
+<body class="impress-not-supported" onload="prettyPrint();">
+
+<div class="fallback-message">
+ <p>Your browser <b>doesn't support the features required</b> by impress.js, so you are presented with a simplified version of this presentation.</p>
+ <p>For the best experience please use the latest <b>Chrome</b>, <b>Safari</b> or <b>Firefox</b> browser.</p>
+</div>
+
+<div id="impress">
+
+ <div id="slide-1" class="step slide" data-x="-1000" data-y="-1500">
+ <h1>Front End Web Efficiency<br />The Top Ten</h1>
+ <h2>Ted VanToll</h2>
+ </div>
+
+ <div class="step slide" data-x="500" data-y="-500">
+ <h2>About Me</h2>
+ <ul>
+ <li>I'm a web developer at <a href="http://liquidweb.com">Liquid Web.</a></li>
+ <li>I have twin boys and I like to use their pictures in my slides.</li>
+ </ul>
+ <img src="img/chase.jpg" />
+ <img src="img/max.jpg" />
+ </div>
+
+ <div class="step slide" data-x="0" data-y="-1500">
+ <h2>The Front End</h2>
+ <h3>Why should you care about performance?</h3>
+
+ <ul>
+ <li>According to research performed by Yahoo, on average 80% of end-user response time is spent on the front end. (<a href="http://developer.yahoo.com/performance/rules.html/">source</a>)</li>
+ <li>A study by Web Performance Today found that 74% of users will leave a site after waiting just 5 seconds for it to load. (<a href="http://www.webperformancetoday.com/2011/07/20/new-findings-mobile-web-users-are-more-disappointed-than-ever/">source</a>)</li>
+ </ul>
+ </div>
+
+ <div class="step slide full_screen" data-x="1000" data-y="-1500">
+ <h2>Where to start?</h2>
+ <img src="/img/chaseConfused.jpg" />
+ </div>
+
+ <div class="step slide" data-x="1500" data-y="-2500">
+ <p>Making a site fast may seem complex.</p>
+ <img src="/img/complex.png" />
+ </div>
+
+ <div class="step slide" data-x="2000" data-y="-1500">
+ <h2>Practicality</h2>
+ <ul>
+ <li>A couple small changes can go a long way.</li>
+ <li>It's important to focus on the things that really matter.</li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="3000" data-y="-1500">
+ <p>There is a lot of bad information out there. These things are vary rarely a bottleneck:</p>
+ <ul>
+ <li>Sheer amount of JavaScript present</li>
+ <li>JavaScript performance</li>
+ <li>CSS</li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="3500" data-z="1000" data-y="-500">
+ <h2>The Practical Top 10 List</h2>
+
+ <p>Where does the list come from?</p>
+
+ <ul>
+ <li>My experience</li>
+ <li>Research of best practices published by <a href="https://developers.google.com/speed/">Google</a>, <a href="http://developer.yahoo.com/performance/rules.html">Yahoo</a>, and others.</li>
+ <li>and...</li>
+ </ul>
+ </div>
+
+ <div class="step slide full_screen" data-x="4500" data-z="1000" data-y="-500">
+ <h2>Lots of bad 3G experiences.</h2>
+ <img src="img/mobile.jpg" />
+ </div>
+
+ <div class="step slide point" data-x="4000" data-y="-1500">
+ <h3>Let's Get Started</h3>
+ </div>
+
+ <div class="step slide" data-x="2500" data-y="-1000" data-z="4000" data-rotate-y="25" data-rotate-z="20">
+ <h2>#1) Reduce HTTP Requests</h2>
+
+ <p>The majority of loading time is spent downloading the various components that make up a web page - images, CSS, JavaScript, etc.</p>
+ <img src="/img/httpRequests.png" />
+ </div>
+
+ <div class="step slide" data-x="3800" data-y="-1000" data-z="4000" data-rotate-y="0" data-rotate-z="20">
+ <h2>RTTs > Size</h2>
+ <ul>
+ <li>RTT = <b>R</b>ound <b>T</b>rip <b>T</b>ime.</li>
+ <li>For small download file sizes, RTT is <b>the</b> major contributing to latency on "fast" connections. (<a href="https://developers.google.com/speed/docs/best-practices/rtt">Source</a>).</li>
+ <li>The average mobile RTT time in the US is ~350 ms (<a href="http://www.slideshare.net/patrickmeenan/velocity-2012-taming-the-mobile-beast">Source</a>).</li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="5100" data-y="-1000" data-z="4000" data-rotate-y="-25" data-rotate-z="20">
+ <h2>Download Times</h2>
+
+ <p>Compare that to download numbers.</p>
+ <ul>
+ <li>On average U.S. users download at 4.93 megs per second (<a href="http://mashable.com/2011/09/21/fastest-download-speeds-infographic/">Source</a>).</li>
+ <li>~1.5 mbsp on mobile even (<a href="http://www.slideshare.net/patrickmeenan/velocity-2012-taming-the-mobile-beast">Source</a>).</li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="6400" data-y="-1000" data-z="4000" data-rotate-y="-50" data-rotate-z="20">
+ <h2>Page Size</h2>
+ <p>According to the HTTP archive the average web page size in 2011 was 965 kb (<a href="http://tech.slashdot.org/story/11/12/22/2015231/average-web-page-approaches-1mb">Source</a>).</p>
+ </div>
+
+ <div class="step slide" data-x="7700" data-y="-1000" data-z="4000" data-rotate-y="-75" data-rotate-z="20">
+ <h2>Connections</h2>
+ <ul>
+ <li>To mitigate the RTT problem browsers download resources in parallel.</li>
+ <li>Most modern browsers use 6 connections per hostname (<a href="http://www.browserscope.org/?category=network">Source</a>). Note that IE7 only allows for 2.</li>
+ <li>Each connection pays the cost of a TCP handshake, which is potentially expensive (typically 200+ ms on 3G <a href="http://www.slideshare.net/patrickmeenan/velocity-2012-taming-the-mobile-beast">Source</a>).</li>
+ </ul>
+ </div>
+
+ <div class="step slide point" data-x="9000" data-y="-1000" data-z="4000" data-rotate-y="-100" data-rotate-z="20">
+ <h3>Moral of the Story</h3>
+ </div>
+
+ <div class="step slide full_screen" data-x="10300" data-y="-1000" data-z="4000" data-rotate-y="-125" data-rotate-z="20">
+ <h2>Lots of small downloads = slow</h2>
+ <img src="img/littleThings.jpg" />
+ </div>
+
+ <div class="step slide point" data-x="11600" data-y="-1000" data-z="4000" data-rotate-y="-150" data-rotate-z="20">
+ <h3>How do you reduce HTTP requests?</h3>
+ </div>
+
+ <div class="step slide full_screen" data-x="8000" data-y="-1000" data-z="-1000" data-rotate-y="0" data-rotate-z="20">
+ <h2>Combine Things!</h2>
+ <img src="img/combine.jpg" />
+ </div>
+
+ <div class="step slide" data-x="8000" data-y="0" data-z="-2000" data-rotate-y="0" data-rotate-z="20">
+ <h2>JavaScript</h2>
+
+ <p>There are a plethora of options. Incorporate one into your workflow (source control hook, build script, release, etc...)</p>
+
+ <ul>
+ <li><a href="http://requirejs.org/docs/optimization.html">require.js optimizer</a></li>
+ <li><a href="http://shrinksafe.dojotoolkit.org/">Dojo Shrinksafe</a></li>
+ <li><a href="http://developer.yahoo.com/yui/compressor/">YUI Compressor</a></li>
+ <li><a href="https://developers.google.com/closure/compiler/">Google Closure Compiler</a></li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="8000" data-y="1000" data-z="-3000" data-rotate-y="0" data-rotate-z="20">
+ <h2>CSS</h2>
+ <ul>
+ <li>Many of the JavaScript minifier / combiners also handle CSS (for example require.js optimizer, Dojo, & YUI).</li>
+ <li>CSS preprocessors such as <a href="http://sass-lang.com/">SASS</a>, <a href="http://lesscss.org/">LESS</a>, and <a href="http://learnboost.github.com/stylus/">Stylus</a> can also handle the combining and minification for you.</li>
+ <li>Don't use @import. It does an HTTP request to retrieve the specified file.</li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="8000" data-y="2000" data-z="-4000" data-rotate-y="0" data-rotate-z="20">
+ <h2>Images</h2>
+ <ul>
+ <li>Use <a href="http://css-tricks.com/css-sprites/">CSS sprites</a>. (<a href="http://l1.yimg.com/a/i/ww/met/sprite_pg_nontheme_20111020_ltr.png">Example from yahoo.com</a>)
+ <li>Use <a href="https://developer.mozilla.org/en-US/docs/data_URIs">data URIs</a>. (Example - magnifying glass on <a href="http://www.google.com/m">Google mobile</a>) to inline images.</li>
+ <li>Use <a href="http://css-tricks.com/flat-icons-icon-fonts/">icon fonts</a> to avoid images.</li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="8000" data-y="3000" data-z="-5000" data-rotate-y="0" data-rotate-z="20">
+ <h2>Images Continued</h2>
+ <p>Don't use images to make things that can easily be made in CSS. If you want a rainbow circular ball with shadows, make it with CSS.</p>
+ <div class="rainbow_ball"></div>
+ <p>Don't worry, old IE users don't need rainbow balls.</p>
+ </div>
+
+ <div class="step slide" data-x="8000" data-y="4000" data-z="-6000" data-rotate-y="0" data-rotate-z="20">
+ <h2>How to Measure</h2>
+ <img src="img/httpInspector.png" />
+ <p>Chrome Dev Tools' <font color="blue">network tab</font>. You can see the <font style="text-shadow: 1px 1px 1px black;" color="yellow">number of requests</font>, <font color="red">filter by request type</font>, as well as <font color="green">view download and latency times</font>.
+ </div>
+
+ <div class="step slide full_screen" data-x="8000" data-y="5000" data-z="-7000" data-rotate-y="0" data-rotate-z="20">
+ <h2>That was a long #1.</h2>
+ <img src="img/asleep.jpg" />
+ </div>
+
+ <div class="step slide point" data-x="8000" data-y="6000" data-z="-8000" data-rotate-y="0" data-rotate-z="20">
+ <h3>Questions?</h3>
+ </div>
+
+ <div class="step slide" data-x="6000" data-y="4000" data-z="-14000" data-rotate-y="60" data-rotate-z="20">
+ <h2>#2) Implement Caching</h2>
+ <ul>
+ <li>Browsers use a cache to reduce the number and size of HTTP requests when loading web pages. You probably know this.</li>
+ <li>Doing it right is not hard, but has the potential to ruin a user's experience without you knowing about it.</li>
+ <li>Caching is immensely important for frequently revisited sites. Yahoo found that 75% - 85% of their pages views were from users with a primed cache (<a href="http://developer.yahoo.com/performance/rules.html">Source</a>).</li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="5000" data-y="3000" data-z="-14000" data-rotate-y="120" data-rotate-z="50">
+ <h2>Browsers and Caching</h2>
+ <ul>
+ <li>Browsers look for the <code>Expires</code>, <code>Cache-Control</code>, <code>Last-Modified</code>, and <code>ETag</code> HTTP headers returned on requested resources to determine how to cache them.</li>
+ <li>Browsers have algorithms for handling resources that have none of these headers present. You don't want this. Set the headers.</li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="4000" data-y="2000" data-z="-14000" data-rotate-y="120" data-rotate-z="80">
+ <h2>Expires & Cache-Control</h2>
+ <p>Specify how long the browser can use the cached resource without checking to see if a new version is available (<a href="https://developers.google.com/speed/docs/best-practices/caching">Source</a>).</p>
+ <p>The only <a href="http://stackoverflow.com/questions/5799906/whats-the-difference-between-expires-and-cache-control-headers">difference between the two</a> is syntax options; it's redundant to specify both</a>. <b>Set a far future expiry using one of these headers on everything not dynamic</b>.</p>
+ </div>
+
+ <div class="step slide" data-x="3000" data-y="2000" data-z="-14000" data-rotate-y="120" data-rotate-z="110">
+ <h2>Expires & Cache-Control - Setting</h2>
+
+ <p>Using Apache? Use the .htaccess from the <a href="http://html5boilerplate.com">HTML5 Boilerplate</a> to get useful snippets (<a href="https://github.com/h5bp/html5-boilerplate/blob/master/.htaccess">full source</a>). For example:</p>
+<pre class="prettyprint">
+# CSS and JavaScript
+ ExpiresByType text/css "access plus 1 year"
+ ExpiresByType application/javascript "access plus 1 year"
+</pre>
+ <p>Not using Apache? There are examples for other server configurations <a href="https://github.com/h5bp/server-configs">here</a>.</p>
+ </div>
+
+ <div class="step slide full_screen" data-x="2000" data-y="2000" data-z="-14000" data-rotate-y="120" data-rotate-z="140">
+ <h2>Before you get started...</h2>
+ <img src="img/flashlight.jpg" />
+ </div>
+
+ <div class="step slide" data-x="500" data-y="2000" data-z="-14000" data-rotate-y="120" data-rotate-z="170">
+ <h2>HTTP Headers - Strong</h2>
+ <ul>
+ <li><code>Expires</code> and <code>Cache-Control</code> are strong headers, meaning, once the browser has downloaded a resource it will not issue any GET requests to check for newer versions until the resource has expired.</li>
+ <li>What happens when you want users to get an updated copy of a resource?</li>
+ </ul>
+ </div>
+
+ <div class="step slide full_screen" data-x="-1000" data-y="2000" data-z="-14000" data-rotate-y="120" data-rotate-z="140">
+ <h2>Bust the Cache</h2>
+ <img src="img/bust.jpg" />
+ </div>
+
+ <div class="step slide" data-x="-2500" data-y="2000" data-z="-14000" data-rotate-y="120" data-rotate-z="110">
+ <h2>Cache Busting</h2>
+ <p>Browsers cache based off full URL paths. Therefore, you can change the path whenever you want to bust the cache. This is easily done server side.</p>
+ <p>For example:</p>
+
+<pre class="prettyprint lang-html">
+&lt;!-- Inject a version number using a server-side templating language of your choice --&gt;
+&lt;script src="/path/to/foo.js?version=1.2.3"&gt;&lt;/script&gt;
+&lt;script src="/path/to/1.2.3/foo.js"&gt;&lt;/script&gt;
+</pre>
+ </div>
+
+ <div class="step slide" data-x="-4000" data-y="2000" data-z="-14000" data-rotate-y="120" data-rotate-z="80">
+ <h2>Last-Modified</h2>
+ <ul>
+ <li>Make sure the <code>Last-Modified</code> header is being included on all resources (most web servers take care of this automatically).</li>
+ <li>The browser will use this header when a page is refreshed by doing a conditional GET on the resource. The resource will not need to be download if it has not been modified (in which a 304 response will be returned).</li>
+ </ul>
+ </div>
+
+ <div class="step slide point" data-x="-5500" data-y="2000" data-z="-14000" data-rotate-y="120" data-rotate-z="50">
+ <h3>Questions?</h3>
+ </div>
+
+ <div class="step slide" data-x="-8000" data-y="4000" data-z="-25000" data-rotate-x="-120" data-rotate-y="160" data-rotate-z="60">
+ <h2>#3) Optimize Images</h2>
+
+ <ul>
+ <li>Images make up the largest chunk of most web pages (<a href="https://developers.google.com/speed/articles/web-metrics">Source</a>). Therefore, it's important to reduce their footprint as much as possible.</li>
+ <li>How?</li>
+ </ul>
+ </div>
+
+ <div class="step slide full_screen" data-x="-9000" data-y="4000" data-z="-25000" data-rotate-x="-120" data-rotate-y="190" data-rotate-z="60">
+ <h2>Compress!</h2>
+ <img src="img/compress.jpg" />
+ </div>
+
+ <div class="step slide" data-x="-10000" data-y="4000" data-z="-25000" data-rotate-x="-120" data-rotate-y="220" data-rotate-z="60">
+ <h2>Compression</h2>
+
+ <p>There are numerous lossless compress algorithms you can simply run against your code base. There are Windows, OS X, Linux, and free web based optimizers out there, but here are a few examples:</p>
+
+ <ul>
+ <li><a href="http://optipng.sourceforge.net/">OptiPNG</a></li>
+ <li><a href="http://jpegclub.org/">JPEGClub</a></li>
+ <li><a href="http://imageoptim.com/">ImageOptim</a> (OS X app)</li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="-11000" data-y="4000" data-z="-25000" data-rotate-x="-120" data-rotate-y="250" data-rotate-z="60">
+ <h2>Tip #1</h2>
+
+ <p>Don't scale images in HTML / CSS.</p>
+
+<pre class="prettyprint lang-html">
+&lt;img src="image1.jpg" height="100" width="100" /&gt;
+&lt;img src="image2.jpg" /&gt;
+&lt;style&gt;
+ [src='image2.jpg'] { height: 100px; width: 100px; }
+&lt;/style&gt;
+</pre>
+
+ <p>For both images above a 100 x 100 pixel image will be displayed on the screen, but for both the full size image will be downloaded from the server. Resize the image on the server instead.</p>
+ </div>
+
+ <div class="step slide" data-x="-12000" data-y="4000" data-z="-25000" data-rotate-x="-120" data-rotate-y="280" data-rotate-z="60">
+ <h2>Tip #2</h2>
+
+ <ul>
+ <li>Images that do not display on the screen are still downloaded by the browser. This includes images hidden via <code>display: none</code>, <code>visibility: hidden</code>, as well as images simply off the screen.</li>
+ <li>Images provided as CSS values such as <code>background-image</code> will not be downloaded until they're needed.</li>
+ </li>
+ </div>
+
+ <div class="step slide" data-x="-9000" data-y="6000" data-z="-6000" data-rotate-x="-20" data-rotate-y="200" data-rotate-z="60">
+ <h2>#4) Optimize 3rd Party Dependencies</h2>
+
+ <ul>
+ <li>3rd party means that you are hitting a server you do not have control over for resource(s).</li>
+ <li>Social media buttons and ads are the common examples.</li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="-8000" data-y="7000" data-z="-6000" data-rotate-x="10" data-rotate-y="200" data-rotate-z="60">
+ <h2>Defer Loading</h2>
+
+ <p>Loading of 3rd party scripts should <b>always</b> be deferred until after the DOM has loaded (i.e. after the <code>DOMContentLoaded</code> event has fired).</p>
+
+<pre class="prettyprint lang-html">
+&lt;-- Simple download of a script from Twitter, WHAT COULD GO WRONG? --&gt;
+&lt;script src="//platform.twitter.com/widgets.js" &gt;&lt;/script&gt;
+</pre>
+ </div>
+
+ <div class="step slide full_screen" data-x="-7000" data-y="8000" data-z="-6000" data-rotate-x="40" data-rotate-y="200" data-rotate-z="60">
+ <h2 style="top: 80%;">THE TWITTER IS DOWN!</h2>
+ <img src="img/surprised.jpg" />
+ </div>
+
+ <div class="step slide" data-x="-6000" data-y="9000" data-z="-6000" data-rotate-x="70" data-rotate-y="200" data-rotate-z="60">
+ <h2>Blocking Scripts</h2>
+
+ <p>Browsers block for JavaScript execution because it could potentially affect the HTML parser (think <code>document.write</code>). Fix? Use the <code>defer</code> and <code>async</code> attributes.</p>
+
+<pre class="prettyprint lang-html">
+&lt;script src="//platform.twitter.com/widgets.js" async &gt;&lt;/script&gt;
+</pre>
+ </div>
+
+ <div class="step slide" data-x="-5000" data-y="10000" data-z="-6000" data-rotate-x="100" data-rotate-y="200" data-rotate-z="60">
+ <h2>defer and async</h2>
+
+ <p><code>defer</code>: Script execution will be delayed until HTML parsing is complete.</p>
+ <p><code>async</code>: Script execution will occur whenever the resource becomes available, regardless of whether HTML parsing is available.</p>
+
+ <p><a href="http://peter.sh/experiments/asynchronous-and-deferred-javascript-execution-explained/">Nice visualization of the difference</a>.</p>
+ </div>
+
+ <div class="step slide" data-x="-4000" data-y="11000" data-z="-6000" data-rotate-x="130" data-rotate-y="200" data-rotate-z="60">
+ <h2>Social Buttons</h2>
+
+ <ul>
+ <li>Including the Facebook, Twitter, and Google Plus buttons costs 19 HTTP requests and 246.7K in bandwidth (<a href="http://www.zurb.com/article/883/small-painful-buttons-why-social-media-bu">Source</a>).</li>
+ <li>Think about whether you really need them.</li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="-4000" data-y="6000" data-z="-6000" data-rotate-x="130" data-rotate-y="250" data-rotate-z="60">
+ <h2>#5) Gzip</h2>
+
+ <ul>
+ <li>Gzip is a compression algorithm understood by browsers and web servers.</li>
+ <li>Should be used on HTML, CSS, and JS resources. Do not use on images or other binary formats.</li>
+ <li>Most useful on large files; it can actually increase the size of small files (<a href="https://developers.google.com/speed/docs/best-practices/payload#GzipCompression">Source</a>).
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="-4000" data-y="6000" data-z="-7000" data-rotate-x="80" data-rotate-y="250" data-rotate-z="60">
+ <h2>Gzip = Big Deal</h2>
+
+ <p>jQuery 1.8.2 goes from 93K --> 32K after GZip compression. Gzip is a big deal.</p>
+ </div>
+
+ <div class="step slide" data-x="-4000" data-y="6000" data-z="-8000" data-rotate-x="30" data-rotate-y="250" data-rotate-z="60">
+ <h2>Gzip: How to use it?</h2>
+
+ <img src="img/gzip.png" />
+ <p><font color="red">Red</font>: Browser tells web server is accepts gzipped resources.</p>
+ <p><font color="blue">Blue</font>: Web server returns a gzip encoded JavaScript resource.</p>
+ </div>
+
+ <div class="step slide" data-x="-4000" data-y="6000" data-z="-9000" data-rotate-x="-20" data-rotate-y="250" data-rotate-z="60">
+ <h2>Gzip Continued</h2>
+ <p>Ensure your web server is setting the <code>Content-Encoding</code> header appropriately.</p>
+ <p><a href="https://github.com/h5bp/html5-boilerplate/blob/master/.htaccess">HTML5 boilerplate's .htaccess</a> includes the configuration for Apache servers.</p>
+ </div>
+
+ <div class="step slide" data-x="-3000" data-y="4000" data-z="-4000" data-rotate-x="-20" data-rotate-y="250" data-rotate-z="60">
+ <h2>#6) Use a CDN</h2>
+ <ul>
+ <li>CDN = <b>C</b>ontent <b>D</b>elivery <b>N</b>etwork</li>
+ <li>Collection of web servers distibuted across multiple locations to deliver content more efficiently to users (<a href="http://developer.yahoo.com/performance/rules.html">Source</a>).</li>
+ <li>Geographically closer servers = lower download times</li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="-3000" data-y="4000" data-z="-3000" data-rotate-x="-20" data-rotate-y="250" data-rotate-z="120">
+ <h2>CDN</h2>
+ <ul>
+ <li>A good CDN will select a server to deliver content from based on network proximity.</li>
+ <li>Because the content is on another domain it is not subject to the connections per hostname limit.</li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="-3000" data-y="4000" data-z="-2000" data-rotate-x="-20" data-rotate-y="250" data-rotate-z="180">
+ <h2>Examples</h2>
+ <p>Google Maps uses multiple domains to workaround the browser's connection per hostname limit.</p>
+ <img src="img/googleMaps.png" />
+ <p>When Yahoo moved static content from application servers to a CDN they saw end-user response time improvements of 20% or more (<a href="http://developer.yahoo.com/performance/rules.html">Source</a>).
+ </div>
+
+ <div class="step slide full_screen" data-x="-20000" data-y="5000" data-z="-2000" data-rotate-x="10" data-rotate-y="80" data-rotate-z="180" style="width: 600px;">
+ <h2>#7) Placement of Resources</h2>
+ <img src="img/together.jpg" />
+ </div>
+
+ <div class="step slide" data-x="-22000" data-y="5000" data-z="-2000" data-rotate-x="10" data-rotate-y="80" data-rotate-z="180">
+ <h2>CSS on Top</h2>
+
+ <ul>
+ <li>Makes pages <i>appear</i> to load faster because it allows the page to load progressively (<a href="http://developer.yahoo.com/performance/rules.html">Source</a>).</li>
+ <li>Putting stylesheets near the bottom of the document can prevent progressive rendering of HTML in many browsers (they block to avoid having to do a repaint of the page when styling changes).</li>
+ <li>If the browser doesn't block, the user will often get a FOUC (<b>F</b>lash <b>O</b>f <b>U</b>nstyled <b>C</b>ontent) since the page will be repainted after the HTML has been rendered.</li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="-24000" data-y="5000" data-z="-2000" data-rotate-x="10" data-rotate-y="80" data-rotate-z="180">
+ <h2>JavaScript on the Bottom</h2>
+
+ <ul>
+ <li>Browsers block on script loading. To ensure the user can see content as soon as possible JavaScript should not be executed until the page's HTML has been parsed.</li>
+ <li>This can also be accomplished by using the <code>async</code> and <code>defer</code> attributes. However, putting scripts at the bottom handles all browsers, not just ones that support <a href="http://caniuse.com/#feat=script-async">async</a> and <a href="http://caniuse.com/#feat=script-defer">defer</a>.
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="-26000" data-y="5000" data-z="-2000" data-rotate-x="10" data-rotate-y="80" data-rotate-z="180">
+ <h2>Make CSS and JS External</h2>
+
+ <ul>
+ <li>Inline <code>style</code> and <code>script</code> blocks cannot be cached, external files can.</li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="-28000" data-y="5000" data-z="-2000" data-rotate-x="10" data-rotate-y="80" data-rotate-z="180">
+ <h2>Ultra Optimization</h2>
+
+ <ul>
+ <li>Put all CSS and JS inline on first request to avoid extra HTTP requests to get the external files. Then, preload the external files for subsequent requests. Use a cookie so server-side code knows whether to include the content inline or external.</li>
+ <li>You'll likely only need if you're developing a high traffic mobile landing page (e.g. <a href="http://www.google.com/m/gp">http://www.google.com/m/gp</a> or <a href="http://m.bing.com/">http://m.bing.com/</a>).</li>
+ <li><a href="http://www.stevesouders.com/blog/2011/03/28/storager-case-study-bing-google/">Read more about this technique</a> (it gets totally cooler with <code>localStorage</code>).</a></li>
+ </ul>
+ </div>
+
+ <div class="step slide full_screen" data-x="-18000" data-y="3000" data-z="-2000" data-rotate-x="10" data-rotate-y="80" data-rotate-z="120">
+ <h2>#8) The DOM is a Mess</h2>
+ <img src="img/dom.jpg" />
+ </div>
+
+ <div class="step slide" data-x="-18000" data-y="4500" data-z="-2000" data-rotate-x="10" data-rotate-y="80" data-rotate-z="60">
+ <h2>Which is faster? By how much?</h2>
+<p>Option 1:</p>
+<pre class="prettyprint">
+var foo = document.getElementById('foo');
+for (var i = 0; i < 1000; i++) {
+ foo.innerHTML += 'a';
+}
+</pre>
+<p>Option 2:</p>
+<pre class="prettyprint">
+var foo = document.getElementById('foo');
+var html = '';
+for (var i = 0; i < 1000; i++) {
+ html += 'a';
+}
+foo.innerHTML = html;
+</pre>
+ </div>
+
+ <div class="step slide" data-x="-18000" data-y="6000" data-z="-2000" data-rotate-x="10" data-rotate-y="80" data-rotate-z="0">
+ <p>1000 times faster!?</p>
+ <img src="img/domResults.png" style="width: 800px;" />
+ <p><a href="http://jsperf.com/bulk-changes-to-the-dom">Run it yourself</a></p>
+ </div>
+
+ <div class="step slide" data-x="-18000" data-y="7500" data-z="-2000" data-rotate-x="10" data-rotate-y="80" data-rotate-z="-60">
+ <h2>Why is the DOM Slow?</h2>
+ <p>The browser has to do A LOT whenever the DOM is changed.</p>
+ <ul class="small">
+ <li>Recompute styles based on parent-child relationships.</li>
+ <li>Recompute dimensions.</li>
+ <li>Notify browser extensions and client scripts of the DOM change.</li>
+ <li>Update JavaScript variables that are handles to DOM nodes.</li>
+ <li><a href="http://stackoverflow.com/questions/6817093/but-whys-the-browser-dom-still-so-slow-after-10-years-of-effort">More...</a></li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="-18000" data-y="9000" data-z="-2000" data-rotate-x="10" data-rotate-y="80" data-rotate-z="-120">
+ <h2>What to do?</h2>
+ <ul class="small">
+ <li>Modify the DOM as little as possible.</li>
+ <li>Try to make big changes "offline" (aka off the DOM).</li>
+ <li>Don't treat the DOM as storage, just use JavaScript variables.</li>
+ </ul>
+ </div>
+
+ <div class="step slide full_screen" data-x="-22000" data-y="7000" data-z="-1000" data-rotate-x="70" data-rotate-y="0" data-rotate-z="-120" style="width: 600px;">
+ <h2>#9) Delegate</h2>
+ <img src="img/delegation.jpg" />
+ </div>
+
+ <div class="step slide" data-x="-22000" data-y="7000" data-z="-2500" data-rotate-x="70" data-rotate-y="0" data-rotate-z="-120">
+ <h2>Example</h2>
+ <p>Turn all table cells red on hover.</p>
+<pre class="prettyprint lang-js">
+var cells = document.getElementsByTagName('td');
+for (var i = 0; i < cells.length; i++) {
+ cells[i].addEventListener('mouseover', function(event) {
+ event.target.style.backgroundColor = 'red';
+ }, false);
+}
+
+//With jQuery
+$('td').bind('mouseover', function() {
+ $(this).css('backgroundColor', 'red');
+});
+</pre>
+ <p>One event per DOM node. More events firing leads to a slower user experience if the event is doing something non-trivial. More events attached leads to more memory consumption.</p>
+ </div>
+
+ <div class="step slide" data-x="-22000" data-y="7000" data-z="-4000" data-rotate-x="70" data-rotate-y="0" data-rotate-z="-120">
+ <h2>Better</h2>
+<pre class="prettyprint lang-js">
+var tables = document.getElementsByTagName('table');
+for (var i = 0; i < tables.length; i++) {
+ tables[i].addEventListener('mouseover', function(event) {
+ if (event.target.nodeName == 'TD') {
+ event.target.style.backgroundColor = 'red';
+ }
+ }, false);
+}
+
+//Or with jQuery
+$('table').on('td', 'mouseover', function() {
+ $(this).css('backgroundColor', 'red');
+});
+</pre>
+ <p>Less events means less memory consumption and a faster user experience.</p>
+ </div>
+
+ <div class="step slide" data-x="-17000" data-y="4000" data-z="-4000" data-rotate-x="40" data-rotate-y="30" data-rotate-z="-120">
+ <h2>#10) Honorable Mentions</h2>
+
+ <ul>
+ <li>Don't set cookies on domains static resources are sent from (useless header will be sent on every request).</li>
+ <li>Don't have an enormous DOM (longer to download, more strain on the browser to render and manage).</li>
+ <li>Don't have 404's, duh. Avoid redirects as much as possible.</li>
+ <li>Preload stuff you know the user will need.</li>
+ </ul>
+ </div>
+
+ <div class="step slide" data-x="-15000" data-y="3000" data-z="-4000" data-rotate-x="40" data-rotate-y="30" data-rotate-z="30">
+ <h2>Tools</h2>
+
+ <ul>
+ <li><a href="https://developers.google.com/chrome-developer-tools/docs/overview">Chrome Dev Tools</a></li>
+ <li><a href="http://getfirebug.com/">FireBug</a></li>
+ <li><a href="http://developer.yahoo.com/yslow/">YSlow</a></li>
+ <li><a href="https://developers.google.com/speed/pagespeed/">Google Page Speed</a></li>
+ </ul>
+ </div>
+
+ <div class="step slide point" data-x="-13000" data-y="3000" data-z="-4000" data-rotate-x="40" data-rotate-y="30" data-rotate-z="180">
+ <h3>Questions?</h3>
+ </div>
+
+ <div class="step slide full_screen" data-x="-11000" data-y="3000" data-z="-4000" data-rotate-x="40" data-rotate-y="30" data-rotate-z="30" style="width: 500px;">
+ <h2>Make Users Happy</h2>
+ <img src="img/usersHappy.jpg" />
+ </div>
+
+ <div class="step slide point" id="end" data-x="-9000" data-y="3000" data-z="-4000" data-rotate-x="50" data-rotate-y="60" data-rotate-z="-120" data-scale="10">
+ <h3>Thanks!</h3>
+ <a href="https://twitter.com/tjvantoll">@tjvantoll</a>
+ </div>
+</div>
+
+<div class="hint">
+ <p>Use a spacebar or arrow keys to navigate</p>
+</div>
+<script>
+if ("ontouchstart" in document.documentElement) {
+ document.querySelector(".hint").innerHTML = "<p>Tap on the left or right to navigate</p>";
+}
+</script>
+
+<script src="js/impress.js"></script>
+<script>impress().init();</script>
+
+</body>
+</html>
View
800 speaking/slides/2012/Efficiency-Top-Ten/js/impress.js
@@ -0,0 +1,800 @@
+/**
+ * impress.js
+ *
+ * impress.js is a presentation tool based on the power of CSS3 transforms and transitions
+ * in modern browsers and inspired by the idea behind prezi.com.
+ *
+ *
+ * Copyright 2011-2012 Bartek Szopka (@bartaz)
+ *
+ * Released under the MIT and GPL Licenses.
+ *
+ * ------------------------------------------------
+ * author: Bartek Szopka
+ * version: 0.5.3
+ * url: http://bartaz.github.com/impress.js/
+ * source: http://github.com/bartaz/impress.js/
+ */
+
+/*jshint bitwise:true, curly:true, eqeqeq:true, forin:true, latedef:true, newcap:true,
+ noarg:true, noempty:true, undef:true, strict:true, browser:true */
+
+// You are one of those who like to know how thing work inside?
+// Let me show you the cogs that make impress.js run...
+(function ( document, window ) {
+ 'use strict';
+
+ // HELPER FUNCTIONS
+
+ // `pfx` is a function that takes a standard CSS property name as a parameter
+ // and returns it's prefixed version valid for current browser it runs in.
+ // The code is heavily inspired by Modernizr http://www.modernizr.com/
+ var pfx = (function () {
+
+ var style = document.createElement('dummy').style,
+ prefixes = 'Webkit Moz O ms Khtml'.split(' '),
+ memory = {};
+
+ return function ( prop ) {
+ if ( typeof memory[ prop ] === "undefined" ) {
+
+ var ucProp = prop.charAt(0).toUpperCase() + prop.substr(1),
+ props = (prop + ' ' + prefixes.join(ucProp + ' ') + ucProp).split(' ');
+
+ memory[ prop ] = null;
+ for ( var i in props ) {
+ if ( style[ props[i] ] !== undefined ) {
+ memory[ prop ] = props[i];
+ break;
+ }
+ }
+
+ }
+
+ return memory[ prop ];
+ };
+
+ })();
+
+ // `arraify` takes an array-like object and turns it into real Array
+ // to make all the Array.prototype goodness available.
+ var arrayify = function ( a ) {
+ return [].slice.call( a );
+ };
+
+ // `css` function applies the styles given in `props` object to the element
+ // given as `el`. It runs all property names through `pfx` function to make
+ // sure proper prefixed version of the property is used.
+ var css = function ( el, props ) {
+ var key, pkey;
+ for ( key in props ) {
+ if ( props.hasOwnProperty(key) ) {
+ pkey = pfx(key);
+ if ( pkey !== null ) {
+ el.style[pkey] = props[key];
+ }
+ }
+ }
+ return el;
+ };
+
+ // `toNumber` takes a value given as `numeric` parameter and tries to turn
+ // it into a number. If it is not possible it returns 0 (or other value
+ // given as `fallback`).
+ var toNumber = function (numeric, fallback) {
+ return isNaN(numeric) ? (fallback || 0) : Number(numeric);
+ };
+
+ // `byId` returns element with given `id` - you probably have guessed that ;)
+ var byId = function ( id ) {
+ return document.getElementById(id);
+ };
+
+ // `$` returns first element for given CSS `selector` in the `context` of
+ // the given element or whole document.
+ var $ = function ( selector, context ) {
+ context = context || document;
+ return context.querySelector(selector);
+ };
+
+ // `$$` return an array of elements for given CSS `selector` in the `context` of
+ // the given element or whole document.
+ var $$ = function ( selector, context ) {
+ context = context || document;
+ return arrayify( context.querySelectorAll(selector) );
+ };
+
+ // `triggerEvent` builds a custom DOM event with given `eventName` and `detail` data
+ // and triggers it on element given as `el`.
+ var triggerEvent = function (el, eventName, detail) {
+ var event = document.createEvent("CustomEvent");
+ event.initCustomEvent(eventName, true, true, detail);
+ el.dispatchEvent(event);
+ };
+
+ // `translate` builds a translate transform string for given data.
+ var translate = function ( t ) {
+ return " translate3d(" + t.x + "px," + t.y + "px," + t.z + "px) ";
+ };
+
+ // `rotate` builds a rotate transform string for given data.
+ // By default the rotations are in X Y Z order that can be reverted by passing `true`
+ // as second parameter.
+ var rotate = function ( r, revert ) {
+ var rX = " rotateX(" + r.x + "deg) ",
+ rY = " rotateY(" + r.y + "deg) ",
+ rZ = " rotateZ(" + r.z + "deg) ";
+
+ return revert ? rZ+rY+rX : rX+rY+rZ;
+ };
+
+ // `scale` builds a scale transform string for given data.
+ var scale = function ( s ) {
+ return " scale(" + s + ") ";
+ };
+
+ // `perspective` builds a perspective transform string for given data.
+ var perspective = function ( p ) {
+ return " perspective(" + p + "px) ";
+ };
+
+ // `getElementFromHash` returns an element located by id from hash part of
+ // window location.
+ var getElementFromHash = function () {
+ // get id from url # by removing `#` or `#/` from the beginning,
+ // so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work
+ return byId( window.location.hash.replace(/^#\/?/,"") );
+ };
+
+ // `computeWindowScale` counts the scale factor between window size and size
+ // defined for the presentation in the config.
+ var computeWindowScale = function ( config ) {
+ var hScale = window.innerHeight / config.height,
+ wScale = window.innerWidth / config.width,
+ scale = hScale > wScale ? wScale : hScale;
+
+ if (config.maxScale && scale > config.maxScale) {
+ scale = config.maxScale;
+ }
+
+ if (config.minScale && scale < config.minScale) {
+ scale = config.minScale;
+ }
+
+ return scale;
+ };
+
+ // CHECK SUPPORT
+ var body = document.body;
+
+ var ua = navigator.userAgent.toLowerCase();
+ var impressSupported =
+ // browser should support CSS 3D transtorms
+ ( pfx("perspective") !== null ) &&
+
+ // and `classList` and `dataset` APIs
+ ( body.classList ) &&
+ ( body.dataset ) &&
+
+ // but some mobile devices need to be blacklisted,
+ // because their CSS 3D support or hardware is not
+ // good enough to run impress.js properly, sorry...
+ ( ua.search(/(iphone)|(ipod)|(android)/) === -1 );
+
+ if (!impressSupported) {
+ // we can't be sure that `classList` is supported
+ body.className += " impress-not-supported ";
+ } else {
+ body.classList.remove("impress-not-supported");
+ body.classList.add("impress-supported");
+ }
+
+ // GLOBALS AND DEFAULTS
+
+ // This is were the root elements of all impress.js instances will be kept.
+ // Yes, this means you can have more than one instance on a page, but I'm not
+ // sure if it makes any sense in practice ;)
+ var roots = {};
+
+ // some default config values.
+ var defaults = {
+ width: 1024,
+ height: 768,
+ maxScale: 1,
+ minScale: 0,
+
+ perspective: 1000,
+
+ transitionDuration: 1000
+ };
+
+ // it's just an empty function ... and a useless comment.
+ var empty = function () { return false; };
+
+ // IMPRESS.JS API
+
+ // And that's where interesting things will start to happen.
+ // It's the core `impress` function that returns the impress.js API
+ // for a presentation based on the element with given id ('impress'
+ // by default).
+ var impress = window.impress = function ( rootId ) {
+
+ // If impress.js is not supported by the browser return a dummy API
+ // it may not be a perfect solution but we return early and avoid
+ // running code that may use features not implemented in the browser.
+ if (!impressSupported) {
+ return {
+ init: empty,
+ goto: empty,
+ prev: empty,
+ next: empty
+ };
+ }
+
+ rootId = rootId || "impress";
+
+ // if given root is already initialized just return the API
+ if (roots["impress-root-" + rootId]) {
+ return roots["impress-root-" + rootId];
+ }
+
+ // data of all presentation steps
+ var stepsData = {};
+
+ // element of currently active step
+ var activeStep = null;
+
+ // current state (position, rotation and scale) of the presentation
+ var currentState = null;
+
+ // array of step elements
+ var steps = null;
+
+ // configuration options
+ var config = null;
+
+ // scale factor of the browser window
+ var windowScale = null;
+
+ // root presentation elements
+ var root = byId( rootId );
+ var canvas = document.createElement("div");
+
+ var initialized = false;
+
+ // STEP EVENTS
+ //
+ // There are currently two step events triggered by impress.js
+ // `impress:stepenter` is triggered when the step is shown on the
+ // screen (the transition from the previous one is finished) and
+ // `impress:stepleave` is triggered when the step is left (the
+ // transition to next step just starts).
+
+ // reference to last entered step
+ var lastEntered = null;
+
+ // `onStepEnter` is called whenever the step element is entered
+ // but the event is triggered only if the step is different than
+ // last entered step.
+ var onStepEnter = function (step) {
+ if (lastEntered !== step) {
+ triggerEvent(step, "impress:stepenter");
+ lastEntered = step;
+ }
+ };
+
+ // `onStepLeave` is called whenever the step element is left
+ // but the event is triggered only if the step is the same as
+ // last entered step.
+ var onStepLeave = function (step) {
+ if (lastEntered === step) {
+ triggerEvent(step, "impress:stepleave");
+ lastEntered = null;
+ }
+ };
+
+ // `initStep` initializes given step element by reading data from its
+ // data attributes and setting correct styles.
+ var initStep = function ( el, idx ) {
+ var data = el.dataset,
+ step = {
+ translate: {
+ x: toNumber(data.x),
+ y: toNumber(data.y),
+ z: toNumber(data.z)
+ },
+ rotate: {
+ x: toNumber(data.rotateX),
+ y: toNumber(data.rotateY),
+ z: toNumber(data.rotateZ || data.rotate)
+ },
+ scale: toNumber(data.scale, 1),
+ el: el
+ };
+
+ if ( !el.id ) {
+ el.id = "step-" + (idx + 1);
+ }
+
+ stepsData["impress-" + el.id] = step;
+
+ css(el, {
+ position: "absolute",
+ transform: "translate(-50%,-50%)" +
+ translate(step.translate) +
+ rotate(step.rotate) +
+ scale(step.scale),
+ transformStyle: "preserve-3d"
+ });
+ };
+
+ // `init` API function that initializes (and runs) the presentation.
+ var init = function () {
+ if (initialized) { return; }
+
+ // First we set up the viewport for mobile devices.
+ // For some reason iPad goes nuts when it is not done properly.
+ var meta = $("meta[name='viewport']") || document.createElement("meta");
+ meta.content = "width=device-width, minimum-scale=1, maximum-scale=1, user-scalable=no";
+ if (meta.parentNode !== document.head) {
+ meta.name = 'viewport';
+ document.head.appendChild(meta);
+ }
+
+ // initialize configuration object
+ var rootData = root.dataset;
+ config = {
+ width: toNumber( rootData.width, defaults.width ),
+ height: toNumber( rootData.height, defaults.height ),
+ maxScale: toNumber( rootData.maxScale, defaults.maxScale ),
+ minScale: toNumber( rootData.minScale, defaults.minScale ),
+ perspective: toNumber( rootData.perspective, defaults.perspective ),
+ transitionDuration: toNumber( rootData.transitionDuration, defaults.transitionDuration )
+ };
+
+ windowScale = computeWindowScale( config );
+
+ // wrap steps with "canvas" element
+ arrayify( root.childNodes ).forEach(function ( el ) {
+ canvas.appendChild( el );
+ });
+ root.appendChild(canvas);
+
+ // set initial styles
+ document.documentElement.style.height = "100%";
+
+ css(body, {
+ height: "100%",
+ overflow: "hidden"
+ });
+
+ var rootStyles = {
+ position: "absolute",
+ transformOrigin: "top left",
+ transition: "all 0s ease-in-out",
+ transformStyle: "preserve-3d"
+ };
+
+ css(root, rootStyles);
+ css(root, {
+ top: "50%",
+ left: "50%",
+ transform: perspective( config.perspective/windowScale ) + scale( windowScale )
+ });
+ css(canvas, rootStyles);
+
+ body.classList.remove("impress-disabled");
+ body.classList.add("impress-enabled");
+
+ // get and init steps
+ steps = $$(".step", root);
+ steps.forEach( initStep );
+
+ // set a default initial state of the canvas
+ currentState = {
+ translate: { x: 0, y: 0, z: 0 },
+ rotate: { x: 0, y: 0, z: 0 },
+ scale: 1
+ };
+
+ initialized = true;
+
+ triggerEvent(root, "impress:init", { api: roots[ "impress-root-