First Ever 3D CSS WordPress Theme

CSS3 has some great support for 3D transforms, perspective, and animation. Currently Safari is the only browser that fully supports it, but I am hoping Firefox and Chrome will add support soon. With that we can take regular objects (WordPress posts in this case) and animate them. I created 3 different shapes the posts can form while rotating. Click a post to view a larger size.

View the Demo or Download the Theme

Note: the 3D and animation only work in recent versions of Safari. Though the site does degrade gracefully in other, less capable browsers. Update: Only Safari in Snow Leopard can fully run this demo. Unfortunately preserve-3d doesn’t appear to be supported in Safari Windows or in Chrome on any platform.

Update 2: Safari 5 added support for this demo on all platforms. Download the new version if you are browsing on Windows. Unfortunately Chrome still doesn’t have support.

In this screen cast the animation doesn’t look very smooth. But when viewed live all the animations are silky smooth. You’ll just have to try it for yourself.

I know this theme isn’t the most practical, but I would love to hear your thoughts on it. Also feel free to download it to learn more about how it works.

Designing Modern Web Forms with HTML 5 and CSS3

Recently I noticed that many web developers are still using HTML tables to layout their forms. Mainly it is because people stick with what they know, and have never taken the time to learn a better way. Once you learn to layout forms with standards compliant CSS it is actually quite easy!

View Demo Download Code

We will be using HTML5 and CSS3 to achieve great style and functionality without causing problems in less capable browsers. To be clear, this code will not look exactly the same in every browser. We are designing for the most advanced browsers, then making sure it still degrades gracefully.

Starting with the right markup.

Here we are using HTML 5 to code the form. Take a look:

[html]
<div id="registration">
<h2>Create an Account</h2>

<form id="RegisterUserForm" action="" method="post">
<fieldset>
<p>
<label for="name">Name</label>
<input id="name" name="name" type="text" class="text" value="" />
</p>

<p>
<label for="tel">Phone Number</label>
<input id="tel" name="tel" type="tel" class="text" value="" />
</p>

<p>
<label for="email">Email</label>
<input id="email" name="email" type="email" class="text" value="" />
</p>

<p>
<label for="password">Password</label>
<input id="password" name="password" class="text" type="password" />
</p>

<p><input id="acceptTerms" name="acceptTerms" type="checkbox" />
<label for="acceptTerms">
I agree to the <a href="">Terms and Conditions</a> and <a href="">Privacy Policy</a>
</label>
</p>

<p>
<button id="registerNew" type="submit">Register</button>
</p>
</fieldset>

</form>
</div>

[/html]

Note the input types. Instead of only using the usual “name” and “password” I also added “tel” and “email”. Most browsers don’t render anything different here, but it makes a big difference for the user experience on Safari mobile (iPhone and iPad). The key difference is a rearranged keyboard to focus on the type of input. Email adds the @ sign as well as a . button. Also the auto-correct changes so it doesn’t try to split domain names into multiple words.

It looks like a minor difference but it is very frustrating to enter an email address into a text input on the iPhone. Your users will thank you for paying attention to the details.

Older browsers that don’t understand HTML 5 forms will just fall back to input type=”text”. Which is just fine for our purposes. Also each field has class of “text” so that I can style them with the CSS input.text selector. Even though they aren’t all text fields, I do want them to look the same. You could use CSS3 selectors instead, but getting that to work in IE is beyond the scope of this article.

Adding basic styling.

Now to style our form. We are going to start with a very simple reset. Please use something more appropriate to your project.

[css]

/* Add whatever you need to your CSS reset */
html, body, h1, form, fieldset, input {
margin: 0;
padding: 0;
border: none;
}

body { font-family: Helvetica, Arial, sans-serif; font-size: 12px; }

[/css]

Now to style the form container.

[css]

#registration {
color: #fff;
background: #2d2d2d;
background: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0, rgb(60,60,60)),
color-stop(0.74, rgb(43,43,43)),
color-stop(1, rgb(60,60,60))
);
background: -moz-linear-gradient(
center bottom,
rgb(60,60,60) 0%,
rgb(43,43,43) 74%,
rgb(60,60,60) 100%
);
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
margin: 10px;
width: 430px;
}

#registration a {
color: #8c910b;
text-shadow: 0px -1px 0px #000;
}

#registration fieldset {
padding: 20px;
}

[/css]

Here we are using CSS3 gradients to set the background of the container. We are using three different background declarations to accommodate different browsers. First we set a background color of #2d2d2d that all browsers will understand, then we overwrite it for -webkit and -moz to use background gradients instead. Since Internet Explorer doesn’t understand gradients it will ignore them and use the solid color specified first.

