Fork me on GitHub

26 Mar 2011

CSS box model hacking

Want to make an HTML element fill 100% of its parent’s width but also give it a border and/or some padding? Since the width of an element is exclusive of its border and padding this can be a pain. However there’s a fairly simple CSS solution that works cross-browser.

Here’s an example. Both input boxes are set to width: 100% and have padding: 5px. The first input shows the problem. Because the padding and border are added to the width of the element it overflows its container. The box model of the second input has been modified so that the padding and border are inside the declared width.

The trick to modifying the box model is to set box-sizing: border-box. Unfortunately that’s not a cross-browser property, only Opera supports it at the moment. To get the same effect in other browsers you will also need to set browser-specific versions as well:

   -moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
    -ms-box-sizing: border-box;
        box-sizing: border-box;
Note that Internet Explorer only supports the -ms-box-sizing property from version 8 upwards so you should probably be judicious with this technique or use an alternative method to get a similar effect in IE7 and below.

25 Mar 2011

Styling with HTML5 form validation

HTML5 specifies a number of enhancements to form inputs that are gradually being implemented by newer browsers. Among the enhancements is support for some level of automatic form validation. When inputs have invalid values the browser may refuse to submit the form. Currently Opera, Safari, Chrome and Firefox 4 have some support for this. IE8 does not. I haven’t experimented with IE9 yet.

Let’s look at an example. A simple registration form has inputs for the name, email and website of a prospective user. Of these name and email are required. The input elements are as follows:

<input type="text" name="name" required>
<input type="email" name="email" required>
<input type="url" name="website">

The required attribute is new in HTML5 as are the input types email and url. All of these have implications for validation. Additionally the new input types, whilst they appear just like regular text inputs in desktop browsers are great for mobile users as they are given optimised virtual keyboard layouts.

CSS3 has :invalid, :required and :optional pseudo-classes that are supported by current versions of Firefox, Chrome, Safari and Opera. Some browsers also refuse to submit the form if a required field is not filled in or invalid values are entered in url or email type fields. Obviously without appropriate feedback this could be a pretty disastrous user experience and thankfully even the Webkit browsers which until recently were blocking form submission without feedback are now handling things better.

  • Firefox 4, Opera 11.01 and Chrome 10.0.648.204 all block form submission if there is an empty required field or invalid value and display a message next to the first such field.
  • Safari 5.0.4 will apply :invalid CSS rules but allows the form to be submitted.

Applying styles to invalid fields is pretty easy. For example to highlight invalid fields with a red border and background:

input {
    border: 1px solid #ccc;
}

input:invalid {
    background: #fff3f3;
    border-color: #f66;
}

You can also combine the :invalid pseudo-class in combination with others. For example to highlight focused fields with a fancy CSS3 box-shadow:

input:focus {
    border-color: #99f;
    outline: none;
     -moz-box-shadow: 0 0 0.25em #99f; 
  -webkit-box-shadow: 0 0 0.25em #99f; 
          box-shadow: 0 0 0.25em #99f; 
}

input:focus:invalid {
     -moz-box-shadow: 0 0 0.25em #f66; 
  -webkit-box-shadow: 0 0 0.25em #f66; 
          box-shadow: 0 0 0.25em #f66;
}

It’s worth noting that Firefox 4 automatically adds a red box-shadow to invalid fields (and not just focused ones). To turn it off you can specify:

input:invalid {
    -moz-box-shadow: none;
}

Of course, the browsers that display messages when they refuse to submit a form do so with different text and different visual effects so creating a consistent cross-browser look and feel with both client and server side validation messages is going to be an interesting challenge.

6 Mar 2011

Date and time inputs vs. usability

Form input controls for date/time values have always been problematic. The more I experiment with different options, the more I think there is no one-size-fits-all solution.

Calendar widgets

