Grow your CSS skills. Land your dream job.

Play Sound on :hover

Published by Chris Coyier

When you google around for how to play a sound with CSS, you'll find:

  1. Some stuff about Counter Strike: Source
  2. Some stuff about play-during and cue-before and stuff that looks promising but really it's for aural stylesheets (accessibility / screen reader stuff) not just how to make donkey grunts when you roll over a menu item in any ol' browser

I'd argue that sounds are part of design and thus the ability to play/trigger it belongs in CSS, but alas, we're not there yet. To play sounds when the mouse goes over a certain area, we're going to need to rely on HTML5 or Flash. But nobody around here wants to deal with Flash right? So let's do it with HTML5, which can play sound through its <audio> element (Firefox 3.5+, Chrome 3+, Opera 10.5+, Safari 4+, IE 9+). To get as much browser support as we can, we'll do it like this with both an MP3 source (WebKit and IE) and an OGG source (Firefox and Opera).

<audio>
	<source src="audio/beep.mp3"></source>
	<source src="audio/beep.ogg"></source>
	Your browser isn't invited for super fun audio time.
</audio>

If you insert the code exactly as above into a page, you won't see or hear anything. If you want a little player element, make sure to use the controls attribute (<audio controls>). If you want it to play but not be seen, make sure to use the autoplay element (<audio autoplay>). Or both...

Our goal is to have the sound play when the mouse hovers over a certain element, like a menu item. Again unfortunately, we can't tell an <audio> element what to do through CSS, so we'll need JavaScript. To play the sound with JavaScript:

var audio = document.getElementsByTagName("audio")[0];
audio.play();

// or with an ID

var audio = document.getElementById("mySoundClip");
audio.play();

Let's use jQuery, just because it's going to make selecting and dealing with events easier.

var audio = $("#mySoundClip")[0];
audio.play();

So to make this sound begin to play when the mouse hovers over a certain element:

var audio = $("#mySoundClip")[0];
$("nav a").mouseenter(function() {
  audio.play();
});

Another way...

The teaser page for the Goodfoot mobile app uses a similar technique to play weird groaning noises (via Dave Rupert) when you hover over the yeti dude. They do it by injecting a new audio element into the DOM everytime that yeti dude is hovered:

$("#speak").mouseenter(function(){
	$("<audio></audio>").attr({ 
		'src':'audio/'+Math.ceil(Math.random() * 5)+'.mp3', 
		'volume':0.4,
		'autoplay':'autoplay'
	}).appendTo("body");
});

That could probably be improved a little, to support OGG as well. Not sure what the volume attribute is all about, that's not spec nor supported anywhere I've seen. This is a modified from Jeffrey Way:

function addSource(elem, path) {
  $('<source>').attr('src', path).appendTo(elem);
}

$("#speak").mouseenter(function(){
     var audio = $('<audio />', {
       autoPlay : 'autoplay'
     });
     addSource(audio, 'audio/'+Math.ceil(Math.random() * 5)+'.mp3');
     addSource(audio, 'audio/'+Math.ceil(Math.random() * 5)+'.ogg');
     audio.appendTo('body');     
});

I'm totally fine with this approach, since it seems to work fine and that's the bottom line. After the sound has been played once it seems to cache and play quickly, which is good.

Another way to handle it would be to put all three audio elements onto the page right away.

<audio preload="auto" id="sound-1" > ... src & fallback ... </audio>
<audio preload="auto" id="sound-2" > ... src & fallback ... </audio>
<audio preload="auto" id="sound-3" > ... src & fallback ... </audio>

Then randomly choose one to play:

$("#speak").mouseenter(function() {
    $("#sound-" + Math.ceil(Math.random() * 3))[0].play();
});

Trials and Troubles: Overlapping Sounds

My original idea for playing with this was a navigation menu that played a little clicking sound while hovering over them. Immediately this uncovered a problem: you can hover over menu items triggering a .play() a lot faster than that sound can finish playing. A single audio element can't play it's own sound in an overlapping way. It just ignores further requests to .play() until it's completed.

My first try was to use .pause() to stop the playing and then .play() again, but in my testing that doesn't help much. It seems to honor the pause but then not the play in many cases.

The smoothest way I could find to do it was to duplicate the audio element for each menu item. That way each menu item has it's own audio clip to play and the sounds can overlap

$("nav a") // loop each menu item
  .each(function(i) {
    if (i != 0) { // only clone if more than one needed
      $("#beep")
        .clone()
        .attr("id", "beep-" + i)
        .appendTo($(this).parent()); 
    }
    $(this).data("beeper", i); // save reference 
  })
  .mouseenter(function() {
    $("#beep-" + $(this).data("beeper"))[0].play();
  });
$("#beep").attr("id", "beep-0"); // get first one into naming convention

View Demo   Download Files

Related

