Responsive & Touch-Friendly Audio Player

A jQuery audio player plugin that is responsive and touch-friendly. The UI is css-only, no images used.

Audio Player: Responsive & Touch-Friendly

You know that feeling when you are in the design heaven of Photoshop (or another maybe not that overpriced app), then come to writing the markup and things like <select>, <input type="radio|checkbox|file" /> throw you back into the harsh reality? Just because the usual CSS styling was not granted to them when God created the earth. Poor <audio> element is no different. Each HTML5-compatible browser has its own visual interpretation of the element.

But we also have events, methods and properties for the <audio> elements, which means it can be manipulated using JavaScript.
Experimenting is nice, but all of this would be worthless without practical use. Despite the fact that video is the most popular type of media on the Internet, there are also situations when audio is important or even the major content, think podcasts or websites of musicians. My situation was quite different though.

One of the projects I’m working on is a service of cloud-based IP telephony (VOIP). I’m building a web-based app which enables our clients to manage their telephony using only a web browser. One of the features that the app has is IVR (Interactive Voice Response). Clients can make their own virtual menus by assigning functions to phone buttons and uploading audio files which are played during the call. Wouldn’t it be nice if our clients could check their uploads by listening to them on their laptop or tablet? That’s why I have built a jQuery plugin for a responsive and touch-friendly audio player.

The plugin

Simply put, it’s a jQuery plugin. jQuery users, who are the majority among all of the JavaScript framework users, will be glad to add it to their jQuery library. The jQuery plugin itself would be pretty much useless without the respective CSS which is responsible for the looks and some of the features summarized below.

Purpose

Don’t confuse this player with the whole media centre like iTunes or so. It is nothing like that. This is a tiny, lightweight player with a very clear purpose: to play a single audio file. I have built it having this credo in mind: “don’t solve problems that do not exist”. You don’t need complex plugins or ugly Flash players with thousands of useless functions to play that damn audio file. Be innovative, be subtle.

How it works

The plugin replaces targeted <audio> elements with some HTML and JavaScript events attached to it.

Features

Responsiveness

Smartphone, tablet or thirty inches large display: the player feels fine with any screen size. Without the need of media queries, a simple, fluid layout was adopted. The player is a quite small object so that’s the easiest part. We will look deeper into this later in the article (CSS part).

Touchableness

It is real, alive and you can touch it. The player can be used on touch-capable screens as well. Everything you can do with the cursor, you can also do with your finger. Every action has its touch events defined and enabled.

Adaptiveness

  • Got JavaScript disabled? No worries, the default browser’s player will do the job.
  • The Volume button hides when volume control is not available (bad for iOS).
  • When the browser does not support the <audio> element entirely or any of the provided audio files, the player then gracefully degrades to a one-button (Play/Pause) <embed /> element based player which will use a third party plugin (mostly Quick Time on Mac, Windows Media Player on Windows) to play the audio.

Image-less

No animals were harmed in the making of this player. I mean, the looks of the player is all CSS, not a single image is used.

Controls

  • The essential Play / Pause and playback progress controls;
  • Volume On / Off / Up / Down controls;
  • Indication of how much of the audio is loaded (buffered).

Nativeness

The player is in no way native, but it fights to be as close to that as possible.
Firstly, it behaves according to defined <audio>-element-specific attributes:

  • src specifies the location (URL) of the audio file;
  • autoplay boolean attribute, specifies whether to play the audio when it is ready;
  • loop boolean attribute, specifies whether to play the audio over again, every time it is finished;
  • preload specifies how the audio file should be loaded, values: auto|metadata|none.

If you are familiar with the <audio> element, you may be wondering where the controls attribute is. The thing is, it has nothing to do with the plugin. The attribute is important when JavaScript is disabled in the browser or the plugin could not be loaded as it assures the default is displayed then.
Secondly, it accepts child elements of <source> and plays the first browser-compatible audio file.

Lightness

The minified version of the plugin is just 4KB large small.

How to use it

Enough of the theory, let the fun part begin!

Initial HTML

Nothing special, just the typical usage of the <audio> tag with some of the attributes from the Nativeness section above (remember what was mentioned about the controls):

<audio src="audio.wav" preload="auto" controls></audio>

