Cleaning up the “CSS only sexy bookmark” demo code
Going through my Google Reader I stumbled upon an article today called “Sexy bookmark like effect in pure CSS“:http://www.webdeveloperjuice.com/2009/12/15/sexy-bookmark-like-effect-using-pure-css/. Normally when I hear “pure CSS” I skip as 99% of these solutions don’t work with a keyboard and are thus a bad idea to use on the web. However, this one intrigued me as I had no clue what a “sexy bookmark like effect” might be.
Turns out it was not a porn bookmark but one of those “share this with the social media” link-bars you have below blog posts to help the copy and paste challenged people out there:
OK, that can’t be that problematic. The trick to do a list of links as a cool rollover using CSS only has been done in 2004 in the first CSS sprites article. Notice that the links are in a list.
Now, the new article’s HTML is the following:
<div class="sharing-cl">
<a class="sh-mail share-sprite" href=""> </a>
<a class="sh-feed share-sprite" href=""></a>
<a class="sh-tweet share-sprite" href=""></a>
<a class="sh-face share-sprite" href=""></a>
<a class="sh-su share-sprite" href=""></a>
<a class="sh-digg share-sprite" href=""></a>
</div>
There are a few things wrong with this in my book:
- There is no semantic structure of what is going on here. Line breaks do not mean anything to HTML so in essence this is a list of links without any separation. Imagine sending three links to a friend in an email or putting them on a page. Would you do it like this: GoogleI can has cheezburgerb3taSpotify ? looks confusing to me…
- There is no content in the links – when CSS is turned off you find nothing whatsoever.
- There is quite a repetion of classes there. When every element in another element has the same class in it then something fishy is going on. Unless this class is used as a handle for – let’s say a microformat, you can get rid of it and use the cascade in CSS. So in this case you can style all the links with
.sharing-cl a{}and get rid of the repeated classes. - A navigation is a structured thing, so instead of a div with links in it, how about using a list? This way when CSS is off, this still makes sense.
So here’s my replacement:
<ul class="sharing-cl">
<li><a class="sh-mail" href="">email</a></li>
<li><a class="sh-feed" href="">feed</a></li>
<li><a class="sh-tweet" href="">twitter</a></li>
<li><a class="sh-face" href="">facebook</a></li>
<li><a class="sh-su" href="">stumbleupon</a></li>
<li><a class="sh-digg" href="">digg</a></li>
</ul>
Of course you should replace the empty href attributes with the real links.
Normally I’d use IDs instead of classes, but as this bar might be used several times in the document, let’s leave it like it is.
The HTML now is 318 bytes instead of 294 which is a slight increase. But:
- It makes sense without CSS
- It is well-structured and makes sense even to screen readers
- The links make sense as they say where they are pointing to.
Let’s check on the CSS:
.sharing-cl{
}
.sharing-cl a{
display:block;
width:75px;
height:30px;
float:left;
}
.sharing-cl .share-sprite{
background:url(http://webdeveloperjuice.com/demos/images/share-sprite.png) no-repeat}
.sharing-cl .sh-su{
margin-right:5px;
background-position:-210px -40px;
}
.sharing-cl .sh-feed{
margin-right:5px;
background-position:-70px -40px;
}
.sharing-cl .sh-tweet{
margin-right:5px;
background-position:-140px -40px;
}
.sharing-cl .sh-mail{
margin-right:5px;
background-position:0 -40px;
}
.sharing-cl .sh-digg{
margin-right:5px;
background-position:-280px -40px;
}
.sharing-cl .sh-face{
background-position:-350px -40px;
}
.sharing-cl .sh-mail:hover{
margin-right:5px;
background-position:0 1px;
}
.sharing-cl .sh-feed:hover{
margin-right:5px;
background-position:-70px 1px;
}
.sharing-cl .sh-tweet:hover{
margin-right:5px;
background-position:-140px 1px;
}
.sharing-cl .sh-su:hover{
margin-right:5px;
background-position:-210px 1px;
}
.sharing-cl .sh-digg:hover{
margin-right:5px;
background-position:-280px 1px;
}
.sharing-cl .sh-face:hover{
background-position:-350px 1px;
}
So here we have a lot of repetition. You also see where the share-sprite class comes in: if you wanted to add an element to that section that is a link but has no image background you just leave out the class. This, however is exactly the wrong approach to CSS. We can assume that every link in this construct gets the background image, which is why it makes more sense to apply the image to the a element with .sharing-cl a{}. As every link has a class you can easily override this as the “odd one out” with for example .sharing-cl a.plain{}.
The same applies to the margin-right:5px. If that is applied to all the links but one, don’t define it for all the others and leave it out at the “odd one out”. Instead, only apply it to the odd one out and save a lot of code.
Final CSS:
.sharing-cl{
overflow:hidden;
margin:0;
padding:0;
list-style:none;
}
.sharing-cl a{
overflow:hidden;
width:75px;
height:30px;
float:left;
margin-right:5px;
text-indent:-300px;
}
.sharing-cl a{
background:url(http://webdeveloperjuice.com/demos/images/share-sprite.png) no-repeat;
}
a.sh-su{background-position:-210px -40px;}
a.sh-feed{background-position:-70px -40px;}
a.sh-tweet{background-position:-140px -40px;}
a.sh-mail{background-position:0 -40px;}
a.sh-digg{background-position:-280px -40px;}
a.sh-face{
margin-right:0;
background-position:-350px -40px;
}
a.sh-mail:hover{background-position:0 1px;}
a.sh-feed:hover{background-position:-70px 1px;}
a.sh-tweet:hover{background-position:-140px 1px;}
a.sh-su:hover{background-position:-210px 1px;}
.sh-digg:hover{background-position:-280px 1px;}
a.sh-face:hover{
margin-right:0;
background-position:-350px 1px;
}
From 1028 bytes down to 880. Just by understanding how CSS works and how the cascade can be used to your advantage. I would have loved to get rid of the a selectors, too, but they are needed for specificity. Notice the overflow on the main selector – this fixes the issue of the floats not being cleared in the original CSS. By using negative text-indent we get rid of the text being displayed, too. Personally I think this is bad and you should try to show the text as you cannot expect end users to know all these icons.
For example:
#text{
margin-top:3em;
font-weight:bold;
font-family:helvetica,arial,sans-serif;
}
#text a{
text-indent:0;
height:auto;
text-align:center;
font-size:11px;
padding-top:35px;
color:#999;
text-decoration:none;
}
You can see the solution in action here:
To me, praising “CSS only solutions” is not enough – if you really love CSS and see it as a better solution than JavaScript then you should also show how people can use its features to create smart, short and flexible code.
Tags: accessibility, bestpractice, cascade, code, css, tutorial, usability




January 8th, 2010 at 3:28 pm
Thanks for highlighting some of these issues. It’s a real shame that people who write good semantic markup (that doesn’t depend on scripted behaviour) drop in widgets like these that undo all of their hard work. This article is a nice reminder that we don’t have to feel excluded, when we can spent 10 minutes tweaking things for the better.
January 8th, 2010 at 3:31 pm
Good point, great example.
One more optimization – you can omit the
margin-right:0;rule ina.sh-face:hover{}, since you already specified that fora.sh-face{}.This reminds me of the old semver.org, which used a CSS framework just to get a very basic layout. I rewrote it without the framework, and these were the results:
January 8th, 2010 at 3:35 pm
hi,
can you explain why you need overflow:hidden on both the UL and A elements?
thx.
January 8th, 2010 at 3:42 pm
As a precaution to seeing the picture repeat.
January 8th, 2010 at 3:48 pm
Excellent response and write-up. Articles like this help clear up the sub-par examples as shown at the original source, and are needed to help people realize there are better (even right/wrong) ways to structure ‘widgets’ like this.
January 8th, 2010 at 4:00 pm
I assume the overflow:hidden is used to clear the floats. overflow:hidden is the new .clearfix. Additionally, in this example, it’s hiding the text…
January 8th, 2010 at 6:19 pm
I did all code in hurry and missed these simple 10 mins tweaks. You did everything very calmly with good concentration.
Thanks for nice clean up. Action appreciated
But still i have some questions :
1. Why you have used .sharing a {} twice when it can be done in once?
2. I found no “id=text” in your code while your CSS says #text{}
3. Why overflow:hidden is used when image is in background? Repetition of image is not possible if width is defined.
January 8th, 2010 at 6:46 pm
OK, first to the points:
1) Good point, this is another optimisation
2) There is none in this post, but on the demo page: “http://isithackday.com/demos/sharing.html”:http://isithackday.com/demos/sharing.html
3) To hide the text of the links. Try it out yourself. If you don’t set the overflow you need to use a ridiculously large text offset to hide it.
To your “code in a hurry” that is an excuse when you build a web site but not when you do a tutorial. Our demo code should be the best we ever write in our lives as this is what people will copy and paste and use without understanding it.
I covered this in detail in the developer evangelism handbook:
January 8th, 2010 at 7:10 pm
RT @codepo8 Cleaning up the “CSS only sexy bookmark” demo code: [link to post] – if you advocate CSS, use its powerful features…
– Posted using Chat Catcher
January 9th, 2010 at 5:30 am
Due to all the overflow:hidden, this keyboard user is left a bit in the cold. When the links are focussed, there is barely any feedback anymore (a small vertical strip of focussing ring is left, the rest is clipped). Doing the same for :focus as what you do for :hover would be friendly.
January 9th, 2010 at 5:09 pm
Very nice, but definitely could use some css transitions. :)
January 11th, 2010 at 12:21 pm
I’m glad to see good coding practises and a level-headed approach to CSS coding in this post. Normally I find so many so much superfluous code in CSS articles the whole thing becomes bloated. All too often people will resort to using non-semantic html which looks terrible when you disable CSS or Images but this works nicely for me. I’m getting tired of people coming up with javascript solutions for things that can be done less intrusively.
Keep up the fine work.
January 31st, 2010 at 12:27 pm
I’m glad that everyone is finding more efficient ways to accomplish the same thing, it’s great really… I just wish that everyone who puts down the developers of plugins and “drop in widgets” for inefficiency could try to understand the fact that we develop for the masses… Not for individuals.
If I only had to develop something to work on a single specific site, then I wouldn’t have to write 500,000 lines of CSS to accomplish something that could be done with just about 1,000 lines…
I have to make sure that every single possible conflict, failure, or other such headache is covered in the plugin, otherwise I’d be inundated with support requests by angry people telling me that my plugin sucks and doesn’t work.
Whereas, if I were writing it to work on a specific site, I could completely do away with about 90% of the checks and failsafes that are in place due to the fact that I would know for certain that the very minimum would make it work.