Helpful HTML Form Feedback With CSS3 Transitions

featured preview CSS3 input form transitions

Designers may have noticed an ever-increasing use of CSS3 transition properties. Website interfaces have been dramatically improved with custom animation styles, all without the need for JavaScript (when used sensibly, of course!)

In this tutorial I want to demonstrate how we can build animation effects in HTML5 input fields. I’ll be designing a simple contact form with a couple of fields and a textarea. Using the CSS3 :valid pseudo class it is easier than ever to customize text inputs. Check out my live demo example to get an idea of what the final product looks like.

Live DemoDownload Source Code

Starting the Document

We need to start with a blank index.html file using the standard HTML5 doctype. I’ll be including some alternate web fonts to spruce up the design. But it’s nothing which will dramatically affect the quality of the tutorial.

<!doctype html>
<html lang="en-US">
<head>
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
  <title>CSS3 Animated Form Inputs</title>
  <meta name="author" content="Jake Rocheleau">
  <link rel="shortcut icon" href="http://designshack.net/favicon.ico">
  <link rel="icon" href="http://designshack.net/favicon.ico">
  <link rel="stylesheet" type="text/css" media="all" href="styles.css">
  <link rel="stylesheet" type="text/css" media="all" href="http://fonts.googleapis.com/css?family=Skranji:400,700|Oxygen:400,700">
</head>

The more interesting section of the page relates to setting up a generic HTML5 form. The submit button doesn’t do anything but reload the page. However it does not suggest you couldn’t link to a backend PHP or Ruby script for data processing, or even connecting via Ajax. The CSS3 transitions should only affect frontend styles and nothing more.

Each input is contained inside a div with the class .row to keep the elements separated. This way it’s much easier to have the label displaying right next to the input field. And similarly to include other notices or warnings over to the right side of the fields. Each input is given the class .txt while the textarea element is styled using .txtarea.

<form id="contactform" name="contact" method="post" action="#">
  <p class="note"><span class="req">*</span> Asterisk fields are required</p>
  <div class="row">
	<label for="name">Your Name <span class="req">*</span></label>
	<input type="text" name="name" id="name" class="txt" tabindex="1" placeholder="Steve Jobs" required>
  </div>
  
  <div class="row">
	<label for="email">E-mail Address <span class="req">*</span></label>
	<input type="email" name="email" id="email" class="txt" tabindex="2" placeholder="address@domain.com" required>
  </div>
  
  <div class="row">
	<label for="subject">Subject <span class="req">*</span></label>
	<input type="text" name="subject" id="subject" class="txt" tabindex="3" placeholder="Advertising/Press Ideas" required>
  </div>
  
  <div class="row">
	<label for="message">Message <span class="req">*</span></label>
	<textarea name="message" id="message" class="txtarea" tabindex="4" required></textarea>
  </div>
  
  <div class="center">
	<input type="submit" id="submitbtn" name="submitbtn" tabindex="5" value="Send Message">
  </div>
</form>

CSS Layout Structure

I want to jump into our CSS code and start by explaining the CSS resets. I use a similar block template for resetting browsers to similar defaults of font sizes, line-height, and also box-sizing. Plus I am setting the various web fonts and structuring basic elements with proper spacing. Feel free to save this template for use in other web projects.

html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
  outline: none;
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  -ms-text-size-adjust: 100%;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}
html { height: 101%; }
body { 
  font-family: 'Oxygen', Arial, Helvetica, sans-serif; 
  font-size: 62.5%; 
  line-height: 1; 
  padding-bottom: 85px;
  background: #f5f7f7 url('images/bg.png'); /* Image Source: http://subtlepatterns.com/paper-fibers/ */
}