You can use this website to generate your own CSS gradients.

Then for the rounded corners we are adding -webkit-border-radius, then -moz-border-radius for the browsers that support it, then adding standard border-radius for when the official spec is adopted in the future (hopefully by IE9).

For the links we are adding a default color, then more importantly adding text-shadow (not supported in IE). The syntax for the text-shadow is this:

[css]

text-shadow: x  y  blur  color;

[/css]

[css]

text-shadow: 0px -1px 0px #000;

[/css]

So we are using that to add a black vertical shadow that gives the text an indented look.

Styling the Input Fields

[css]

input.text {
-webkit-border-radius: 15px;
-moz-border-radius: 15px;
border-radius: 15px;
border:solid 1px #444;
font-size: 14px;
width: 90%;
padding: 7px 8px 7px 8px;
background: #ddd;
background: -moz-linear-gradient(
center bottom,
rgb(225,225,225) 0%,
rgb(215,215,215) 54%,
rgb(173,173,173) 100%
);
background: -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0, rgb(225,225,225)),
color-stop(0.54, rgb(215,215,215)),
color-stop(1, rgb(173,173,173))
);
color:#333;
text-shadow:0px 1px 0px #FFF;
-moz-box-shadow: 0px 1px 0px #777;
-webkit-box-shadow: 0px 1px 0px #777;
box-shadow: 0px 1px 0px #777;
}

[/css]

Here we are adding background gradients again, remember to specify the default for older browsers. The rounded corners also give the fields a nice pill shape.

The new part is that we used a box-shadow to give it a recessed look. The syntax is the same for box-shadow as it is for text-shadow. So box-shadow: 0px 1px 0px #777; is a light colored shadow, with no blur, that is down 1px. This combined with a dark stroke gives it the look below.

Adding Icons.

Next we will add icons to each field so that it is more easily identified at a glance. With CSS3 we are able to use multiple backgrounds to have both a gradient and an image. First create a sprite image of all your icons combined into one file. This will decrease HTTP requests, simplify your markup, and improve page load. An example of the icons I used are on the right.

You will want to replace the earlier code for the input field backgrounds with this new code.

[css]

background: #ddd url(‘img/inputSprite.png’) no-repeat 4px 6px;
background: url(‘img/inputSprite.png’) no-repeat 4px 6px, -moz-linear-gradient(
center bottom,
rgb(225,225,225) 0%,
rgb(215,215,215) 54%,
rgb(173,173,173) 100%
);
background:  url(‘img/inputSprite.png’) no-repeat 4px 6px, -webkit-gradient(
linear,
left bottom,
left top,
color-stop(0, rgb(225,225,225)),
color-stop(0.54, rgb(215,215,215)),
color-stop(1, rgb(173,173,173))
);

[/css]

We are able to add multiple backgrounds by separating each one with a comma. To accommodate the new icons we will also need to change the right padding to 30px.

[css]
padding: 7px 8px 7px 30px;
[/css]

Then specify the background position for each field individually so that it will display the correct icon. The exact values will depend on the icons that you use. Note that the order of the icons in the sprite does not have to match the order of the input fields.

[css]

input#email {
background-position: 4px 5px;
background-position: 4px 5px, 0px 0px;
}
input#password {
background-position: 4px -20px;
background-position: 4px -20px, 0px 0px;
}
input#name {
background-position: 4px -46px;
background-position: 4px -46px, 0px 0px;
}
input#tel {
background-position: 4px -76px;
background-position: 4px -76px, 0px 0px;
}

[/css]

Here the first background-position is for the browsers that don’t support multiple background images, the second is for the gradient position on the browsers that do support it.

Styling the Header & Submit Button

[css]

#registration h2 {
color: #fff;
text-shadow: 0px -1px 0px #000;
text-align: center;
padding: 18px;
margin: 0px;
font-weight: normal;
font-size: 24px;
font-family: Lucida Grande, Helvetica, Arial, sans-serif;
border-bottom: solid #181818 1px;
-moz-box-shadow: 0px 1px 0px #3a3a3a;
-webkit-box-shadow: 0px 1px 0px #3a3a3a;
box-shadow: 0px 1px 0px #3a3a3a;
}

[/css]

Using a bottom border and a box shadow we are able to create an indented separating line without any additional markup.

For the submit button we will use an sprite that has 3 states for :link, :hover, and :active.

You can then use different background positions to shift the image up for each state. This keeps your HTTP requests to a minimum and also prevents a flicker while the browser loads an image for the :hover state.

[css]

