Creating an iOS App with Cordova, Part 2: Prototyping the User Interface

It’s been a while since I wrote the first part of this article – some of the open source software I’d based the original post on has changed significantly.

The largest change is that PhoneGap is now called Cordova. After Nitobi’s acquisition by Adobe, the name of the project was changed, and stewardship handed to the Apache Foundation. Aside from confusing the hell out of people, this doesn’t affect us much, as for our purposes the API has stayed largely the same.

The framework I had been prototyping the UI with – Ratchet – has also changed. Previously it had only supported iOS-style visuals, but with version two, the Ratchet team have rewritten the framework, decoupling the theme component to support Android and other platform specific styles.

Prototyping the UI

Let’s start by opening Terminal, and creating a new folder to keep all our code in:

mkdir book-app
cd book-app

We’re going to use Bower to manage front end dependencies. If you haven’t heard of it before, Bower is a package manager for front end libraries – in the same way that npm is used for Node.js packages. I’m assuming that you already have Bower installed, so let’s create go ahead and a bower.json file:

bower init

Bower will ask you a load of questions to generate the bower.json file:

[?] name: book-app
[?] version: 0.0.1
[?] description: 
[?] main file: 
[?] what types of modules does this package expose? 
[?] keywords: 
[?] authors: Nikki <your@email.com>
[?] license: MIT
[?] homepage: 
[?] set currently installed components as dependencies? No
[?] add commonly ignored files to ignore list? Yes
[?] would you like to mark this package as private which prevents it from being accidentally published to the registry? YesN) y

{
  name: 'book-app',
  version: '0.0.1',
  authors: [
    'Nikki <your@email.com>'
  ],
  license: 'MIT',
  private: true,
  ignore: [
    '**/.*',
    'node_modules',
    'bower_components',
    'test',
    'tests'
  ]
}

[?] Looks good? Yes

Once the config file has been created, install Ratchet and Jasmine, remembering to save them as dependencies.

bower install ratchet jasmine --save
Initial sketches

Next we’ll start creating the view. We’ve already got our sketches from the last tutorial, so with those in mind, lets flesh out the structure by writing the markup. Create a html file for each of the main three views…

touch index.html archive.html options.html

…and open up the Ratchet quick start guide at the page for the basic template.

Open up the index.html file in your text editor (I use love adore Sublime Text 3) and copy the header and footer of the basic template into it.  Change the CSS and JS file references to the correct ones.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Ratchet template page</title>

    <!-- Sets initial viewport load and disables zooming  -->
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">

    <!-- Makes your prototype chrome-less once bookmarked to your phone's home screen -->
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">

    <!-- Include the compiled Ratchet CSS -->
    <link rel="stylesheet" href="bower_components/ratchet/dist/css/ratchet.min.css">

    <!-- Include the compiled Ratchet JS -->
    <script src="bower_components/ratchet/dist/js/ratchet.min.js"></script>
  </head>
  <body>

...

  </body>
</html>

We also need to link to a theme, so paste the reference to the iOS theme just below the main styles:

<link rel="stylesheet" href="bower_components/ratchet/dist/css/ratchet-theme-ios.min.css">

Open up Ratchet’s components documentation.  In our UI sketches we designed an application bar at the top, and a navigation bar at the bottom, with a button for each of the main views.  Let’s create the top bar, with a button to the right for adding new books.

<header class="bar bar-nav">
  <a class="icon icon-plus pull-right" href="#"></a>
  <h1 class="title">ReadLog Stack</h1>
</header>

The Ratchet docs say that all bars must be added before the content, so let’s create that bottom bar next:

<nav class="bar bar-tab">
  <ul class="tab-inner">
    <li class="tab-item active">
      <a href="index.html">
        <span class="icon icon-bars"></span>
        <span class="tab-label">Stack</span>
      </a>
    </li>
    <li class="tab-item">
      <a href="archive.html">
        <span class="icon icon-pages"></span>
        <span class="tab-label">Archive</span>
      </a>
    </li>
    <li class="tab-item">
      <a href="options.html">
        <span class="icon icon-gear"></span>
        <span class="tab-label">Options</span>
      </a>
    </li>
  </ul>
</nav>

And finally, we’ll create the content container:

<div class="content">
  <ul>
    <li>Books</li>
    <li>Books</li>
    <li>Books</li>
  </ul>
</div>

Copy index.html and paste the markup into archive.html and options.html.  If you open this up in Chrome and enable mobile device emulation, you should see something that looks like this:

readlog-p2

I’m going to stop here for now. In part three, I’ll be writing failing tests in Jasmine, which we’ll use to discover more of our application’s functionality. We can then develop the UI accordingly.

You can find the code for this tutorial on Github: https://github.com/nikki/ReadLog-App-Tutorial

Be sure to check back in roughly a year’s time! By then – if you’re lucky – I might have finished part three 😉

Creating an iOS Application with PhoneGap, Part 1: User Experience

Hello, and welcome!  I’m going to show you how to create an iOS application – from start to finish – with HTML, CSS, JavaScript and PhoneGap.

In this first part, I’ll be planning the project. I’m going to start by discussing the importance of User Experience (UX) design, deciding upon features, and finishing off with some sketches. In part two, I’ll get down to prototyping the UI. In part three I’ll write failing tests with Jasmine. In part four, I’ll develop the application; and finally, in part five I’ll finish the app by wrapping it with PhoneGap, and deploying it to an iPhone with Xcode.

