├── CHANGELOG.md
├── README.md
├── build
├── build
├── build.xml
└── google-compiler-20100917.jar
├── compass
├── config.rb
└── scss
│ └── style.scss
├── css
├── img
│ └── html5.png
└── style.css
├── demo.html
└── js
├── cssanimation.jquery.js
├── cssanimation.jquery.min.js
├── cssanimation.js
├── cssanimation.min.js
└── src
├── cssanimation.jquery.js
├── cssanimation.js
└── requestanimationframe.js
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # 0.2 (2011/06/14)
2 | - Added `iterationCount` property to allow for repeating animations.
3 | - Added support for Firefox (FF5 will support CSS Animations).
4 | - Fixed a bug in `CSSAnimation.find` where trying to interrogate a stylesheet from another domain could throw a security error.
5 |
6 | # 0.1 (2011/05/20)
7 | - Initial release
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CSS3 Animation Keyframe Events
2 | CSS3 Animations are great but the current implementation doesn't trigger Javascript Events for each Keyframe [(see here for more information)](http://blog.joelambert.co.uk/2011/05/17/keyframe-events-for-css3-animations/).
3 |
4 | The CSSAnimation object provides the events the browser vendors left out! This allows you to bind event handlers to `cssAnimationKeyframe` events and perform any additional code that needs to happen at each keyframe.
5 |
6 | *Note: This won't work as well on Mobile Webkit until `webkitRequestAnimationFrame()` is implemented!*
7 |
8 | ## Tested Under
9 | - Safari 5
10 | - Chrome 12
11 | - Firefox 5
12 |
13 | ## May/should also work for
14 | - iOS (see above caveat about Mobile WebKit)
15 |
16 | # Requirements
17 | A browser capable of rendering CSS3 Animations.
18 |
19 | # Usage
20 | Create the CSS animation keyframes in CSS as you would normally, for example with Safari/Chrome:
21 |
22 | @-webkit-keyframes boxrotate {
23 | 0% {
24 | -webkit-transform: translate3d(0, 0, 0);
25 | background: #da371e;
26 | }
27 |
28 | 25% {
29 | -webkit-transform: translate3d(0px, 200px, 0) rotate(90deg);
30 | background: #da3ab9;
31 | }
32 |
33 | 50% {
34 | -webkit-transform: translate3d(200px, 200px, 0) rotate(180deg);
35 | background: #34b6da;
36 | }
37 |
38 | 75% {
39 | -webkit-transform: translate3d(200px, 0, 0) rotate(270deg);
40 | background: #88da50;
41 | }
42 |
43 | 100% {
44 | -webkit-transform: translate3d(0, 0, 0) rotate(360deg);
45 | background: #da371e;
46 | }
47 | }
48 |
49 | Next trigger the animation on a specified DOM element:
50 |
51 | var elem = document.getElementById('animateme');
52 |
53 | // Trigger the animation named 'boxrotate' with duration 3000ms
54 | CSSAnimation.trigger(elem, 'boxrotate', 3000);
55 |
56 | There is also a jQuery plugin provided for convenience (`cssanimation.jquery.js`):
57 |
58 | $('#animateme').cssanimation('boxrotate', 3000);
59 |
60 | You can then listen for `cssAnimationKeyframe` events the same way you'd listen for any other. Here's an example using jQuery:
61 |
62 | $('#animateme').bind('cssAnimationKeyframe', function(event){
63 | var text = "";
64 |
65 | switch(event.originalEvent.keyText) {
66 | case '0%':
67 | text = "down ↓"; break;
68 | case '25%':
69 | text = "right →"; break;
70 | case '50%':
71 | text = "up ↑"; break;
72 | case '75%':
73 | text = "left ←"; break;
74 | case '100%':
75 | text = "click me"; break;
76 | };
77 |
78 | $('#text').html(text);
79 | });
80 |
81 | # Limitations
82 |
83 | Currently events will only be fired for keyframes at 5% increments (e.g. 0%, 5%, 10% etc). So if you have a keyframe at 23%, you won't be notified. This is similar in design to how [jQuery Runloop](http://farukat.es/journal/2011/02/514-new-creation-jquery-runloop-plugin) works.
84 |
85 | You can change this if you want but you may begin to miss events! If you really want to change this you can by passing in an option to either the native function or jQuery plugin:
86 |
87 | // Native
88 | CSSAnimation.trigger(elem, 'boxrotate', 3000, {
89 | base: 1 // Raise events for keyframes at 1% increments
90 | });
91 |
92 | // jQuery
93 | elem.cssanimation('boxrotate', 3000, {
94 | base: 1 // Raise events for keyframes at 1% increments
95 | });
96 |
97 | # How does it work?
98 |
99 | Using the `requestAnimFrame()` shim by [Paul Irish](http://paulirish.com/2011/requestanimationframe-for-smart-animating/) we can get very accurate callbacks (@60fps), this means that:
100 |
101 | > The browser can optimize concurrent animations together into a single reflow and repaint cycle, leading to higher fidelity animation. For example, JS-based animations synchronized with CSS transitions.
102 |
103 | This enables us to work out when a keyframe ought to have occured and raise a suitable event.
104 |
105 | # Contributing
106 |
107 | Contribution is welcomed but to make it easier to accept a pull request here are some guidelines:
108 |
109 | - Please make all changes into the source files found under `js/src`. You can then use the build tool (PHP script found at `./build/build`) to create the concatenated and minified files.
110 |
111 | - Please [camelCase](http://en.wikipedia.org/wiki/CamelCase) your variables, especially if they are used in the options object.
112 |
113 | # License
114 |
115 | CSSAnimation Keyframe Events is Copyright © 2011 [Joe Lambert](http://www.joelambert.co.uk) and is licensed under the terms of the [MIT License](http://www.opensource.org/licenses/mit-license.php).
--------------------------------------------------------------------------------
/build/build:
--------------------------------------------------------------------------------
1 | #!/usr/bin/php
2 | docroot ? $xml->docroot : "./";
13 |
14 | $version = $xml->version ? $xml->version : "1.0";
15 |
16 | // Process each output file
17 | foreach($xml->output->file as $output)
18 | {
19 | $concat = "";
20 | $attr = $output->attributes();
21 |
22 | $outputname = $attr['name'] ? $attr['name']."" : "javascript";
23 |
24 | // Concat javascript files
25 | foreach($output->source as $file)
26 | $concat .= file_get_contents(dirname(__FILE__)."/$docroot/$file").";\n\n";
27 |
28 | // Process any replacements
29 | $concat = str_replace('@VERSION', $version, $concat);
30 |
31 | // Save to disk
32 | $max_path = dirname(__FILE__)."/$docroot/$outputname.js";
33 | file_put_contents($max_path, $concat);
34 |
35 | // Compile and minify with Google Closure Compiler
36 | $min_path = dirname(__FILE__)."/$docroot/$outputname.min.js";
37 |
38 | system("java -jar ".escapeshellarg(dirname(__FILE__)."/google-compiler-20100917.jar")." --js ".escapeshellarg($max_path)." --warning_level QUIET --js_output_file ".escapeshellarg($min_path));
39 | }
40 | ?>
--------------------------------------------------------------------------------
/build/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 0.2
4 | ../js/
5 |
6 |
7 | src/cssanimation.js
8 | src/requestanimationframe.js
9 |
10 |
11 | src/cssanimation.jquery.js
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/build/google-compiler-20100917.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelambert/CSSAnimationKeyframeEvents/cb72cdee63a5ec193353522520b69896b3f72aea/build/google-compiler-20100917.jar
--------------------------------------------------------------------------------
/compass/config.rb:
--------------------------------------------------------------------------------
1 | # Require any additional compass plugins here.
2 |
3 | # Set this to the root of your project when deployed:
4 | http_path = "/"
5 | css_dir = "../css"
6 | sass_dir = "scss"
7 | images_dir = "../css/img"
8 | javascripts_dir = "javascripts"
9 |
10 | # You can select your preferred output style here (can be overridden via the command line):
11 | # output_style = :expanded or :nested or :compact or :compressed
12 |
13 | # To enable relative paths to assets via compass helper functions. Uncomment:
14 | # relative_assets = true
15 |
16 | # To disable debugging comments that display the original location of your selectors. Uncomment:
17 | # line_comments = false
18 |
19 |
20 | # If you prefer the indented syntax, you might want to regenerate this
21 | # project again passing --syntax sass, or you can uncomment this:
22 | # preferred_syntax = :sass
23 | # and then run:
24 | # sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass
25 |
--------------------------------------------------------------------------------
/compass/scss/style.scss:
--------------------------------------------------------------------------------
1 | /* Welcome to Compass.
2 | * In this file you should write your main styles. (or centralize your imports)
3 | * Import this file using the following HTML or equivalent:
4 | * */
5 |
6 | @import "compass/reset";
7 | @import "compass/css3";
8 | @include reset-html5;
9 |
10 | @-webkit-keyframes boxrotate {
11 | 0%
12 | {
13 | -webkit-transform: translate3d(0, 0, 0);
14 | background: #da371e;
15 | }
16 |
17 | 25%
18 | {
19 | -webkit-transform: translate3d(0px, 200px, 0) rotate(90deg);
20 | background: #da3ab9;
21 | }
22 |
23 | 50%
24 | {
25 | -webkit-transform: translate3d(200px, 200px, 0) rotate(180deg);
26 | background: #34b6da;
27 | }
28 |
29 | 75%
30 | {
31 | -webkit-transform: translate3d(200px, 0, 0) rotate(270deg);
32 | background: #88da50;
33 | }
34 |
35 | 100%
36 | {
37 | -webkit-transform: translate3d(0, 0, 0) rotate(360deg);
38 | background: #da371e;
39 | }
40 | }
41 |
42 | @-moz-keyframes boxrotate {
43 | 0%
44 | {
45 | -moz-transform: translate(0, 0);
46 | background: #da371e;
47 | }
48 |
49 | 25%
50 | {
51 | -moz-transform: translate(0px, 200px) rotate(90deg);
52 | background: #da3ab9;
53 | }
54 |
55 | 50%
56 | {
57 | -moz-transform: translate(200px, 200px) rotate(180deg);
58 | background: #34b6da;
59 | }
60 |
61 | 75%
62 | {
63 | -moz-transform: translate(200px, 0) rotate(270deg);
64 | background: #88da50;
65 | }
66 |
67 | 100%
68 | {
69 | -moz-transform: translate(0, 0) rotate(360deg);
70 | background: #da371e;
71 | }
72 | }
73 |
74 | html
75 | {
76 | background: #222;
77 | font-family: helvetica, arial, sans-serif;
78 | color: #EEE;
79 | text-shadow: 0 1px 0 rgba(#000, 0.2);
80 | }
81 |
82 |
83 |
84 | em
85 | {
86 | font-style: italic;
87 | }
88 |
89 | code
90 | {
91 | font-family: courier;
92 | padding: 0.3em;
93 | margin: 0 0.2em;
94 | background: rgba(#FFF, 0.1);
95 | @include border-radius(3px);
96 | @include box-shadow(0px 1px 3px rgba(#000, 0.5));
97 | }
98 |
99 | body
100 | {
101 |
102 | header
103 | {
104 | background: #333;
105 | padding: 10px;
106 | overflow: auto;
107 |
108 | a
109 | {
110 | color: #CCC;
111 | text-decoration: none;
112 | }
113 |
114 | a.name
115 | {
116 | font-family: 'Pacifico';
117 | font-size: 1.1em;
118 | margin-right: 1em;
119 | position: relative;
120 | top: 3px;
121 | }
122 |
123 | a.writeup
124 | {
125 | font-size: 0.8em;
126 | border-bottom: 1px dashed #CCC;
127 |
128 | &:after
129 | {
130 | content: ' \2192';
131 | }
132 | }
133 |
134 | a.twitter
135 | {
136 | float: right;
137 | }
138 |
139 | div.nav
140 | {
141 | float: right;
142 | font-size: 0.7em;
143 | padding: 0.75em;
144 | padding-right: 1.5em;
145 |
146 | a
147 | {
148 | margin-left: 1.5em;
149 |
150 | &:hover
151 | {
152 | border-bottom: 1px dashed #CCC;
153 | }
154 | }
155 | }
156 | }
157 |
158 | section#container
159 | {
160 | width: 230px;
161 | height: 230px;
162 | background: rgba(#FFF, 0.1);
163 | margin: 100px auto 50px;
164 | padding: 20px;
165 | @include box-shadow(0px 1px 6px rgba(#000, 0.5));
166 | cursor: pointer;
167 |
168 | div#animate
169 | {
170 | width: 30px;
171 | height: 30px;
172 | background: #da371e;
173 | @include border-radius(3px);
174 | /* border: 1px solid rgba(#000, 0.2);
175 | @include background-clip(padding);*/
176 | }
177 |
178 | div#text
179 | {
180 | text-align: center;
181 | font-size: 3em;
182 | margin-top: 1em;
183 | }
184 | }
185 |
186 | section#blurb
187 | {
188 | width: 600px;
189 | margin: 0px auto;
190 | line-height: 1.6em;
191 |
192 | a
193 | {
194 | color: #FFF;
195 | text-decoration: none;
196 | border-bottom: 1px dashed #CCC;
197 | }
198 |
199 | h1
200 | {
201 | font-size: 2em;
202 | font-weight: bold;
203 | }
204 |
205 | p
206 | {
207 | margin: 1.6em 0;
208 | }
209 |
210 | h2
211 | {
212 | font-size: 2em;
213 | font-weight: bold;
214 | margin-top: 1.3em;
215 | }
216 |
217 | .note
218 | {
219 | font-size: 0.8em;
220 | color: #666 !important;
221 | }
222 |
223 | section.code
224 | {
225 | h3
226 | {
227 | background: rgba(#FFF, 0.2);
228 | @include box-shadow(0px 1px 6px rgba(#000, 0.5));
229 | padding: 0.5em 0.8em;
230 |
231 | span
232 | {
233 | font-family: times, georgia, serif;
234 | font-style: italic;
235 | font-size: 1.1em;
236 | }
237 | }
238 |
239 | pre
240 | {
241 | @include box-shadow(0px 1px 6px rgba(#000, 0.5));
242 | @include border-radius(0px 0px 3px 3px);
243 | padding: 1em;
244 | font-family: courier;
245 | font-size: 0.8em;
246 | background: rgba(#FFF, 0.5);
247 | color: #111;
248 | text-shadow: 0 1px 0 rgba(#FFF, 0.4);
249 | margin-bottom: 3em;
250 | }
251 | }
252 | }
253 |
254 | section#details
255 | {
256 | text-align: center;
257 | padding-bottom: 4em;
258 |
259 | a
260 | {
261 | margin-left: 1em;
262 | padding: 1em;
263 | background: rgba(#FFF, 0.1);
264 | @include border-radius(3px);
265 | color: #EEE;
266 | text-shadow: 0 1px 0 rgba(#FFF, 0.2);
267 | text-decoration: none;
268 | border: 1px solid rgba(#FFF, 0.3);
269 | font-weight: bold;
270 | font-size: 0.8em;
271 |
272 | &:first-child
273 | {
274 | margin-left: 0;
275 | }
276 |
277 | &:hover
278 | {
279 | background: rgba(#FFF, 0.3);
280 | color: #000;
281 | }
282 | }
283 | }
284 |
285 | footer
286 | {
287 | font-size: 0.7em;
288 | text-align: center;
289 | margin-bottom: 3em;
290 | margin-top: 5em;
291 |
292 | img
293 | {
294 | margin-top: 2em;
295 | }
296 |
297 | a
298 | {
299 | color: #FFF;
300 | text-decoration: none;
301 | border-bottom: 1px dashed #CCC;
302 | }
303 | }
304 | }
305 |
306 | div#carbonads-container
307 | {
308 | div.carbonad
309 | {
310 | background: #353535;
311 | margin: 2em auto 3em;
312 | border: 1px solid rgba(#FFF, 0.1);
313 | @include border-radius(3px);
314 | text-align: left;
315 | }
316 | }
317 |
--------------------------------------------------------------------------------
/css/img/html5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/joelambert/CSSAnimationKeyframeEvents/cb72cdee63a5ec193353522520b69896b3f72aea/css/img/html5.png
--------------------------------------------------------------------------------
/css/style.css:
--------------------------------------------------------------------------------
1 | /* Welcome to Compass.
2 | * In this file you should write your main styles. (or centralize your imports)
3 | * Import this file using the following HTML or equivalent:
4 | * */
5 | /* line 17, ../../../../../.gem/ruby/1.8/gems/compass-0.11.1/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
6 | html, body, div, span, applet, object, iframe,
7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
8 | a, abbr, acronym, address, big, cite, code,
9 | del, dfn, em, img, ins, kbd, q, s, samp,
10 | small, strike, strong, sub, sup, tt, var,
11 | b, u, i, center,
12 | dl, dt, dd, ol, ul, li,
13 | fieldset, form, label, legend,
14 | table, caption, tbody, tfoot, thead, tr, th, td,
15 | article, aside, canvas, details, embed,
16 | figure, figcaption, footer, header, hgroup,
17 | menu, nav, output, ruby, section, summary,
18 | time, mark, audio, video {
19 | margin: 0;
20 | padding: 0;
21 | border: 0;
22 | font-size: 100%;
23 | font: inherit;
24 | vertical-align: baseline;
25 | }
26 |
27 | /* line 20, ../../../../../.gem/ruby/1.8/gems/compass-0.11.1/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
28 | body {
29 | line-height: 1;
30 | }
31 |
32 | /* line 22, ../../../../../.gem/ruby/1.8/gems/compass-0.11.1/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
33 | ol, ul {
34 | list-style: none;
35 | }
36 |
37 | /* line 24, ../../../../../.gem/ruby/1.8/gems/compass-0.11.1/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
38 | table {
39 | border-collapse: collapse;
40 | border-spacing: 0;
41 | }
42 |
43 | /* line 26, ../../../../../.gem/ruby/1.8/gems/compass-0.11.1/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
44 | caption, th, td {
45 | text-align: left;
46 | font-weight: normal;
47 | vertical-align: middle;
48 | }
49 |
50 | /* line 28, ../../../../../.gem/ruby/1.8/gems/compass-0.11.1/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
51 | q, blockquote {
52 | quotes: none;
53 | }
54 | /* line 101, ../../../../../.gem/ruby/1.8/gems/compass-0.11.1/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
55 | q:before, q:after, blockquote:before, blockquote:after {
56 | content: "";
57 | content: none;
58 | }
59 |
60 | /* line 30, ../../../../../.gem/ruby/1.8/gems/compass-0.11.1/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
61 | a img {
62 | border: none;
63 | }
64 |
65 | /* line 115, ../../../../../.gem/ruby/1.8/gems/compass-0.11.1/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
66 | article, aside, details, figcaption, figure,
67 | footer, header, hgroup, menu, nav, section {
68 | display: block;
69 | }
70 |
71 | /* line 115, ../../../../../.gem/ruby/1.8/gems/compass-0.11.1/frameworks/compass/stylesheets/compass/reset/_utilities.scss */
72 | article, aside, details, figcaption, figure,
73 | footer, header, hgroup, menu, nav, section {
74 | display: block;
75 | }
76 |
77 | @-webkit-keyframes boxrotate {
78 | /* line 12, ../compass/scss/style.scss */
79 | 0% {
80 | -webkit-transform: translate3d(0, 0, 0);
81 | background: #da371e;
82 | }
83 |
84 | /* line 18, ../compass/scss/style.scss */
85 | 25% {
86 | -webkit-transform: translate3d(0px, 200px, 0) rotate(90deg);
87 | background: #da3ab9;
88 | }
89 |
90 | /* line 24, ../compass/scss/style.scss */
91 | 50% {
92 | -webkit-transform: translate3d(200px, 200px, 0) rotate(180deg);
93 | background: #34b6da;
94 | }
95 |
96 | /* line 30, ../compass/scss/style.scss */
97 | 75% {
98 | -webkit-transform: translate3d(200px, 0, 0) rotate(270deg);
99 | background: #88da50;
100 | }
101 |
102 | /* line 36, ../compass/scss/style.scss */
103 | 100% {
104 | -webkit-transform: translate3d(0, 0, 0) rotate(360deg);
105 | background: #da371e;
106 | }
107 | }
108 |
109 | @-moz-keyframes boxrotate {
110 | /* line 44, ../compass/scss/style.scss */
111 | 0% {
112 | -moz-transform: translate(0, 0);
113 | background: #da371e;
114 | }
115 |
116 | /* line 50, ../compass/scss/style.scss */
117 | 25% {
118 | -moz-transform: translate(0px, 200px) rotate(90deg);
119 | background: #da3ab9;
120 | }
121 |
122 | /* line 56, ../compass/scss/style.scss */
123 | 50% {
124 | -moz-transform: translate(200px, 200px) rotate(180deg);
125 | background: #34b6da;
126 | }
127 |
128 | /* line 62, ../compass/scss/style.scss */
129 | 75% {
130 | -moz-transform: translate(200px, 0) rotate(270deg);
131 | background: #88da50;
132 | }
133 |
134 | /* line 68, ../compass/scss/style.scss */
135 | 100% {
136 | -moz-transform: translate(0, 0) rotate(360deg);
137 | background: #da371e;
138 | }
139 | }
140 |
141 | /* line 75, ../compass/scss/style.scss */
142 | html {
143 | background: #222;
144 | font-family: helvetica, arial, sans-serif;
145 | color: #EEE;
146 | text-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
147 | }
148 |
149 | /* line 85, ../compass/scss/style.scss */
150 | em {
151 | font-style: italic;
152 | }
153 |
154 | /* line 90, ../compass/scss/style.scss */
155 | code {
156 | font-family: courier;
157 | padding: 0.3em;
158 | margin: 0 0.2em;
159 | background: rgba(255, 255, 255, 0.1);
160 | -moz-border-radius: 3px;
161 | -webkit-border-radius: 3px;
162 | -o-border-radius: 3px;
163 | -ms-border-radius: 3px;
164 | -khtml-border-radius: 3px;
165 | border-radius: 3px;
166 | -moz-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.5);
167 | -webkit-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.5);
168 | -o-box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.5);
169 | box-shadow: 0px 1px 3px rgba(0, 0, 0, 0.5);
170 | }
171 |
172 | /* line 103, ../compass/scss/style.scss */
173 | body header {
174 | background: #333;
175 | padding: 10px;
176 | overflow: auto;
177 | }
178 | /* line 109, ../compass/scss/style.scss */
179 | body header a {
180 | color: #CCC;
181 | text-decoration: none;
182 | }
183 | /* line 115, ../compass/scss/style.scss */
184 | body header a.name {
185 | font-family: 'Pacifico';
186 | font-size: 1.1em;
187 | margin-right: 1em;
188 | position: relative;
189 | top: 3px;
190 | }
191 | /* line 124, ../compass/scss/style.scss */
192 | body header a.writeup {
193 | font-size: 0.8em;
194 | border-bottom: 1px dashed #CCC;
195 | }
196 | /* line 129, ../compass/scss/style.scss */
197 | body header a.writeup:after {
198 | content: ' \2192';
199 | }
200 | /* line 135, ../compass/scss/style.scss */
201 | body header a.twitter {
202 | float: right;
203 | }
204 | /* line 140, ../compass/scss/style.scss */
205 | body header div.nav {
206 | float: right;
207 | font-size: 0.7em;
208 | padding: 0.75em;
209 | padding-right: 1.5em;
210 | }
211 | /* line 147, ../compass/scss/style.scss */
212 | body header div.nav a {
213 | margin-left: 1.5em;
214 | }
215 | /* line 151, ../compass/scss/style.scss */
216 | body header div.nav a:hover {
217 | border-bottom: 1px dashed #CCC;
218 | }
219 | /* line 159, ../compass/scss/style.scss */
220 | body section#container {
221 | width: 230px;
222 | height: 230px;
223 | background: rgba(255, 255, 255, 0.1);
224 | margin: 100px auto 50px;
225 | padding: 20px;
226 | -moz-box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.5);
227 | -webkit-box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.5);
228 | -o-box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.5);
229 | box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.5);
230 | cursor: pointer;
231 | }
232 | /* line 169, ../compass/scss/style.scss */
233 | body section#container div#animate {
234 | width: 30px;
235 | height: 30px;
236 | background: #da371e;
237 | -moz-border-radius: 3px;
238 | -webkit-border-radius: 3px;
239 | -o-border-radius: 3px;
240 | -ms-border-radius: 3px;
241 | -khtml-border-radius: 3px;
242 | border-radius: 3px;
243 | /* border: 1px solid rgba(#000, 0.2);
244 | @include background-clip(padding);*/
245 | }
246 | /* line 179, ../compass/scss/style.scss */
247 | body section#container div#text {
248 | text-align: center;
249 | font-size: 3em;
250 | margin-top: 1em;
251 | }
252 | /* line 187, ../compass/scss/style.scss */
253 | body section#blurb {
254 | width: 600px;
255 | margin: 0px auto;
256 | line-height: 1.6em;
257 | }
258 | /* line 193, ../compass/scss/style.scss */
259 | body section#blurb a {
260 | color: #FFF;
261 | text-decoration: none;
262 | border-bottom: 1px dashed #CCC;
263 | }
264 | /* line 200, ../compass/scss/style.scss */
265 | body section#blurb h1 {
266 | font-size: 2em;
267 | font-weight: bold;
268 | }
269 | /* line 206, ../compass/scss/style.scss */
270 | body section#blurb p {
271 | margin: 1.6em 0;
272 | }
273 | /* line 211, ../compass/scss/style.scss */
274 | body section#blurb h2 {
275 | font-size: 2em;
276 | font-weight: bold;
277 | margin-top: 1.3em;
278 | }
279 | /* line 218, ../compass/scss/style.scss */
280 | body section#blurb .note {
281 | font-size: 0.8em;
282 | color: #666 !important;
283 | }
284 | /* line 226, ../compass/scss/style.scss */
285 | body section#blurb section.code h3 {
286 | background: rgba(255, 255, 255, 0.2);
287 | -moz-box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.5);
288 | -webkit-box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.5);
289 | -o-box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.5);
290 | box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.5);
291 | padding: 0.5em 0.8em;
292 | }
293 | /* line 232, ../compass/scss/style.scss */
294 | body section#blurb section.code h3 span {
295 | font-family: times, georgia, serif;
296 | font-style: italic;
297 | font-size: 1.1em;
298 | }
299 | /* line 240, ../compass/scss/style.scss */
300 | body section#blurb section.code pre {
301 | -moz-box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.5);
302 | -webkit-box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.5);
303 | -o-box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.5);
304 | box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.5);
305 | -moz-border-radius: 0px 0px 3px 3px;
306 | -webkit-border-radius: 0px 0px 3px 3px;
307 | -o-border-radius: 0px 0px 3px 3px;
308 | -ms-border-radius: 0px 0px 3px 3px;
309 | -khtml-border-radius: 0px 0px 3px 3px;
310 | border-radius: 0px 0px 3px 3px;
311 | padding: 1em;
312 | font-family: courier;
313 | font-size: 0.8em;
314 | background: rgba(255, 255, 255, 0.5);
315 | color: #111;
316 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.4);
317 | margin-bottom: 3em;
318 | }
319 | /* line 255, ../compass/scss/style.scss */
320 | body section#details {
321 | text-align: center;
322 | padding-bottom: 4em;
323 | }
324 | /* line 260, ../compass/scss/style.scss */
325 | body section#details a {
326 | margin-left: 1em;
327 | padding: 1em;
328 | background: rgba(255, 255, 255, 0.1);
329 | -moz-border-radius: 3px;
330 | -webkit-border-radius: 3px;
331 | -o-border-radius: 3px;
332 | -ms-border-radius: 3px;
333 | -khtml-border-radius: 3px;
334 | border-radius: 3px;
335 | color: #EEE;
336 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);
337 | text-decoration: none;
338 | border: 1px solid rgba(255, 255, 255, 0.3);
339 | font-weight: bold;
340 | font-size: 0.8em;
341 | }
342 | /* line 273, ../compass/scss/style.scss */
343 | body section#details a:first-child {
344 | margin-left: 0;
345 | }
346 | /* line 278, ../compass/scss/style.scss */
347 | body section#details a:hover {
348 | background: rgba(255, 255, 255, 0.3);
349 | color: #000;
350 | }
351 | /* line 286, ../compass/scss/style.scss */
352 | body footer {
353 | font-size: 0.7em;
354 | text-align: center;
355 | margin-bottom: 3em;
356 | margin-top: 5em;
357 | }
358 | /* line 293, ../compass/scss/style.scss */
359 | body footer img {
360 | margin-top: 2em;
361 | }
362 | /* line 298, ../compass/scss/style.scss */
363 | body footer a {
364 | color: #FFF;
365 | text-decoration: none;
366 | border-bottom: 1px dashed #CCC;
367 | }
368 |
369 | /* line 309, ../compass/scss/style.scss */
370 | div#carbonads-container div.carbonad {
371 | background: #353535;
372 | margin: 2em auto 3em;
373 | border: 1px solid rgba(255, 255, 255, 0.1);
374 | -moz-border-radius: 3px;
375 | -webkit-border-radius: 3px;
376 | -o-border-radius: 3px;
377 | -ms-border-radius: 3px;
378 | -khtml-border-radius: 3px;
379 | border-radius: 3px;
380 | text-align: left;
381 | }
382 |
--------------------------------------------------------------------------------
/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CSS3 Animation Keyframe Events
6 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
57 |
58 |
59 |
63 |
64 | Keyframe Events for CSS3 Animations
65 | CSS3 Animations are great but the current implementation doesn't trigger Javascript Events for each Keyframe (see here for more information ) .
66 | The CSSAnimation
object provides the events the browser vendors left out! This allows you to bind event handlers to cssAnimationKeyframe
events and perform any additional code that needs to happen at each keyframe.
67 | Note: This won't work as well on Mobile Webkit until webkitRequestAnimationFrame()
is implemented!
68 |
69 |
73 |
74 |
--------------------------------------------------------------------------------
/js/cssanimation.jquery.js:
--------------------------------------------------------------------------------
1 | (function(){
2 | /**
3 | * jQuery wrapper function around CSSAnimation.trigger()
4 | * @param {String} animationName The name given to the @-webkit-keyframes animation
5 | * @param {Integer} duration The length of time of the animation (in milliseconds)
6 | * @param {Object} opts An optional set of options used to override the defaults
7 | */
8 | $.fn.cssanimation = function(animation, duration, opts) {
9 | return this.each(function(index, elem){
10 | CSSAnimation.trigger(elem, animation, duration, opts);
11 | });
12 | };
13 | })();;
14 |
15 |
--------------------------------------------------------------------------------
/js/cssanimation.jquery.min.js:
--------------------------------------------------------------------------------
1 | (function(){$.fn.cssanimation=function(a,b,c){return this.each(function(e,d){CSSAnimation.trigger(d,a,b,c)})}})();
2 |
--------------------------------------------------------------------------------
/js/cssanimation.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve CSSAnimation v0.2
3 | * Provides 'cssAnimationKeyframe' events for keyframe animations.
4 | * http://www.joelambert.co.uk/cssa
5 | *
6 | * Copyright 2011, Joe Lambert. All rights reserved
7 | * Free to use under the MIT license.
8 | * http://www.opensource.org/licenses/mit-license.php
9 | */
10 |
11 | var CSSAnimation = {
12 | version: '0.2'
13 | };
14 |
15 | // Locate a WebKitCSSKeyframesRule
16 | // Modified version of code found @ http://stackoverflow.com/questions/2961544/cssrules-is-empty
17 | CSSAnimation.find = function(a) {
18 | var ss = document.styleSheets;
19 | for (var i = ss.length - 1; i >= 0; i--) {
20 | try {
21 | var s = ss[i],
22 | rs = s.cssRules ? s.cssRules :
23 | s.rules ? s.rules :
24 | [];
25 |
26 | for (var j = rs.length - 1; j >= 0; j--) {
27 | if ((rs[j].type === window.CSSRule.WEBKIT_KEYFRAMES_RULE || rs[j].type === window.CSSRule.MOZ_KEYFRAMES_RULE) && rs[j].name == a){
28 | return rs[j];
29 | }
30 | }
31 | }
32 | catch(e) { /* Trying to interrogate a stylesheet from another domain will throw a security error */ }
33 | }
34 | return null;
35 | };
36 |
37 | // Trigger a CSS3 Animation on a given element
38 | /**
39 | * Trigger a CSS3 Animation on a given element
40 | * @param {DOMElement} elem The DOM Element to apply the animation to
41 | * @param {String} animationName The name given to the @-webkit-keyframes animation
42 | * @param {Integer} duration The length of time of the animation (in milliseconds)
43 | * @param {Object} opts An optional set of options used to override the defaults
44 | */
45 |
46 | CSSAnimation.trigger = function(elem, animationName, duration, opts) {
47 | var keyframes = {}, loggedKeyframes = {}, animation = null, element = elem, start = 0, cycle = 0, options = {
48 | base: 5,
49 | easing: 'linear',
50 | iterationCount: 1
51 | },
52 | prefixes = ['Webkit', 'Moz'];
53 |
54 | // Enable option setting
55 | for(var k in opts)
56 | options[k] = opts[k];
57 |
58 | // Prevent animation triggers if the animation is already playing
59 | if(element.isPlaying)
60 | return;
61 |
62 | // Can we find the animaition called animationName?
63 | animation = CSSAnimation.find(animationName);
64 |
65 | if(!animation)
66 | return false;
67 |
68 | // Work out the timings of keyframes
69 | keyframes = {};
70 |
71 | for(var i=0; i < animation.cssRules.length; i++)
72 | {
73 | var kf = animation.cssRules[i],
74 | name = kf.keyText,
75 | percentage = 0;
76 |
77 | // Work out the percentage
78 | name == 'from' ? percentage = 0 :
79 | name == 'to' ? percentage = 1 :
80 | percentage = name.replace('%', '') / 100;
81 |
82 | // Store keyframe for easy recall
83 | keyframes[(percentage*100)+'%'] = kf;
84 | }
85 |
86 | // Start the animation
87 | start = new Date().getTime();
88 |
89 | // Variables used by the runloop
90 | var current = percentage = roundedKey = keyframe = null,
91 | raiseEvent = function(keyText, elapsedTime) {
92 | var event = document.createEvent("Event");
93 | event.initEvent("cssAnimationKeyframe", true, true);
94 | event.animationName = animationName;
95 | event.keyText = keyText;
96 | event.elapsedTime = elapsedTime;
97 | element.dispatchEvent(event);
98 | },
99 |
100 | i=0,
101 | found=false,
102 |
103 | applyCSSAnimation = function(anim) {
104 | found = false;
105 | for(i=0; i=0;g--)try{for(var d=i[g],e=d.cssRules?d.cssRules:d.rules?d.rules:[],c=e.length-1;c>=0;c--)if((e[c].type===window.CSSRule.WEBKIT_KEYFRAMES_RULE||e[c].type===window.CSSRule.MOZ_KEYFRAMES_RULE)&&e[c].name==a)return e[c]}catch(l){}return null};
11 | CSSAnimation.trigger=function(a,i,g,d){var e={},c={},l=null,o=0,q=0,j={base:5,easing:"linear",iterationCount:1},k=["Webkit","Moz"],h;for(h in d)j[h]=d[h];if(!a.isPlaying){l=CSSAnimation.find(i);if(!l)return false;e={};for(var b=0;b= 0; i--) {
20 | try {
21 | var s = ss[i],
22 | rs = s.cssRules ? s.cssRules :
23 | s.rules ? s.rules :
24 | [];
25 |
26 | for (var j = rs.length - 1; j >= 0; j--) {
27 | if ((rs[j].type === window.CSSRule.WEBKIT_KEYFRAMES_RULE || rs[j].type === window.CSSRule.MOZ_KEYFRAMES_RULE) && rs[j].name == a){
28 | return rs[j];
29 | }
30 | }
31 | }
32 | catch(e) { /* Trying to interrogate a stylesheet from another domain will throw a security error */ }
33 | }
34 | return null;
35 | };
36 |
37 | // Trigger a CSS3 Animation on a given element
38 | /**
39 | * Trigger a CSS3 Animation on a given element
40 | * @param {DOMElement} elem The DOM Element to apply the animation to
41 | * @param {String} animationName The name given to the @-webkit-keyframes animation
42 | * @param {Integer} duration The length of time of the animation (in milliseconds)
43 | * @param {Object} opts An optional set of options used to override the defaults
44 | */
45 |
46 | CSSAnimation.trigger = function(elem, animationName, duration, opts) {
47 | var keyframes = {}, loggedKeyframes = {}, animation = null, element = elem, start = 0, cycle = 0, options = {
48 | base: 5,
49 | easing: 'linear',
50 | iterationCount: 1
51 | },
52 | prefixes = ['Webkit', 'Moz'];
53 |
54 | // Enable option setting
55 | for(var k in opts)
56 | options[k] = opts[k];
57 |
58 | // Prevent animation triggers if the animation is already playing
59 | if(element.isPlaying)
60 | return;
61 |
62 | // Can we find the animaition called animationName?
63 | animation = CSSAnimation.find(animationName);
64 |
65 | if(!animation)
66 | return false;
67 |
68 | // Work out the timings of keyframes
69 | keyframes = {};
70 |
71 | for(var i=0; i < animation.cssRules.length; i++)
72 | {
73 | var kf = animation.cssRules[i],
74 | name = kf.keyText,
75 | percentage = 0;
76 |
77 | // Work out the percentage
78 | name == 'from' ? percentage = 0 :
79 | name == 'to' ? percentage = 1 :
80 | percentage = name.replace('%', '') / 100;
81 |
82 | // Store keyframe for easy recall
83 | keyframes[(percentage*100)+'%'] = kf;
84 | }
85 |
86 | // Start the animation
87 | start = new Date().getTime();
88 |
89 | // Variables used by the runloop
90 | var current = percentage = roundedKey = keyframe = null,
91 | raiseEvent = function(keyText, elapsedTime) {
92 | var event = document.createEvent("Event");
93 | event.initEvent("cssAnimationKeyframe", true, true);
94 | event.animationName = animationName;
95 | event.keyText = keyText;
96 | event.elapsedTime = elapsedTime;
97 | element.dispatchEvent(event);
98 | },
99 |
100 | i=0,
101 | found=false,
102 |
103 | applyCSSAnimation = function(anim) {
104 | found = false;
105 | for(i=0; i