You Are Browsing: HTML5

19th Jul

CSS3/HTML5 animated image tooltips

I’ve got a project coming up where, as part of a site rebuild, I would be replacing some old flash content with some updated and more semantic HTML5. The Flash content in question was a product image that had several icons on it, which when hovered would display a bit more information about that area of the product. As well as the fact this would then make the content accessible to devices such as the iPhone which don’t support Flash, it also makes the content easier to update using a CMS such as WordPress.

Here’s my recreation of this using HTML5 and CSS3. Please note this is just for demonstration purposes’ only, and the image is copyright to Chris Polack.

Ok, let’s check out some code! Here’s the HTML…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<section id="wrapper">
    <article>
        <h1>Image with pure CSS animated tooltips</h1>
        <figure>
            <a href="#" class="caption one">
                <aside>This is a dog, woof woof woof!</aside>
            </a>
 
            <a href="#" class="caption two">
                <aside>Check out this dudes haircut.</aside>
            </a>
 
            <a href="#" class="caption three">
                    <aside>Graffiti, ten points if you can read what it says.</aside>
            </a>
 
        <figcaption>Hover the <span class="dot">dot</span> for information.</figcaption>
        </figure>
    </article>
</section><!-- /#wrapper -->

So, reasonably straight forward… We’re using the new HTML5 figure element to wrap the whole image, and the new figcaption element for the main caption. I was going to use figcaption for all the captions but the HTML5 spec states that each figure should only have one figcaption. I decided to use another new element aside, for the pop-out captions as it seemed the most semantically appropriate: secondary content that is related to the main content. These are wrapped in anchor tags (using anchors to wrap block level elements is allowed and validates in HTML5).

Then on to the CSS…

1
2
3
4
5
6
7
section,
article,
aside,
figure,
figcaption {
    display:block;
}

First we run a quick reset to ensure our new elements will be displayed how we want them, and then the rest of the CSS…

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
article {
    width:760px;
    margin:0 auto;
}
figure {
    background: url(img/tooltips.jpg) no-repeat;
    width:760px;
    height:500px;
    position:relative;
    margin:0;
    padding:0;
}
h1 {
    color:#fff;
    font-weight:normal;
}
a {
    position:absolute;
}
a:before {
    content: "";
    display:block;
    position: relative;
    top: 23px;
}
a:before,
span.dot {
    height:10px;
    width:10px;
    background:orange;
    border-radius:5px;
    vertical-align: middle;
}
span.dot {
    text-indent:-9999px;
    display:inline-block;
}
.caption.one {
    top: 210px;
    left: 305px;
}
.caption.two {
    top: 210px;
    left: 680px;
}
.caption.three {
    top: 360px;
    left: 330px;
}
a {
    width:174px; /*10px extra for dot, 10px for arrow, 4px for box-shadow */
    overflow:hidden;
    text-decoration:none;
    color:#333;
    font-size:12px;
}
a aside {
    background:#fff;
    padding:10px;
    width:130px;
    border-radius:4px;
    position:relative;
    margin:0 0 4px 0; /*to show box shadow*/
    box-shadow: 2px 2px 4px rgba(0,0,0,0.5);
    right:200px;
    opacity:0.0;
    -webkit-transition: all 0.2s linear;
    -moz-transition: all 0.2s linear;
    -o-transition: all 0.2s linear;
}
a aside:before {
    content: "";
    position: absolute;
    left: -8px;
    top: 10px;
    border-top:8px solid transparent;
    border-right:8px solid #fff;
    border-bottom:8px solid transparent;
    display: block;
    width: 0;
    height:0;
}
a:hover aside {
    right:-20px;
    opacity:1.0;
}
figcaption {
    background:#000;
    background:rgba(0,0,0,0.8);
    position:absolute;
    bottom:0;
    padding:10px;
    color:#fff;
    width: 740px;
}