We’re going to create a really simple book cataloguing application, inspired by my personal experience with ReadMore (iOS).

ss1
ReadMore App by Navel Labs

ReadMore is an app I’ve used since 2010. It keeps track of the books you’re currently reading, books you’ve read, etc.; but it also logs how long it takes you to read each book. It’s a great little app, but the one big downside for me is that the time tracking functionality is tightly coupled with the archiving functionality. Time tracking is a feature I’m not interested in, but the app requires me to enter (fake) time data in order to save a book to the archive. I just want to be able to see, at a glance, the books I’m currently reading, and books I’ve read.

If I was being sensible, I’d simply browse the App Store for a suitable alternative; but that wouldn’t make a very interesting blog post.

Instead, I’m going to roll my own, and show you how I did it. Before I get started though, I’d like to take a moment to talk about user experience design.

User Experience Design

User experience is, at it’s core, concerned with one thing: how do users feel about your product? Is it intuitive? Cohesive? A delight to use? Or is using your product the pain point of a person’s day?

User experience designers, therefore, are engaged in the process of creating a positive user experience. This is accomplished by researching user needs, designing a solution to meet those needs, and validating the proffered solution with user testing.

Before user-centred design became the standard approach to designing software, designers approached projects with only a superficial understanding of it’s intended users. The design was based on what the designers thought the client wanted, as opposed to what they actually needed. The result was often disappointing.

tree_swing_development_requirements
Image credit: Paragon Innovations, Inc.

If your app is clunky and frustrating to use, you can be sure that users won’t stick with it for long. Creating a product that no one wants to use is a futile gesture, and a sure-fire way to bankrupt yourself in the process. This is why UX is so important! Customer loyalty? Employee productivity? User satisfaction? All are affected by UX, and all directly affect your bottom line.

Okay, you’re convinced. UXD is great. So where do you start? User Surveys? Personas? Wireframes? Usability Testing? Unfortunately, there is no right answer, no magical combination of UXD techniques that, applied to a project, will always guarantee a perfect outcome. But you can be assured that any effort you make to learn more about your users can only yield positive results. Less uncertainty means less time spent in fruitless debate, a smoother build process, and a better end product.

ux-diagram
Image credit: studio aum

Now that I’ve highlighted just how important UX is, I’m going to dive straight in at the deep end with some user stories. As a developer, I find that this is the best way to nail down a feature set, because each story represents a feature, and each feature is an actionable, measurable, and (most importantly) testable step to getting a product shipped.

Planning Features using User Stories

user story asteroids
Image credit: Andrew Fuqua

The template for a user story is as follows: As a user role I want feature so I can benefit. Using this template, we can describe all of the features we want the app to have. Let’s create the first user story for our book catalogue.

As a user, I want to be able to create a book record and save it to a list so that I can see which books I’m currently reading.

This one is pretty straightforward. In fact, this story represents the functionality of the app at it’s most basic level. It’s safe to say that similar stories will exist for the rest of the CRUD (create, read, update, delete) paradigm, so lets skip over them for now. (As we’re creating a single-role application, I’m going to forgo writing ‘as a user…’ for the remaining stories.)

… I want to be able to pre-populate a book record by searching for the book online, so that I don’t have enter a record manually.

Straightforward at first glance, but how should you be able to search specifically?

… I should be able to search by title, author, or barcode, to make it easy to enter a book record.

So, this feature confers a time-saving benefit. Imagine, though, that this were a commercial project. What if the project planner just assumed that the user should be able to search by title and nothing else? It’s not a great example, but you see the point I’m trying to make – loose ends can be a disaster for your project, so it’s best to keep asking questions until there are no more questions to ask.

I’ll probably use the Amazon or Google Books API here, and there’s an open source PhoneGap plugin I can use to read barcodes with a phone’s camera, so I have this part covered.

… I want to be able to view books by category, so I can see the different genres of books I’m reading.

This is a utility benefit. I read technical books for work, and sci-fi books for fun. It would be useful for me to be able to differentiate between the two at a glance.

… I want to be able to archive books that I’ve read, so that I only see books that I’m currently reading.

If we don’t separate ‘current’ books from ‘completed’ books, we’re going to end up with one long, not very useful list. Perhaps we could create a separate view for archived books?

… I want to be able to export data from the app, so that I can import it into other applications.

A user’s data belongs to the user, not to your app. They should be able to use it elsewhere (Goodreads, for example) if they choose to. I’ll export the book list to CSV and JSON, saving each as a document with the help of PhoneGap’s FileWriter API.

Also, backups are always useful. I lost a portion of my ReadMore reading list when I upgraded to iOS 7 beta, and I was incredibly annoyed about it. So, I’ll enable Document File Sharing in iTunes – any files exported will be accessible in here (it’s just a simple case of drag and drop to the desktop), and they’ll also automatically be saved with everything else when the user initiates a device backup.

These user stories describe the entire feature set of our application. In part two I’ll show you how to translate these stories into actionable steps with Behaviour Driven Design (BDD), but right now I’d like to talk about the UX challenges creating a hybrid app presents.

Hybrid App UX

User needs are one rung on the ladder of user experience. Your choice of tech stack can present it’s own problems.

