equal height search form / form chaos

The world of css knows many grey zones. Areas where a healthy css developer would rather not tread if they had anything to say about it, but can be conquered with a serious dose of willpower. There is worse though. The black holes of css make us cringe only by thinking of them. That exact same cringe you might notice when a designer starts talking about pixel differences in forms. Oh, the horror!

defining our goal

There are countless articles written on how input elements differ across browsers and operating systems, even OS themes. The conclusion of these articles is always the same. Don't mess with them. And usually I agree. In a normal form there are limits to styling form elements, if only to safeguard our own sanity. Small differences in size, spacing and appearance between input elements is something inherent to the web. In other cases though, I can understand the designer's frustration.

One of those cases is the small search form often found in the header of a site. A prominent element within a site usually consisting of a text input and a submit button. The design is normally tightly integrated into the whole header so any pixel differences there can result in a sloppy overall feel really fast. One long-running frustration is that the height of both text input and submit is hard to match cross-platform, cross-browser. But there are ways. We're talking css after all.

The goal here will be to create a consistent setup for a text input and submit button so they can easily be given a fixed and equal height, rendering the same cross-browser. It will get hacky and you will need to get your hands dirty, but in the end it might actually we worth the trouble, especially when used sparingly.

defining the problem

input[type="text"], input[type="submit"] {height:2em;}

In short, the code above illustrates what I am hoping to do. Add an equal height to the text input and submit button and hope they are rendered with the same height by all browsers. Of course, it won't be as simple as that. The first problem is easy to fix though. Both element appear to have a different base font-size in certain browsers, so adding a font-size:100% to both elements helps us forward a little.

The biggest problem lies with the borders though. The border-width on the submit button is included into the height, the border-width on the text input has no impact on the height of the element. In other words, the border on the text input is drawn on the outside while the border on the submit button is drawn on the inside. Some quick experiments with the -vendor-box-sizing css property didn't result in much (unless you don't need to worry about ie6 and ie7), so let's try the hard way.

input[type="text"], input[type="submit"]{height:2em; font-size:100%; border-width:0;}

The only smart thing to do is to disable the borders on both text input and submit button and to provide some generic wrappers to take over the styling. By doing that you avoid differences in rendering height between the two input elements. I know it's not very clean but at least it works.

the html code

<div class="search"> <form id="searchForm" action="#" method="post"> <div class="inputWrap"><input type="text" /></div> <div class="submitWrap"><input type="submit" /></div> </form> </div>

This is the final html code we will be using for our search form. Not complete rubbish, only the .inputWrap and .submitWrap elements are obsolete from a structural point of view. We will use these two elements for faking the borders around the input elements, on top of that we'll need to float both wrappers. Note that adding a display:inline-block (rather than floating) is also on option, but applying the floats gives us a little more control over the spacing between the two, which I prefer.

In Opera, Chrome and Safari there will still be a slight difference in height between the elements. This is caused by a padding on the text input which can be removed quite easily. And by adding a line-height the same as the element height we'll have better alignment of the submit button text (Chrome) and text input text (IE). All of this results in the following code:

.inputWrap, .submitWrap {float:left; border:1px solid #000;} input[type="text"], input[type="submit"]{height:2em; line-height:2em; font-size:100%; border-width:0; padding:0;}

This will yield perfect results in Safari, Chrome, Firefox and Opera on both Windows and Mac, sadly IE still experiences some of problems (but what else is new, right). There will be strange spaces popping up which shouldn't be there, but nothing a couple of floats (and display:inline fixes) won't solve. Here's the ie7- css code.

/* ie7- specific css */ .search .textfield {float:left; display:inline;}

putting it all together

.inputWrap, .submitWrap {float:left; border:1px solid #000;} input[type="text"], input[type="submit"]{height:2em; line-height:2em; font-size:100%; border-width:0; padding:0;} /* ie7- specific css */ .search .textfield {float:left; display:inline;}

That's "all" you need to have a search form show up consistently in a range of browsers and OSes. If you want some live example code you can check the test page:

Note that a similar problem exists with input elements widths, in that case though the -vendor-box-sizing property (border-box) proves a lot more useful. Sadly ie6 and ie7 don't seem to like it that much when it comes to defining heights.

I wouldn't recommend using this for every form and every input element, but when two inputs need to align pixel perfect, ensuring design consistency, it's a very useful option. If anything, it's a good trick to win points with your designers.