The Problem Of CSS Form Elements

Advertisement

Before 1998, the birth year of CSS Level 2, form elements were already widely implemented in all major browsers. The CSS 2 specification did not address the problem of how form elements should be presented to users. Because these elements are part of the UI of every Web document, the specification’s authors preferred to leave the visual layout of such elements to the default style sheet of Web browsers.

Through the years, this lack of detail in the CSS specification has forced Web developers to produce a significant number of tests and examples whose primary goal is 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’s Tests

Back in 2004 and later in 2007, Roger Johansson created a complete test suite for form elements and CSS. These seminal tests, which can be found in his article “Styling Form Controls With CSS, Revisited1,” lead to the frustrating conclusion that Johansson 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 of — or at least a reasonable compromise between — the browser’s default rendering and the author’s styles.

The Default Model

The CSS 2.1 specification states in its proposed default style sheet for HTML42 that form elements such as textarea, input and select are inline-block elements:

textarea, input, select {
   display: inline-block;
}

Conversely, the form and fieldset elements are block-level elements:

fieldset, form {
   display: block;
}

The default model proposed by the CSS specification stops here. All other visual aspects of form elements rely on the browser’s default style sheet. However, the above rules indicate the following:

  • Inline-block elements can be styled using an inline formatting context. This implies the use of CSS properties such as line-height and vertical-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. As well, 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 and legend elements because legend relies entirely on the default styles provided by Web browsers.

How do Web developers manage these problems?

Defining Dimensions

Web developers soon noticed that Web browsers handle inline-block elements oddly when it comes to defining 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 instead to use 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 normalize them:

input, select {
   width: 120px;
   font: 1em Arial, sans-serif;
}

For an example, see the page “CSS: Defining Form Element Dimensions3” on jsFiddle.

Once the font in use is normalized, you can add padding to give some inner spacing to the element’s box:

input, select {
   width: 120px;
   font: 1em Arial, sans-serif;
   padding: 3px 6px;
}

The input elements and textarea also show a border that affects their box model:

input[type="text"],
input[type="password"],
textarea {
   border: 1px solid #ccc;
}

The input elements of the types button and submit have additional padding set by Web browsers. So, a common practice is to normalize them:

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 our padding is not always able to normalize this property. For example, in a Webkit-based browser, you might have this:

input[type="button"], input[type="submit"],
input[type="reset"], input[type="file"]::-webkit-file-upload-button,
button {
   -webkit-box-align: center;
   text-align: center;
   cursor: default;
   color: buttontext;
   padding: 2px 6px 3px;
   border: 2px outset buttonface;
   border-image: initial;
   background-color: buttonface;
   box-sizing: border-box;
}
input[type="button"], input[type="submit"], input[type="reset"] {
   -webkit-appearance: push-button;
   white-space: pre;
}

Padding is also used on the fieldset and legend elements but with different results:

  • Setting the padding on fieldset to 0 will reset the default indentation of the legend elements in some browsers (though not in IE).
  • Setting the padding on legend to 0 has the effect of making this element shrink.

Select boxes, checkboxes and radio buttons can be normalized with good results with only a few properties, namely:

  • font-family,
  • font-size,
  • width (on select boxes),
  • padding.

Applying 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 one of two approaches:

  1. Use floating,
  2. Use the default inline-block context on some of these elements.

When you use floating, elements are automatically turned into block-level elements. This means that form elements are now subject to the nine rules that govern floated elements4.

vertical-grid15
Form elements can be vertically or horizontally aligned.

With floats, the main challenge is to achieve 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 with the contents of a label element. In this case, you could use relative positioning, padding or margins on the element that contains only text:

label {
   float: left;
   padding-top: 0.4em;
   width: 5em;
   margin-right: 1em;
}

Another problem arises with buttons. In this case, when you have a button whose dimensions are greater than those of 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 works with checkboxes and radio buttons. Relative positioning can even be applied to normalize the left indentation of the legend element within a fieldset element, the only difference being that you would use the left property instead of top.