Using a hybrid app can sometimes feel like you’ve taken a trip to the Uncanny Valley. The app may be work perfectly, but it doesn’t feel the way you expect it to. This is the unavoidable consequence of using a WebView; instead of having native controls and components to work with, you have to create everything from scratch with HTML, CSS and JavaScript. Users, accustomed to a platform’s behaviour, expect your app to follow the same conventions. Often this expectation goes unmet, and users can become frustrated with your app as a result.

For example, a button, if bound with a standard click handler rather than a touch handler, can take 300ms to trigger it’s associated event when tapped. 300ms of latency will not go unnoticed.

So, why bother with hybrid apps at all, why not just go native? Developing a hybrid app is still the fastest, most cost-effective way to get an app built and deployed across multiple platforms. The issues cited above only tend to arise when a developer takes a one-size-fits-all approach to building the app. Hybrid apps are not a panacea; if you plonk the same codebase down on iOS and Android without any modification, you’re going to have a bad time. Care must be taken to meet the expectations of users on each platform you intend to deploy to.

UX Sketching

On to sketching. I’m terrible at drawing, but sketching is always a useful exercise. The real value of sketching lies in how quickly you can spot obvious problems – a textual description of a feature can mask problems that will leap out at you when you put pencil to paper.

IMG_0078-1
Initial UX sketches

My all time favourite post on UX sketching is by Peiter Buick over on Smashing Magazine.  In his article, The Messy Art of UX Sketching, Peiter delves into the power of UX sketching, and discusses the tools and techniques behind it.  He explains it much better than I could, so it’s well worth a read.

Next Time…

In the next tutorial, I’ll be prototyping the user interface, and writing failing tests with Jasmine. Stay tuned!

Further Reading

Coding Horror – Avoiding the Uncanny Valley of User Interface
Smashing Magazine – Effectively Planning UX Projects

portfolio-redesign

Portfolio Redesign

The redesign of my portfolio has finally gone live, I hope you like it! I wanted something a bit cleaner looking than the old site – I fiddled around for ages in Photoshop, but I’m a really harsh judge of my own work (I never feel like it’s good enough!) so I opted for a customised version of Classica instead.  Otherwise I’d never be finished!

There’s an easter egg on the homepage – it’s pretty good, so it’s almost a shame it’s hidden.  I think I might put it on it’s own page next week. (I should mention, it uses the HTML5 Canvas API, so it’s been disabled for anything that doesn’t support Canvas.  Get a better browser!)

In other news: I went to not one, but two of Remy (& Julieanne!) Sharp’s workshop’s recently – they were both part of the LeftLogic Big Workshop Tour.  The first was the HTML5 APIs one in Manchester, the second was the Node.JS last week in London.  They were both pretty awesome, and I met some really cool people, but I’m not going to write about them right now, because I couldn’t do them justice in this short blog post.  A workshop review is definitely on my to-do list.

Work on my jQuery liteAccordion plugin has slowed since it’s last release, but I have a lot of big plans for it when I finally get some free time (damn clients, paying my bills *grumble*)

Anyways, happy bank holiday!  If you have any feedback regarding the redesign (or the little surprise on the homepage) please let me know in the comments below.

Tschüss!

detection2

HTML5 Forms Support Detection with JavaScript

In this tutorial, we’ll continue developing our HTML5 form.  In the last tutorial, we styled the form with some of the new CSS3 properties; this time we’re going to detect support for the new HTML5 input types.

We need to detect whether the browser supports the new HTML5 input types natively – if not, we can use this knowledge to fall back to JavaScript where appropriate.  It is important to note that there currently isn’t a lot of browser support for these input types: Opera 10.6 has the most complete support, Safari 5 and Chrome 5 have partial support, Firefox 3.6.8 and IE8 (as usual) are dead in the water.  If you’re dabbling with HTML5 at all, you’ll know that support is patchy at best, and you should treat tutorials like this one as instructional rather than definitive.  So whilst this information is current now, the specification is still undergoing revision (and will be for a while yet!).

Support Detection

If a browser doesn’t support a particular attribute value, it will degrade to the default value text.  In theory, this is how we test for browser support – we create a new input element in JavaScript (in memory only, don’t append it to the DOM), assign to it the attribute value we want to detect support for, and then query the element’s type attribute.  If the attribute retains the value that you assigned to it, the browser supports it.  Otherwise, if it returns the default value, the browser doesn’t support it. Using this method, we can loop through all the new input types and log the results to console to see what we get back:

var inputs = ['search', 'tel', 'url', 'email', 'datetime', 'date', 'month', 'week', 'time', 'datetime-local', 'number', 'color', 'range'],
    len = inputs.length;

for (var i = 0; i < len; i++) {
    var input = document.createElement('input');
    input.setAttribute('type', inputs[i]);
    console.log(inputs[i] + ' -> ' + input.type);
}

Notice that I began the above statement with the qualifier “in theory.”  Whilst this method should technically work, some browsers are prone to giving false positives, i.e. asserting that they support a particular input type, when in reality, they don’t.  Take a look at the output produced for the basic test above:

Only Firefox, IE8 and Opera are telling the truth! If you visually check in Safari and Chrome whether the UI improvements or validation functionality is present (using Mike Taylor’s HTML5 Input form, for example), it’s pretty evident that Safari and Chrome are not being entirely honest with us.  So how do we test for support if two of the major browsers are telling porkies?  Well, you have to go a step further and test for both UI improvements and validation functionality manually.