Comments

  1. I love alternatives to using Flash and I’ll have to use this one in the future. Thanks Chris!

    • Adam
      Permalink to comment#

      How do I loop the menu item ?

    • Alan
      Permalink to comment#

      I am frustrated with this, all I see is just mouseenter im trying to fricking figure out, instead of hover effect , the click effect i tried mouseclick on mousedown onmouseclick onclick , where the hell is the click effect , second how the hell am i suppose to use some of these examples, specially the last one “Trials and Troubles: Overlapping Sounds” ….. there are a bunch of id’s names’ and words that i have no idea what they are or resemble. #nav a.. well i assume thats your nav bar and all the “a” links, but the “#beep” ? what is that , is that your audio file, your audio id from the src? or an id you made up for the audio file or w.e, the “id” is that just what we have to put? or are you teling us that a random id replaces that and if so which one, the “beep-” the “beeper” and the #beep and the “beep-0″ what is that , they can be made up id’s by you, they can be the sound file, you should put the html in so we know which exact id or word your placing in the javascript, everything is all over the place. Put the html so we can simply “connect the dots” with our own html to our javascript.

  2. Ok I dig it! Cool tutorial, but aren’t sounds the most annoying thing on websites? I mean when people are browsing at work then suddenly music starts playing, or everytime you roll over a navigation you hear that annoying “click” “click” “click”.

    I’m just saying. Good tutorial though ;)

    • Yeah, I agree. I would accept it if it was a very very quiet “click” like if you went to the last part of the demo and turn the volume down to where theres about two millimeters of space away from the bottom

  3. Chris, when why click the demo button, my antivirus says that it is “HTML script infection” and aborts connection.

    Nice article, though.

  4. Tom Silva
    Permalink to comment#

    Thanks for the tutorial, but this makes me shutter thinking of people actually adding this to their site’s navigation buttons. 2advanced-era bleepity-boopity websites all over again…

  5. Haha! “weird groaning noises”

  6. shitwizard
    Permalink to comment#

    Check out Scott Schiller’s Sound Manager 2. It’s an excellent, excellent, library. It’s used by Last.FM when the user clicks the play button next to a song that’s in an unordered list (as opposed to the main player). Schiller uses it on his own website to do exactly what you’re describing (with the hover effect) here @ http://www.schillmania.com/

    I believe the latest version will even utilize HTML5 as needed.

  7. If the goal is to drive users away from a website, annoying little sounds on navigation should be very effective.

    It’s an interesting proof of concept but I shudder to think where it will lead.

  8. Folks —

    Totally get where you are coming from on the “Eww gross” angle.

    Sounds can be misused.

    But.

    Color can be misused. Images can be misused. Fonts can be misused. Words can be misused. Paint can be misused. Hammers and Nails can be misused.

    This is just a tech demo which gives us the power to be creative. Use wisely.

    • Your completely correct – in the right environment this would be completely acceptable. Think about sites targeted toward children or just on buttons on something like Pandora or Last.FM which is sound oriented.

    • I said completely twice in the first sentence and would really love to edit it… :)

    • I am interested in creating an animated profile image on my artist page. What I would like to accomplish is that when people are interested in me and they click on my animated profile picture one of my songs began to play. I wanted the picture to be animated so that it draws attention to it but not be annoying.

    • Muhammad-All-In
      Permalink to comment#

      Exactly…Most people are cookie cutter figures though, stamped out of what they think they’re supposed to be and couldn’t create their way out of a wet paper bag because their little teacher one time told them never to learn how to make UX more interactive.

      The same people saying that sound is annoying probably don’t make much use of their other senses either.

      Thanks for the tutorial and trying to help people learn.

  9. Last example of JavaScript code is the best solution, I can now hear many active hovers per one second. Thanks Chris!

  10. I immediately thought of my old college instructor that despised Flash and all weird clicks and sounds on webpages unless it’s a site for music or video. I wonder what he would think of this. It’s very innovative to say the least.

  11. Oh god, I thought these annoying flash-hover sounds were a thing of the past. I agree, knowledge is good, but I really hope this doesn’t start trending with html sites..

  12. This is an amazing tut!! i saw lot of arguments goin on out here but whatever it is, it is a good thing that we can have sounds on hover without using flash!!

    ooh! how I love it though!! :D

  13. Permalink to comment#

    I read your article a few hours ago already, now I just came back to check on the comments. And I have to say that I’m very happy about the reactions you are gettting ;)

  14. That is great post. It’s very nice. Thanks for shearing your ideas.

  15. lastlifelost
    Permalink to comment#

    Nice idea! I do wonder if there’s a way to do this without JS. One thought that comes to mind is using CSS :before or :after selectors. Perhaps something like


    .navSelect:hover:after {
    content: "

    Your browser isn't invited for super fun audio time.
    "
    }

    I’m not sure if you can stack pseudoclasses, so it may have to be something like .navSelect:hover span:after or a:after.

    Wouldn’t this get the desired result and technically be controlled by CSS?

    • lastlifelost
      Permalink to comment#

      sorry, post got eaten… Here’s what it should have been:


      .navSelect:hover:after {
      content: "
      <audio autoplay>
      <source src="audio/beep.mp3"></source>
      <source src="audio/beep.ogg"></source>
      Your browser isn't invited for super fun audio time.
      </audio>

      Your browser isn't invited for super fun audio time.
      "
      }

    • I’m afraid that doesn’t work. What you put in the content property is treated like a string, last time I tried html elements were not created that way.

  16. David Smith
    Permalink to comment#

    Adding my two cents – just be very, very careful where you use this. So far I can’t imagine any circumstances where it would be appropriate, but there may be some.

  17. Permalink to comment#

    Could you queue the sound events by adding them to the fxqueue?

    Also, you might want to add the id to the first html block as it’s used for the rest of the example.

  18. Permalink to comment#

    Great read, I was just working on a website that requires accessibility as its number one priority. Unfortunately aural stylesheets are deprecated and CSS 3 speech modules are still in the working draft. However I did find the aural box model to be interesting. You can find it here

  19. Permalink to comment#

    even I prefer to use flash this tutorial might be helpfull for me,
    thanks

  20. I just try your demo, so COOL!
    Something like flash, but faster loading time for the page, need not to wait from 20% to 100%.
    I think that it is more suitable for blogs, or personal website, not too good for online shop.
    I will try, thank you.

  21. Hugo
    Permalink to comment#

    “Play Sound on :hover”?
    Wouldn’t “Play sound using javascript” be a better title for this article since that’s what you’re really doing? It’s not as amazing as playing using :hover, but the title is a rather misleading…
    Also, sounds on web pages are pure evil^^ (not counting music & video players).

  22. Lweek
    Permalink to comment#

    It is better call stop() first before new play() to prevent silent buttons. Also there is way using jQuery to add sound dynamicaly and dynamicaly delete them from dom as they are played. So It can play more sounds at same time.

  23. This is a great tutorial well distributed and explained, having sounds on a hover state can be annoying, but this tutorial is just to explain that sound can be applied without the use of flash.
    HTML 5 has loads of potential to do great things and definitely one to look out for the future.

  24. Permalink to comment#

    how about long audio?
    can we stop it when the mouse out of the hover area?

  25. Thanks for this, it was just what I needed :D
    Does anyone know if there any way of changing the control buttons using CSS?

  26. Permalink to comment#

    Now there is just no argument left for the use of flash, animation and sound wit css :-)

  27. Permalink to comment#

    This is really cool. However, if abused it could quickly become very annoying! HTML5 looks really good, although I’m not sure Flash is going to be dropped for quite some time yet!

  28. I think Flash will be dropped very soon. I don’t think it will ever be eliminated as a medium for video (among other features), but as HTML5 moves up as a force for video, Flash will loose it’s tentative foothold.

    I don’t know any designers who care about web standards and semantics that still employ flash in their (critical) arsenal. I think it will always have a place, but will supplement and enhance websites rather than be critical to it’s integrity.

    /rant

  29. Permalink to comment#

    Interesting stuff! Thanks!

    BTW this [0] doesn’t make any sense:
    var audio = $(“#mySoundClip”)[0];

  30. For what it’s worth, you’d probably want to cache the result of the Math.random call, otherwise there’s a chance that the sound files will be completely different.

    Not that it matters for this demo anyway :)

  31. Ace
    Permalink to comment#

    How would this work if you based the sound off the element class instead of id? So all divs/span/etc with class1 on hover play class1.mp3; class2 -> class2.mp3, etc…?

  32. How it can be done through Joomla Menu System . Is it possible to make a Integration between Joomla Module menu and this method .
    Joomla menu code will done Dynamicly

  33. zinzinzibidi
    Permalink to comment#

    Thanks buddy. That works. =)

  34. seculla
    Permalink to comment#

    It’s calling an enormous script without which it won’t work:

    http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js

    Can anyone make a real tutorial how to call simplest “audio/click.mp3″ on hover?

    • Alan
      Permalink to comment#

      Here, this is what I got, I downloaded a mp3 sound called “beep-29.mp3″ so in the html of my home page I put this

      then in the javascript, inside the “$(document).ready( function() {}” thing,

      I put this var audio = $(“#audio”)[0];
      $(“#topmenu a”).mouseenter(function() {
      audio.play();
      });

      “#audio” obviously links to the id “audio” I gave to the audio tag, and the “#topmenu a” is the ID I gave my top nav bar and its targeting the links, the buttons on the top bar.

      Thats it, what I dont like about these examples, specialy the trial and and troubles overlapping sounds is that whoever posted that, did NOT post any of the HTML, so that means that i have no idea what to replace or put in my code becuase i dont know which ID’s are which and what goes where. They need to put the html so we know exactly which id’s are being called and which words go where.

  35. Doug

    Rather than cloning the audio reset the playback head by setting the currentTime.

    .mouseenter(function() {
    beepThree.pause();
    beepThree.currentTime = 0;
    beepThree.play();
    })

This comment thread is closed. If you have important information to share, you can always contact me.

*May or may not contain any actual "CSS" or "Tricks".