Latest TweetsVerify any search engine or visitor via CLI Forward-Reverse Lookup perishablepress.com/cli-forwar…
Perishable Press

jQuery Hover Swap Text

Things have been busy! I’m working on a new book and site and having a blast. I’ll share more on that later, but for now I just want to get back into posting at Perishable Press. To kick it into gear, here is one of the jQuery snippets I’m using at the new book site.

jQuery Hover Swap Text

There is probably a better way to do this, but I needed a way to swap link text with the title attribute on hover. Nothing fancy, and I thought for sure there would be an easier/existing way of doing this with jQuery, but didn’t see anything so came up with this lil’ snippet:

Note: see the updates appended to this article for better ways of doing this :)
// jQuery hover swap text @ https://perishablepress.com/jquery-hover-swap-text/
function xycss_swap_text(){
	$('a').hover(function(){
		var title = $(this).attr('title');
		var text  = $(this).text();
		$(this).text(title).attr('rel', text).removeAttr('title').wrapInner('<span />');

	},function(){
		var title = $(this).text();
		var text  = $(this).attr('rel');
		$(this).text(text).attr('title', title);
	});
}
$(document).ready(function(){
	xycss_swap_text();
});

Just drop into your JavaScript file and edit the $('a') selector with your choice. Going thru, this is just a jQuery hover function that swaps the contents of the title attribute with the anchor text. I also wrap the hover text with a <span> (for styling purposes), but you can yank that out of there if it’s not needed.

Update

Bryan Watson extends this snippet into more of a plugin format:

(function($){

    // Swap text with title attribute
    $.fn.swapTitleAttr = function() {

        var title = this.attr('title');
        var text  = this.text();

        $(this).wrapInner('<span />');

        $(this).hover(function(){
            $(this).text(title).attr('rel', text).removeAttr('title');
        },function(){
            $(this).text(text).attr('title', title).removeAttr('rel');
        });
    };

})(jQuery);

$(document).ready(function(){
    $('a').swapTitleAttr();
});

As Bryan explains, with this version “the vars are outside of the hover function (and don’t need to be redefined). Plus, it makes the function reusable for any selector with a title attribute.”

Update 2

Jack Rugile refines the previous method even further “with a temporary switch to inline-block with a specified width:

(function($){

    $.fn.txtSwap = function() {
        var $this = $(this);
        var title = $this.attr('title');
        var text  = $this.text();
        var origWidth = $this.width();

        $this.hover(function(){
            $this.text(title).attr('rel', text).removeAttr('title');
            if($this.width() < origWidth){
                $this.css({'display' : 'inline-block', 'width' : origWidth+'px'});
            }
        },function(){
            $this.text(text).attr('title', title).removeAttr('rel');
            $this.css({'display' : 'inline', 'width' : 'auto'});
        });
    };

})(jQuery);
$(document).ready(function(){
    $('a').txtSwap();
});

Check out Jack’s comment for further info.

Update 3

Bryan Watson improves the previous version by making it work with any element and any attribute:

// jQuery Plugin
(function($){

    // Swap text with any attribute
    $.fn.swapAttr = function(attribute) {

        if (!attribute) { var attribute = 'title'; }

        $(this).hover(function(){

            var $this           = $(this);
            var text            = $this.text();
            var attributeValue  = $this.attr(attribute);
            var defaultWidth    = $this.width();

            if (attributeValue) {
                $this.text(attributeValue).attr('data-defaultText', text);

                if(defaultWidth > $this.width()) {
                    $this.width(defaultWidth);
                }
            }

        },function(){

            var $this           = $(this);
            var defaultText     = $this.attr('data-defaultText');

            $this.text(defaultText).removeAttr('data-defaultText').width('auto');
        });
    };

})(jQuery);

$(document).ready(function(){
    $('a').swapAttr();
    $('#link2').swapAttr('rel');
});

Check out Bryan’s follow-up comment for the scoop :)

Update 4

Nukleo further improves the plugin with better chainability:

// jQuery Plugin
(function($){

    // Swap text with any attribute
    $.fn.swapAttr = function(attribute) {

        if (!attribute) { var attribute = 'title'; }

        return this.each(function(){

            $(this).hover(function(){

                var $this           = $(this);
                var text            = $this.text();
                var attributeValue  = $this.attr(attribute);
                var defaultWidth    = $this.width();

                if (attributeValue) {
                    $this.text(attributeValue).attr('data-defaultText', text);

                    if(defaultWidth > $this.width()) {
                        $this.width(defaultWidth);
                    }
                }

            },function(){

                var $this           = $(this);
                var defaultText     = $this.attr('data-defaultText');

                $this.text(defaultText).removeAttr('data-defaultText').width('auto');
            });

        });
    };

})(jQuery);