However, support for data validation is currently pretty flakey – that’s interpreting it generously.  It appears that some browsers validate the data properly, whilst others don’t check the data but pass it as valid anyway (see this discussion for details).  This probably won’t be resolved for a long time, so we’re going to validate data with JavaScript – experiments are one thing, but the state of implementation is so fragmented at this point that it’s not actually of any use to us.  So in the next part of this tutorial, validation will be handled by JavaScript exclusively.  What about the UI improvements?  If the UI improvements are supported, we’ll use those, otherwise we’ll provide the functionality ourselves.  Sounds like a plan!

We need to test for these UI improvements to see if they’re present in the browser.  UI improvements can be best described as things that we’d usually have to implement a widget for in Calendar in OperaJavaScript –  like a date picker or calendar – except now they’re implemented by the browser. We test for them by passing a text value to our mock-input, and then checking what gets returned – any new UI functionality shouldn’t be able to hold a text value.  If a string is returned, there’s no UI improvement; if anything else is returned (e.g. a numerical value in the case of range, or an empty value in most other cases) then a UI improvement is present.  One caveat: there are no detectable improvements or validation where the telephone and search inputs are concerned as yet, so we have to eliminate these from the first part of the test.

var inputs = ['search', 'tel', 'url', 'email', 'datetime', 'date', 'month', 'week', 'time', 'datetime-local', 'number', 'color', 'range'],
len = inputs.length,
uiSupport = [];

for (var i = 0; i < len; i++) {
    var input = document.createElement('input');
    input.setAttribute('type', inputs[i]);
    var notText = input.type !== 'text';

    if (notText && input.type !== 'search' && input.type !== 'tel') {
        input.value = 'testing';
        if (input.value !== 'testing') {
            console.log(input.type);
        }
    }
}

In the FF and IE consoles, we don’t get any data returned, as expected.  Safari and Chrome return a non-string value for range only.  Opera returns a non-string value for datetime, date, month, week, time, datetime-local, number and range.  The last thing we have to do is store this information in an array so that we can refer to it later, then wrap the whole code block in a function so that the variables have some semblance of a namespace.

(function() {
    var inputs = ['search', 'tel', 'url', 'email', 'datetime', 'date', 'month', 'week', 'time', 'datetime-local', 'number', 'color', 'range'],
    len = inputs.length,
    uiSupport = [];

    for (var i = 0; i < len; i++) {
        var input = document.createElement('input');
        input.setAttribute('type', inputs[i]);
        var notText = input.type !== 'text';

        if (notText && input.type !== 'search' && input.type !== 'tel') {
            input.value = 'testing';
            if (input.value !== 'testing') {
                uiSupport.push(input.type);
                // console.log(uiSupport);
            }
        }
    }
})();

uiSupport will store the names of the input type attributes that are supported, so we can use them when we come to create our fallbacks in the next tutorial.

Quick Tip: If you need to detect support for some of the other input attributes – autofocus, for example, or any of the other new HTML5 elements, it’s definately worth checking out Modernizr.  Modernizr has the added benefit of having IE support baked in, so there’s no need to include an additional HTML5 shim to get the new (header, section, etc.) tags working.

form-styling-css3

Form Styling with CSS3

Today we’re going to continue developing our HTML5 contact form, using CSS.

Extract the inline CSS from the head of the form and paste it into a new document.  Name this new stylesheet style.css and make a reference to it in the head of the form HTML.  At the top of style.css, I’ve imported Eric Meyer’s stylesheet reset (named “reset.css”) and removed the star (*) selector that temporarily reset the margin and padding.  (NB: never use the start selector in production!)  Your stylesheet should now look like this:

@charset "utf-8";
@import "reset.css";