Calendar widgets such as the jQuery UI date picker or the Opera HTML5 date input are very popular and can be a slick looking addition to a form. I don’t think they’re entirely positive though and certainly don’t work in all situations. They’re great when you don’t know exactly the date you want (I want to book a flight around Easter time) or you need to have an overview of the calendar (I need to set a reminder for GGUG on the third Tuesday of every month). However, when trying to enter your date of birth the widget is just in the way. Even if the widget is keyboard accessible and doesn’t force you to page month-by-month to the correct year you can almost certainly type the date quicker than you can find and select it in a calendar widget.

Multi-field inputs

A multi-field input works well for entering familiar dates such as your date of birth or for transcribing data. They’re not so good when you need the context a calendar widget affords (please don’t force your users to mentally calculate what date the 3rd Tuesday of next month is).

With a multi-field input it’s vital to remember that users in different places will expect to enter dates in a different order. For example, here in the UK we use the completely logical dd mm yyyy order whilst an American will, bizarrely, want to put the month before the day. It’s not particularly difficult to build a tag that renders the fields in a different order according to the request locale. Using the HTML5 placeholder attribute (or a suitable fallback for older browsers) is invaluable to ensure that users know which field is which.

A possible optimisation is to auto-tab between fields after the user has typed the requisite number of digits. In that case you should allow for the user to correct mistakes, so backspacing or using the cursor keys should also automatically jump between fields otherwise the auto-tabbing behaviour becomes more a hinderance than a help for fat-fingered typists like me.

Selects in a multi-field input

It’s very common to use a select input for some or all portions of the date. Personally, I pretty much detest this practice as it combines all the inconvenience of a calendar widget with none of the contextual information. Grails’ <g:datePicker> tag does exactly this. Not only are select elements like this bulking out the page with huge option lists (Grails’ datePicker dumps 8.6Kb of markup in your page without time fields!) but they are cumbersome to input values into with the keyboard because so many values start with the same character. An arguable exception is a select for the month field as presenting textual values rather than numbers is a little friendlier and the option list is short enough and the values distinct enough to allow for reasonably quick keyboard selection.

I suspect the rationale for using select elements is often that it all but ensures the user can’t enter an invalid value (I’ve even seen significant hoop-jumping done in Javascript to ensure values such as 30th February can’t be entered). I think it’s preferable to give the user a clear input and trust them to do the right thing with it rather than forcing them to use an awkward input so that they can’t get it wrong.

Simple textual inputs

You shouldn’t rule out using just a basic text input. In fact for monotonous data entry purposes it is probably optimal. The keystrokes to enter a date become muscle memory and there’s no fiddling about tabbing between day, month and year fields or grabbing the mouse to pick options from a select element. Obviously the down-side is that a plain text input is error-prone and very liable to confuse users unless the expected format is made clear.

HTML5

HTML5 specifies various new date and time input types which seems like good news but has some significant drawbacks at the moment. I can only imagine the new input types are designed to be rendered as native browser widgets (currently only Opera actually does so) as the required format is just about the most inconvenient imaginable for text entry. Sure, as a developer it’s appealing to require that dates have to be entered as yyyy-mm-dd as you no longer have to support varied input formats but no user in the world would naturally type a date that way. Therefore, to make such inputs usable you really need to use Javascript to proxy them with a widget or a set of multi-field inputs. Fine, but what about users who disable Javascript or use mobile or assistive devices that might not cope particularly well with the widgets? The fallback - a text input into which the user must type a machine-readable RFC3339 date - is pretty unfriendly.

What’s worse is that Webkit based browsers such as Chrome and Safari will render the new input types as regular text inputs but refuse to submit a form containing incorrectly formatted values and unbelievably provide no user feedback whatsoever when they do so.

I’m inclined to think that the useful support for the new input types is so minimal and the actively user-hostile handling of them so much more widespread that they’re best avoided altogether.

So, to sum up:

  • Think about who your users are and what they are trying to accomplish with this particular input field and give them the right input for the job at hand.
  • If they need to type some or all of the value make sure it’s clear what format is expected or which field is which.
  • Allow for people to enter values in the order they are comfortable with and above all don’t force them to type it in a machine-readable format.
  • Don’t strand Chrome and Safari users with broken HTML5 input types.