Making Better Forms with only CSS using :focus and :checked pseudo classes

A lot of people like to style their forms with javascript, and why not, its the most common way to handle user interaction on any website. But there’s another way too. Using the :focus and :checked pseudo classes, along with some other less common CSS syntax, you can make really interesting forms with all the same user ineraction that would normally come from javascript. Take a look at this form below which is has no javascript, and without looking at the source code, see if you can figure out how I did this.

Must contain a number

So what did I do here? There’s a few things going on. First, when you click on the “Password” text field, you get a nice styling with the box shadow which is simple enough, but you also get extra password hint text that appears below it. With the check box, you should notice two things. First, I’m using a custom check box which is actually an image instead of the browser default, and second that we also have an additional text field that appears when we check the box. And believe it or not, all of the styling takes up less lines of code than someone would typically use if they were using javascript. Lets take a look at the source code and go through it line by line.

<form>
<label for="password">Password</label>
<input name="password" id="password" type="text">
<p>Must contain a number</p>
<label for="thecheckbox">Do you have a website?</label>
<input name="thecheckbox" id="thecheckbox" type="checkbox">
<div>
<div>
<input type="text" placeholder="url">
</div>
</div>
</form>

<style>
input[type="text"] + p {visibility:hidden;}
input[type="text"]:focus + p{visibility:visible}
input[type="checkbox"]{opacity:0; position:relative; z-index:10;}
input[type="checkbox"] + div {background:url(check_box.png) no-repeat 167px 0px;padding:10px; position:relative; top:-17px}
input[type="checkbox"]:checked + div {background:url(check_box_checked.png) no-repeat 167px 0px;padding:10px; position:relative; top:-17px}
input[type="checkbox"] + div div{visibility:hidden; margin-top:10px;}
input[type="checkbox"]:checked + div div{visibility:visible}
</style>

Thats not too traditional of CSS now is it? Many of you are probably looking at this trying to figure out exactly what the “+” does. It’s actually quite simple what I’ve done here. The HTML is pretty straight forward. I have some labels and input fields, a paragraph and two divs at the end. Now for the CSS

input[type="text"] + p {visibility:hidden;}
input[type="text"]:focus + p{visibility:visible}

The “+” selector is a little less known, but fully supported by browsers. In this case, its used to select the “p” tag that comes directly after the text field. The “+” is known as an adjacent selector, and it will select only the element that comes immediately after the former element. So for h1 + p only 1 “p” will be selected (for each h1), and only the first one after an “h1”. The :focus pseudo class is somewhat self explanitory… So what I’ve done in these first two lines, is I hide the paragraph, unless the text field is in focus.

input[type="checkbox"]{opacity:0; position:relative; z-index:10;}
input[type="checkbox"] + div {background:url(check_box.png) no-repeat 167px 0px;padding:10px; position:relative; top:-17px}
input[type="checkbox"]:checked + div {background:url(check_box_checked.png) no-repeat 167px 0px;padding:10px; position:relative; top:-17px}

The first thing I do here is make it so that the checkbox is invisable to users, but still completely exists in the DOM. I also give it a z-index of 10 to put the invisable checkbox ontop of the image that will be shown. So users will think that they’re clicking on the image, but really are clicking on the checkbox as usual. Again I use the “+” selector to select the first div that comes directly after the checkbox, I give it the image that looks like a typical checkbox, and position it exactly where the now invisable checkbox lies. Again, the :checked pseudo class is pretty self explanitory, and when its checked, I’m changing the image in the div to be an image of a checked box. And no I didn’t use a sprite here although I could have, but I just wanted to keep the syntax as simple as possible for this demonstration.

input[type="checkbox"] + div div{visibility:hidden; margin-top:10px;}
input[type="checkbox"]:checked + div div{visibility:visible}

If you’ve been following along this whole time, then this last part should make sence by now. I select the div, inside the div, that comes directly after the checkbox. Give it a margin to position it correctly, and hide it, unless the person checks the box.

I would love to see what interesting things you can do with the :focus and :checked pseudo classes. Please feel free to post links below in the comments of some some examples that you’ve come up with, but no javascript allowed! (If you dont want to post your own sites you can always use jsfiddle.net)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>