This will only load the audio.wav file. Be careful with the preload and do not preload too many files at once. Use values none or metadata for a lighter effect.

Feel brave enough? You can autoplay the file when it loads and then loop it:

<audio src="audio.wav" preload="auto" controls autoplay loop></audio>

To support as many browsers as possible you can specify multiple audio formats in this way:

<audio preload="auto" controls>
	<source src="audio.wav" />
	<source src="audio.mp3" />
	<source src="audio.ogg" />
</audio>

Plugin Call

Now that we have this huge and heavy HTML done, let’s add some JavaScript beneath simply by adding a few lines:

<audio src="audio.wav" preload="auto" controls></audio>
<script src="jquery.js"></script>
<script src="audioplayer.js"></script>
<script>$( function() { $( 'audio' ).audioPlayer(); } );</script>

On the 4th line the plugin is applied to the audio element. You can also target elements using an appropriate method from a really wide range of selectors, for example: <audio class="music"… and then use $( '.music' )….

Besides that, the audioPlayer element has some optional parameters. The most important one is called classPrefix. The passed value becomes a class name for the parent element and class name prefix for child elements. Other parameters may only be advantageous for languages other than English. Using them is easy:

$( 'audio' ).audioPlayer(
{
	classPrefix: 'player', // default value: 'audioplayer'
	strPlay: 'Play', // default value: 'Play'
	strPause: 'Pause', // default value: 'Pause'
	strVolume: 'Volume', // default value: 'Volume'
});

The Magic

Just kidding, there is nothing too magical here. I’m just trying to grab you attention for this important moment. When you call an instance of the plugin, it replaces the <audio> element entirely with the new piece of custom HTML code. There are two types of code:
Full – when the audio element and at least one of the given audio files is compatible with the browser:

<div class="audioplayer">
	<audio src="audio.wav" preload="auto" controls></audio>
	<div class="audioplayer-playpause" title="Play"><a href="#">Play</a></div>
	<div class="audioplayer-time audioplayer-time-current">00:00</div>
	<div class="audioplayer-bar">
		<div class="audioplayer-bar-loaded"></div>
		<div class="audioplayer-bar-played"></div>
	</div>
	<div class="audioplayer-time audioplayer-time-duration">&hellip;</div>
	<div class="audioplayer-volume">
		<div class="audioplayer-volume-button" title="Volume"><a href="#">Volume</a></div>
		<div class="audioplayer-volume-adjust"><div><div></div></div></div>
	</div>
</div>

Moreover, there are three unmentioned class names assigned to the parent element when:

  • audioplayer-playing – audio is being played (e.g. <div class="audioplayer audioplayer-playing">);
  • audioplayer-mute – volume is muted (e.g. <div class="audioplayer audioplayer-mute">);
  • audioplayer-novolume – no volume adjustment is available (e.g. <div class="audioplayer audioplayer-novolume">).

Mini – when the audio element is not supported or none of the given audio files is compatible with the browser:

<div class="audioplayer audioplayer-mini">
	<embed src="audio.wav" width="0" height="0" volume="100" autostart="false" loop="false" />
	<div class="audioplayer-playpause" title="Play"><a href="#">Play</a></div>
</div>

Sadly, but in this situation the friendship between JavaScript and <embed /> is not great. Therefore, the player gracefully degrades to a simplified one-button (Play and Pause) player. And this is okay for older browsers:

Remember the Adaptiveness paragraph from above? That was the theory and this is the practice.

CSS

All that’s left is to apply some styles to the HTML code above! To save your time and make CSS goal-focused, I will not use gradients, shadows and other fancy properties in the code below (but you will find it in the demo). It means if you apply the CSS below, your player will look like this:

Some notes before diving into the CSS:

  • We’ll go though the CSS from left to right regarding the player describing each zone in the following order:
    1. Parent element and inner structure
    2. Play / Pause button
    3. Timers
    4. Progress bar
    5. Volume adjuster
  • Almost all size units are ems in order to ensure scalability and consistency. In the comments, following the em, you’ll find their equivalent in pixels when the body font size is 100% (16px).

Parent element and inner structure

