-
Notifications
You must be signed in to change notification settings - Fork 4
/
atom.xml
443 lines (261 loc) · 26.4 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<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-12-04T21:48:22-05:00</updated>
<id>http://tjvantoll.com/</id>
<author>
<name><![CDATA[TJ VanToll]]></name>
<email><![CDATA[tj.vantoll@gmail.com]]></email>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[Creating Cross Browser Scrollable <tbody>s - A CSS Only Approach]]></title>
<link href="http://tjvantoll.com/2012/11/10/creating-cross-browser-scrollable-tbody/"/>
<updated>2012-11-10T15:44:00-05:00</updated>
<id>http://tjvantoll.com/2012/11/10/creating-cross-browser-scrollable-tbody</id>
<content type="html"><![CDATA[<p>By default the <code>overflow</code> CSS property does not apply to table group elements (<code><thead></code>, <code><tbody></code>, or <code><tfoot></code>). <a href="https://developer.mozilla.org/en-US/docs/Firefox_4_for_developers#Miscellaneous_CSS_changes">As of Firefox 4</a> this behavior is consistent across all browser implementations.</p>
<p>Therefore, if you attempt to apply a CSS <code>height</code> and <code>overflow: scroll</code> to a <code><tbody></code> it will have no effect in modern browsers. You can see this for yourself <a href="http://jsfiddle.net/tj_vantoll/vU494/">here</a>.</p>
<p>But having a scrolling table body with fixed headers is a useful UI element, so how do you work around this?</p>
<!--more-->
<h3>The Solution</h3>
<p>Here is my solution:</p>
<p><pre class="codepen" data-height="400" data-type="result" data-href="JEKIu" data-user="tjvantoll"><code></code></pre>
<script async src="http://codepen.io:/assets/embed/ei.js"></script></p>
<h3>How does it work?</h3>
<p>The first step is to set the <code><tbody></code> to <code>display: block</code> so an <code>overflow</code> and <code>height</code> can be applied. From there the rows in the <code><thead></code> need to be set to <code>position: relative</code> and <code>display: block</code> so that they'll sit on top of the now scrollable <code><tbody></code>.</p>
<p>That's really about it.</p>
<h3>Unfortunate Part #1: Old Internet Explorer</h3>
<p>When you set a <code>height</code> on a <code><tbody></code> Internet Explorer < 10 applies that <code>height</code> to every table cell, which is of course wonderful.</p>
<p>My workaround for this is to conditionally create a wrapper <code><div></code>. When it's present I give it the <code>height</code> and <code>overflow</code> and remove the <code>height</code> from the <code><tbody></code>.</p>
<p>``` html Wrap table for IE</p>
<!--[if lte IE 9]>
<div class="old_ie_wrapper">
<!--<![endif]-->
<pre><code><table>
<!-- Contents of the table -->
</table>
</code></pre>
<!--[if lte IE 9]>
</div>
<!--<![endif]-->
<p>```</p>
<p>The headers will scroll with the table body, but the table will at least be usable. You could also create <a href="http://paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/">conditional classes on the <html> tag</a> to handle this as well.</p>
<h3>Unfortunate Part #2: Widths</h3>
<p>Because the <code><thead></code> is relatively positioned each table cell needs an explicit <code>width</code>.</p>
<p><code>css
td:nth-child(1), th:nth-child(1) { width: 100px; }
td:nth-child(2), th:nth-child(2) { width: 100px; }
td:nth-child(3), th:nth-child(3) { width: 100px; }
</code></p>
<p>But unfortunately that is not enough. When a scrollbar is present browsers allocate space for it, therefore, the <code><tbody></code> ends up having less space available than the <code><thead></code>. Notice the slight misalignment this creates:</p>
<p><img src="/images/posts/2012-11-10/Alignment-Issue.png" title="Alignment issue with scroll bar" alt="Alignment issue with scroll bar" /></p>
<p>The only workaround I could come up with was to set a <code>min-width</code> on all columns except the last one.</p>
<p><code>css
td:nth-child(1), th:nth-child(1) { min-width: 100px; }
td:nth-child(2), th:nth-child(2) { min-width: 100px; }
td:nth-child(3), th:nth-child(3) { width: 100px; }
</code></p>
<h3>The Good</h3>
<p>Despite these issues the solution does work in all browsers back to IE6 with no JavaScript dependency.</p>
<p>The markup to create the table is simple and semantic. I've seen workarounds for this issue that use <code><div></code>s instead of <code><table></code>s or multiple aligned <code><table></code>s and those always felt dirty to me.</p>
<p>The code is free to use and do whatever you want with it. If you have any suggestions for improvements or find any issues please let me know in the comments.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[maxlength Constraint Validation Oddities in Major Browsers]]></title>
<link href="http://tjvantoll.com/2012/10/17/maxlength-constraint-validation-oddities/"/>
<updated>2012-10-17T12:48:00-04:00</updated>
<id>http://tjvantoll.com/2012/10/17/maxlength-constraint-validation-oddities</id>
<content type="html"><![CDATA[<p>The <code>maxlength</code> attribute has been around in browsers for a long time. When provided all browsers prevent the user entering a value that exceeds the <code>maxlength</code>.</p>
<p>For example you cannot type more than 2 characters in the textbox below:</p>
<p><input type="text" maxlength="2" /></p>
<h3>Constraint Validation</h3>
<p><a href="https://developer.mozilla.org/en-US/docs/HTML/HTML5/Constraint_validation_">Constraint validation</a> is an HTML5 spec that provides native client side form validation in the browser. As part of its <a href="https://developer.mozilla.org/en-US/docs/HTML/Forms_in_HTML#Constraint_Validation_API">API</a>, all <code><input></code> and <code><textarea></code> elements have a <code>validity.tooLong</code> property that is <code>true</code> when the length of the <code>value</code> exceeds the <code>maxlength</code>.</p>
<p>But if the browser prevents this then why does the property exist?</p>
<!--more-->
<h3>Prefilled value Attribute</h3>
<p>Assume that you're filling the <code>value</code> of form elements with information from a database and you end up with something like this:</p>
<p><code><input type="text" maxlength="1" value="ABC" /></code></p>
<p>How will the browser handle this?</p>
<p>All browsers will prevent entry of additional characters, but they do not trim excess characters already present. Additionally all browsers will allow a form containing the above input to submit. <em>Note: Opera is the only browser to set the <code>validity.tooLong</code> property to <code>true</code> in this situation. Despite this, it does not prevent form submission.</em></p>
<p>Why is submission not prevented? The key is in the <a href="http://www.whatwg.org/specs/web-apps/current-work/#concept-input-value-dirty-flag">specification</a>:</p>
<blockquote><p>Constraint validation: If an element has a maximum allowed value length, its dirty value flag is true, its value was last changed by a user edit (as opposed to a change made by a script), and the code-unit length of the element's value is greater than the element's maximum allowed value length, then the element is suffering from being too long.</p></blockquote>
<p>The <a href="http://www.whatwg.org/specs/web-apps/current-work/#concept-input-value-dirty-flag">dirty flag</a> essentially means the the user has changed the value of an element. Therefore, in order to be <code>tooLong</code> the element must have been last interacted with by a user edit.</p>
<h3>Actually Triggering tooLong</h3>
<p>So let's take another approach. What happens if you have the same input:</p>
<p><code><input type="text" maxlength="1" value="ABC" /></code></p>
<p>...remove one character, then submit? You can try it for yourself below:</p>
<iframe style="width: 100%; height: 180px;" src="http://jsfiddle.net/tj_vantoll/epCQe/embedded/result,html/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
<p>Upon edit IE10 and Chrome will set the <code>validity.tooLong</code> property to <code>true</code> and prevent form submission. If the user attempts to submit a form after removing the "C" they will see the following in those browsers:</p>
<p><img src="/images/posts/2012-10-17/Chrome.png" title="Chrome" alt="Chrome" />
<img src="/images/posts/2012-10-17/IE10.png" title="IE10" alt="IE10" /></p>
<p>Firefox, Safari, and Opera incorrectly handle this situation and allow the form to be submitted anyways.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[HTML5 Form Validation - Start Using it in Production Applications]]></title>
<link href="http://tjvantoll.com/2012/08/30/html5-form-validation-start-using-it-in-production-applications/"/>
<updated>2012-08-30T00:00:00-04:00</updated>
<id>http://tjvantoll.com/2012/08/30/html5-form-validation-start-using-it-in-production-applications</id>
<content type="html"><![CDATA[<p>Forms suck, yet, they make or break the most crucial online transactions. Building web forms sucks as well; the APIs and lack of customizability has confused and frustrated people for years. As a byproduct an abundance of horribly unusable forms have been created for everyone to suffer through.</p>
<p>Therefore <em>anything</em> that makes this process easier should be greeted with joy and enthusiasm.</p>
<p>HTML5 does just this by including a built in <a href="https://developer.mozilla.org/en-US/docs/HTML/Forms_in_HTML#Constraint_Validation_API">client side form validation mechanism</a> designed to make implementing client side validation powerful, seamless, and most importantly - easy to implement.</p>
<p>Great! Despite this, HTML5 form validation is a topic relegated to presentations and demos; I personally have yet to fill out a web form in the wild that actually makes use of it.</p>
<p>Why?</p>
<!--more-->
<h3>Browser Support</h3>
<p>One reason people avoid HTML5 form validation is lack (or perceived lack) of browser support for the new APIs. However the <a href="http://caniuse.com/#feat=form-validation">list of supported browsers</a> now includes the latest version of every major browser, including:</p>
<ul>
<li>IE 10</li>
<li>Firefox 4+</li>
<li>Chrome 10+</li>
<li>Safari 5+</li>
<li>Opera 10+</li>
<li>Opera Mobile</li>
<li>Chrome for Android</li>
<li>Firefox for Android</li>
</ul>
<h3>What to do in unsupported browsers?</h3>
<p>This is <em>the</em> problem. Despite browser support being relatively good, for most sites there are still going to be a substantial amount of users with browsers that simply do not support the new APIs. Therefore, if you are intending to support these users you have to start forking your code to support both browsers with native support and browsers without it.</p>
<p>While this can absolutely be done, it's time consuming and a bit of a nuisance. It's faster and easier to simply ditch the native validation and use your own. In this case you don't have to worry about multiple code paths; every user in every browser will hit the same codepath and get the same experience.</p>
<h3>What if we did nothing?</h3>
<p>But what if we took a new approach to this problem - simply don't do client side validation in unsupported browsers, at all. This is advantageous for a number of reasons.</p>
<p>1) <strong>No dual maintenance</strong>. One thing that has always bothered me about doing validation on both the client and server side is that you're validating the #1 principle of software development - <a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself"><strong>D</strong>on't <strong>R</strong>epeat <strong>Y</strong>ourself</a>.</p>
<p>2) <strong>No dependencies</strong>. If you only use native browser APIs to provide client side validation you don't have to worry about maintaining plugin or library dependencies that might not be maintained.</p>
<p>3) <strong>Faster and easier</strong>. The browser APIs are simple and easy to use. Want to make a field required? <a href="http://wufoo.com/html5/attributes/09-required.html">Add the <code>required</code> attribute</a>. Want to make a field only accept email address? <a href="http://wufoo.com/html5/types/1-email.html">Add <code>type=email</code> to your <code><input></code> field</a>.</p>
<p>4) <strong>Future Friendly</strong>. Although currently a number of older browsers (namely IE <= 9) do not support the new APIs, eventually they all will. Therefore, eventually all users will hit the client side validation as intended.</p>
<h3>But, you can't just not validate data... right?</h3>
<p>Of course you have to validate client submitted data, but you already need to be doing that on the server side anyways. What this approach requires you to do is simply return formatted error messages from your server side processing and <a href="http://uxdesign.smashingmagazine.com/2011/11/08/extensive-guide-web-form-usability/">display them in a usability friendly way</a>. You're likely doing that already.</p>
<h3>What About Polyfills?</h3>
<p><a href="http://remysharp.com/2010/10/08/what-is-a-polyfill/">Polyfills</a> are great and a number of <a href="https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills">HTML5 form validation polyfills</a> exist. My problem with polyfills in this case is that they add a dependency that I believe is unnecessary.</p>
<h3>Conclusion</h3>
<p>HTML5 provides native solutions to validating client side data and most all modern browsers support it. Yet, most people are still relying on the JavaScript hacks we've been using for well over a decade now.</p>
<p>It's time. Come to the dark side.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[onscroll Event Issues on Mobile Browsers]]></title>
<link href="http://tjvantoll.com/2012/08/19/onscroll-event-issues-on-mobile-browsers/"/>
<updated>2012-08-19T00:00:00-04:00</updated>
<id>http://tjvantoll.com/2012/08/19/onscroll-event-issues-on-mobile-browsers</id>
<content type="html"><![CDATA[<p>All browsers fire an <code>onscroll</code> event on the <code>window</code> object whenever the window is scrolled. On desktop browsers this event is fired continuously as the user scrolls, but on most all mobile browsers the event is not fired until the <em>scrolling action</em> comes to a complete stop.</p>
<!--more-->
<p>You can see this by scrolling in the example below:</p>
<iframe style="width: 100%; height: 300px;" src="http://jsfiddle.net/tj_vantoll/p4pww/13/embedded/result,html,js,css/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
<p>The <code>onscroll</code> event count and the value of <code>window.scrollY</code> (<a href="https://developer.mozilla.org/en-US/docs/DOM/window.scrollY">the number of pixels the document has been scrolled vertically</a>) displayed on the top of the screen in the example are updated in an <code>onscroll</code> event handler.</p>
<p>If you're viewing this on any desktop browser you'll see that as you scroll the <code>onscroll</code> event is continuously firing, <code>window.scrollY</code> is continuously updating, and the blue box (which is present so you can visibly tell whether the browser re-paints the screen) is continuously moving.</p>
<h3>Enter Mobile</h3>
<p>If you try the same demo on iOS Safari (5.0), the default Android browser <= 2.3, Opera Mobile, or IE on Windows Phone 7 you'll notice something quite different. As you scroll the <code>onscroll</code> event isn't fired, <code>window.scrollY</code> isn't updated, and the blue box does not move until the scrolling has come to a complete stop.</p>
<p>You can see this in the video below (the video shows iOS Safari but the same behavior occurs in the other listed browsers):</p>
<iframe width="420" height="315" src="http://www.youtube.com/embed/5-vOJEP3x28" frameborder="0" allowfullscreen></iframe>
<h3>Why</h3>
<p>These mobile browsers simply do not fire the <code>onscroll</code> event until scrolling has completely stopped. This includes not only the touch based scrolling itself, but additionally any momentum that the user gives on the scroll. The event will not fire until it stops. This is a problem if you want to apply a visual change to the screen as the user scrolls.</p>
<h3>Other Mobile Browsers</h3>
<p>Firefox for Android does fire the <code>onscroll</code> event and updates <code>window.clientY</code> as you scroll, but strangely it doesn't re-paint the screen for any changes that have been applied.</p>
<p>The Android browser in Ice Cream Sandwich fires the event but doesn't feel very responsive and only sporadically re-paints the DOM to move the blue box. Luckily, Jelly Bean's Android browser handles this example perfectly; everything is updated and rendered smoothly as the user scrolls.</p>
<h3>The Problem</h3>
<p>In my case I wanted to apply a change to the DOM for every pixel that the user scrolled, exactly like moving the blue box in the example above.</p>
<p>So the question is, can we work around this limitation and get desktop <code>onscroll</code> functionality in a mobile friendly way?</p>
<h3>Workaround Attempt - setInterval</h3>
<p>My first attempt was to set an interval that did what I wanted to do in the <code>onscroll</code> event. Yes the code will run continuously instead of just when the user scrolls, but it's somewhere to start.</p>
<p>``` javascript
setInterval(function() {</p>
<pre><code>// Logic
</code></pre>
<p>}, 20);
```</p>
<p>The problem with this approach is that iOS Safari, Android <= 2.3, and Opera Mobile do not run any functions queued through <code>setInterval</code> or <code>setTimeout</code> while a scroll is being performed. The execution will simply be paused until the scroll has completed.</p>
<p>Here's an example that simply appends an asterisk to a div every 500 milliseconds using <code>setInterval</code>:</p>
<iframe style="width: 100%; height: 300px;" src="http://jsfiddle.net/tj_vantoll/NfkEg/7/embedded/result,js,html,css/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
<p>If you're viewing this in a desktop browser and you scroll, you can see that the asterisks will continue to be created.</p>
<p>However, on the affected mobile browsers (iOS Safari, Android <= 2.3, Opera Mobile), because the function queued through <code>setInterval</code> is paused, asterisk creation stops the moment you start scrolling and doesn't resume until you stop.</p>
<p>This video shows this behavior on iOS Safari (5.0):</p>
<iframe width="560" height="315" src="http://www.youtube.com/embed/XkLvV9aPcYQ" frameborder="0" allowfullscreen></iframe>
<p>This example works perfectly (scrolling doesn't stop asterisk creation) on the default Ice Cream Sandwich / Jelly Bean browser, Firefox for Android, and IE for Windows Phone 7.</p>
<h3>Workaround Attempt 2 - Use Touch Events</h3>
<p>Since the <code>setInterval</code> approach failed on the big mobile browsers my next thought was to use touch events instead.</p>
<p>Most mobile browsers fire <a href="http://blog.jquery.com/2012/04/10/getting-touchy-about-patents/">Apple's flavor</a> of <a href="https://developer.mozilla.org/en-US/docs/DOM/Touch_events">touch events</a> as the user interacts with the screen via touch (the notable exception being Window's Mobile since Microsoft has their own touch model).</p>
<p>In particular the <code>ontouchmove</code> event is fired as the user moves their finger (or stylus, etc) across the screen. Since users on touch devices need to move their finger across the screen to scroll, this seemed like the perfect alternative to <code>onscroll</code>.</p>
<p>Therefore I modified my example to use <code>ontouchmove</code> instead of <code>onscroll</code>:</p>
<iframe style="width: 100%; height: 300px;" src="http://jsfiddle.net/tj_vantoll/RFdve/10/embedded/result,js,html,css/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
<p>If you scroll on the above example on a desktop browser nothing will be updated since the counters are being driven by the <code>ontouchmove</code> event. On mobile browsers a wide variety of things happen:</p>
<ul>
<li>Android: The <code>ontouchmove</code> event does get fired as the user moves the screen. However the DOM updates are very sporadic and feel very jerky. This is true of the default Android browser in Gingerbread, Ice Cream Sandwich, and Jelly Bean although it gets better in later versions.</li>
<li>Firefox for Android: The <code>ontouchmove</code> events fires but DOM updates made in the <code>ontouchmove</code> event take effect sporadicly if at all. Everything feels very jerky at best.</li>
<li>Opera Mobile: <code>ontouchmove</code> events occur but DOM changes are not applied until scrolling is complete.</li>
<li>iOS Safari: On <code>ontouchmove</code> event is fired as the screen is moved and the DOM does get re-painted. This is only mobile browser where this approach made a substantial difference.</li>
</ul>
<p>One consistent issue with this approach is that the <code>ontouchmove</code> event is only fired when the user's finger remains on the screen. Meaning, if the user gives any momentum to the scroll, <code>ontouchmove</code> events will not be fired while the window is scrolling and their finger is not on the screen.</p>
<p>You can see this in the video below:</p>
<iframe width="420" height="315" src="http://www.youtube.com/embed/wied94KmwKw" frameborder="0" allowfullscreen></iframe>
<p>So what does all of this mean about using the <code>ontouchmove</code> event to mimic desktop <code>onscroll</code> functionality? At the moment there are too many inconsistencies to rely on this behavior in any way. If you only need to support iOS Safari this approach works reasonably.</p>
<h3>Workaround Attempt 3 - Don't <em>Really</em> Scroll</h3>
<p>Another <em>solution</em> out there is to disable native scrolling altogether and use JavaScript to mimic scrolling instead.</p>
<p>``` javascript
$('window').on('touchmove', function(event) {</p>
<pre><code>//Prevent the window from being scrolled.
event.preventDefault();
//Do something like call window.scrollTo to mimic the scrolling
//request the user made.
</code></pre>
<p>});
```</p>
<p>Unfortunately such techniques are usually utilized to create fixed height/width scrolling areas and are not intended (nor especially practical) for full screens. If you are only interested in a scrolling event for a small section of the page you might want to look into something such as <a href="http://cubiq.org/iscroll-4">iScroll 4</a>.</p>
<h3>Conclusion</h3>
<p>Unlike desktop browsers, most all mobile browsers simply do not fire an <code>onscroll</code> event until the scrolling action comes to a complete stop.</p>
<p>The only mobile browser that handled this event elegantly in my testing was Android's Jelly Bean browser. Therefore, if you need any sort of cross browser support you're simply out of luck; there is simply no cross browser viable workaround to mimic the desktop behavior. If you have had success implementing this by some other means please let me know in the comments.</p>
<h3>Disclaimer</h3>
<p>I haven't been able to test this in Chrome for Android and I know there are other mobile browsers that I'm missing. If someone else has this capability I'd love to know how they handle these situations.</p>
<p>Also while I did verify these findings on physical devices for Firefox for Android, Android 2.3's default browser, and Safari on iOS 5; the rest of my testing was limited to simulators / emulators. From past experience I know that simulator / emulator testing is no substitute for the real thing. Therefore, if you find any discrepancies in my findings please let me know in the comments so I can update the post.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Subpixel Animation Issues in IE < 9]]></title>
<link href="http://tjvantoll.com/2012/08/16/subpixel-animation-issues-in-ie-less-than-9/"/>
<updated>2012-08-16T21:56:00-04:00</updated>
<id>http://tjvantoll.com/2012/08/16/subpixel-animation-issues-in-ie-less-than-9</id>
<content type="html"><![CDATA[<p>While there are definitely <a href="http://ejohn.org/blog/sub-pixel-problems-in-css/">cross browser discrepancies handling subpixels</a>, this one caught me by surprise. Take the following:</p>
<p>``` html</p>
<div id="box"></div>
<script>
var box = document.getElementById('box');
box.style.left = '10.25px';
console.log(box.style.left);
</script>
<p>```</p>
<p>This simply sets a value for the <code>left</code> CSS property then immediately retrieves it. In Chrome 22, Firefox 14, Safari 6, Opera 12, IE >= 9, iOS 5, and Android <code>10.25px</code> will be logged.</p>
<p>In IE < 9 <code>10px</code> is logged. While not all browsers can accurately render the subpixel values, I had assumed all of them would've at least allowed the assignment. I was wrong. Internet Explorer will simply round the value to the nearest integer.</p>
<p>Why is this a problem? <!--more-->Take the following code.</p>
<p>``` html</p>
<div id="box"></div>
<script>
var box = document.getElementById('box');
box.style.left = '0px';
setInterval(function() {
var currentLeft = box.style.left.replace('px', '');
currentLeft = parseFloat(currentLeft);
box.style.left = currentLeft + 0.25 + 'px';
}, 20);
</script>
<p>```</p>
<p>This sets an interval that will increase the <code>left</code> property of a box by <code>0.25</code> pixels every 20 milliseconds. Doing so will move the box left across the screen as seen below:</p>
<iframe style="width: 100%; height: 150px;" src="http://jsfiddle.net/tj_vantoll/PBsLt/9/embedded/result,js,html/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
<p>Great. Unfortunately in IE < 9 the box will not move. Within the interval function the value to increment is being retrieved from the element itself, which, in IE < 9 will continuously return the rounded value.</p>
<p>The way around this is simply to use store off the value of the property outside of the animation loop itself.</p>
<p>``` html</p>
<div id="box"></div>
<script>
var left = 0;
var box = document.getElementById('box');
setInterval(function() {
box.style.left = left + 'px';
left += 0.25;
}, 20);
</script>
<p>```</p>
<p>This has the added benefit of being more efficient since you save a property retrieval on every invocation of the loop.</p>
]]></content>
</entry>
</feed>