Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 51f7bf7c82
Fetching contributors…

Cannot retrieve contributors at this time

954 lines (639 sloc) 45.439 kb
<?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-08-12T21:58:05-04: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[HTML5 Form Validation - Showing All Error Messages]]></title>
<link href="http://tjvantoll.com/2012/08/05/html5-form-validation-showing-all-error-messages/"/>
<updated>2012-08-05T16:21:00-04:00</updated>
<id>http://tjvantoll.com/2012/08/05/html5-form-validation-showing-all-error-messages</id>
<content type="html"><![CDATA[<p><a href="http://caniuse.com/#feat=form-validation">Browsers that support HTML5 form validation</a> have one thing in common; if a <code>&lt;form&gt;</code> is submitted and has errors on multiple fields, the browser will only display the first error to the user.</p>
<p>Turns out the spec leaves the specific means of handling multiple errors up to the browser itself:</p>
<p><blockquote><p>Report the problems with the constraints of at least one of the elements given in unhandled invalid controls to the user. User agents may focus one of those elements in the process, by running the focusing steps for that element, and may change the scrolling position of the document, or perform some other action that brings the element to the user's attention.</p></p><p><p>User agents may report more than one constraint violation. User agents may coalesce related constraint violation reports if appropriate (e.g. if multiple radio buttons in a group are marked as required, only one error need be reported).</p><footer><strong>HTML5 Specification</strong> <cite><a href='http://www.whatwg.org/specs/web-apps/current-work/#the-constraint-validation-api'>www.whatwg.org/specs/web-apps/&hellip;</a></cite></footer></blockquote></p>
<p>The key part here being that user agents (i.e. browsers) <strong>MAY</strong> report more than one constraint violation (i.e. error). Turns out they all decided not to.</p>
<!--more-->
<p>You can see this in your browser below (assuming it <a href="http://caniuse.com/#feat=form-validation">supports HTML5 form validation</a> and is not Safari, more on that later). Both fields are <code>required</code>, but if you submit the form you will only see an error for the first field.</p>
<pre class="codepen" data-type="result" data-href="FBGvu" data-user="tjvantoll" data-host="http://codepen.io"><code></code></pre>
<script async src="http://codepen.io/assets/embed/ei.js"></script>
<p>Here's what it looks like on supported browsers if you attempt to submit this empty <code>&lt;form&gt;</code>:</p>
<h5>Chrome 21</h5>
<p><img src="/images/posts/2012-08-05/Chrome.png" title="Chrome" alt="Chrome" /></p>
<h5>Firefox 14</h5>
<p><img src="/images/posts/2012-08-05/Firefox.png" title="Firefox" alt="Firefox" /></p>
<h5>Opera 12</h5>
<p><img src="/images/posts/2012-08-05/Opera.png" title="Opera" alt="Opera" /></p>
<p>As you can see, all three only give an error for the first field. Firefox at least has the decency to put a red border around all fields with invalid data by default.</p>
<p>The one noticeable browser missing from the list above is Safari. Even though Safari supports the constraint validation API, the validation itself is turned off.</p>
<h3>Usability</h3>
<p>From a usability perspective showing the users only the first error message is bad. Imagine how frustrating it would be to continually correct errors just to be presented with the next error in the sequence. If you've ran into a form such as this before you know what I'm talking about.</p>
<p>Luckily, browsers provide a <a href="http://www.whatwg.org/specs/web-apps/current-work/#the-constraint-validation-api">constraint validation API</a> that can be used to provide this functionality.</p>
<h3>Using the Validation API</h3>
<p>All dom nodes now possess a <a href="http://www.whatwg.org/specs/web-apps/current-work/#dom-cva-willvalidate_">willValidate</a> property that indicates whether the node is a candidate for form validation.</p>
<p>Nodes in which <code>willValidate</code> is <code>true</code> also have a <code>validity</code> property. The <code>validity</code> property resolves to a <a href="https://developer.mozilla.org/en-US/docs/DOM/ValidityState">ValidityState object</a> which contains information about whether the field has validation errors, as well as the error message the browser will display to the user. You can leverage this API to display all error messages whenever a <code>&lt;form&gt;</code> is submitted.</p>
<h3>The Code</h3>
<p>Here's how I accomplished this with a jQuery dependent script.</p>
<p>``` html
<form></p>
<pre><code>&lt;ul id="errorMessages"&gt;&lt;/ul&gt;
&lt;label for="name"&gt;Name:&lt;/label&gt;
&lt;input type="text" required /&gt;
&lt;label for="comments"&gt;Comments:&lt;/label&gt;
&lt;textarea id="comments" required&gt;&lt;/textarea&gt;
&lt;input type="submit" value="Submit" /&gt;
</code></pre>
<p></form>​</p>
<script>
$(function() {
//Keep track of whether there are any errors on the form for Safari.
var formHasErrors = false;
var showAllErrorMessages = function() {
$('#errorMessages').empty();
formHasErrors = false;
//Find everything within the form
$('form').find('*').each(function(index, node) {
if (node.willValidate && node.validity && !node.validity.valid) {
formHasErrors = true;
//Find the field's corresponding label
var label = $('label[for=' + node.id + ']');
//Opera incorrectly does not fill the validationMessage property.
var message = node.validationMessage || 'Invalid value.';
$('#errorMessages')
.show()
.append('<li><span>' + label.html() + '</span> ' + message + '</li>');
}
});
};
$('input[type=submit]').on('click', showAllErrorMessages);
$('input[type=text]').on('keypress', function(event) {
//keyCode 13 is Enter
if (event.keyCode == 13) {
showAllErrorMessages();
}
});
//Handle for Safari not having HTML5 form validation active.
$('form').on('submit', function(event) {
if (formHasErrors) {
event.preventDefault();
}
});
});​
</script>
<p>```</p>
<p>You can see the results in your browser below:</p>
<pre class="codepen" data-type="result" data-href="eLvlf" data-user="tjvantoll" data-host="http://codepen.io"><code></code></pre>
<p>Here's how it looks in Chrome 21:</p>
<p><img src="/images/posts/2012-08-05/Chrome-full.png" title="Chrome" alt="Chrome" /></p>
<p>A couple things to note:</p>
<p>1) If a user attempts to submit a form and gets validation errors, a <code>submit</code> event is never fired for the <code>&lt;form&gt;</code>. Therefore, instead of listening for <code>submit</code> on the <code>&lt;form&gt;</code>, I instead listen for a <code>click</code> on the <code>&lt;input type="submit"&gt;</code>. Since the user is also able to submit the form pressing enter in text inputs, I attach a <code>keypress</code> listener to them to ensure the same logic runs.</p>
<p>2) In my example I start each error message with the contents of the field's <code>&lt;label&gt;</code>. This is because the messages for each field are often identical. An alternative approach would be to use another constraint validation API method, <a href="http://www.whatwg.org/specs/web-apps/current-work/#dom-cva-setcustomvalidity">setCustomValidity</a> to set a completely custom message.</p>
<p>3) The <code>node.willValidate &amp;&amp; node.validity</code> check will be <code>false</code> in all browsers that do not support the constraint validation API. Therefore this code will simply do nothing in browsers that do not support HTML5 form validation.</p>
<p>4) Opera incorrectly does not fill the <code>validationMessage</code> property. Therefore the check <code>var message = node.validationMessage || 'Invalid value.'</code> is necessary so a message is displayed for Opera.</p>
<p>5) In order to make Safari display the error messages I manually keep track of whether there are any validation errors in the <code>&lt;form&gt;</code>. If there are I prevent the <code>&lt;form&gt;</code> from submitting in a <code>submit</code> event.</p>
<p>6) I do nothing to style the individual fields based on whether they have valid data. The HTML5 spec provides a number of CSS hooks to do this and I would recommend reading <a href="http://html5doctor.com/css3-pseudo-classes-and-html5-forms/">CSS Pseudo-Classes and HTML5 Forms</a> from <a href="http://html5doctor.com">html5 Doctor</a> if you're interested in including such styling.</p>
<h3>That's a Lot of Code to Do Something Simple</h3>
<p>Yep. While browser support is getting to be quite good for HTML5 forms the implementations themselves are still a bit buggy. Nevertheless, this approach will work for displaying all validation errors to the end user.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[DOM Element References as Global Variables]]></title>
<link href="http://tjvantoll.com/2012/07/19/dom-element-references-as-global-variables/"/>
<updated>2012-07-19T22:33:00-04:00</updated>
<id>http://tjvantoll.com/2012/07/19/dom-element-references-as-global-variables</id>
<content type="html"><![CDATA[<p>Quiz: What is logged when the following markup is rendered?</p>
<p>``` html
<html></p>
<pre><code>&lt;head&gt;&lt;/head&gt;
&lt;body&gt;
&lt;button id="bar"&gt;Button&lt;/button&gt;
&lt;script&gt;
console.log(bar);
&lt;/script&gt;
&lt;/body&gt;
</code></pre>
<p></html>
```</p>
<p>Syntax error obviously, right? Wrong. All major browser rendering engines will log a reference to the <code>&lt;button&gt;</code> node. This includes Trident (IE), Gecko (Firefox), WebKit (Chrome, Safari, etc), and Presto (Opera).</p>
<h3>Wait. What?</h3>
<p>Ah, I get it, there's no doctype on that markup. So this a quirks mode only thing then right? Wrong. <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=622491">As of Firefox 14</a> the latest version of all major browsers will produce the same result IN STANDARDS MODE.</p>
<p>``` html
&lt;!DOCTYPE html>
<html></p>
<pre><code>&lt;head&gt;&lt;/head&gt;
&lt;body&gt;
&lt;button id="bar"&gt;Button&lt;/button&gt;
&lt;script&gt;
console.log(bar); //Reference to &lt;button&gt;, even in standards mode
&lt;/script&gt;
&lt;/body&gt;
</code></pre>
<p></html>
```</p>
<!--more-->
<h3>So What's Going On?</h3>
<p>Believe it or not this is actually correct behavior per the HTML specification.</p>
<p><blockquote><p>6.2.4 Named access on the Window object</p></p><p><p>The Window interface supports named properties. The supported property names at any moment consist of:</p></p><p><blockquote><p>the value of the name content attribute for all a, applet, area, embed, form, frame, frameset, iframe, img, and object elements in the active document that have a name content attribute, and<br/>the value of the id content attribute of any HTML element in the active document with an id content attribute.</p><footer><strong>HTML Specification</strong> <cite><a href='http://www.whatwg.org/specs/web-apps/current-work/#named-access-on-the-window-object'>www.whatwg.org/specs/web-apps/&hellip;</a></cite></footer></blockquote></p></blockquote>
<p>What this is saying is that the value of the <code>name</code> attribute of certain elements and the value of the <code>id</code> attribute of ALL elements are accessible via the <code>window</code> object in the browser. So, if you have a node <code>&lt;button id="foo"&gt;&lt;/button&gt;</code>, then <code>window.foo</code> will be resolved to a reference to the <code>&lt;button&gt;</code>. From this point forward I will refer to this behavior as named access.</p>
<h3>How is This Standard Behavior?</h3>
<p>This behavior is an old Internet Explorer <em>feature</em>. I can only imagine that it was intended to be a convenience for web developers that got sick of typing <code>document.getElementById</code> over and over again. (this is way before jQuery and other popular toolkits came to be). Regardless of the reasoning, IE shipped with this functionality and a whole lot of people utilized it.</p>
<p>Other rendering engines were faced with the difficult decision of implementing non-standard behavior or remaining incompatible with a slew of websites written specifically for Internet Explorer.</p>
<p>Gecko implemented this functionality but originally turned it on only in quirks mode. They recently took the extra step and <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=622491">turned named access on in standards mode with Firefox 14</a>.</p>
<p>Webkit and Presto have had named access in standards mode for some time now. <a href="https://www.w3.org/Bugs/Public/show_bug.cgi?id=11960">Webkit recently considered relegating this behavior to quirks mode</a>, however, they decided on leaving it enabled in standards mode. Apparently there is still just too much stuff out there relying on this behavior to remove it in standards mode. Believe it or not Microsoft even <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=737760">shipped a marketing demo</a> that directly referenced named DOM elements, preventing it from functioning in Gecko.</p>
<p>One of the main aims of the HTML5 specification is to standardize browser behavior, however quirky it might be. Therefore, this functionality made it into the specification.</p>
<h3>Why is This Behavior Bad?</h3>
<p>I've alluded to the fact that this behavior is bad, but I've haven't gotten into details as to why.</p>
<h4>There is a high potential for bugs to be introduced into the system</h4>
<p>Let's say you have some code that looks something like this:</p>
<p>``` html
<html></p>
<pre><code>&lt;head&gt;&lt;/head&gt;
&lt;body&gt;
&lt;input type="text" id="choice"&gt;&lt;/button&gt;
&lt;script&gt;
var choice = 'foo';
//Lots more JavaScript
doSomethingVeryComplicated(choice);
&lt;/script&gt;
&lt;/body&gt;
</code></pre>
<p></html>
```</p>
<p>Since a global <code>choice</code> variable is being created, <code>window.choice</code> will resolve to the string <code>foo</code> and not a reference to the <code>&lt;input&gt;</code>. This is because the <code>&lt;input&gt;</code> reference is being <a href="http://en.wikipedia.org/wiki/Variable_shadowing">shadowed</a> by the variable declaration. This works the same way as a variable with the same name being declared in a nested function.</p>
<p>``` javascript
(function() {</p>
<pre><code>var x = 2;
var y = function() {
var x = 3;
//Logs 3 instead of 2 because the value defined in the outer
//function is shadowed by the x defined in the inner function.
console.log(x);
};
y();
</code></pre>
<p>}());
```</p>
<p>This is all well and good. However, let's say that during a refactor of this code the <code>var choice = 'foo';</code> line is accidentally removed. Under normal circumstances this would cause a syntax error because <code>window.choice</code> would now be undefined. However, because there is a DOM node with an <code>id</code> of <code>choice</code>, that reference will now refer to the DOM node instead. This can easily lead to unexpected behavior.</p>
<p>The flip side of this situation is also true. If you have an element <code>&lt;div id="bar"&gt;&lt;/div&gt;</code> and use <code>window.bar</code> to refer to it, that code will break if you create JavaScript variable using <code>var</code> in the same scope (i.e. <code>var bar = 2;</code>).</p>
<h4>Mistyping</h4>
<p>Say you mistype the name of your variable and happen to type a named DOM element. SURPRISE!</p>
<h4>Non-trivial cost for the browser to implement</h4>
<p>In order for these named elements to be available, the browser has to create a list of all named elements and maintain it as the page changes. I can't offer any specific metrics as to how much time and memory this takes, but there is a cost, especially on pages with a large number of named elements.</p>
<h4>Named elements will be shadowed by properties natively defined on <code>window</code>.</h4>
<p>If you <em>were</em> to go the route of using named access you'd have to be careful to avoid using named elements with values that are predefined on the <code>window</code> already.</p>
<p>For example you cannot refer to a <code>&lt;input id="location"&gt;</code> by <code>window.location</code> because that <a href="https://developer.mozilla.org/en/DOM/window.location">already resolves to an object</a> with information about the URL of the current document.</p>
<p>There are a number of other property names on the <code>window</code> object that you could easily see being used to name a DOM element - <code>event</code>, <code>history</code>, <code>name</code>, <code>self</code>, <code>status</code>, and <code>toolbar</code> to name a few.</p>
<h4>Browsers have inconsistent implementations.</h4>
<p>Even though this is behavior is now standardized, there are still browser quirks in the way named access is implemented.</p>
<h5>IE and Form Elements</h5>
<p>IE will (incorrectly) make the <code>name</code> attribute of form elements available on the <code>window</code> object.</p>
<p>``` html
&lt;!DOCTYPE html>
<html></p>
<pre><code>&lt;head&gt;&lt;/head&gt;
&lt;body&gt;
&lt;form&gt;
&lt;input name="foo" /&gt;
&lt;/form&gt;
&lt;script&gt;
//Logs a reference to the &lt;input&gt; in IE.
//Syntax error in all other rendering engines.
console.log(foo);
&lt;/script&gt;
&lt;/body&gt;
</code></pre>
<p></html>
```</p>
<h5>Name Attribute on Anchor Tags</h5>
<p>Per the spec, <code>&lt;a&gt;</code> tags should be accessible on the <code>window</code> object via the value of their <code>name</code> attribute. However, this only works in IE and Opera.</p>
<p>``` html
&lt;!DOCTYPE html>
<html></p>
<pre><code>&lt;head&gt;&lt;/head&gt;
&lt;body&gt;
&lt;a name="foo"&gt;&lt;/a&gt;
&lt;script&gt;
//Logs a reference to the &lt;a&gt; in IE and Opera.
//Syntax error in Gecko and WebKit.
console.log(foo);
&lt;/script&gt;
&lt;/body&gt;
</code></pre>
<p></html>
```</p>
<h5>Multiple Named Attributes with the Same Value</h5>
<p>Per this portion of the spec:</p>
<p><blockquote><p>...if elements has only one element, return that element and abort these steps.</p></p><p><p>Otherwise return an HTMLCollection rooted at the Document node, whose filter matches only named elements with the name name.</p><footer><strong>HTML Specification</strong> <cite><a href='http://dev.w3.org/html5/spec/single-page.html#dom-window-nameditem'>dev.w3.org/html5/spec/&hellip;</a></cite></footer></blockquote></p>
<p>What this is staying is that when there are multiple named properties with the same name, the browser should return an array when that property is referenced (instead of a reference to a specific DOM node). As an example given this markup:</p>
<p>``` html
&lt;!DOCTYPE html>
<html></p>
<pre><code>&lt;head&gt;&lt;/head&gt;
&lt;body&gt;
&lt;input id="one"&gt;
&lt;input id="one"&gt;
&lt;script&gt;
console.log(one);
&lt;/script&gt;
&lt;/body&gt;
</code></pre>
<p></html>
```</p>
<p>...an array with references to the two <code>&lt;input&gt;</code> nodes should be logged per the spec. And it will be in all browsers except Firefox. Firefox 14 will simply log the first element.</p>
<p>Having two elements with the same <code>id</code> is invalid HTML, but the browser will still render it just fine. Even with the best of intentions these sorts of things do happen, especially in larger, dynamic applications.</p>
<h3>More?</h3>
<p>These are simply the bugs that I've ran into, I'm sure there are more. If you know of any let me know in the comments and I can update this list.</p>
<h3>But won't strict mode prevent this?</h3>
<p><a href="https://developer.mozilla.org/en/JavaScript/Strict_mode">ECMAScript 5 strict mode</a> prevents you assigning values to variables before they are declared. Therefore this...</p>
<p>``` javascript
(function() {</p>
<pre><code>foo = 2;
</code></pre>
<p>}());
```</p>
<p>will execute just fine whereas this...</p>
<p>``` javascript
(function() {</p>
<pre><code>'use strict';
foo = 2;
</code></pre>
<p>}());
```</p>
<p>...will produce a syntax error that <code>foo</code> is not defined. This is great, but it will not stop you from accessing named properties on the <code>window</code> object.</p>
<p>``` html</p>
<div id="foo"></div>
<script>
(function() {
'use strict';
console.log(foo);
});
</script>
<p>```</p>
<p>This will log a reference to the <code>&lt;div&gt;</code> in standards mode in the latest version of all modern browsers. Strict mode will only prevent you from assigning values to variables that have yet to be declared. If you're simply using a variable then strict mode doesn't protect you. Therefore, you're not prevented from accessing name properties on the global <code>window</code> object.</p>
<h3>What to do instead</h3>
<p>Use <code>document.getElementById</code> to retrieve references to DOM nodes via their <code>id</code> attribute.</p>
<p>``` html
<button id="foo"></button></p>
<script>
document.getElementById('foo');
</script>
<p>```</p>
<p>To get a reference to a DOM node via its <code>name</code> attribute you can use <code>document.querySelectorAll</code>.</p>
<p>``` html
<a name="bar"></a></p>
<script>
document.querySelectorAll('[name=bar]');
</script>
<p>```</p>
<p><code>document.querySelectorAll</code> is not safe to use in IE &lt;= 8, so if you need to support older IE look into using a toolkit such as <a href="http://jquery.com">jQuery</a> to select the DOM nodes that you need.</p>
<h3>Conclusion</h3>
<p>All major browsers now make named properties available on the global <code>window</code> object in standards mode. It's important to know that browsers do this because you'll likely run into this at some point. However, never purposely utilize this functionality. If you see others use it tell them to stop, ridicule them, do whatever it takes. Help <a href="http://movethewebforward.org/">move the web forward</a>.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Default Browser Handling of the CSS text-transform Property]]></title>
<link href="http://tjvantoll.com/2012/07/10/default-browser-handling-of-the-css-text-transform-property/"/>
<updated>2012-07-10T21:05:00-04:00</updated>
<id>http://tjvantoll.com/2012/07/10/default-browser-handling-of-the-css-text-transform-property</id>
<content type="html"><![CDATA[<p>The <code>text-transform</code> CSS property is most frequently used to uppercase and lowercase text. According to the <a href="http://www.w3.org/TR/CSS21/text.html#caps-prop">CSS 2.1 specification</a> it is also an inherited property, meaning, when no value is specified on a given element, it should inherit its parent's <code>text-transform</code> value.</p>
<p>If no parents have a <code>text-transform</code> property defined, the element will take on the default value of <code>none</code>.</p>
<p>Where it gets interesting is that all browsers define default <code>text-transform</code> properties for certain form elements. What does this mean? <!--more-->Let's say you have the following markup:</p>
<p>``` html</p>
<div>
<input type="text" value="foo" />
<input type="submit" value="bar" />
</div>
<p>```</p>
<p>Both <code>foo</code> and <code>bar</code> will appear lowercased in all major browsers. You can see this for yourself below:</p>
<iframe style="width: 100%; height: 120px;" src="http://jsfiddle.net/tj_vantoll/DxANv/1/embedded/result,html,css/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
<p>This happens because all browser vendors include <code>text-transform: none</code> in their user agent stylesheet for those elements. Therefore the <code>text-transform: uppercase</code> rule declared on the parent node is not inherited.</p>
<p>Unfortunately, but not surprisingly, browsers are not consistent about their default values for all elements.</p>
<h3>What the Browsers Do</h3>
<p>The following chart shows popular browser rendering engines and whether their user agent stylesheet includes <code>text-transform: none</code> for the listed elements.</p>
<table>
<thead>
<tr>
<th>Rendering Engine</th>
<th>input[type=submit]</th>
<th>input[type=text]</th>
<th>select</th>
<th>textarea</th>
<th>button</th>
</tr>
</thead>
<tbody>
<tr>
<td>Trident (Internet Explorer)</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td><strong>No</strong></td>
</tr>
<tr>
<td>Gecko (Firefox)</td>
<td>Yes</td>
<td>Yes</td>
<td><strong>No</strong></td>
<td>Yes</td>
<td><strong>No</strong></td>
</tr>
<tr>
<td>WebKit (Chrome, Safari, etc...)</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
<td>Yes</td>
</tr>
<tr>
<td>Presto (Opera)</td>
<td>Yes</td>
<td>Yes</td>
<td><strong>No</strong></td>
<td>Yes</td>
<td><strong>No</strong></td>
</tr>
</tbody>
</table>
<p>The rendering engines that have a <strong>No</strong> for a given element declare no default for <code>text-transform</code>. Therefore, those elements will inherit the value from their parent.</p>
<h3>What Does This Mean?</h3>
<p>The browser differences occur on the <code>button</code> and <code>select</code> elements. Therefore, if you apply a <code>text-transform</code> value to a node, AND that node has children <code>button</code> / <code>select</code> nodes, AND you do not apply a <code>text-transform</code> value to the <code>button</code> or <code>select</code> nodes themselves... you'll get different behavior in different browsers.</p>
<p>For example:</p>
<p>``` html
&lt;!DOCTYPE html>
<html></p>
<pre><code>&lt;head&gt;
&lt;style&gt;
form { text-transform: uppercase; }
&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;form&gt;
&lt;!-- "foo" will be uppercase in IE, Firefox, and Opera --&gt;
&lt;!-- "foo" will be lowercase in WebKit based browsers --&gt;
&lt;button&gt;foo&lt;/button&gt;
&lt;!-- "bar" will be uppercase in Firefox and Opera --&gt;
&lt;!-- "bar" will be lowercase in IE and WebKit based browsers --&gt;
&lt;select&gt;
&lt;option&gt;bar&lt;/option&gt;
&lt;/select&gt;
&lt;/form&gt;
&lt;/body&gt;
</code></pre>
<p></html>
```</p>
<h3>Consistency</h3>
<p>You could make arguments as to whether the user agent stylesheets <em>should</em> be defaulting the <code>text-transform</code> of various form elements to <code>none</code>, but to most people all that matters is that the behavior is consistent. It's easy enough to override the defaults if you don't like them.</p>
<p>Therefore to get consistent behavior you would <em>think</em> you would need to set the default value of <code>button</code> and <code>select</code> elements to either <code>none</code> or <code>inherit</code>.</p>
<p>``` css
/<em> Option 1 - Don't inherit values in all browsers </em>/
button, select { text-transform: none; }</p>
<p>/<em> Option 2 - Inherit values in all browsers </em>/
button, select { text-transform: inherit; }
```</p>
<p>But unfortunately for whatever reason Option 2 doesn't work on the <code>&lt;select&gt;</code> in IE &lt;= 7, Safari, and most interestingly, doesn't take effect in Chrome until you click on <code>&lt;select&gt;</code>. You can verify this behavior for yourself below:</p>
<iframe style="width: 100%; height: 120px;" src="http://jsfiddle.net/tj_vantoll/dUjXB/10/embedded/result,html,css/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
<p>Fortunately Option 1 does indeed produce the same behavior in IE6+, Firefox, Chrome, Safari, and Opera. Therefore to normalize <code>text-transform</code> you need to include the following in your stylesheet.</p>
<p><code>css Cross Browser text-transform Goodness
button, select { text-transform: none; }
</code></p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Creating a Native HTML 5 Datepicker with a Fallback to jQuery UI]]></title>
<link href="http://tjvantoll.com/2012/06/30/creating-a-native-html5-datepicker-with-a-fallback-to-jquery-ui/"/>
<updated>2012-06-30T17:06:00-04:00</updated>
<id>http://tjvantoll.com/2012/06/30/creating-a-native-html5-datepicker-with-a-fallback-to-jquery-ui</id>
<content type="html"><![CDATA[<p>The recently released Chrome 20 features support for native datepickers on <code>&lt;input&gt;</code> nodes with a <code>[type=date]</code> attribute. The list of browsers that support native datepickers now includes Chrome, Opera 11+, Opera Mobile, and iOS 5+ (see <a href="http://caniuse.com/#feat=input-datetime">caniuse.com</a>). Therefore, now is a great time to start using them in your web applications.</p>
<!--more-->
<h3>Using</h3>
<p>Using the native datepickers is easy, just change the <code>type</code> attribute of your date inputs from <code>text</code> to <code>date</code>.</p>
<p>``` html Converting to a native HTML5 datepicker</p>
<!-- Before -->
<p><input type="text" /></p>
<!-- After -->
<p><input type="date" />
```</p>
<p>Here is what the user will see in supported browsers:</p>
<h4>Chrome 20</h4>
<p><img src="/images/posts/2012-06-30/Chrome.png" title="Chrome 20" alt="Chrome 20" /></p>
<h4>Opera 12</h4>
<p><img src="/images/posts/2012-06-30/Opera.png" title="Opera 12" alt="Opera 12" /></p>
<h4>Opera Mobile</h4>
<p><img src="/images/posts/2012-06-30/Opera%20Mobile.png" title="Opera Mobile" alt="Opera Mobile" /></p>
<h4>iOS 5</h4>
<p><img src="/images/posts/2012-06-30/iOS5.png" title="iOS 5" alt="iOS 5" /></p>
<h3>Advantages</h3>
<p>Why would use the native solution?</p>
<p>First and foremost there are no dependencies. There is no need to bring in a library or toolkit, it's all native. Therefore, you save some bytes by not having to ship the JavaScript / CSS to make the datepicker work.</p>
<p>Furthermore you can be guaranteed that it will work perfectly on all devices that support the native datepicker. It's not dependent on JavaScript so it'll even work for users that have JavaScript disabled.</p>
<p>Another key advantage is that devices can give alternative means of input for date controls. For example note the native date control in iOS 5:</p>
<p><img src="/images/posts/2012-06-30/iOS5.png" title="iOS 5" alt="iOS 5" /></p>
<p>It will be a lot easier for the user to input a date with those controls, plus you can be guaranteed that you'll receive input in the correct format.</p>
<h3>Disadvantages</h3>
<p>The main disadvantage of using a native datepicker is that you have a lot less control. There are no hooks to control the look of the date picker; you get what the browser wants to give you. You also have a lot less control over the behavior. Here's a small sampling of things that jQuery UI's datepicker can do that you cannot do with the native control.</p>
<ul>
<li>Only allow selection on certain days of the week.</li>
<li>Control the formatting of the headers in the control (Monday vs Mon vs M).</li>
<li>View multiple months at the same time.</li>
</ul>
<p>If any of this functionality is important to your application you'll probably want to stick with the jQuery UI solution.</p>
<h3>Best of Both Worlds</h3>
<p><a href="http://modernizr.com">Modernizr</a> gives you the ability to detect whether the browser supports native datepickers. The following shows how you can use the native datepicker when available, and fallback to jQuery UI's datepicker in unsupported browsers.</p>
<p>``` javascript Detect native support for datepickers and fallback to jQuery UI
if (!Moderniz.inputtypes.date) {</p>
<pre><code>$('input[type=date]').datepicker();
</code></pre>
<p>}
```</p>
<p>You can see how your browser handles this situation here:</p>
<iframe style="width: 100%; height: 120px;" src="http://jsfiddle.net/p58bt/2/embedded/result,html,js/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
<h3>Conclusion</h3>
<p>With Chrome adding support for native datepickers a large chunk web users now have the ability to use native pickers. Therefore, now is a great time to consider using them in your applications.</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Detecting Print Requests with JavaScript]]></title>
<link href="http://tjvantoll.com/2012/06/15/detecting-print-requests-with-javascript/"/>
<updated>2012-06-15T00:00:00-04:00</updated>
<id>http://tjvantoll.com/2012/06/15/detecting-print-requests-with-javascript</id>
<content type="html"><![CDATA[<p>CSS has a well supported mechanism for applying changes only when the user is printing a document, <a href="http://coding.smashingmagazine.com/2011/11/24/how-to-set-up-a-print-style-sheet/">print stylesheets</a>. They allow you to alter the presentation of a web page for the printer by applying rules that will only be interpreted for printing. This is great for common tasks like hiding non-essential content, using more print friendly typography, and adjusting the layout to better suit the size and shape of paper.</p>
<p>Print stylesheets are great for making presentational changes for printing, but sometimes you need the full power of JavaScript. And in order to do respond to print requests in JavaScript you need the browser to notify you that a print request occurred.</p>
<!--more-->
<h3>onbeforeprint and onafterprint</h3>
<p>IE5+ fires <code>onbeforeprint</code> and <code>onafterprint</code> events before and after the user requests the page to be printed.</p>
<p>``` javascript onbeforeprint and onaferprint
window.onbeforeprint = function() {</p>
<pre><code>console.log('This will be called before the user prints.');
</code></pre>
<p>};
window.onafterprint = function() {</p>
<pre><code>console.log('This will be called after the user prints');
</code></pre>
<p>};
```</p>
<p>These events are not part of any specification but they are very convenient. Because of this <a href="https://developer.mozilla.org/en/DOM/window.onbeforeprint#Browser_compatibility">Firefox added support for both events in version 6</a>. However, WebKit and Opera do not support the events. Therefore, for cross browser compatibility these events aren't going to cut it.</p>
<h3>WebKit's Solution</h3>
<p>WebKit has a bug (#<a href="https://bugs.webkit.org/show_bug.cgi?id=19937">19937</a>) out there to implement these events, but progress has stopped because the implementation of another API made this functionality possible already - <code>window.matchMedia</code>.</p>
<h3>window.matchMedia</h3>
<p>The <code>window.matchMedia</code> <a href="https://developer.mozilla.org/en/DOM/window.matchMedia">API</a> provides a means of determining whether the current <code>document</code> matches a given <a href="https://developer.mozilla.org/En/CSS/Media_queries">media query</a>. For example:</p>
<p>``` javascript window.matchMedia
if (window.matchMedia(' (min-width: 600px) ').matches) {</p>
<pre><code>console.log('The viewport is at least 600 pixels wide');
</code></pre>
<p>} else {</p>
<pre><code>console.log('The viewport is less than 600 pixels wide');
</code></pre>
<p>}
```</p>
<p>You can also use this API to add listeners that will be fired whenever the result of the media query changes. In the above example the <code>matches</code> criteria will be met whenever the viewport is at least 600px wide. If you wanted to receive notifications whenever the viewport crossed the 600px threshold you could use the following.</p>
<p>``` javascript window.matchMedia with notifications
var mediaQueryList = window.matchMedia(' (min-width: 600px) ');
mediaQueryList.addListener(function(mql) {</p>
<pre><code>if (mql.matches) {
console.log('The viewport is at least 600 pixels wide');
} else {
console.log('The viewport is less than 600 pixels wide');
}
</code></pre>
<p>});
```</p>
<p><a href="http://caniuse.com/#feat=matchmedia">If your browser supports window.matchMedia</a> you can see this behavior live below by resizing your browser window under 600px and checking your browser's JavaScript console.</p>
<iframe style="width: 100%; height: 200px;" src="http://jsfiddle.net/tj_vantoll/uYJxy/2/embedded/result,js,css/" allowfullscreen="allowfullscreen" frameborder="0"></iframe>
<p>Interestingly, it turns out you can also use this same technique to listen for the <code>print</code> media being applied when the user requests the document to be printed (<a href="http://code.google.com/p/chromium/issues/detail?id=105743">hat tip to Ben Wells</a>):</p>
<p>``` javascript Using window.matchMedia to detecting print requests
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(function(mql) {</p>
<pre><code>if (mql.matches) {
console.log('onbeforeprint equivalent');
} else {
console.log('onafterprint equivalent');
}
</code></pre>
<p>});
```</p>
<p>This works great in Chrome 9+ and Safari 5.1 (with the exception of the fact that the <a href="http://code.google.com/p/chromium/issues/detail?id=105743">listeners fire twice in Chrome</a>). However, it doesn't work in Firefox or IE10, even though they both support <code>window.matchMedia</code>.</p>
<h4>Update (July 16th, 2012)</h4>
<p>I created a bug on Firefox's issue tracker for this defect - <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=774398">https://bugzilla.mozilla.org/show_bug.cgi?id=774398</a>. I'll update this post when I hear back.</p>
<h3>Combining the Approaches</h3>
<p>If you combine the two approaches you can detect print requests in IE 5+, Firefox 6+, Chrome 9+, and Safari 5.1+ (unfortunately Opera doesn't support either approach).</p>
<p>``` javascript Cross browser print request detection
(function() {</p>
<pre><code>var beforePrint = function() {
console.log('Functionality to run before printing.');
};
var afterPrint = function() {
console.log('Functionality to run after printing');
};
if (window.matchMedia) {
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(function(mql) {
if (mql.matches) {
beforePrint();
} else {
afterPrint();
}
});
}
window.onbeforeprint = beforePrint;
window.onafterprint = afterPrint;
</code></pre>
<p>}());
```</p>
<p>Note that your event handlers might potentially have to deal with the fact that they're going to be called twice per print request in Chrome.</p>
<h3>Why Would I Use This?</h3>
<p>For most situations print stylesheets are all you need to prepare the document for printing. But I can think of a couple practical uses of the JavaScript event.</p>
<h3>Responsive Print Images</h3>
<p>One use is substituting a higher quality image for the purposes of printing. Traditionally <a href="http://www.cssnewbie.com/print-friendly-images/">web browsers have displayed images at 72dpi and most printers can handle 300dpi+</a>. While some newer devices are able to display images at much higher resolutions, most users are still using a screen that will show web images at much lower resolutions than their printer can handle.</p>
<p>Therefore an image that might look just fine on the user's screen might look fuzzy and grainy when printed out. For most images this is acceptable, but it might be an issue for prominent images on regularly printed documents, like a company logo. You probably want that to look crisp when printed out.</p>
<p>The <a href="http://www.alistapart.com/articles/hiresprinting">technique to work around this</a> involves loading both images, showing only the lower quality one by default, then hiding the low quality image and showing the high quality one in the print stylesheet. The main downfall of this approach is that the end user has to download both images regardless of whether they're going to print the page. Users on 3G devices that have no intention or capability of printing the document will still have to download your high resolution logo.</p>
<p>With the ability to detect print requests in JavaScript you can substitute the higher quality image on the fly when the user requests the page to be printed.</p>
<p>``` html Substituting higher quality images when printing
<img src="low-quality.jpg" id="company_logo" alt="My Company" /></p>
<script>
(function() {
var upgradeImage = function() {
document.getElementById('company_logo')
.setAttribute('src', 'high-quality.png');
};
if (window.matchMedia) {
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(upgradeImage);
}
window.onbeforeprint = upgradeImage;
});
</script>
<p>```</p>
<p>The nice thing about this approach is that users that never print will not have to download the high quality image. This technique also degrades nicely; users with browsers that don't support the print events will simply print the lower quality image.</p>
<h3>Tracking Print Requests</h3>
<p>Print events can also be used to track the number of times users print pages within a site or application. Because of the lack of total browser support you wouldn't capture every print request, but this would be sufficient for getting a rough idea of how often people are printing.</p>
<p>``` javascript Tracking Print Requests
(function() {</p>
<pre><code>var afterPrint = function() {
// Here you would send an AJAX request to the server to track that a page
// has been printed. You could additionally pass the URL if you wanted to
// track printing across an entire site or application.
};
if (window.matchMedia) {
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(function(mql) {
if (!mql.matches) {
afterPrint();
}
});
}
window.onafterprint = afterPrint;
</code></pre>
<p>}());
```</p>
<h3>So can I use this in a "real" application?</h3>
<p>Sure, just make sure what you're doing degrades nicely for users using a browser in which the event will not be fired.</p>
<p>Can you think of any other practical uses of detecting print requests in JavaScript? If so let me know in the comments.</p>
<h4>Update (July 16th, 2012)</h4>
<p>Per the comments I've found that in addition to all the bugs mentioned above, certain browsers trigger the after print event early (with either <code>onafterprint</code> or the <code>window.matchMedia</code> handler implementation).</p>
<p>``` html
&lt;!DOCTYPE html>
<html></p>
<pre><code>&lt;head&gt;
&lt;script&gt;
var beforePrint = function() {
document.getElementById('printImage').src =
'http://stackoverflow.com/favicon.ico';
};
var afterPrint = function() {
document.getElementById('printImage').src =
'http://google.com/favicon.ico';
};
if (window.matchMedia) {
var mediaQueryList = window.matchMedia('print');
mediaQueryList.addListener(function(mql) {
if (mql.matches) {
beforePrint();
} else {
afterPrint();
}
});
}
window.onbeforeprint = beforePrint;
window.onafterprint = afterPrint;
&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;img id="printImage" src="http://google.com/favicon.ico" /&gt;
&lt;/body&gt;
</code></pre>
<p></html>
```</p>
<p>When printing the above document you would expect Stack Overflow's favicon to print, when in actuality Google's favicon prints. Both events fire, but the after print event fires before the printing actually occurs, which in this case reverts the changes made in the before print event.</p>
<p>I was able to recreate this problem in Chrome and Firefox.</p>
<p>Therefore do not do anything that relies on the after print event to fix what the before print event did. For responsive print images this shouldn't be an issue because there should be no harm leaving the higher quality image in place; the user has already downloaded it.</p>
]]></content>
</entry>
</feed>
Jump to Line
Something went wrong with that request. Please try again.