*
{
	-webkit-box-sizing: border-box;
	-moz-box-sizing: border-box;
	box-sizing: border-box;
}
.audioplayer
{
	height: 2.5em; /* 40 */
	color: #fff;
	background: #333;
	position: relative;
	z-index: 1;
}

	/* fallback case (read Adaptiveness chapter) */
	.audioplayer-mini
	{
		width: 2.5em; /* 40 */
		margin: 0 auto;
	}

	/* inner elements positioning (helps to achieve responsiveness) */
	.audioplayer > div
	{
		position: absolute;
	}

If you have never used box-sizing: border-box, then it is the right time to start. This is a game-changing technique. Having this and making first-level inner elements position absolute, we will achieve responsiveness. Don’t get what I mean? Check the following scheme:

Tiny elements have a fixed width, and that is totally fine as long as they are tiny, while the progress bar is fluid along with the parent element. There are also more responsive techniques suitable for the player.

Play / Pause button

.audioplayer-playpause
{
	width: 2.5em; /* 40 */
	height: 100%;
	text-align: left;
	text-indent: -9999px;
	cursor: pointer;
	z-index: 2;
	top: 0;
	left: 0;
}
	.audioplayer-mini .audioplayer-playpause
	{
		width: 100%;
	}
	.audioplayer-playpause:hover,
	.audioplayer-playpause:focus
	{
		background-color: #222;
	}
	.audioplayer-playpause a
	{
		display: block;
	}

	/* "play" icon when audio is not being played */
	.audioplayer:not(.audioplayer-playing) .audioplayer-playpause a
	{
		width: 0;
		height: 0;
		border: 0.5em solid transparent; /* 8 */
		border-right: none;
		border-left-color: #fff;
		content: '';
		position: absolute;
		top: 50%;
		left: 50%;
		margin: -0.5em 0 0 -0.25em; /* 8 4 */
	}

	/* "pause" icon when audio is being played */
	.audioplayer-playing .audioplayer-playpause a
	{
		width: 0.75em; /* 12 */
		height: 0.75em; /* 12 */
		position: absolute;
		top: 50%;
		left: 50%;
		margin: -0.375em 0 0 -0.375em; /* 6 */
	}
		.audioplayer-playing .audioplayer-playpause a:before,
		.audioplayer-playing .audioplayer-playpause a:after
		{
			width: 40%;
			height: 100%;
			background-color: #fff;
			content: '';
			position: absolute;
			top: 0;
		}
		.audioplayer-playing .audioplayer-playpause a:before
		{
			left: 0;
		}
		.audioplayer-playing .audioplayer-playpause a:after
		{
			right: 0;
		}

Timers

.audioplayer-time
{
	width: 4.375em; /* 70 */
	height: 100%;
	line-height: 2.5em; /* 40 */
	text-align: center;
	z-index: 2;
	top: 0;
}
	.audioplayer-time-current
	{
		border-left: 1px solid #111;
		left: 2.5em; /* 40 */
	}
	.audioplayer-time-duration
	{
		right: 2.5em; /* 40 */
	}
		.audioplayer-novolume .audioplayer-time-duration
		{
			border-right: 0;
			right: 0;
		}

Progress bar

.audioplayer-bar
{
	height: 0.875em; /* 14 */
	background-color: #222;
	cursor: pointer;
	z-index: 1;
	top: 50%;
	right: 6.875em; /* 110 */
	left: 6.875em; /* 110 */
	margin-top: -0.438em; /* 7 */
}
	.audioplayer-novolume .audioplayer-bar
	{
		right: 4.375em; /* 70 */
	}
	.audioplayer-bar div
	{
		width: 0;
		height: 100%;
		position: absolute;
		left: 0;
		top: 0;
	}
	.audioplayer-bar-loaded
	{
		background-color: #555;
		z-index: 1;
	}
	.audioplayer-bar-played
	{
		background: #007fd1;
		z-index: 2;
	}

Volume adjuster

