Reader Jaime Morrison emailed in:
I’ve been mulling the idea of going with a link style in which a link’s underline “slides-up” to become a background highlight on hover.
I started mulling over a few ideas on how to do this myself. Ultimately, I tried two different things but neither one of them is absolutely perfect.
Take One
We know we’re going to be using jQuery here (or some JavaScript library), because of the animation. My first though was to set relative positioning on the links, then use jQuery to append empty <span>’s to each link. The span would be 1px tall (like an underline), be absolutely positioned 1 pixel down from the bottom, and have a width of 100% (as long as the link). Then on hover, you would animate the height of the span to the line-height.
$(function() {
var $el = $(),
linkHeight = parseInt($("p").css("line-height")),
speed = 175; // 1000 = 1 second
$("#first a").each(function() {
$el = $(this);
// If the link spans two lines, put a line break before it.
if ($el.height() > linkHeight) {
$el.before("<br />");
}
$el.prepend("<span></span>");
}).hover(function() {
$el = $(this);
$el.find("span").stop().animate({ height: linkHeight, opacity: 0.3 }, speed);
}, function() {
$el = $(this);
$el.find("span").stop().animate({ height: "1px", opacity: 1 }, speed);
});
});
As it turns out, this kinda works, but it’s littered with little weird problems and cross browser inconsistencies. For example, what if a link breaks into two lines? The span certainly wouldn’t work in that case. So I tried to fix it by first measuring the height of the link and if that was higher than the line-height (like it would be if it’s two lines), then insert a break before it, so it’s all on one line. Works, but it can create some weirdly ragged paragraphs.
Other more major problems: no version of IE will animate the span up properly. The span will always sit on top of the text, so it needs to be have opacity for the text to be readable. I tried wrapping the text in an <em> and fighting it with z-index, but no dice. And even in Firefox, a link that begins a new line, for whatever reason, doesn’t want to work.
So, Take One is a flop…
Take Two
The biggest problem it seemed to me with Take One was the multi-line links. In trying to think of a way to solve that, it seemed like using the actual background property of the link would be the best way to go.
In this take, I created a big block of red color as an image. I set that as the background to the link, but pushed it down using background positioning. I set the overflow on the links to hidden, and pushed down that background just far enough that only a sliver showed through. Then on hover, the background position is animated to pull it back up underneath the entire link.
$(function() {
var $el = $(),
speed = 175; // 1000 = 1 second
// SECOND TECHNIQUE
$("#second a").hover(function() {
$el = $(this);
$el.stop().animate({ backgroundPosition: "(0px 0px)", color: "white" }, speed);
}, function() {
$el = $(this);
$el.stop().animate({ backgroundPosition: "(0px 15px)", color: "#900" }, speed);
});
});
One of the concerns with this technique is how different browsers handle line-height. If I set up the underline to be 1px tall in Firefox, many browsers (e.g. WebKit) show no underline at all, as apparently the line-height is one less pixel tall and thus the entire background image is hidden. As such, I made it 2px tall in Firefox, and then WebKit showed it as 1px. Inconsistant, but it works.
This would be a “perfect” solution, except IE 7 cludges links that are multi-line or the begin a new line, covering the entire link in background from the start. IE 8 gets it right.
So in the end, neither one of these is totally perfect. If you have an alternate solution to this “underline animates up to be a background on hover”, let me know.
You can see the demos here.
UPDATE
As suggested by a few people, I added a Technique #3, which is an adaptation of #2. The links now have bottom borders of 1px (border color and background color match), and the background slides up from a greater distance away, which should solve the IE 7 issue.
Ohh nice. A jQuery challenge :) Will let you know if I succeed :)
Actually, i give up :) I tried something but ended up with same thing you had in the second example, i think that’s the best as it can get.
Haha! You suck!
I look forward on seeing your solution…
Neat effect.
Will try :)
I really like the effect of Take Two – looks very slick!
Very sexy effect :)
Not a big fan to be honest, I think it looks rather tacky and not particularly smooth. I admire your efforts though, good job.
When I read it, I thought it sounded pretty cool. But I agree with Sam; the (working) demo just makes it look a bit amateurish. Dunno why.
yep… it takes me back to the vernacular days of html for some reason, when animated gifs and rolling marquis governed the land and if a trick was available/discovered, it had to be used. with that said, however, clients love this stuff. so i’ll save this for one of those days when i absolutely can not convince a client that less is more.
After a couple quick attempts I couldn’t come up with anything that beats either option. In the few tests I ran option #2 seems the most reliable.
I will agree with Sam though that it’s not a very pretty effect. Maybe if the change was subtle enough and worked with the design. Not something I think I will ever find a use for.
Anyhow it was a fun experiment and I wish I had more time to play this morning. Something to come back to for sure.
As a modification to Take Two, you could try using an actual bottom border on the link, completely hide the background image, then slide it up on hover.
Make the bottom border the same color the same color as the background image (for the illusion) and hopefully you’ll avoid the Firefox/WebKit discrepancies this way.
Still not perfect but I thought I’d throw that out there.
I think that’s the ticket. I’ll give it a shot when I can.
If this is Technique #3, FYI it doesn’t work in Chrome.
Sorry, must have caught the page in the addition of the code. Working fine now. Please delete this and above comment. :)
Chrome is fine for me.
//Offtopic: Chris – you’re highlighting for yourself on comments is lost when you reply in an indented conversation.
@Mayo errr.. no it’s not!
Though I don’t see it as an issue in the demo, my first thought when I read ‘border’ is the box model.
Usually a border is outside the box model, but does have effect on the page, so the a line with link would take up 1px more, right ?
If that’s true, then an
outline
seems more appropiate.—
Gringer
PS: I think in the article you ment to write “first thought”, instead of “first though”. Only 1 letter added, but a different word ;-)
[OOT] Chris, can you give CSS tutorials related to usability and accessibility, thanks before.
Nice effect!!!
I know the take 1 was classed as a flop but i really like the transparent effect, i think the solid image block doesn’t look very nice :/
I think I will have a play around with this and get the same effect but too work on multilines! Im still in the mood for using the shift up 1px link atm though :p
I’ve seen this done so elegantly by a jquery/css guy on his blog, but I’ve been looking for a half hour and can’t find his site. The effect was exactly like you described, with an underline that grew into a gorgeous rounded-cornered box.
If anyone knows the site I’m talking about I’d love to hear from you!
Gimmicky. Less is more when it comes to something as simple as hyperlinks. What’s next, blinking backgrounds?!?
@Chris – hmmm.. Add some sound, then will be a perfect solution. Please think about this. Best regards!
And if it’s sound effects from the first Doom game it would be more than perfect!
you don’t need the dollar sign in front of your variables. and what is this? $el = $(),
that variable seems to carry no meaning?
A lot of developers prepend a “$” on any variable which has a jQuery collection of elements.
I declare it once at the top, so I don’t have to re-delcare it with var = in each instance below. Seems to make sense to me, but if there is a better way please enlighten.
And Austin is correct, I like putting the $ on variables I intened to be a group of elements rather than just a value.
Doing $el = $() needlessly queries the DOM and returns an empty jQuery object. Since you’re redefining $el before you even use it, this doesn’t make a whole lot of sense.
Doing something like var $el, speed = 175; is probably want you want and will be more performant.
Yes, but you are declaring AND assigning it to nothing. A Simple declaration will do.
var $el;
Great, thanks for the clarification. I didn’t know you could delcare a variable without assigning it. Not much a programmer, you see.
Then you might want to read the book “JavaScript, the Good Parts”, and find out more about the cool parts of the JavaScript language, though the book does not talk of the DOM.
Good site none-the-less.
Yeah. Kinda choppy and distracting. Especially when the links fall on two lines.
Creative though.
I quite like the effect, maybe it looks a little tacky because of the colors used. I think subtle coloring would probably work better. Nice little experiment though Chris I can see a few people adopting it.
Chris, all this talk about links lately. I wondering how you were able to get the underline on your hover events to be a different color then the text itself? Sorry this is slightly off topic.
Has anyone tried this in the old crappy IE6? I use border-bottom on my links and when viewed in IE6 they don’t appear. Not that I am worried about the borders or anything but it seems that it wouldn’t work for this. I don’t have IE6 installed but unfortunately people are still using it.
Hi Chris!
Your script is a little bit buggy. Visited Links will be displayed in white.
On a white Background a nice Effect :-)
Can anyone solve the problem?
When you increase text size (using the browser View Zoom tool) the #2 solution increases the width of the bottom border on the links which looks really ugly.
#1 and #3 are fine though…
Wonderful tutorial… I will tried it
If you wanted to be completely insane, you could combine it with the CSS3 background-gradient (see http://snook.ca/archives/html_and_css/multiple-bg-css-gradients) feature to remove the need for an image.
You’d need to set several gradient stop levels that moved the desired background colour up/down by certain pecentages.
Please leave our link styles alone, thx.
Interesting stuff! Technique #3 is the only one that works well when you increase the font size.
With the easing plugin this could make for an extremely fancy main navigation. I’ll drop a post here if I try it sometime.
Interesting effect, I am going to work on #3 as that one looks promising. Thnaks for the share.
Good tutorial you are amazing
Nice work, but remember, you should always bind to the focus event as well. Not everyone uses a mouse to navigate…
Nice idea for an effect. I wouldn’t use it on all the links though. It could be cool for some “call to action” links etc. Joe McCann has a good point about binding it to the focus event as well.
yes on technique e works in ie6 and firefox 2
yes only technique 3 works in ie6 and firefox 2