form { width: 460px; padding: 20px; color: #333333; font-family: Verdana, Geneva, sans-serif; font-size: 12px; margin: 0 auto }
fieldset { border: 0; padding: 10px; margin-bottom: 10px; background: #F6F6F6 }
legend { padding: 5px 10px }
label, span { float: left; clear: left; display: block; width: 180px; padding-right: 20px; text-align: right }
input, textarea, select { float: left; width: 200px }
.submit { width: 100px; float: right; margin-right: 33px }
select { width: 206px }
p { overflow: hidden; margin-bottom: 10px }
.contact-method label { clear: none; width: auto }
.contact-method input { float: none; width: 20px }

We’re just going to make a quick couple of changes before we start.

Firstly, add ‘height: 26px; line-height: 26px’ to the ‘label, span’ selector to vertically centre the text within the input labels.

Secondly, there’s a bit of a bug in IE concerning legends and fieldsets – IE bleeds the background colour of the fieldset behind the legend.  To recify this, we’re going to add a little bit more margin to the bottom of the fieldset, and position the legend absolutely within it.

Unfortunately, positioning the legends absolutely within a fieldset that has padding triggers a bug in Firefox.  This bug causes Firefox to calculate the legend’s position incorrectly, so to fix this, we’re going to remove the padding from the top of the fieldset, and add that padding to the first paragraph in the fieldset instead.  Add “padding-top: 0” to the fieldset attribute, and “p:first-of-type { padding-top: 25px }” underneath the fieldset style.  I rarely see :first-of-type used out in the wild, as :first-child can often be used in a similar context.  However, :first-of-type selects the element that is the first sibling of that type within it’s parent, rather than just selecting the first child.  Very useful!

Now that we’ve fixed that, we’ve broken IE again by removing the padding. Add the hack “padding-top: 25px9” to the fieldset selector and we should be good to go.

With these changes, your css should look like this:

form { width: 460px; padding: 20px; color: #333333; font-family: Verdana, Geneva, sans-serif; font-size: 12px; margin: 0 auto }
fieldset { position: relative; padding: 10px; padding-top: 0; padding-top: 25px9; margin-bottom: 30px; background: #F6F6F6 }
legend { padding: 6px 12px; position: absolute; left: 10px; top: -11px }
label, span { float: left; clear: left; display: block; width: 180px; padding-right: 20px; text-align: right; height: 26px; line-height: 26px }
input, textarea, select { float: left; width: 200px }
.submit { width: 100px; float: right; margin-right: 33px }
select { width: 206px }
p { overflow: hidden; margin-bottom: 10px }
p:first-of-type { padding-top: 25px }
.contact-method label { clear: none; width: auto }
.contact-method input { float: none; width: 20px }

Now that we have a base template for our form, we can start adding styles.

Border Radius

We’re going to add a rounded corner to the fieldsets, legends and submit button, add background and text colours to the legends, and change the style of the submit button. At the moment, we still have to use vendor prefixes for border-radius, so this style declaration usually consists of three lines:

#style {
    -webkit-border-radius: <value>;
    -moz-border-radius: <value>;
    border-radius: <value>;
}

Edit your css using the styles highlighted below.

form { width: 460px; padding: 20px; color: #333333; font-family: Verdana, Geneva, sans-serif; font-size: 12px; margin: 0 auto }
fieldset { position: relative; padding: 10px; padding-top: 0; padding-top: 25px9; margin-bottom: 30px; background: #F6F6F6; -webkit-border-radius: 8px; -moz-border-radius: 8px; border-radius: 8px }
legend { padding: 5px 10px; background-color: #4F709F; color: white; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px }
label, span { float: left; clear: left; display: block; width: 180px; padding-right: 20px; text-align: right; height: 26px; line-height: 26px }
input, textarea, select { float: left; width: 200px }
.submit { width: 100px; float: right; margin-right: 38px; border: 0; padding: 5px 10px; background: #4F709F; color: white; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px }
select { width: 202px }
p { overflow: hidden; margin-bottom: 10px }
p:first-of-type { padding-top: 25px }
.contact-method label { clear: none; width: auto }
.contact-method input { float: none; width: 20px }

The last fieldset on the form should look like this:

I think it’s easy to go overboard with border-radius, so we’ll leave that bit there for now.  Next up, background gradients.

Background Gradients

We have to use vendor prefixes to enable this to work in Firefox and Webkit.  Unlike border radius, each vendor uses a different syntax for their style declaration, so it can be a little confusing.  There are more properties associated with setting a background gradient style, but I’ve listed the most common ones below.

Firefox has linear gradient and radial gradient values…

#style {
    background-image: -moz-linear-gradient( [<point> || <angle>,]? <stop>, <stop> [, <stop>]* );
    background-image: -moz-radial-gradient( [<position> || <angle>,]? [<shape> || <size>,]? <stop>, <stop>[, <stop>]* )
}

…whereas Webkit allows you to specify whether the gradient is a linear or radial one within “-webkit-gradient”:

#style {
    background-image: -webkit-gradient(<type>, <point> [, <radius>]?, <point> [, <radius>]? [, <stop>]*)
}

Note that you can also specify these gradients within the “background” shorthand property.

For our form, we’ll be using a grey border on the input boxes, and a slight gradient on the fieldsets.

form { width: 460px; padding: 20px; color: #333333; font-family: Verdana, Geneva, sans-serif; font-size: 12px; margin: 0 auto }
fieldset { position: relative; padding: 10px; padding-top: 0; padding-top: 25px9; margin-bottom: 30px; background: #F6F6F6; -webkit-border-radius: 8px; -moz-border-radius: 8px; border-radius: 8px; background: -webkit-gradient(linear, left top, left bottom, from(#EEEEEE), to(#FFFFFF)); background: -moz-linear-gradient(center top, #EFEFEF, #FFFFFF 100%) }
legend { padding: 6px 12px; position: absolute; left: 10px; top: -36px; background-color: #4F709F; color: white; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px }
label, span { float: left; clear: left; display: block; width: 180px; padding-right: 20px; text-align: right; height: 26px; line-height: 26px }
input, textarea, select { float: left; width: 200px; border: 1px solid #d9d9d9 }
.submit { width: 100px; float: right; margin-right: 37px; border: 0; padding: 5px 10px; background: #4F709F; color: white; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px }
textarea { background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), color-stop(1%, #EEEEEE), to(#FFFFFF)) }
select { width: 202px }
p { overflow: hidden; margin-bottom: 10px }
p:first-of-type { padding-top: 25px }
.contact-method label { clear: none; width: auto }
.contact-method input { float: none; width: 20px }

After these styles have been added, you should see something that looks like the image below.

Next we’re going to add a drop shadow to make the bottom corners of the fieldsets a little more prominent.

Box Shadow

Box shadow is similar to border-radius syntax-wise, you need to specify two vendor prefix properties and the official property as defined in the CSS3 spec.  Border-radius takes 3 lengths: the horizontal offset, the vertical offset, and the blur radius; and a colour.

#style {
    -webkit-box-shadow: <horz>, <vert>, <blur>, <color>;
    -moz-box-shadow: <horz>, <vert>, <blur>, <color>;
    box-shadow: <horz>, <vert>, <blur>, <color>;
}

We’re going to add a box shadow to the fieldsets, the legends, and the submit button, using the values highlighted below.  Notice that we’re also adding 4px margin to prevent the overflow: auto property on the parent paragraph tag from clipping the shadow on the bottom of the submit button.

form { width: 460px; padding: 20px; color: #333333; font-family: Verdana, Geneva, sans-serif; font-size: 12px; margin: 0 auto }
fieldset { position: relative; padding: 10px; padding-top: 0; padding-top: 25px9; margin-bottom: 30px; background: #F6F6F6; -webkit-border-radius: 8px; -moz-border-radius: 8px; border-radius: 8px; background: -webkit-gradient(linear, left top, left bottom, from(#EFEFEF), to(#FFFFFF)); background: -moz-linear-gradient(center top, #EFEFEF, #FFFFFF 100%); box-shadow: 3px 3px 10px #ccc; -moz-box-shadow: 3px 3px 10px #ccc; -webkit-box-shadow: 3px 3px 10px #ccc }
legend { padding: 6px 12px; position: absolute; left: 10px; top: -11px; background-color: #4F709F; color: white; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; box-shadow: 2px 2px 4px #888; -moz-box-shadow: 2px 2px 4px #888; -webkit-box-shadow: 2px 2px 4px #888 }
label, span { float: left; clear: left; display: block; width: 180px; padding-right: 20px; text-align: right; height: 26px; line-height: 26px }
input, textarea, select { float: left; width: 200px; border: 1px solid #d9d9d9 }
.submit { width: 100px; float: right; margin-right: 37px; border: 0; padding: 5px 10px; background: #4F709F; color: white; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; box-shadow: 2px 2px 4px #888; -moz-box-shadow: 2px 2px 4px #888; -webkit-box-shadow: 2px 2px 4px #888; margin-bottom: 4px }
textarea { background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), color-stop(1%, #EEEEEE), to(#FFFFFF)) }
select { width: 202px }
p { overflow: hidden; margin-bottom: 10px }
p:first-of-type { padding-top: 25px }
.contact-method label { clear: none; width: auto }
.contact-method input { float: none; width: 20px }

Very Useful Tip: You can also use rgba values with box shadow, achieving an effect similar to the one I described in my CSS3 Alpha Transparent Gradients post.

Text Shadow

Next we’ll add a bit of text shadow on the legends and submit button to make them stand out a little more.  The text shadow property is pretty much the same as box shadow.  It takes 3 values and a colour, that is, the x value of the shadow, the y value of the shadow, the blur radius, and a colour.  However, this time we don’t have to use vendor prefixes, as native property is supported in all current browsers.

#style {
    text-shadow: <horz>, <vert>, <blur>, <color>;
}

Add the highlighted lines below to your css.

form { width: 460px; padding: 20px; color: #333333; font-family: Verdana, Geneva, sans-serif; font-size: 12px; margin: 0 auto }
fieldset { position: relative; padding: 10px; padding-top: 0; padding-top: 25px9; margin-bottom: 30px; background: #F6F6F6; -webkit-border-radius: 8px; -moz-border-radius: 8px; border-radius: 8px; background: -webkit-gradient(linear, left top, left bottom, from(#EFEFEF), to(#FFFFFF)); background: -moz-linear-gradient(center top, #EFEFEF, #FFFFFF 100%); box-shadow: 3px 3px 10px #ccc; -moz-box-shadow: 3px 3px 10px #ccc; -webkit-box-shadow: 3px 3px 10px #ccc }
legend { padding: 6px 12px; position: absolute; left: 10px; top: -11px; background-color: #4F709F; color: white; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; box-shadow: 2px 2px 4px #888; -moz-box-shadow: 2px 2px 4px #888; -webkit-box-shadow: 2px 2px 4px #888; text-shadow: 1px 1px 1px #333 }
label, span { float: left; clear: left; display: block; width: 180px; padding-right: 20px; text-align: right; height: 26px; line-height: 26px }
input, textarea, select { float: left; width: 200px; border: 1px solid #d9d9d9 }
.submit { width: 100px; float: right; margin-right: 37px; border: 0; padding: 5px 10px; background: #4F709F; color: white; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; box-shadow: 2px 2px 4px #888; -moz-box-shadow: 2px 2px 4px #888; -webkit-box-shadow: 2px 2px 4px #888; margin-bottom: 4px; text-shadow: 1px 1px 1px #333 }
textarea { background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), color-stop(1%, #EEEEEE), to(#FFFFFF)) }
input:focus, textarea:focus, select:focus { background: white; border-color: #666 }
select { width: 202px }
p { overflow: hidden; margin-bottom: 10px }
p:first-of-type { padding-top: 25px }
.contact-method label { clear: none; width: auto }
.contact-method input { float: none; width: 20px }

Focus Highlighting

We’re going to add one last style, to make the input boxes more prominent when they’re in focus…

nput:focus, textarea:focus, select:focus { border-color: #666 }

…and one last tweak, to make the input boxes a little bigger.

input, textarea, select { padding: 3px; float: left; width: 200px; border: 1px solid #d9d9d9 }
select { width: 208px }

The final CSS should look like this:

form { width: 460px; padding: 20px; color: #333333; font-family: Verdana, Geneva, sans-serif; font-size: 12px; margin: 0 auto }
fieldset { position: relative; padding: 10px; padding-top: 0; margin-bottom: 30px; background: #F6F6F6; -webkit-border-radius: 8px; -moz-border-radius: 8px; border-radius: 8px; background: -webkit-gradient(linear, left top, left bottom, from(#EFEFEF), to(#FFFFFF)); background: -moz-linear-gradient(center top, #EFEFEF, #FFFFFF 100%); box-shadow: 3px 3px 10px #ccc; -moz-box-shadow: 3px 3px 10px #ccc; -webkit-box-shadow: 3px 3px 10px #ccc }
legend { padding: 6px 12px; position: absolute; left: 10px; top: -11px; background-color: #4F709F; color: white; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; box-shadow: 2px 2px 4px #888; -moz-box-shadow: 2px 2px 4px #888; -webkit-box-shadow: 2px 2px 4px #888; text-shadow: 1px 1px 1px #333 }
label, span { float: left; clear: left; display: block; width: 180px; padding-right: 20px; text-align: right; height: 26px; line-height: 26px }
input, textarea, select { padding: 3px; float: left; width: 200px; border: 1px solid #d9d9d9 }
.submit { width: 100px; float: right; margin-right: 37px; border: 0; padding: 5px 10px; background: #4F709F; color: white; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; box-shadow: 2px 2px 4px #888; -moz-box-shadow: 2px 2px 4px #888; -webkit-box-shadow: 2px 2px 4px #888; margin-bottom: 4px; text-shadow: 1px 1px 1px #333 }
textarea { background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), color-stop(1%, #EEEEEE), to(#FFFFFF)) }
input:focus, textarea:focus, select:focus { background: white; border-color: #666 }
select { width: 208px }
p { overflow: hidden; margin-bottom: 10px }
p:first-of-type { padding-top: 25px }
.contact-method label { clear: none; width: auto }
.contact-method input { float: none; width: 20px }

View Demo

In the next tutorial, I’ll show you how to test for browser support of the new input types.

html5-form-tutorial

HTML5 Form Tutorial

In part one of this four five part tutorial, we’re going to create a contact form using the new HTML5 input attributes.  It must be stated outright that as browser support is still lacking for these attributes, this tutorial is for illustrative purposes only – I wouldn’t recommend using the new input types in a production environment yet.  That being said, it’s interesting to know what’s in store for us just around the corner.  Let’s get started.

HTML Template

This is the base template we’re going to use for the form.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8" />
  <title>Contact Form</title>
</head>
<body>
</body>
</html>

As you can see, we’re using the HTML5 doctype.  Notice that the meta tag defining the character set is shorter than in previous versions of the language:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

In HTML5, the http-equiv and content attributes are superfluous, so we can strip those out.  The same goes for the type attribute in the style and script tags – we no longer need to define the type as text/javascript or text/css, as it’s implied by the tag name.

Input Types

Horse and PloughThe input element, as specified in HTML4, has ten values for it’s type attribute: button, checkbox, file, hidden, image, password, radio, reset, submit, and text.  The text input in particular has become the work-horse of HTML forms, used to capture a wide range of alphanumeric data.  This will change with the adoption of the new HTML5 input types.  In the same way that div is set to be superceded by header, nav, article, section, aside, and footer, the text attribute will be displaced by more semantic type attributes (search, tel, url, email, datetime, date, month, week, time, datetime-local, number, color and range) that accurately describe the data to be entered into them.

Contact Form

The form we’re going to create will not be a run-of-the-mill contact form, it will be aimed at satisfying the needs of a freelancer.  It’s purpose will be to collect enquiries from clients regarding potential projects – this enables us to examine how these new input types might work in a real-world setting.

The data our form will capture is as follows (the input type we will use is in brackets):

  • Name (text)
  • Company (text)
  • Email (email)
  • Telephone (tel)
  • Website (url)
  • Type of Project (select)
  • Projected Completion Date (date)
  • Estimated Budget (number)
  • Additional Details (textarea)
  • Please contact me by Email | Phone (radio)
  • Best time to contact? (time, disabled unless ‘contact by phone’ selected)

We’re going to seperate these properties into 3 fieldsets to make the form a little easier on the eye, and create the label and inputs for them.  The markup will look like this:

<form>
  <fieldset>
    <p><label>Name</label><input type="text" /></p>
    <p><label>Company</label><input type="text" /></p>
    <p><label>Email</label><input type="email" /></p>
    <p><label>Telephone</label><input type="tel" /></p>
    <p><label>Website</label><input type="url" /></p>
  </fieldset>
  <fieldset>
    <p><label>Type of Project</label></p>
    <p>
      <select>
        <option>HTML/CSS Build</option>
        <option>Custom jQuery Plugin</option>
        <option>Wordpress Template</option>
        <option>Other</option>
      </select>
    </p>
    <p><label>Projected Completion Date</label><input type="date" /></p>
    <p><label>Estimated Budget (&pound;)</label><input type="number" /></p>
    <p><label>Additional Details</label><textarea rows="5"></textarea></p>
  </fieldset>
  <fieldset>
    <p class="contact-method">
      <span>Please contact me by&hellip;</span>
      <label><input type="radio" value="Phone" checked="checked" /> Phone</label>
      <label><input type="radio" value="Email" /> Email</label>
    </p>
    <p><label>Best time to contact?</label><input type="time" /></p>
    <p><input class="submit" type="submit" name="submit" /></p>
  </fieldset>
</form>

Notice that we’ve added a class to the submit button and to the paragraph containing the contact method.  In an ideal world we’d be able to use a pseudo class like nth-child to style these elements, but it isn’t supported in IE6&7, so we’ll stick with normal classes for now.  We’re going to add a bit of basic CSS, just to make the form look a little nicer for the time being.

* { margin: 0; padding: 0 }
form { width: 460px; padding: 20px; color: #333333; font-family: Verdana, Geneva, sans-serif; font-size: 12px; margin: 0 auto }
fieldset { border: 0; padding: 10px; margin-bottom: 10px; background: #F6F6F6 }
legend { padding: 5px 10px }
label, span { float: left; clear: left; display: block; width: 180px; padding-right: 20px; text-align: right }
input, textarea, select { float: left; width: 200px }
.submit { width: 100px; float: right; margin-right: 37px }
select { width: 202px }
p { overflow: hidden; margin-bottom: 10px }
.contact-method label { clear: none; width: auto }
.contact-method input { float: none; width: 20px }

We’ll revisit the CSS in the next part of this tutorial.

Form Accessibility

In it’s present state, the form isn’t very accessible to people using screen readers, so we’re going to make some improvements by adding a legend to the fieldset, adding input names IDs (correction 01/05/11: names for php enabled forms, IDs for accessible form controls.  With thanks to Nick :)), and associating the input with it’s counterpart label using the ‘for’ attribute.  A brief note – there is some debate between accessibility experts on whether it’s better to wrap the input with it’s label, rather than creating sibling elements.  I think it’s a matter of personal preference – using the ‘for’ attribute creates an explicit association between the two elements.

As this form is contained within a basic page, it’s not necessary to define tab indices; the flow of the page is pretty basic and should tab in the correct order.  However, if you’re working with more complex markup, other elements on the page may interfere with the flow of the document – in this situation it’s best practice to define tab indices to assist with navigation of the page.

Once the modifications are complete, the markup will look like this:

<form>
  <fieldset>
    <legend>Contact Details</legend>
    <p><label for="name">Name</label><input id="name" type="text" /></p>
    <p><label for="company">Company</label><input id="company" type="text" /></p>
    <p><label for="email">Email</label><input id="email" type="email" /></p>
    <p><label for="telephone">Telephone</label><input id="telephone" type="tel" /></p>
    <p><label for="website">Website</label><input id="website" type="url" /></p>
  </fieldset>
  <fieldset>
    <legend>Project Details</legend>
    <p>
      <label for="project-type">Type of Project</label>
      <select id="project-type">
        <option>HTML/CSS Build</option>
        <option>Custom jQuery Plugin</option>
        <option>Wordpress Template</option>
        <option>Other</option>
      </select>
    </p>
    <p><label for="completion-date">Projected Completion Date</label><input id="completion-date" type="date" /></p>
    <p><label for="project-budget">Estimated Budget (&pound;)</label><input id="project-budget" type="number" /></p>
    <p><label for="project-details">Additional Details</label><textarea id="project-details" rows="5"></textarea></p>
  </fieldset>
  <fieldset>
    <legend>Contact Preferences</legend>
    <p>
      <span>Please contact me by&hellip;</span>
      <label><input id="contact-method" type="radio" value="Phone" checked="checked" /> Phone</label>
      <label><input id="contact-method" type="radio" value="Email" /> Email</label>
    </p>
    <p><label for="contact-time">Best time to contact?</label><input id="contact-time" type="time" /></p>
    <p><input type="submit" id="submit" value="Submit Form" /></p>
  </fieldset>
</form>

View Demo

Next time, we’ll be looking at sprucing our form up a bit with CSS. Stay tuned.

Photo Credit: Trevor Dennis on Flickr

html5-doctype

HTML5 Doctype: Make the Switch!

There is a great deal of confusion surrounding the implementation of HTML5 amongst some developers.  Some believe that we shouldn’t be using HTML5 because it’s not ‘ready’, and that using the HTML5 doctype is dangerous because older browsers don’t support HTML5.

Lets be clear: you can switch to using the HTML5 doctype in your projects right now; the new features may not be supported in older browsers.  For example, IE doesn’t support the new structural elements (header, nav, article, section, aside, footer), and needs a little CSS & JavaScript support to get them to work.  The doctype however works perfectly well.  The main practical effect of switching

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

or

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

to

<!DOCTYPE html>

is that standards mode is triggered.  There’s no excuse for not using a strict doctype in either case.

So why make the switch?  There are two main reasons, the first is to simplify your markup.  You get to write less code, and shave a few bytes off the document size.  The second is to enable you to use some of the features of HTML5 in newer browsers now, whilst ensuring graceful degradation in older browsers.

It’s analogous to the situation with CSS2.1/CSS3 in some respects.  You might create a fancy button with a gradient background, rounded corners and text shadow with CSS3 for newer browsers; the same button in IE would be square, have a flat background colour and no text shadow.  You have the option to prop up IE with graphics in a conditional stylesheet, or just leave it like it is.  It’s the same case, for example, with the new date input type – this will gracefully degrade into a text input in browsers that don’t support it; it’s up to you whether you want to implement a JavaScript date picker or not.

Just because some features aren’t supported by older browsers, doesn’t mean we can’t use them!  If we thought like that then we’d all still be limited to CSS1, as IE8 is the only browser to support CSS 2.1 completely.

What I’m listening to right now: Radiohead – “Where I End and You Begin”