.audioplayer-volume
{
	width: 2.5em; /* 40 */
	height: 100%;
	border-left: 1px solid #111;
	text-align: left;
	text-indent: -9999px;
	cursor: pointer;
	z-index: 2;
	top: 0;
	right: 0;
}
	.audioplayer-volume:hover,
	.audioplayer-volume:focus
	{
		background-color: #222;
	}
	.audioplayer-volume-button
	{
		width: 100%;
		height: 100%;
	}

		/* "volume" icon */
		.audioplayer-volume-button a
		{
			width: 0.313em; /* 5 */
			height: 0.375em; /* 6 */
			background-color: #fff;
			display: block;
			position: relative;
			z-index: 1;
			top: 40%;
			left: 35%;
		}
			.audioplayer-volume-button a:before,
			.audioplayer-volume-button a:after
			{
				content: '';
				position: absolute;
			}
			.audioplayer-volume-button a:before
			{
				width: 0;
				height: 0;
				border: 0.5em solid transparent; /* 8 */
				border-left: none;
				border-right-color: #fff;
				z-index: 2;
				top: 50%;
				right: -0.25em;
				margin-top: -0.5em; /* 8 */
			}
			.audioplayer:not(.audioplayer-mute) .audioplayer-volume-button a:after
			{
				/* "volume" icon by Nicolas Gallagher, http://nicolasgallagher.com/pure-css-gui-icons */
				width: 0.313em; /* 5 */
				height: 0.313em; /* 5 */
				border: 0.25em double #fff; /* 4 */
				border-width: 0.25em 0.25em 0 0; /* 4 */
				left: 0.563em; /* 9 */
				top: -0.063em; /* 1 */
				-webkit-border-radius: 0 0.938em 0 0; /* 15 */
				-moz-border-radius: 0 0.938em 0 0; /* 15 */
				border-radius: 0 0.938em 0 0; /* 15 */
				-webkit-transform: rotate( 45deg );
				-moz-transform: rotate( 45deg );
				-ms-transform: rotate( 45deg );
				-o-transform: rotate( 45deg );
				transform: rotate( 45deg );
			}

	/* volume adjuster */
	.audioplayer-volume-adjust
	{
		width: 100%;
		height: 6.25em; /* 100 */
		cursor: default;
		position: absolute;
		left: 0;
		top: -9999px;
		background: #222;
	}
		.audioplayer-volume:not(:hover) .audioplayer-volume-adjust
		{
			opacity: 0;
		}
		.audioplayer-volume:hover .audioplayer-volume-adjust
		{
			top: auto;
			bottom: 100%;
		}
		.audioplayer-volume-adjust > div
		{
			width: 40%;
			height: 80%;
			background-color: #555;
			cursor: pointer;
			position: relative;
			z-index: 1;
			margin: 30% auto 0;
		}
			.audioplayer-volume-adjust div div
			{
				width: 100%;
				height: 100%;
				position: absolute;
				bottom: 0;
				left: 0;
				background: #007fd1;
			}
	.audioplayer-novolume .audioplayer-volume
	{
		display: none;
	}

That’s it! Check out the demo if you haven’t yet or download the full source.

Be sure to share your thoughts, insights or experience in the comments. Thank you.

Tagged with:

Osvaldas Valutis

Osvaldas is a web designer who thinks in code and a creator of Readerrr. Osvaldas is based in Klaipeda, Lithuania.

Stay up to date with the latest web design and development news and relevant updates from Codrops.

Feedback 67

