Before 1998, the birth year of CSS Level 2, form elements were already widely implemented in all major browsers. The CSS 2 specifications did not address the problem of how form elements should be presented to users. Since this kind of elements are part of the UI of every web document, CSS preferred to leave the visual layout of these elements to the default stylesheet of web browsers. Through the years, this lack of details in the CSS specifications forced web developers to produce a significant amount of tests and examples whose primary goal was to reduce form elements to a common visual denominator in order to get a cross-browser rendering of elements such as input
, select
, fieldset
, legend
and textarea
. In this article we will cover some of the CSS patterns used by web developers to tame the visual layout of form elements.
Roger Johansson tests
Back in 2004, and later on in 2007, Roger Johansson created a complete test suite on form elements and CSS. These seminal tests, that can be found at http://www.456bereastreet.com/archive/200701/styling_form_controls_with_css_revisited/, lead to a frustrating conclusion that Roger summarizes with the following words:
So what does this experiment show? Like I already stated, it shows that using CSS to style form controls to look exactly the same across browsers and platforms is impossible. It also shows that most browsers ignore many CSS properties when they are applied to form controls.
Despite the underlying truth of these conclusions, web developers continued to extensively test CSS styles on form elements to find the Holy Grail or at least a reasonable compromise between browser's default rendering and author's styles.
The default model
CSS 2.1 specifications state in their proposed default stylesheet for HTML4 that form elements such as textarea
, input
and select
are inline-block elements:
textarea,
input, select { display: inline-block }
On the contrary, the form
and fieldset
elements are block-level elements:
fieldset, form { display: block }
The default model proposed by the CSS specifications stops here. All other visual aspects of form elements rely on the browser's default stylesheet. However, the above rules indicate that:
- Inline-block elements can be stylized using an inline formatting context. This implies the use of CSS properties such as
line-height
andvertical-align
to control the height of the box and its vertical alignment. Padding and margins can also be applied to define the outer and inner spacing of the affected box. Also, inline-block elements accept widths and heights because they share the block formatting model. - Block-level elements can be styled using the well-known block formatting context. However, problems arise with the
fieldset
andlegend
elements becauselegend
entirely relies on the default styles provided by web browsers.
How web developers manage these problems?
Defining dimensions
Web developers soon noticed an odd handling of inline-block elements by web browsers when it comes to define dimensions. Defining an height often leads to unexpected results:
input, select {
width: 120px;
height: 32px;
}
Developers tried to fix this problem by turning these elements into block-level elements:
input, select {
width: 120px;
height: 32px;
display: block;
}
Results are still poor except for the textarea
element. A common pattern to solve this problem is to avoid the height
property and use instead the font-size
and padding
properties.
Browsers do not use the same font family and size on these elements, so the first thing to do is to normalize them:
input, select {
width: 120px;
font: 1em Arial, sans-serif;
}
Once normalized the font in use, you can add some padding to add some inner spacing to the element's box:
input, select {
width: 120px;
font: 1em Arial, sans-serif;
padding: 3px 6px;
}
input
elements and textarea
also show a border that affects their box model:
input[type="text"],
input[type="password"],
textarea {
border: 1px solid #ccc;
}
input
elements of type button
and submit
have an additional padding set by web browsers, so a common practice is normalizing it:
input[type="button"],
input[type="submit"] {
padding: 2px;
}
The problem with this approach is that web browsers also apply vendor-specific properties to these elements so that our padding is not always able to normalize this property.
Padding is also used on the fieldset
and legend
elements but with different results:
- When applied to
fieldset
, zeroing padding resets the default indentation of thelegend
elements in some browsers (not in IE). - When applied to
legend
, zeroing padding has the effect to make this element shrink.
Select boxes, checkboxes and radio buttons can be normalized with good results only with a few properties, namely:
font-family
font-size
width
(on select boxes)padding
Trying to apply other properties to this group of elements often leads to inconsistent results across browsers.
Alignment
Form elements can be vertically or horizontally aligned. They can be laid out on the same line or as a group of boxes on multiple rows. To align them on the same line you can follow two approaches:
- Use floating
- Use the default inline-block context on some of these elements.
When you use floating, elements are automatically turned into block-level elements. This implies that now form elements are subject to the nine rules that govern floated elements.
With floats the main problem is to correctly achieve a good vertical alignment on the current line. In this case, using vertical margins or padding is a common practice:
input, select {
width: 120px;
float: left;
margin-top: 0.4em;
}
This approach works when you do not have to align boxes with text, such as the content of a label
element. In this case, you can use relative positioning, padding or margins on the element which contains solely text:
label {
float: left;
padding-top: 0.4em;
width: 5em;
margin-right: 1em;
}
Another problem arises with buttons. In this particular case, when you have a button whose dimensions are greater than other elements, you can force its vertical alignment with relative positioning:
input[type="submit"] {
float: left;
width: 90px;
position: relative;
top: 0.4em;
}
This approach with relative positioning also applies to checkboxes and radio buttons. Also, relative positioning can be applied to normalize the left indentation of the legend
element within a fieldset
. The only difference in this case is that you use the left
property instead of top
.
When you use an inline formatting context, you can rely on the vertical-align
property to vertically align elements:
label, input[type="text"] {
vertical-align: middle;
margin-right: 1em;
}
Good results can be achieved when you combine this property with the line-height
property. However, this property must be set on the parent element. If you set this property directly on the form elements, this will affect their computed height:
div.form-row {
line-height: 1.4;
}
Using a declared height on the parent element is also effective when combined with the same value of line-height:
div.form-row {
line-height: 1.8;
height: 1.8em;
}
Also, in an inline formatting context you can use the text-align
property on the parent element to align elements to right, left or center them.
File inputs
File inputs are a completely different problem. Historically, this kind of form elements has been always protected by the default algorithms of web browsers in order to prevent any possible security problem. Major problems arise when you try to change their default appearance.
Web developers usually wrap this element in a container and hide the input element by adjusting its opacity:
div.file {
width: 150px;
height: 50px;
overflow: hidden;
background: url(upload-btn.png) no-repeat;
}
div.file input[type="file"] {
display: block;
width: 150px;
height: 50px;
opacity: 0;
}
However, in some browsers setting dimensions on both elements produces different results. For example, the default layout provided by Gecko-based browsers also includes a text field where the name of the chosen file appears before the upload. Other browsers don't provide this feature and, consequently, button's dimensions are calculated differently.
Conclusions
Totally taming form elements is impossible due to the lack of details in the CSS specifications and the default styles applied by web browsers. However, by following some common practices is possible to reduce (but not eliminate) the differences and achieve good visual results.