When using inline formatting, 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 by combining 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’s elements, their computed height would be affected:

.form-row {
   line-height: 1.4;
}

Using a declared height on the parent element is also effective when paired with the same value for the line height:

.form-row {
   line-height: 1.8;
   height: 1.8em;
}

With inline formatting, you can also use the text-align property on the parent element to align elements to the right, left or center.

The Strange Case Of File Inputs

The file input element — that is, <input type="file"/> — is a special case. This kind of element must always be visible and recognizable in the browser’s UI for security reasons. This implies that browsers deliberately ignore some style rules (such as those related to visibility) and tend to apply the algorithms defined in their default style sheet.

Furthermore, the default rendering varies from browser to browser: some browsers display only a single button, while others add a text field to display the path of the uploaded file.

Web developers, however, soon found a way to circumvent these limitations. First, they wrapped the input element in a container:

<form action="" method="post" enctype="multipart/form-data">
   <div class="upload">
      <input type="file" name="upload"/>
   </div>
</form>

Then, they hid the input element using the opacity property and applied certain styles to the input’s container:

.upload {
   width: 157px;
   height: 57px;
   background: url(upload.png) no-repeat;
   overflow: hidden;
}

.upload input {
   display: block !important;
   width: 157px !important;
   height: 57px !important;
   opacity: 0 !important;
   overflow: hidden !important;
}​

Notice the !important statement. This is the preferred way to override the browser’s default rules.

For an example, see the page “CSS: Styling Inputs of Type ‘file’6” on jsFiddle.

Conclusion

Totally taming form elements is impossible due to the lack of detail in the CSS specification and because of the default styles applied by Web browsers. However, by following some common practices, reducing (though not eliminating) the differences and achieving good visual results are possible.

(al)

Footnotes

  1. 1 http://www.456bereastreet.com/archive/200701/styling_form_controls_with_css_revisited/
  2. 2 http://www.w3.org/TR/CSS21/sample.html
  3. 3 http://jsfiddle.net/gabrieleromanato/J2nUn/
  4. 4 http://www.w3.org/TR/CSS21/visuren.html#floats
  5. 5 http://www.smashingmagazine.com/wp-content/uploads/2013/02/vertical-grid1.jpg
  6. 6 http://jsfiddle.net/gabrieleromanato/mxq9R/

↑ Back to topShare on Twitter

Gabriele Romanato is a web developer. Contributor of the W3C CSS Test Suite, he is also skilled with jQuery and WordPress. You can find more about him by visiting his blog or his Facebook page. He is also on Twitter.