Comments are closed.
  1. Thank you for this great tutorial. What is about iOS 6 ? On mobile devices both players are visible. My bad?

    • Great observation, Andreas. Problem found and fixed. Should be visible in a few moments. Be sure to check the demo again.

  2. This is an excellent plugin thanks so much for sharing. It is difficult to find compatible HTML5 audio/video players so this is definitely a handy reference.

  3. Pretty nice but, it doesn’t appear to work in IE8. Getting javascript (Object doesn’t support this property or method) errors. Also, you just see a grey box. Once you click it, you see the ‘pause’ icon but, with no sound.

    • @Bruno

      Well my friend, given this statement :

      “Sadly, but in this situation the friendship between JavaScript and is not great. Therefore, the player gracefully degrades to a simplified one-button (Play and Pause) player. And this is okay for older browsers:”

      I assumed there was some lightweight fallback in place. When people mention “older browsers” in a tutorial, they are generally referring to IE7 and/or IE8.

    • Thanks for that. <=IE8 is a world apart. jQuery should be called from <head>, not <body>. Works for me this way.

  4. Thank you for your great tut!

    In my latest Opera browser, under the volume button “Infinity:NaN:NaN” text appear. After refreshing the page, disappear.

  5. Hello!
    Thanks for sharing this awesome player ! 😉
    Do you envisage to make a video version ?
    Thanks!!

  6. Doesn’t work on iOS. While selected, the highlighter in Safari highlights the entire player and asks if you want to copy/define. Any fix for this?

    • Works perfectly on iOS6. But I haven’t tested it on earlier versions. Which is yours?

  7. Hi.. This is a really great player! In fact.. just the thing I’m looking for.. Though I’m noticing some kind of a bug (I’m not sure if it’s just my phone) but when I load the player and hit play and the music plays.. then I hit the power button to turn the screen off.. the music still plays.. but when I unlock my phone and load the browser again.. the player hangs and the browser shuts down. Did I break it? I’m using iOS 6.01 and iPhone 4.

  8. Nice article. The gradients are displaying strangely compared to other browsers in IE10. I looked into what the problem was and you (accidentally I guess) use radial gradients for IE instead of linear gradients like other browsers.

    This is the case for .audioplayer-volume-adjust, .audioplayer-volume-adjust div div, .audioplayer-bar-played and .audioplayer.

    Another issue is you use the standard syntax without prefix, but no browser will use this as you use the now older syntax. This has fairly recently changed to use the to keyword, and reverses the direction keyword. For example the following line:

    background: linear-gradient( left , #007fd1, #c600ff );

    Should become:

    background: linear-gradient( to right, #007fd1, #c600ff );

    Most browsers now support this syntax, and the old syntax is being phased out. Fixing this will keep it working in all modern browsers going forward.

  9. Hi, this is a cool player. But I encountered an error under Chrome browser: INDEX_SIZE_ERR, in two places: one is in updateLoadBar function, the error occurs occasionally when loading the page. If it occurs, theAudio.buffered.length is 0 (and theAudio.duration is NaN). The other one is in adjustVolume function, it occurs when the volume reaches its max value.

  10. Hi..great plugin.However, anyway customizing it with icon font for the UI controls? Because they will break if the page is zoomed, especially the volume control button.

  11. Hi,
    I’ve been trying to use this script for multiple audio players but I am getting a js error:
    Line 456: Uncaught Error: INDEX_SIZE_ERR: DOM Exception 1

    Am I doing anything wrong here?

  12. Awesome player, thanks a bunch!

    So far, everything seems to be working properly….all except for one major issue with Firefox:

    If the audio is set to autoplay, Firefox seems to generate multiple “layers” of the audio file that play all at once. The pause button on the player stops one of these layers, but not all of them.
    This does not seem to happen with autoplay turned off, so I made a script to take that out of the audio tag if Firefox is being used…but obviously this isn’t where I want to leave it.

    Not sure how much can really be done about this, just thought I’d pass it on!

    • Hello,

      I am experiencing bug in responsive audio player, with multiple layers. You mentioned, that You made a script to solve it, any chance You might be kind to share it?

  13. to fix the javascript bug INDEX_SIZE_ERR.

    in audioplayer.js around line 103
    change
    change :
    barLoaded.width( ( theAudio.buffered.end( 0 ) / theAudio.duration ) * 100 + '%' ); if( theAudio.buffered.end( 0 ) >= theAudio.duration ){ clearInterval( updateLoadBar ); }
    to:
    if(theAudio.buffered.length > 0){ if(theAudio.duration > 0){ barLoaded.width( ( theAudio.buffered.end( 0 ) / theAudio.duration ) * 100 + '%' ); } if( theAudio.buffered.end( 0 ) >= theAudio.duration ){ clearInterval( updateLoadBar ); } }

  14. Hi!
    I’m using a few of these audio players on the same page to stream an album track-by-track.
    I was wondering if anyone knows if there is a way to have all other playing tracks stop when play is clicked on another?
    Thanks!

  15. Great player. But on Using this and I can see it in your demo as well, I get a js error in console:

    Uncaught Error: INDEX_SIZE_ERR: DOM Exception 1

    Though it does not cause any impact but still, any idea how can we overcome it. I have tried playing with preload (auto/metadata/none) but it still persists.

    • I have the same problem here.
      If you call the script on $(window).load, it works…

    • Ok, I just found something, if you replace these lines :
      y.width(v.buffered.end(0) / v.duration * 100 + "%"); if (v.buffered.end(0) >= v.duration) clearInterval(C)
      by these lines
      if ( v.duration && v.buffered.length){ y.width(v.buffered.end(0) / v.duration * 100 + "%"); if (v.buffered.end(0) >= v.duration) clearInterval(C) }
      I just doen’t have this problem anymore,
      hope it will fix yours…

  16. Hello,

    I’m having trouble with the autoplay, when i use this, the controls won’t work.

    can you help me?

    THANKS!

  17. How is this RESPONSIVE & TOUCH-FRIENDLY AUDIO PLAYER automatic play without click?

    It can be possible….

  18. This looks like a great audio player – is there a way to have more than one audio file to play? have a playlist and have next and previous buttons to be able to navigate through a certain number of audio files?

  19. very good but one problem , when i place the player ,the div class=”audioplayer-playpause” is not at the good place , and move in the middle of the .autoplayer , is there issue for this problem?

  20. Hi,

    the plugin is great, thanks a lot.

    I cant get it working in WordPress… Can you help ?

  21. Yes, great plugin !
    But on my android phone i experiment issues :
    on Chrome, i can see the native audioplayer and not the responsive one
    on android web browser, i have only play/pause button and my file does not play (i’ve got the ogg, mp3 and wav file )

    Any idea ?

  22. Don’t know if this has been posted yet, but for everyone having trouble with the autoplay function (controls not working after play starts), here’s a quick workaround:

    $(‘.audioplayer-playpause’).trigger(‘click’);

    Insert that in an event to simulate a click on the play button, instead of autoplay. Works like a charm.

  23. Great plugin!
    I’ve got an issue using Chrome though (version 25) where I can’t drag the sliders, either the progress bar or the volume.
    Same page works fine in IE9 (not tested in anything else yet, sorry).
    I get the pointer cursor as if I’ll be able to drag them but can’t actually move the sliders, as if they’re simply not draggable elements 🙁

    Any ideas?

  24. Have been looking for a good looking HTML5 audio player for a looooong time! This is just brilliant! Thanks! 😀

  25. can I use this plugin for SoundCloud audio?
    please help.
    hope someone is there to guide me in this regard.

  26. Thanks for this little player! I tweaked the style and made a container. It still needs refining. A nice project to work on. Thanks for the tip on the js autoplay bug in Firefox.

  27. Hi there,
    i’m using the player on mobile devices and i’m looking for a way to pause the player when the page lost focus.
    Anyone has an idea how to do that ?

    • i’m also looking for a way to ditch the volume control.
      Sorry for all the trouble and thanks in advance 🙂

  28. The day you have a flash fallback for this I will use it. Nonetheless, great plugin. Just needs a flash fallback.

  29. Dear Osvaldas,

    That’s a fine work!!! It’s a fantastic player!
    But I have a problem with it: when the music stays at 01:00 / or maybe at 01:00:00 – I can’t try it – the player shows 00:60 seconds. It could be a little bit strange. Could you help me to solve this problem as fast as you can, because I use this great plugin for a HTML5 DVD that I have to finailze until August 5th.

    Thank you for your help!
    All the best,
    Peter

  30. I am using the audio player download and have some issues. I have a Mac OS X, Mountain Lion.

    #1) Does not work with Firefox. All you see is the play button. It can be clicked and hear the sound but no progress bar or speaker control.

    #2) The wrapper’s ‘width’ attribute works as expected (ie changes width of the control), but the ‘height’ does not change the height and acts as a position attribute (y-axis).

    #3) When you start the control via $(‘#myaudioplayer’)[0].play(), the start button does not change to a pause button.

    Any ideas would be appreciated.

    Thanks

  31. Hello, Great share. I have a question, if I want to set volume to 70% from code how it can be done?

  32. Thanks for your audio player.
    I have a issue that I cannot see the processing bar of diagram.
    How can I see the bar?

  33. Great! But how do I get it at autostart? This is my current code:

    $( function() { $( ‘audio’ ).audioPlayer(); } );

  34. Hello … Not an issue, but a question:

    I have the player positioned fixed at the top of the page. How can I make the volume open the other way around so I can actually see and use it?

    Any Ideas? thanks

    • hi

      did you find a way to stop or pause the other tracks while playing a second player on the same page?