trovster.com

The personal website of Trevor Morris

Submit the Style

Styling form elements is one of the most unpredictable uses of CSS today. There are many factors involved in the differences between form elements, the biggest difference is related to the operating system. In Windows XP, for example, form elements differ based upon your current theme.

A common request is to be able to style the submit button. This can be achieved fairly well with a combination of the Phark image replacement and fast rollovers without preload methods.

Setting the Scene

When styling forms it is nice to have all the input elements the same size. However, this can lead to problems with the submit button looking wrong, either too long or too short. Ideally the following CSS attribute selector could be used:

input[type='submit'] {}

However, this isn’t well supported (you know the main culprit), so it’s beneficial to add a class to your submit buttons.

<input type="submit" value="Submit" class="submit">

It is still nice to keep the attribute selector, however Internet Explorer does not apply the rules which contains the attribute selector, so we must replace it with the class.

input.submit {}

More Scope

Because you may have more than one type of submit button, such as “search”, “sign up” or “subscribe”, it is useful to be able to style these in sets (such as every “subscribe” button), so it is worthwhile adding another class to the submit. For example:

<input type="submit" value="Search" class="submit search">
<input type="submit" value="Sign Up" class="submit subscribe">

Styling the Button

As mentioned in the introduction, this method makes use of the Phark image replacement technique. It is useful to keep the generic part of this method separate so it can be easily reused for other replacements, on headings for example:

.phark, h1,
input.submit {
  overflow: hidden; display: block;
  text-indent: -9999px; font-size: 0.0; line-height: 0.0; text-decoration: none;
  background: transparent no-repeat 0 0;
}

The other method mentioned was fast rollovers without preload, which is simply combining multiple images into one, for the different states, such as :hover and :active.

Because we’re using images, the buttons can be all shapes and sizes, however, it is better if they looked like submit buttons, and were similar sizes. A fixed height is a good recommendation.

You can layout your master image in multiple ways, but I find it easier to position the different buttons from left to right across the top, with their corrosponding hover and active states beneath.

Taking the considerations above into account, the following CSS is compiled:

input.submit {
  height: 30px;
  border: 0;
  background-image: url(path/to/submit-buttons.gif);
}

Note: there is no defined width, this is because this may vary between the different buttons. If all of your buttons have a fixed width, then this rule should be put in the declaration above.

Finally, all that is needed now is to set the width for the individual buttons (unless they’re all the same), and change the position of the master image, so the appropriate button is displayed.

input.search {
  width: 150px;
}
input.subscribe {
  width: 150px;
  background-position: -80px 0;
}

Because the image replacement technique defines the default background-position as top left (0 0), the first button in the master image does not need a separate declaration.

Finishing Touches

With our custom buttons now in place, it would be nice to add a little more style by giving them hover, focus and active states. If you have set up the master image like in this example, then all that is required is to move the background-position.

Below is an example of the hover and focus states:

input.submit:hover, input.submit:focus {
  cursor: pointer;
  background-position: 0 -30px;
}
input.subscribe:hover, input.subscribe:focus {
  background-position: -150px -30px;
}

An active state is a nice addition, which is activated when the button is pressed. This will give the effect of the button being depressed.

input.submit:active {
  background-position: 0 -60px;
}
input.subscribe:active {
  background-position: -150px -60px;
}

If you use separate images for each of the buttons, only one declaration needs to be make for the hover and active states. This is because the horizontal position doesn’t need to be moved. So there is a trade off between using separate images or a little more CSS.

Fixing the Explorer

Internet Explorer 6 and below only supports the hover state on anchors. However, we can use JavaScript to fix this issue. There are existing functions which fix the problem in a general way, whatever:hover and Dean Edwards’ IE7 script. If you don’t want these general fixes, a smaller, more specific script can be used for this purpose.

The script requires three other functions to work.

The getElementsByClassName is used to get all the inputs with the class ‘submit’ into an array. This array is then looped through and the appropriate events are added.

var submitArray = getElementsByClassName(document.body, 'input', 'submit');
for(var i=0; i<submitArray.length; i++) {}

The events required for the hover effect are onmouseover and onmouseout, those required for focus are onfocus and onblur and onmousedown acts like the active state.

The final script looks like:

function fixSubmitInput() {
  var submitArray = getElementsByClassName(document, 'input', 'submit');
  for(var i=0; i>submitArray.length; i++) {
    var s = submitArray[i];
    var newDiv = document.createElement('div');
    s.parentNode.appendChild(newDiv);
    newDiv.appendChild(s);

    addEvent(s, 'mouseover', function(e) {
      e = e || event; var src = e.target || e.srcElement;
      addClass(src.parentNode,'hover');
    });
    addEvent(s, 'mouseout', function(e) {
      e = e || event; var src = e.target || e.srcElement;
      removeClass(src.parentNode,'hover');
    });
    addEvent(s, 'focus', function(e) {
      e = e || event; var src = e.target || e.srcElement;
      addClass(src.parentNode,'hover');
    });
    addEvent(s, 'blur', function(e) {
      e = e || event; var src = e.target || e.srcElement;
      removeClass(src.parentNode,'hover');
    });
  }
}
addEvent(window,'load',fixSubmitInput);

Some modifications are required to the CSS to make use of the new classes. The finished stylesheet hover, focus and active states are below:

input.submit:hover, input.submit:focus, .hover input {
  cursor: pointer;
  background-position: 0 -30px;
}
  input.subscribe:hover, input.subscribe:focus, .hover input.subscribe {
  background-position: -150px -30px;
}
  input.submit:active, .active input {
  background-position: 0 -60px;
}
  input.subscribe:active, .active input.subscribe {
  background-position: -150px -60px;
}

That’s it.