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. the player looks nice and easy

    i like to use about 20 players on one page
    how can i pause track when i play another one?