So, there’s quite a bit going on there, but there’s only a few key points to look at.

  1. The orange dots are created with a :before pseudo class on the anchor‘s.
  2. The parent figure element is has relative positioning, allowing for it’s child anchor elements to be positioned absolutely.
  3. The anchor‘s have an explicit width set, and are set to hide the overflow.
  4. The asides are positioned relatively, hiding them from view, this position is then changed (and animated with CSS3 transitions) when the anchor is hovered.
  5. The arrows on the side of the captions are based on a CSS technique by Nicolas Gallagher using pseudo elements.

So far this works in all the modern browsers… but, using Modernizr we can get the same animated experience in older versions on internet explorer too. I grabbed a customised version, containing a basic HTML5 Shim and feature detection for CSS3 transitions.

1
2
3
4
5
6
7
<script src="modernizr.js"></script>
	<script>
		Modernizr.load({
			test: Modernizr.csstransitions,
			nope: ['http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js', 'animate.js']
		});
	</script>

I loaded in the script the my page head, and using Modernizr‘s built in Yep Nope library we can choose to load further resources based on browser support. Here we test if the browser supports CSS transitions, if the answer is no, we then load in a Google CDN copy of jQuery and our own animation file…

1
2
3
4
5
6
7
$(document).ready(function() {
	$('figure a').hover(function(){
				$(this).find('aside').animate({right:'-20px'},{queue:false,duration:500});
			}, function(){
				$(this).find('aside').animate({right:'200px'},{queue:false,duration:500});
			});
});

…which effectively does exactly the same as the CSS transitions. Tested in IE8 and works fine.

So thats that! I’d love to hear any suggestions of how the semantics or markup could be improved or if you find somewhere to put this to use! This could also be taken further, if necessary to force IE support for border-radius and box-shadow, but I’m perfectly content with old browsers seeing little orange squares rather than circles, as long as the interaction still works.

Here’s my demo.

20th Jun

HTML5 Webforms — Placeholders

Part of the HTML5 Forms spec that is already being implemented in many browsers is the ‘Placeholder’ attribute.

Like many things in the HTML5 spec, this comes from what people are already doing, in this case with things like the jQuery Watermark Plugin. It creates light grey text in text input boxes giving the user direction to what and how data should be entered. This is especially useful in giving direction on how to enter things like dates in more complex web forms.

For example:

1
2
<label>Date of Birth</label>
<input type="text" name="DOB" placeholder="dd/mm/yy">

There’s also lightweight and robust JS plugins available to force support of the placeholder attribute in older browsers.

The HTML5 spec states:

The placeholder attribute should not be used as an alternative to a label.

This is definitely important for most custom and/or complex forms, but I think for something simple like a search input the label really isn’t necessary. I decided to take this further on this site with the WordPress comments form, which are very ubiquitous across the web and familiar to users, you can get away losing the labels and simply using placeholders. It simplifies the form and removes visual clutter.

I decided to do this with the comments on this site, but I wanted to make sure that users definitely have JS enabled, forcing the placeholder, before removing the labels. I also wanted to avoid editing the core WordPress comments markup to I opted to add the place holders with jQuery.

Warning! The label element is still needed, especially to disabled users who might be using screen reader software. It is still an important semantic piece of the mark-up and we want to make sure it isn’t ignored by screens readers by using techniques like

1
label {display:none;}

…Instead I opted for

1
label {position:absolute; right:9999px;}

which visually hides it off the screen but is still readout by screen readers.

Here’s the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//Lets HTML5 awesomify the respond inputs
jQuery('#respond #author')
	.attr('placeholder', 'John Smith *');
jQuery('#respond #email')
	.attr('placeholder', 'hello@example.com *');
jQuery('#respond #url')
	.attr('placeholder', 'www.yourwebsite.com');
jQuery('#respond #comment')
	.attr('placeholder', 'Well hello there! *');
//Then get rid of the labels...
jQuery('#respond label, #respond span.required').css({
	position: 'absolute',
	right: '9999px'
});

Worth considering: a growing user trend is the use of the tab key to move focus between inputs. As soon as focus is set on the input the placeholder text is removed (which is good because the user doesn’t have to delete it themselves). What this does mean is that they can no longer see what they meant to be entering! In this context of something so familiar I felt the trade off of visual simplicity vs usability was worth it.

Wooooah there buddy!