mozilla

Revision 347183 of HTML forms in legacy browsers

  • Revision slug: HTML/Forms/HTML_forms_in_legacy_browsers
  • Revision title: HTML forms in legacy browsers
  • Revision id: 347183
  • Created:
  • Creator: Jeremie
  • Is current revision? No
  • Comment

Revision Content

All web developers learn very quickly (and sometimes painfully) that the Web is a very rough place for them. Our worst curse is legacy browsers. Okay, let's admit it, when we said "legacy browser" we all have good old Internet Explorer in mind... but it's fare from the only one. A one-year old Firefox such as the ESR version is a legacy browser too. And in the mobile world? When the browser is stuck with the OS? Yes, there is many legacy Android phone or iPhone not up to date with their stock browsers and they are also legacy browsers.

Sadly, dealing with that wilderness is part of the job. Fortunately, there are a few tricks to know that can help you to solve 80% of the trouble or so.

Learn about it

Actually, the most important thing is to read documentation about those browsers to try to understand the common patterns (for example, the CSS support is the biggest issue with HTML forms in many cases). You are at the right place to start. Just check the support of the elements (or DOM interface) you want to use, MDN as compatibility tables available for many elements, property or API that can be used in a web page. But there are other external resources that can be amazingly helpful:

Browser vendors documentation

Independent documentation

  • Can I Use if you need information about cutting edge technologies
  • Quirks Mode is an amazing resource about browsers' compatibility. The mobile part is one of the best available at the moment.
  • Position Is Everything is the best resource available about rendering bugs in legacy browsers and their work around (if any).
  • Webplateform.org is the documentation project supported by W3C and all browser vendors, including Mozilla.

Make things simple

Because HTML forms involves complex interaction, there is one rule of thumb: keep it as simple as possible. There is so many case were we want forms "nicer" or "with advanced functionality", but building efficient HTML Forms is not a question of design or technology. Just as a reminder, take the time to read this article about forms usability on UX For The Masses.

Graceful degradation is web developer best friend.

Graceful degradation and progressive enhancement are development patterns that allow you to build great stuff by supporting a wide range of browsers at the same time. When you build something for a modern browser, and you want to be sure it will work one-way or another on legacy browsers, you are performing graceful degradation.

Let's see some examples related to HTML forms

HTML input types

The new input types brought by HTML5 are very cool because the way they degrade is highly predictable. If a browser does not know the value of the {{htmlattrxref("type","input")}} attribute of an {{HTMLElement("input")}} element, it will fallback as if the value were text.

<label for="myColor">
  Pick a color
  <input type="color" id="myColor" name="color">
</label>
Chrome 24 Firefox 18
Screen shot of the color input on Chrome for Mac OSX Screen shot of the color input on Firefox for Mac OSX

CSS Attribute Selectors

The CSS Attribute selectors are very useful with HTML Forms but some legacy browsers do not support it. In that case, it's customary to double the type with an equivalent class:

<input type="number" class="number">
input[type=number] {
  /* This can fail in some browsers */
}

input.number {
  /* This will work everywhere */
}