#registerNew {
width: 203px;
height: 40px;
border: none;
text-indent: -9999px;
background: url(‘img/createAccountButton.png’) no-repeat;
cursor: pointer;
float: right;
}
#registerNew:hover { background-position: 0px -41px; }
#registerNew:active { background-position: 0px -82px; }

[/css]

Moving Labels Inline with jQuery.

To further style the forms I want to move the label inside the field itself. This technique is largely based on the work from Trevor Davis at Viget Labs.

[html]

<script type="text/javascript">

$(document).ready(function() {
/*
* In-Field Label jQuery Plugin
* http://fuelyourcoding.com/scripts/infield.html
*
* Copyright (c) 2009 Doug Neiner
* Dual licensed under the MIT and GPL licenses.
* Uses the same license as jQuery, see:
* http://docs.jquery.com/License
*
* @version 0.1
*/
(function($) { $.InFieldLabels = function(label, field, options) { var base = this; base.$label = $(label); base.$field = $(field); base.$label.data("InFieldLabels", base); base.showing = true; base.init = function() { base.options = $.extend({}, $.InFieldLabels.defaultOptions, options); base.$label.css(‘position’, ‘absolute’); var fieldPosition = base.$field.position(); base.$label.css({ ‘left': fieldPosition.left, ‘top': fieldPosition.top }).addClass(base.options.labelClass); if (base.$field.val() != "") { base.$label.hide(); base.showing = false; }; base.$field.focus(function() { base.fadeOnFocus(); }).blur(function() { base.checkForEmpty(true); }).bind(‘keydown.infieldlabel’, function(e) { base.hideOnChange(e); }).change(function(e) { base.checkForEmpty(); }).bind(‘onPropertyChange’, function() { base.checkForEmpty(); }); }; base.fadeOnFocus = function() { if (base.showing) { base.setOpacity(base.options.fadeOpacity); }; }; base.setOpacity = function(opacity) { base.$label.stop().animate({ opacity: opacity }, base.options.fadeDuration); base.showing = (opacity > 0.0); }; base.checkForEmpty = function(blur) { if (base.$field.val() == "") { base.prepForShow(); base.setOpacity(blur ? 1.0 : base.options.fadeOpacity); } else { base.setOpacity(0.0); }; }; base.prepForShow = function(e) { if (!base.showing) { base.$label.css({ opacity: 0.0 }).show(); base.$field.bind(‘keydown.infieldlabel’, function(e) { base.hideOnChange(e); }); }; }; base.hideOnChange = function(e) { if ((e.keyCode == 16) || (e.keyCode == 9)) return; if (base.showing) { base.$label.hide(); base.showing = false; }; base.$field.unbind(‘keydown.infieldlabel’); }; base.init(); }; $.InFieldLabels.defaultOptions = { fadeOpacity: 0.5, fadeDuration: 300, labelClass: ‘infield’ }; $.fn.inFieldLabels = function(options) { return this.each(function() { var for_attr = $(this).attr(‘for’); if (!for_attr) return; var $field = $("input#" + for_attr + "[type=’text’]," + "input#" + for_attr + "[type=’password’]," + "input#" + for_attr + "[type=’tel’]," + "input#" + for_attr + "[type=’email’]," + "textarea#" + for_attr); if ($field.length == 0) return; (new $.InFieldLabels(this, $field[0], options)); }); }; })(jQuery);

$("#RegisterUserForm label").inFieldLabels();
});

</script>

[/html]

The line “$(“#RegisterUserForm label”).inFieldLabels();” is what activates the script for those particular labels. Make sure to change the ID if yours is different. I modified the script to add support for the input types “tel” and “email”. If you choose to use others you will need to write those in (near the end of the script).

We are also adding a class of .infield to the labels that need to be restyled. This way if JavaScript is disabled the form will degrade gracefully. Here is the necessary CSS:

[css]

fieldset label.infield /* .infield label added by JS */ {
color: #333;
text-shadow: 0px 1px 0px #fff;
position: absolute;
text-align: left;
top: 3px !important;
left: 35px !important;
line-height: 29px;
}
[/css]

Sometimes the browser auto-complete can interfere with the inline form fields (especially on login boxes). If this is an issue for your site then you can add autocomplete=”off” to the input fields.

Note: We could have used the HTML5 Placeholder attribute instead, but this method works better in older browsers and also I like how it looks better.

How it looks in Internet Explorer

Because we designed first for modern browsers, certain less capable browsers will not be able to display the form in its best possible look. Here is what IE users will see:

Not as pretty, but everything still functions perfectly.

That’s all!

Please ask any questions and give feedback in the comments.

View Demo Download Code