鼠标悬停时播放声音

Avatar of Chris Coyier
Chris Coyier

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 200 美元的免费积分!

当您在谷歌上搜索如何使用 CSS 播放声音时,您会发现

  1. 一些关于反恐精英:起源的内容
  2. 一些关于play-duringcue-before 的内容,以及看起来很有希望但实际上是用于 听觉样式表(辅助功能/屏幕阅读器内容),而不是如何在任何浏览器中将驴叫声与菜单项悬停关联起来

我认为声音是设计的一部分,因此播放/触发声音的能力应该属于 CSS,但可惜我们还没有达到这一步。 要在鼠标悬停在某个区域时播放声音,我们需要依赖 HTML5 或 Flash。 但是这里没有人想处理 Flash,对吧? 所以让我们用 HTML5 来做,它可以通过其<audio> 元素播放声音(Firefox 3.5+、Chrome 3+、Opera 10.5+、Safari 4+、IE 9+)。 为了获得尽可能广泛的浏览器支持,我们将使用 MP3 源(WebKit 和 IE)和 OGG 源(Firefox 和 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>

如果您将代码完全按照上述方式插入页面,您将看不到或听不到任何内容。 如果您想要一个小播放器元素,请确保使用 controls 属性(<audio controls>)。 如果您希望它播放但不可见,请确保使用 autoplay 元素(<audio autoplay>)。 或者两者兼而有之……

我们的目标是在鼠标悬停在某个元素(例如菜单项)上时播放声音。 遗憾的是,我们无法通过 CSS 告诉<audio> 元素该怎么做,因此我们需要 JavaScript。 要使用 JavaScript 播放声音

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

// or with an ID

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

让我们使用 jQuery,因为它可以使选择和处理事件变得更容易。

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

因此,要使此声音在鼠标悬停在某个元素上时开始播放

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

另一种方法……

针对 Goodfoot 移动应用程序 的预告页面使用了类似的技术,在您将鼠标悬停在雪人身上时播放奇怪的呻吟声(通过 Dave Rupert)。 他们通过在每次将鼠标悬停在雪人身上时将新的音频元素注入 DOM 来实现这一点

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

这可能需要稍微改进一下,以便也支持 OGG。 不确定 volume 属性是做什么用的,这不在 规范 中,而且我在任何地方都没有看到它得到支持。 这是根据 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');     
});

我完全赞同这种方法,因为它看起来运行良好,这就是底线。 声音播放一次后似乎会被缓存并快速播放,这很好。

另一种处理方法是立即将所有三个音频元素放到页面上。

<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>

然后随机选择一个播放

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

试验与麻烦:重叠的声音

我最初的想法是使用一个导航菜单,在将鼠标悬停在菜单项上时播放轻微的点击声。 立即发现了这个问题:您可以比声音完成播放的速度快得多地将鼠标悬停在菜单项上并触发.play()。 单个音频元素无法以重叠的方式播放自身声音。 它只是忽略进一步的.play() 请求,直到它完成播放。

我的第一次尝试是使用.pause() 停止播放,然后再次使用.play(),但在我的测试中,这并没有多大帮助。 它似乎会遵守暂停,但在许多情况下不会遵守播放。

我发现最流畅的方法是为每个菜单项复制音频元素。 这样,每个菜单项都有自己的音频片段可以播放,并且声音可以重叠

$("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

查看演示   下载文件

相关