styling forms – the 21st century way

Based on an amazing article from ZURB I recommend you have a look at I have revisited their technique to:

  • deliver the same solution in jQuery
  • use a bit more flexible CSS (at least in my view)
  • redesign our search box

Up until now we have been using a simple JavaScript solution:

<form id="search" action="/index.php" method="get">
<div>
<input class="search_string" type="text" name="search_string" id="search_string" onfocus="if (this.value == this.defaultValue) this.value = '';" onblur="if (trim(this.value) == '') this.value = this.defaultValue;" onmouseover="this.focus();" value="search DocuView" />
<input class="search_submit" type="submit" name="search_submit" id="search_submit" value="" />
<input class="hidden" type="hidden" name="page" value="search" />
</div>
</form>

It worked just fine. Displayed the desired value in the input field and on focus it’d replace it with cursor… We use that in combination with:

<body class="documents" onload="document.forms[0].elements[0].focus();">

which would automatically focus on the form’s search field upon loading the document AND:

function trim(string)
{
return string.replace(/^\s+|\s+$/g, '')
}

The sought after not built-in JavaScript trim function (there is a jQuery alternative, see below).

Since then I have also read this article on optimising and styling the submit/search button in IE6/IE7 or generally any browser not supporting text-indent on button elements.

Now for the NEW code

I have used more or less the same code as seen at ZURB.

<form id="search" action="/testing/label.php" method="get">
<div>
<label for="search-string" class="overlay"><span>search Docu<strong>View</strong></span></label>
<input class="search-string" type="text" name="search-string" id="search-string" value="search]" />
<input type="submit" name="search-submit" id="search-submit" value="search DocuView" />
</div>
</form>

I have used an id for the form to make the CSS specific, easier to insert and start using immediately. I have to admit I have tried to omit the extra class on the label but the jQuery code stopped working (and frankly I do not know why yet – I’m hoping some of you will help me shed some light on it/I’ll figure out why soon). Anywho…

Coding the form behaviour

I have used relative units (em) to ensure the form scales with the size of the font. Also our tweaked version of Eric Meyer’s Reset CSS is used. The result is acceptably similar in all major browsers (IE7/8, Firefox 3.5, Opera 9, Safari 4, Chrome 2, IE6 is having a problem displaying the submit button as defined – maybe some of you will know how to solve that). In Opera the input field is *slightly* lower than I’d like it to be. I have tried cheating it: converted all the values from relative to fixed (em -> px), using 16px font (.75em = 12px, .5em = 8px, .25em = 4px) + I had to add “invisible” (white) borders to both the search-string input field and the span contained in the label but to no avail. At this point there does not seem to be a way to achieve pixel perfect overlay between the input field and the span (in XHTML Strict). Yet!

Apart from converting the JavaScript from the Prototype to jQuery I have also added validating and styling the label when user deletes the contents of the input field OR loads the page with AutoFill/submitted form values in it. Also instead of using the not-yet-100%-supported opacity/transition all I’m changing is the color of the font in the span.

$(document).ready(function()
{
// Select all textboxes and assign them to an array
var input	=	$('#search-string');
var label	=	$('label.overlay');

if (!$.trim(input.val())	==	'')
{
label.addClass('focus').addClass('hastext');
}
else
{
label.removeClass('focus').removeClass('hastext');
}

// Fade the label back when a field gains focus
input.focus(function()
{
if ($.trim($(this).val())	==	'')
{
label.addClass('focus');
}
else
{
label.addClass('hastext');
}
});

// Fade the label back when the user starts to type
input.keyup(function(e)
{
//	empty? label->focused
if ($.trim($(this).val())	==	'')
{
label.removeClass('hastext').removeClass('focus').addClass('focus');
}
else
{
label.addClass('hastext');
}
});

// Check if a field is empty when the user switches out
input.blur(function()
{
if ($.trim($(this).val())	==	'')
{
label.removeClass('focus').removeClass('hastext');
}
});
});

Don’t forget to include the jQuery library! I have devised a demo and have started implementing this throughout our software. As ZURB warned: do not overuse it. I was happy to find semantically friendlier and in a way much better solution than we have used so far.

Finally: the CSS

body { font-size: 100%; font-family: Helvetica, Arial, sans-serif; line-height: 1.5; }
strong { font-weight: bold; }
#search { width: 20em; color: white; background-color: black; margin: 2em; }
#search div { position: relative; height: 3em; }
#search input { border: 0 none; font-family: Helvetica, Arial, sans-serif; font-size: 100%; }
#search label { position: absolute; left: .5em; top: .5em; width: 19em; height: 2em; background: white; z-index: 1; font-size: 100%; }
#search span { color: black; display: block; padding: .25em 0 0 .25em; border: 0 none; /*border-left: 1px solid white;*/ /*border-top: 2px solid white;*/ }
#search .focus span { color: #ccc; }
#search .hastext span { color: white; }
#search #search-string { position: absolute; z-index: 10; top: .5em; left: .5em; width: 87%; height: 2em; background: none; padding: .25em 0 0 .25em; /*border-top: 2px solid white;*/ }
#search #search-submit { background: transparent url(http://img.docuview.co.uk/sprite/search.png) no-repeat center center; height: 100%; width: 13%; font-size: 0; text-indent: -9999px; line-height: 0; display: block; position: absolute; top: 0; right: 0; z-index: 10; overflow: hidden; }

Thank you, ZURB guys, for the inspiration, I absolutely love the idea! I hope you find the implementation as useful as I have.

Bookmark and Share

Leave a Reply