Note that the following is useless (because it's redundant) and can fail in some browsers:

input[type=number],
input.number {
  /* This can fail in some browsers because if they do not understand
     one of the selectors, they will skip the whole rule */
}

Forms' button

There is 2 ways to define buttons within HTML forms:

  • The {{HTMLElement("input")}} element with its attribute {{htmlattrxref("type","input")}} set to the values button, submit, reset or image
  • The {{HTMLElement("button")}} element

The former can make things a little difficult if you want to apply some CSS by using the element selector:

<input type="button" class="button" value="click me">
input {
  /* This rule will turn off the default rendering for buttons define with an input element */
  border: 1px solid #CCC;
}

input.button {
  /* This will NOT restore the default rendering */
  border: none;
}

input.button {
  /* That neither! Actually there is no standard way to do it in any browsers */
  border: auto;
}

The latter suffer two possible issues:

  • A bug in some old version of Internet Explorer. When the user click on it, it's not the content of the {{htmlattrxref("value","button")}} attribute that is send but the HTML content available between the starting and ending tag of the {{HTMLElement("button")}} element. This is an issue only if you want to send such a value, for example if the processing of the data depends on the button the user clicks on.
  • Some very old browsers does not use submit as the default value for the {{htmlattrxref("type","button")}} attribute, so it's recommended to always set the attribute {{htmlattrxref("type","button")}} on {{HTMLElement("button")}} elements.
<!-- To click on this button will send "<em>Do A</em>" instead of "A" in some cases -->
<button type="submit" name="IWantTo" value="A">
  <em>Do A</em>
</button>

Choosing one-way or the other is up to you based on your project's constrains.

Let it go with css.

The biggest issue with HTML Forms and legacy browsers is the support for CSS. As detailed in this article, it's something very difficult. Even if it's still possible to do a few adjustments on text elements (such as sizing or font color), there are always side effects. The best approach remains to not style HTML Form widgets at all (But you can still apply styles to all the things around). If you are a professional and if your client requires it, in that case, you can investigate some hard technique such as rebuilding widgets with JavaScript. But in that case, do not hesitate to charge you client for such a foolishness.

Feature detection and polyfills

If JavaScript is an awesome technology in modern browsers, legacy browsers have many issues with it.

Unobstructive JavaScript

One of the biggest problems is the availability of APIs. For that reason, it's considered best practice to work with unobstructive JavaScript. It's a development pattern that defines two requirements:

  • A strict separation between structure and behaviors.
  • If the code breaks, the content and the basic functionalities must remain accessible and usable.

Opera folks have very well detailed those principles on webplateform.org.

The Modernizr library

However, there are many cases where a good polyfill can help a lot by providing missing API. Actually, using JavaScript to improve JavaScript is the safer way to use polyfills. Using polyfills to improve the CSS or HTML support is risky due to the fact there is many cases where JavaScript can break (Network issues, script conflict, etc.). But with JavaScript, if you work with unobstructive JavaScript in mind, il polyfill are missing, it's no big deal.

The best way to polyfill missing API is by using the Modernizr library and its spin off project: YepNope. Modernizr is a library that allows you to test the availability of functionality in order to act accordingly. On its own side, YepNope is a conditional loading library.

Here is an example:

Modernizr.load({
  // This will test if your bowser supports the HTML5 form validation API
  test : Modernizr.formvalidation,
 
  // If the browser does not support it, the following polyfill will be loaded
  nope : form-validation-API-polyfill.js,
 
  // In any case, your core App file that depend on that API will be loaded
  both : app.js,
 
  // Once both files are loaded, this function is called in order to initialize the App.
  complete : function () {
    app.init();
  }
});

The Modernizr team conveniently maintains a list of great polyfills. Just pick what you need.

Note: Modernizr has other awesome features to help you dealing with unobstructive JavaScript and graceful degradation technics, do not hesitate to read the documentation.

Beware of performance

Even if scripts like Modernizr are very aware of performance, loading a 200Ko polyfill can hit the performance of your application. This is especially critical with legacy browsers; many of them have a very slow JavaScript engine that can make the execution of all your polyfills painful for the user. Performance is a subject on its own, but legacy browser are very sensible to it: basically, there are slow and it's quite often to ask them to process more JavaScript than modern browsers so pay attention to this. Sometimes, loosing a functionalty will lead to a better user experience. As a last reminder, just always think about the end users.

Conclusion

As you can see, dealing with legacy browsers is not just about forms. It's a whole set of technics that you'll have to master but it's another story. If you read all the article of that HTML Forms guide, you should now be at ease to use them, so do not hesitate to improve that guide.
 

Revision Source

<p>All web developers learn very quickly (and sometimes painfully) that the Web is a very rough place for them. Our worst curse is legacy browsers. Okay, let's admit it, when we said "legacy browser" we all have good old Internet Explorer in mind... but it's fare from the only one. A one-year old Firefox such as <a href="http://www.mozilla.org/en-US/firefox/organizations/" title="http://www.mozilla.org/en-US/firefox/organizations/">the ESR version</a> is a legacy browser too. And in the mobile world? When the browser is stuck with the OS? Yes, there is many legacy Android phone or iPhone not up to date with their stock browsers and they are also legacy browsers.</p>
<p>Sadly, dealing with that wilderness is part of the job. Fortunately, there are a few tricks to know that can help you to solve 80% of the trouble or so.</p>
<h2 id="Know_your_enemy">Learn about it</h2>
<p>Actually, the most important thing is to read documentation about those browsers to try to understand the common patterns (for example, the CSS support is the biggest issue with HTML forms in many cases). You are at the right place to start. Just check the support of the elements (or DOM interface) you want to use, MDN as compatibility tables available for many elements, property or API that can be used in a web page. But there are other external resources that can be amazingly helpful:</p>
<h3 id="Browser_vendors_documentation">Browser vendors documentation</h3>
<ul>
  <li>Mozilla: You're at the right place, just browse MDN</li>
  <li>Microsoft: <a href="http://msdn.microsoft.com/en-us/library/ff410218%28v=vs.85%29.aspx" rel="external" title="http://msdn.microsoft.com/en-us/library/ff410218%28v=vs.85%29.aspx">Internet Explorer Standards Support Documentation</a></li>
  <li>Opera: <a href="http://www.opera.com/docs/specs/" rel="external" title="http://www.opera.com/docs/specs/">Web specification support in Opera</a></li>
  <li>WebKit: Because there are several different editors, things are a little more trickier
    <ul>
      <li><a href="https://www.webkit.org/blog/" rel="external" title="https://www.webkit.org/blog/">The WebKit blog</a> and <a href="http://planet.webkit.org/" rel="external" title="http://planet.webkit.org/">Planet WebKit</a> aggregate the best articles by WebKit core developers.</li>
      <li><a href="http://www.chromium.org/developers/web-platform-status" title="http://www.chromium.org/developers/web-platform-status">The chromium web site</a> is also important</li>
      <li>As well as <a href="https://developer.apple.com/technologies/safari/" rel="external" title="https://developer.apple.com/technologies/safari/">the Apple web site</a></li>
    </ul>
  </li>
</ul>
<h3 id="Independent_documentation">Independent documentation</h3>
<ul>
  <li><a href="http://caniuse.com" rel="external" title="http://caniuse.com">Can I Use</a> if you need information about cutting edge technologies</li>
  <li><a href="http://www.quirksmode.org" rel="external" title="http://www.quirksmode.org">Quirks Mode</a> is an amazing resource about browsers' compatibility. <a href="http://www.quirksmode.org/mobile/" rel="external" title="http://www.quirksmode.org/mobile/">The mobile part</a> is one of the best available at the moment.</li>
  <li><a href="http://positioniseverything.net/" rel="external" title="http://positioniseverything.net/">Position Is Everything</a> is the best resource available about rendering bugs in legacy browsers and their work around (if any).</li>
  <li><a href="http://webplatform.org" title="http://webplatform.org">Webplateform.org</a> is the documentation project supported by W3C and all browser vendors, including Mozilla.</li>
</ul>
<h2 id="Make_things_simple">Make things simple</h2>
<p>Because <a href="/en-US/docs/HTML/Forms" title="/en-US/docs/HTML/Forms">HTML forms</a> involves complex interaction, there is one rule of thumb: <a href="http://en.wikipedia.org/wiki/KISS_principle" rel="external" title="http://en.wikipedia.org/wiki/KISS_principle">keep it as simple as possible</a>. There is so many case were we want forms "nicer" or "with advanced functionality", but building efficient HTML Forms is not a question of design or technology. Just as a reminder, take the time to read this article about <a href="http://www.uxforthemasses.com/forms-usability/" rel="external" title="http://www.uxforthemasses.com/forms-usability/">forms usability on UX For The Masses</a>.</p>
<h3 id="Graceful_degradation_is_web_developer_best_friend.">Graceful degradation is web developer best friend.</h3>
<p><a href="http://www.sitepoint.com/progressive-enhancement-graceful-degradation-choice/" rel="external" title="http://www.sitepoint.com/progressive-enhancement-graceful-degradation-choice/">Graceful degradation and progressive enhancement</a> are development patterns that allow you to build great stuff by supporting a wide range of browsers at the same time. When you build something for a modern browser, and you want to be sure it will work one-way or another on legacy browsers, you are performing graceful degradation.</p>
<p>Let's see some examples related to HTML forms</p>
<h4 id="HTML_input_types">HTML input types</h4>
<p>The new input types brought by HTML5 are very cool because the way they degrade is highly predictable. If a browser does not know the value of the {{htmlattrxref("type","input")}} attribute of an {{HTMLElement("input")}} element, it will fallback as if the value were <code>text</code>.</p>
<pre class="brush: html">
&lt;label for="myColor"&gt;
&nbsp; Pick a color
&nbsp; &lt;input type="color" id="myColor" name="color"&gt;
&lt;/label&gt;</pre>
<table>
  <thead>
    <tr>
      <th scope="col" style="text-align: center;">Chrome 24</th>
      <th scope="col" style="text-align: center;">Firefox 18</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th style="text-align: center;"><img alt="Screen shot of the color input on Chrome for Mac OSX" src="/files/4575/color-fallback-chrome.png" style="width: 139px; height: 35px;" /></th>
      <th style="text-align: center;"><img alt="Screen shot of the color input on Firefox for Mac OSX" src="/files/4577/color-fallback-firefox.png" style="width: 245px; height: 30px;" /></th>
    </tr>
  </tbody>
</table>
<h4 id="CSS_Attribute_Selectors">CSS Attribute Selectors</h4>
<p>The <a href="/en-US/docs/CSS/Attribute_selectors" title="/en-US/docs/CSS/Attribute_selectors">CSS Attribute selectors</a> are very useful with <a href="/en-US/docs/HTML/Forms" title="/en-US/docs/HTML/Forms">HTML Forms</a> but some legacy browsers do not support it. In that case, it's customary to double the type with an equivalent class:</p>
<pre class="brush: html">
&lt;input type="number" class="number"&gt;</pre>
<pre class="brush: css">
input[type=number] {
  /* This can fail in some browsers */
}

input.number {
  /* This will work everywhere */
}</pre>
<p>Note that the following is useless (because it's redundant) and can fail in some browsers:</p>
<pre class="brush: css">
input[type=number],
input.number {
  /* This can fail in some browsers because if they do not understand
     one of the selectors, they will skip the whole rule */
}</pre>
<h4 id="Forms'_button">Forms' button</h4>
<p>There is 2 ways to define buttons within HTML forms:</p>
<ul>
  <li>The {{HTMLElement("input")}} element with its attribute {{htmlattrxref("type","input")}} set to the values <code>button</code>, <code>submit</code>, <code>reset</code> or <code>image</code></li>
  <li>The {{HTMLElement("button")}} element</li>
</ul>
<p>The former can make things a little difficult if you want to apply some CSS by using the element selector:</p>
<pre class="brush: html">
&lt;input type="button" class="button" value="click me"&gt;</pre>
<pre class="brush: css">
input {
  /* This rule will turn off the default rendering for buttons define with an input element */
  border: 1px solid #CCC;
}

input.button {
  /* This will NOT restore the default rendering */
  border: none;
}

input.button {
  /* That neither! Actually there is no standard way to do it in any browsers */
  border: auto;
}</pre>
<p>The latter suffer two possible issues:</p>
<ul>
  <li>A bug in some old version of Internet Explorer. When the user click on it, it's not the content of the {{htmlattrxref("value","button")}} attribute that is send but the HTML content available between the starting and ending tag of the {{HTMLElement("button")}} element. This is an issue only if you want to send such a value, for example if the processing of the data depends on the button the user clicks on.</li>
  <li>Some very old browsers does not use <code>submit</code> as the default value for the {{htmlattrxref("type","button")}} attribute, so it's recommended to always set the attribute {{htmlattrxref("type","button")}} on {{HTMLElement("button")}} elements.</li>
</ul>
<pre class="brush: html">
&lt;!-- To click on this button will send "&lt;em&gt;Do A&lt;/em&gt;" instead of "A" in some cases --&gt;
&lt;button type="submit" name="IWantTo" value="A"&gt;
  &lt;em&gt;Do A&lt;/em&gt;
&lt;/button&gt;</pre>
<p>Choosing one-way or the other is up to you based on your project's constrains.</p>
<h3 id="Let_it_go_with_css.">Let it go with css.</h3>
<p>The biggest issue with HTML Forms and legacy browsers is the support for CSS. As <a href="/en-US/docs/Property_compatibility_table_for_form_widgets" title="/en-US/docs/Property_compatibility_table_for_form_widgets">detailed in this article</a>, it's something very difficult. Even if it's still possible to do a few adjustments on text elements (such as sizing or font color), there are always side effects. The best approach remains to not style HTML Form widgets at all (But you can still apply styles to all the things around). If you are a professional and if your client requires it, in that case, you can investigate some hard technique such as <a href="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets" title="/en-US/docs/HTML/Forms/How_to_build_custom_form_widgets">rebuilding widgets with JavaScript</a>. But in that case, do not hesitate to <a href="http://www.smashingmagazine.com/2011/11/03/“but-the-client-wants-ie-6-support”/" rel="external" title="http://www.smashingmagazine.com/2011/11/03/“but-the-client-wants-ie-6-support”/">charge you client for such a foolishness</a>.</p>
<h2 id="Feature_detection_and_polyfills">Feature detection and polyfills</h2>
<p>If JavaScript is an awesome technology in modern browsers, legacy browsers have many issues with it.</p>
<h3 id="Unobstructive_JavaScript">Unobstructive JavaScript</h3>
<p>One of the biggest problems is the availability of APIs. For that reason, it's considered best practice to work with unobstructive JavaScript. It's a development pattern that defines two requirements:</p>
<ul>
  <li>A strict separation between structure and behaviors.</li>
  <li>If the code breaks, the content and the basic functionalities must remain accessible and usable.</li>
</ul>
<p>Opera folks have very well detailed <a href="http://docs.webplatform.org/wiki/concepts/programming/the_principles_of_unobtrusive_javascript" rel="external" title="http://docs.webplatform.org/wiki/concepts/programming/the_principles_of_unobtrusive_javascript">those principles on webplateform.org</a>.</p>
<h3 id="The_Modernizr_library">The Modernizr library</h3>
<p>However, there are many cases where a good polyfill can help a lot by providing missing API. Actually, using JavaScript to improve JavaScript is the safer way to use polyfills. Using polyfills to improve the CSS or HTML support is risky due to the fact there is many cases where JavaScript can break (Network issues, script conflict, etc.). But with JavaScript, if you work with unobstructive JavaScript in mind, il polyfill are missing, it's no big deal.</p>
<p>The best way to polyfill missing API is by using the <a href="http://modernizr.com" rel="external" title="http://modernizr.com">Modernizr</a> library and its spin off project: <a href="http://yepnopejs.com" rel="external" title="http://yepnopejs.com">YepNope</a>. Modernizr is a library that allows you to test the availability of functionality in order to act accordingly. On its own side, YepNope is a conditional loading library.</p>
<p>Here is an example:</p>
<pre class="brush: js">
Modernizr.load({
  // This will test if your bowser supports the HTML5 form validation API
  test : Modernizr.formvalidation,
 
  // If the browser does not support it, the following polyfill will be loaded
  nope : form-validation-API-polyfill.js,
 
  // In any case, your core App file that depend on that API will be loaded
  both : app.js,
 
  // Once both files are loaded, this function is called in order to initialize the App.
  complete : function () {
    app.init();
  }
});</pre>
<p>The Modernizr team conveniently maintains <a href="https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills" rel="external" title="https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills">a list of great polyfills</a>. Just pick what you need.</p>
<div class="note">
  <p><strong>Note:</strong> Modernizr has other awesome features to help you dealing with unobstructive JavaScript and graceful degradation technics, do not hesitate to <a href="http://modernizr.com/docs/" rel="external" title="http://modernizr.com/docs/">read the documentation</a>.</p>
</div>
<h3 id="Beware_of_performance">Beware of performance</h3>
<p>Even if scripts like Modernizr are very aware of performance, loading a 200Ko polyfill can hit the performance of your application. This is especially critical with legacy browsers; many of them have a very slow JavaScript engine that can make the execution of all your polyfills painful for the user. Performance is a subject on its own, but legacy browser are very sensible to it: basically, there are slow and it's quite often to ask them to process more JavaScript than modern browsers so pay attention to this. Sometimes, loosing a functionalty will lead to a better user experience. As a last reminder, just always think about the end users.</p>
<h2 id="Conclusion">Conclusion</h2>
<p>As you can see, dealing with legacy browsers is not just about forms. It's a whole set of technics that you'll have to master but it's another story. If you read all the article of that <a href="/en-US/docs/HTML/Forms" title="/en-US/docs/HTML/Forms">HTML Forms guide</a>, you should now be at ease to use them, so do not hesitate to improve that guide.<br />
  &nbsp;</p>
Revert to this revision