Advertising
  1. 1

    This is fantastic. Thank you!

    0
    • 2

      Gabriele Romanato

      February 27, 2013 7:11 am

      Thanks. But there’s still a lot to do when it comes to select boxes styled only via CSS. I’m going to test something later.

      0
  2. 3

    Box-sizing is crucial to layout form elements, especially with fluid designs. Once I have box-sizing everything else isnt too bad.

    0
  3. 6

    This is great reminder! Thank you.

    0
  4. 8

    Check out Nathan Smith’s Formalize and Harvest’s Chosen (both available on GitHub) to quickly normalize the look and feel of form elements across browsers.

    0
  5. 10

    Thanks for the great post! Just today I published a codepen with a collection of form layout best practices which worked well for me.

    Since IE7 is almost dead, I make heavy use of box-sizing:border-box. This makes a adaptive, responsive layout much easier.

    Have a look and resize your browser: http://codepen.io/levito/pen/btBzL

    0
  6. 12

    Great!, But I faced the problem with select box and text box padding. I have to give different padding to both to make them same size. Is there any way i can use same padding for select and text box both?

    0
    • 13

      Gabriele Romanato

      February 27, 2013 9:05 pm

      Select boxes are different than normal input boxes. The main problem with select boxes is that most of their visual appearance is entirely delegated to the browser’s default stylesheet. The HTML KickStart framework offers an interesting way for taming select boxes.

      0
  7. 14

    Hi tnx for the article. Good material this is. However, i have a question about the last part.
    Your ‘trick’ for styling input[type=file] does not seem to work well in Firefox and ie10 (did not test below). In FF the top of the button is not opening the window. In IE10 in the left of the button i have to click twice to open the window and for the rest of the button it seems okay. It acts a little weird.

    tnx again,

    0
    • 15

      Hi. The problem is due to the different default layout provided by web browsers to file inputs. Chrome shows only a single button for choosing files and the name of the selected file appears as a text string right near the button. IE and Firefox, instead, add a text input to the default button to display the name of the file. That’s why dimensions are calculated differently. Also consider that for security reasons there is a limit to the CSS customization you can apply to file inputs.

      0
  8. 16

    I discovered the other day that Android has a bug in that it renders s as text inputs if either a border or background is applied, which is a pretty big usability issue.

    Unfortunately, there’s no pure CSS way of selecting/excluding the Android Browser, so as a workaround, I’m using CssUserAgent (http://cssuseragent.org/) and Layout Engine (http://mattstow.com/layout-engine.html) combined, which will add a class of .ua-android-browser to the tag.

    I can then style all s except on Android Browser, like so:

    html:not(.ua-android-browser) select { background: #0f0; border: 1px solid #ff0; }

    You can read and vote for my bug here, if you like: http://code.google.com/p/android/issues/detail?id=48379

    0
  9. 20

    A very annoying thing with styling form elements is the fact that width-definitions are irregular. Imagine a definition like

    input[type="text"], select { width: 200px; }

    This is not usable, because a select box is always a few pixels shorter than the input text field (mostly between 10 and 14 px). Why do i have to always make an extra definition for my select fields?

    0
  10. 24

    Jaymelensonn Judan

    February 28, 2013 3:45 am

    Great!

    0
  11. 25

    Here’s a little hack i use alot. usually when building dynamic forms or dynamic layout

    - get a div and float it to left.
    - another div with overflow:hidden. ( without float )
    // overflow hidden initially cause the block to render as 100% width – ( the floated element/’s )

    0
  12. 26

    Don’t style your select. I can’t stand any over styling of form elements this comment form is about as far as you should go. The minute you start messing with input fields is when you decide you would rather have something look ‘nice’ instead of work properly on any device/browser. Just don’t do it.

    0
    • 27

      Gabriele Romanato

      March 2, 2013 8:32 pm

      If your form elements must match the overall design of your website, then you should try to style them accordingly. This is certainly true when your clients ask you to do so. :-)

      0
      • 28

        If your client wants you to make forms look the same in every browser, ask them to take out their iPhone or iPad. Then ask them if they want the same customized dropdown there.

        You should always tell your client about the impacts caused by customizing form element behavior. They can make your site slow, hard to maintain, buggy and hard to use.

        You’ll find that it’s often okay to only apply slight form element styling. This can save you a lot of headaches and your client has more money left for you to put in cool projects.

        0
  13. 29

    It was really useful artical and as a Web designer, i had problems but not now……..Thanks

    0
  14. 30

    I think checkbox and radiobuttons are missing in this, are you going to cover them in another article – part 2?

    0
  15. 31

    Thanks a lot for a great article about form elements. Form elements have always given me disappointment since never I am able fully implement a mockup with a form as I thought of.

    Looking forward to more great article.

    0
  16. 32

    Didn’t we agree that websites cannot and should not look exactly the same across browsers? So why treat forms differently?

    0
  17. 33

    I’m surprised nobody’s mentioned normalize.css – see http://necolas.github.com/normalize.css/

    0
  18. 34

    Why would you want to “reduce (though not eliminating) the differences”? Does anybody still believe in pixel-perfect or that any page will look exactly the same across all browsers?

    0

Leave a Comment

Yay! You've decided to leave a comment. That's fantastic! Please keep in mind that comments are moderated and rel="nofollow" is in use. So, please do not use a spammy keyword or a domain as your name, or else it will be deleted. Let's have a personal and meaningful conversation instead. Thanks for dropping by!

↑ Back to top