CSS-Plus
CSS-Plus
Play with web technologies

Forms, jQuery and CSS3

July 05, 2010
Attention: This article is old and the content is outdated. I've left the article here for historical purposes.

Everyone needs to create a form at one point or another and I've got a few rules I generally stick to when designing and developing forms in general.

Before we get started on actually coding the form, let's recap on the dos and don'ts of forms

It should be simple

It can get complicated quite quickly

This could confuse you and/or the user. If the user gets confused, lost or overwhelmed, there is a high chance that he/she will close the page and you will have lost a potential customer/submitter.

Avoid overwhelming the user

Don't give the user unnecessary options, such as "Fill this in if you have chose option B". Rather have an extra field fade in or pop-up if a certain option was chosen. Create a mini wizard if it is appropriate.

Validation syndrome

Don't add captchas, validate the names, surnames, telephone numbers and emails unless you are getting spammed with false information all the time. Validation is there to help the user as well as obtain valid information, so don't give the users a bad user experience.

Be wise, Optimize

The content should be efficient.

Don't ask for unnecessary information. The longer it takes for the person to complete the form, the higher the chance is that he/she may leave.

The HTML should be as simple as possible. - Semantic markup makes your browser smile

don't use <div>s when you don't need to I've found pre-defined elements work better cross-browser than divs. We have <form>, <fieldset>, <legend>, <label>, <input>, <select> and <option> to work with. They were created for a reason, use them.

Visually appealing

Don't over do the CSS3

Sometimes people inappropriately overdo the drop/text-shadow and it gives me the impression that the site was designed by an amateur developer.

Be subtle

You could use drop shadows, text-shadows, rounded corners, hover and focus events, etc. every single time you develop anything, but be subtle. A drop-shadow or text-shadow that is barely noticible at first could make a whole world of difference to the atmosphere of the web-page.

Now that we have the basics down, let's get started.

The plan

My plan is to create a wizard-type form - with next and previous buttons - in order to add an element of simplicity. Basically, I'm going to follow the above 'tips' and use them while I create this form.

The HTML

<form action="">
    <fieldset>
        <legend>Step One</legend>

        <label for="name">Name:</label>
        <input id="name" name="name" type="text" size="20" />

        <label for="email">Email:</label>
        <input id="email" name="email" type="text" size="25" />
    </fieldset>

    <fieldset>
        <legend>Step Two</legend>

        <label for="company">Company:</label>
        <input id="company" name="company" type="text" size="20" />

        <label for="tel-no">Tel No:</label>
        <input id="tel-no" name="tel-no" type="text" size="20" />

        <label for="fax-no">Fax No:</label>
        <input id="fax-no" name="fax-no" type="text" size="20" />
    </fieldset>

    <fieldset>
        <legend>Step Three</legend>

        <label for="country">Country:</label>
        <input id="country" name="country" type="text" size="20" />

        <label for="address">Address:</label>
        <input id="address" name="address" type="text" size="20" />

        <label for="state">State:</label>
        <select id="state" name="state">
            <option value="Option one">Option one</option>
            <option value="Option two">Option two</option>
            <option value="Option three">Option three</option>
        </select>

        <br class="clear" />

        <input id="submit" type="submit" value="Submit" />
    </fieldset>
</form>

The HTML is fairly simple. I've added the for, name and id attributes because it's more semantic to do so than to leave it out.

The form has the empty attribute 'action' because every form has to have an action. If the action attribute is not added, the page will not validate.

A legend is the heading text on top of the border. It requires no styling (from us) in order to achieve this effect cross-browser. All that is needed is a <legend> within a <fieldset>. Pretty decent, right?

The CSS

form {
    width: 760px;
}
fieldset {
    background: #827254;
    border: 2px solid #c7b795;
    margin: 0 0 20px 0;
    padding: 15px 10px;
}
fieldset.submit {
    background: none;
    border: none;
    margin: 0;
    padding: 0 10px;
}
fieldset legend {
    color: #fff;
    font-weight: bold;
    text-shadow: 4px 4px 7px #4d412a;
}
fieldset input {
    border: 1px solid #516764;
    border-right-color: #504532;
    border-bottom-color: #504532;
    height: 25px;
    line-height: 25px;
    margin: 0 20px 0 0;
    padding: 0 2px;
}
fieldset input:last-child {
    margin: 0;
}
fieldset input:focus {
    border: 1px solid #4d412a;
}
fieldset label {
    margin: 0 10px 0 0;
}
fieldset input[type="submit"] {
    background: #827254;
    border: 3px solid #585246;
    color: #e5d8b9;
    cursor: pointer;
    height: auto;
    line-height: 15px;
    margin: 20px 0 0 0;
    padding: 4px 6px;
}
fieldset input[type="submit"]:hover {
    color: #fff;
}