$(document).ready(function(){
    $('a').swapAttr().css({'color':'#ccc'});
    $('#link2').swapAttr('rel');
});

Check out Nukleo’s comment for more info.

Update 5

Martin tweeted this alternate way of swapping text using only CSS:

“@perishable I once did it by using the CSS display property (inline & none). An example is on my website’s sidebar.”

Update 6

No idea why I didn’t think of this before.. but after reading martin’s tweet about using CSS, I remembered that swapping anchor text with title text is easily accomplished with CSS by combining the content property and attr() selector:

a:hover { content: attr(title); }

The jQuery method are far more flexible, but for simple cases, this should do the trick just fine.

Better way?

Drop some hints if you know an easier way of doing this — I’m sure there’s a better way :)

Jeff Starr
About the Author Jeff Starr = Creative thinker. Passionate about free and open Web.
Archives
14 responses
  1. Matt Zimmermann December 12, 2011 @ 12:24 pm

    A nice and simple function. Thanks Jeff.

  2. Look good so far Jeff.

    Just thinking about extending this snippet into more of a plugin format, you could set it up like so:

    http://jsfiddle.net/f4hNB/2/

    That way the vars are outside of the hover function (and don’t need to be redefined). Plus, it makes the function reusable for any selector with a title attribute.

    • Jeff Starr

      Excellent — this is why I like to post code snippets — always a better way =)

      Article updated with this new version. Thanks Bryan :)

    • Glad I could help!

      I’m sure there is more optimizations that could be done. You could strip away the span wrap, as well as not adding the ‘rel’ attribute as that wouldn’t provide any real semantic or SEO benefits.

      This would probably be cleanest solution:
      http://jsfiddle.net/f4hNB/3/

      For styling you could simply target a:hover instead of adding extra markup or classes/ids.

  3. Pretty cool effect, Jeff.

    I modified Bryan’s plugin slightly. I noticed weird things happening when the title swap text was shorter than the original text. If you hovered on the text from the right side, the change would occur, but then you would lose hover instantly, and it would snap back.

    For inline links, you probably don’t want that snap to happen, and probably don’t want the rest of the text to reflow (unless it is needed when the title text is longer than the original text).

    This jsFiddle addresses that issue with a temporary switch to inline-block with a specified width: http://jsfiddle.net/jackrugile/Wk7e6/

    • After looking at Jack’s update (Nice job Jack), I actually found another silly bug in the code. It was revealed when I put multiple elements on the page. Simple scope issue.

      I’ve fixed the bugs and enhanced my own (and Jack’s) plugin. Now it will work with any element and any attribute, at the same time fixing the width-on-hover bug if the swapped text is shorter than the default text.

      http://jsfiddle.net/f4hNB/5/

  4. This is a cool little plugin but it breaks chainability. I updated Bryan’s jsfiddle code to fix that (and added a color change to show that chainability works now) : http://jsfiddle.net/f4hNB/12/

  5. Very cool fellas!

    I’m a newbie but impressed with this kind of sizzle. So, what does this do for a site? Why would you do it? Does it not slow down the load time of a site (read somewhere that this is bad for ranking).

    It would be really helpful for us less educated folks if you could discuss the “why” for this sort of thing.

    Keep up the great work!

    Kief

  6. Jeff Starr

    Article now updated with these improvements. Also gonna mention some CSS alternatives that people have mentioned (on Twitter).

    Thanks guys for your help! :)

  7. Shadow Caster December 14, 2011 @ 5:16 am

    Really cool article thank you. Note, the awesome css trick at the end (update 6) won’t work with FF 3.6 and below nor IE8 and below. I haven’t tried IE9 or a newer FF.

  8. Bharat Chowdary December 27, 2011 @ 11:35 pm

    Awesome, it good it includes all those improvements as Updates, need a bit of patience to do that. Also, this shows how you care for your blog readers. Thanks Jeff.

  9. Martin C├ęsare December 29, 2011 @ 1:30 pm

    It was quite a surprise to see my tweet as an option in this conversation. It feels good! :-)

  10. Eric Schwarz December 31, 2011 @ 9:55 am

    Definitely off topic… but why do you disable comments after so many days? I can see some potential problems it fixes but at the same time creates even more. The whole reason I bring it up is because I want to say how you witch from Firefox to Chrome bothers me because everyone is jumping ship to something I know that is flawed right now. I keep running into problems where chrome displays CSS differently, and for me that very upsetting. Also if you visit my free WordPress theme at adventure.schwarttzy.com you will see that the CSS3 shading trick preform very poorly in Chrome but perfectly in FireFox.

    Hopefully you enjoyed my two cents, and again sorry for being off topic.

[ Comments are closed for this post ]