::selection { background: #d2bef5; }
::-moz-selection { background: #d2bef5; }
::-webkit-selection { background: #d2bef5; }

br { display: block; line-height: 2.2em; } 

table { border-collapse: collapse; border-spacing: 0; }
img { border: 0; max-width: 100%; }

Moving into the core body section we have a wrapper div using the ID #w. This is centered on the page with a limited width of 660px. The internal row elements are styled as block containers, with internal labels and form input fields.

/* form styles */
form .row { 
  display: block;
  padding: 7px 8px;
  margin-bottom: 7px;
}
form .row:hover {
  background: #f1f7fa;
}

form label {
  display: inline-block;
  font-size: 1.2em;
  font-weight: bold;
  width: 120px;
  padding: 6px 0;
  color: #464646;
  vertical-align: top;
}
form .req { color: #ca5354; }

form .note { 
  font-size: 1.2em;
  line-height: 1.33em;
  font-weight: normal;
  padding: 2px 7px;
  margin-bottom: 10px;
}

form input:focus, form textarea:focus { outline: none; }

/* placeholder styles: http://stackoverflow.com/a/2610741/477958 */
::-webkit-input-placeholder { color: #aaafbd; font-style: italic; } /* WebKit */
:-moz-placeholder { color: #aaafbd; font-style: italic; }           /* Mozilla Firefox 4 to 18 */
::-moz-placeholder { color: #aaafbd; font-style: italic; }          /* Mozilla Firefox 19+ */ 
:-ms-input-placeholder { color: #aaafbd; font-style: italic; }      /* Internet Explorer 10+ */

The small class .req is for required asterisk characters used throughout the labels. But even more interesting is the last section of code for overriding the internal placeholder text. Not all CSS3 browsers fully support these properties, but they do work in updated Webkit and Mozilla engines.

You’ll notice the internal form text placeholders are now italicized and take on a text color shade of dark grey/blue. I find this extra CSS helps to distinguish from the actual user-typed letters vs placeholder sample text.

Styling with Transitions

I want to jump into the final section discussing how we can use pseudo classes to perform animations. The most important styles begin with the .txt and .txtarea classes used on each form element.

form .txt {
  display: inline-block;
  padding: 8px 9px;
  padding-right: 30px;
  width: 240px;
  font-family: 'Oxygen', sans-serif;
  font-size: 1.35em;
  font-weight: normal;
  color: #898989;
  background-color: #f0f0f0;
  background-image: url('images/checkmark.png');
  background-position: 110% center;
  background-repeat: no-repeat;
  border: 1px solid #ccc;
  text-shadow: 0 1px 0 rgba(255,255,255,0.75);
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
  -webkit-box-shadow: 0 1px 2px rgba(25, 25, 25, 0.25) inset, -1px 1px #fff;
  -moz-box-shadow: 0 1px 2px rgba(25, 25, 25, 0.25) inset, -1px 1px #fff;
  box-shadow: 0 1px 2px rgba(25, 25, 25, 0.25) inset, -1px 1px #fff;
  -webkit-transition: all 0.3s linear;
  -moz-transition: all 0.3s linear;
  transition: all 0.3s linear;
}

form .txtarea {
  display: inline-block;
  padding: 8px 11px;
  padding-right: 30px;
  width: 320px;
  height: 120px;
  font-family: 'Oxygen', sans-serif;
  font-size: 1.35em;
  font-weight: normal;
  color: #898989;
  background-color: #f0f0f0;
  background-image: url('images/checkmark.png');
  background-position: 110% 4%;
  background-repeat: no-repeat;
  border: 1px solid #ccc;
  text-shadow: 0 1px 0 rgba(255,255,255,0.75);
  -webkit-box-sizing: content-box;
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
  -webkit-box-shadow: 0 1px 4px -1px #a8a8a8 inset;
  -moz-box-shadow: 0 1px 4px -1px #a8a8a8 inset;
  box-shadow: 0 1px 4px -1px #a8a8a8 inset;
  -webkit-transition: all 0.3s linear;
  -moz-transition: all 0.3s linear;
  transition: all 0.3s linear;
}

I have done a lot of customizing with newer CSS3 properties. But also note how I have split up the individual background settings by their unique properties – like background-color and background-image. This is necessary when we need to animate the checkmark into the input without sliding all the way from the left. Instead we keep it tucked just off to the right where it is hidden from view, and then animate in from the right side.

form .txt:focus, form .txtarea:focus {
  width: 300px;
  color: #545454;
  background-color: #fff;
  background-position: 110% center;
  background-repeat: no-repeat;
  border-color: #059;
  -webkit-box-shadow: 0 1px 4px -1px #a8a8a8 inset, 0 1px rgba(255, 255, 255, 0.6), 0 0 11px rgba(70, 100, 200, 0.7);
  -moz-box-shadow: 0 1px 4px -1px #a8a8a8 inset, 0 1px rgba(255, 255, 255, 0.6), 0 0 11px rgba(70, 100, 200, 0.7); 
  box-shadow: 0 1px 4px -1px #a8a8a8 inset, 0 1px rgba(255, 255, 255, 0.6), 0 0 11px rgba(70, 100, 200, 0.7); 
}
form .txtarea:focus { 
  width: 375px; 
  background-position: 110% 4%;
}

form .txt:valid {
  background-color: #deecda;
  background-position: 98% center;
  background-repeat: no-repeat;
  color: #7d996e;
  border: 1px solid #95bc7d;
}
form .txtarea:valid {
  background-color: #deecda;
  background-position: 98% 4%;
  background-repeat: no-repeat;
  color: #7d996e;
  border: 1px solid #95bc7d;
}
form .txt:focus:valid, form .txtarea:focus:valid {
  -webkit-box-shadow: 0 1px 4px -1px #a8a8a8 inset, 0 1px rgba(255, 255, 255, 0.6), 0 0 11px rgba(120, 200, 70, 0.7);
  -moz-box-shadow: 0 1px 4px -1px #a8a8a8 inset, 0 1px rgba(255, 255, 255, 0.6), 0 0 11px rgba(120, 200, 70, 0.7); 
  box-shadow: 0 1px 4px -1px #a8a8a8 inset, 0 1px rgba(255, 255, 255, 0.6), 0 0 11px rgba(120, 200, 70, 0.7);  
}

You’ll also notice that the codes for :focus and :valid are very different. This is another reason why splitting the properties is such a good idea, because we might animate something in one pseudo class but not the other. Each transition property is targeting all changes, so this means you have to be careful about which properties are being updated.

Consider that the user might enter a valid name only to delete it a few seconds later. Our valid selector will need to re-animate back to the basic properties – but still keeping the :focus properties displaying as well. Segmented animation is the key to getting these styles working. It will require some trial & error but these effects could also be duplicated on every legacy browser with additional JavaScript.

One other aspect of the animated form is the submit button. Obviously the additional effects are negligible compared to the input fields. But I think all the properties are worth examining since they do relate to each other.

#submitbtn {
  height: 70px;
  width: 275px;
  padding: 0;
  cursor: pointer;
  font-family: 'Oxygen', Arial, sans-serif;
  font-size: 2.0em;
  color: #0a528f;
  text-shadow: 1px 1px 0 rgba(255,255,255,0.65); 
  border-width: 1px;
  border-style: solid;
  border-color: #317bd6 #3784e3 #2d74d5 #3774e3;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
  background-color: #4581e5;
  background-image: -webkit-gradient(linear, left top, left bottom, from(#6faefd), to(#4581e5));
  background-image: -webkit-linear-gradient(top, #6faefd, #4581e5);
  background-image: -moz-linear-gradient(top, #6faefd, #4581e5);
  background-image: -ms-linear-gradient(top, #6faefd, #4581e5);
  background-image: -o-linear-gradient(top, #6faefd, #4581e5);
  background-image: linear-gradient(top, #6faefd, #4581e5);
  -moz-box-shadow: 1px 1px 3px rgba(0,0,0,0.4), 0 1px 0 rgba(255, 255, 255, 0.5) inset;
  -webkit-box-shadow: 1px 1px 3px rgba(0,0,0,0.4), 0 1px 0 rgba(255, 255, 255, 0.5) inset;
  box-shadow: 1px 1px 3px rgba(0,0,0,0.4), 0 1px 0 rgba(255, 255, 255, 0.5) inset;
  -webkit-transition: all 0.3s linear;
  -moz-transition: all 0.3s linear;
  transition: all 0.3s linear; 
}
#submitbtn:hover, #submitbtn:focus {
  -webkit-box-shadow: 0 0 15px rgba(70, 100, 200, 0.9);
  -moz-box-shadow: 0 0 15px rgba(70, 100, 200, 0.9);
  box-shadow: 0 0 15px rgba(70, 100, 200, 0.9);
}

#submitbtn:active {
  -webkit-box-shadow: 0 0 15px rgba(70, 100, 200, 0.9), 0 1px 3px rgba(0,0,0,0.4) inset;
  -moz-box-shadow: 0 0 15px rgba(70, 100, 200, 0.9), 0 1px 3px rgba(0,0,0,0.4) inset;
  box-shadow: 0 0 15px rgba(70, 100, 200, 0.9), 0 1px 3px rgba(0,0,0,0.4) inset;
}

Instead of setting up various background properties I’ve just used CSS3 gradients and their vendor-specific prefixes. This keeps the background stable while still enhancing the box shadows via hover and active states.

css3 animation howto input forms styles screenshot

Live DemoDownload Source Code

Final Thoughts

The process of building formal CSS3 animations does take work. There are external libraries like Animate.css which can help, but still do not provide as much support as JavaScript. Thankfully the CSS3 standards are advanced enough to provide basic animations – hover, focus, and similar pseudo classes.

I do hope this tutorial can offer a sample codebase for web developers. You can learn a lot by just practicing techniques for a couple of hours. Feel free to download a copy of my sample codes and play around with different settings. It is not as difficult as you might expect to implement similar transitions on your own website.

Design Shack

Leave a Comment