/*
	Navigation
*/
div.nav {
    width: 200px;
    margin: 0 auto;
}
#prev,
#next {
    display: block;
    background: #827254;
    border: 3px solid #585246;
    color: #e5d8b9;
    cursor: pointer;
    height: auto;
    line-height: 15px;
    margin: 20px 0 0 0;
    padding: 4px 6px;
    text-align: center;
    width: 65px;
}
#prev {
    float: left;
}
#next {
    float: right;
}
#prev:hover,
#next:hover {
    color: #fff;
}

/*
	CSS3
*/
fieldset,
fieldset input,
#prev,
#next {
    border-radius: 5px;
    -moz-border-radius: 5px;
}
fieldset {
    box-shadow: inset 0 0 10px #4d412a;
    -moz-box-shadow: inset 0 0 10px #4d412a;
    -webkit-box-shadow: inset 0 0 10px #4d412a;
}
fieldset input:focus {
    box-shadow: inset 0 0 7px #a4a4a4;
    -moz-box-shadow: inset 0 0 7px #a4a4a4;
    -webkit-box-shadow: inset 0 0 7px #a4a4a4;
}
fieldset input[type="submit"]:hover,
#prev:hover,
#next:hover {
    -moz-box-shadow: 0 0 5px #5f553e;
}

In general, I don't usually use black as a drop-shadow colour. I normally find a darker tone of the background colour and use that.

As you can see, along with CSS3, I've used the selector[type="submit"] selector. IE 6 and 7 have a few problems with this (Don't they always), but I've made sure it gracefully degrades.

And here is the IE specific stylesheet:

form {
    width: 780px;
}
fieldset {
    background: none;
}

The jQuery Javascript

I tend to create the javascript after I have completed the HTML and CSS. That way I know that the page will be functional without javascript.

The first thing I'm going to do is remove div#nav from the HTML and inject that into the page via javascript, as it will be a useless element to include if javascript is disabled.

$(document).ready(function() {
    $("form").prepend(
        '<div class="nav"><a id="prev" href="#">Previous</a><a id="next" href="#">Next</a></div><div class="clear"></div>'
    );
    $("#prev").css("display", "none");

    $("fieldset")
        .not(":first")
        .css("display", "none");

    $("#next").click(function() {
        $("fieldset:visible")
            .css("display", "none")
            .next()
            .fadeIn();
        $("#prev").css("display", "block");

        if ($("fieldset:last").is(":visible")) {
            $("#next").css("display", "none");
        }
    });

    $("#prev").click(function() {
        $("fieldset:visible")
            .css("display", "none")
            .prev()
            .fadeIn();
        $("#next").css("display", "block");

        if ($("fieldset:first").is(":visible")) {
            $("#prev").css("display", "none");
        }
    });
});

The jQuery is saying:

  1. Target the form and prepend the HTML we typed up earlier
  2. Target #prev and hide it - So that the users can't click previous while they are on slide one
  3. Target fieldset, but not the first fieldset, and change the display to none
  4. When you click on next, hide the visible fieldset, and display the next fieldset
  5. Whenever next is clicked, the display of #prev is changed to block - Because there is never a scenario where #prev should be hidden once next is clicked
  6. When you click on next, hide the visible fieldset, and display the next fieldset
  7. If the last fieldset is visible, hide the #next button in order stop the user from continuing past the last slide
  8. And finally, if #prev is clicked, do the exact opposite of #next

Pretty cool how jQuery reads so nicely, huh?

$("fieldset")
    .not(":first")
    .css("display", "none");

Target fieldset, not the first, change the CSS display property to none.

If you have any questions or anything to say, feel free to leave a comment.

Demo