How to Style an Audio Element
Tags: css, beginners, javascript, tutorial
Published: 2021-08-30 13:58:03

---
title: How to Style an Audio Element
published: true
date: 2021-08-30 11:06:50 UTC
tags: CSS,Beginners,Javascript,tutorial
canonical_url: https://blog.shahednasser.com/how-to-style-an-audio-element/
cover_image: https://blog.shahednasser.com/static/6442d5682c1a7a2e766617a762f38531/jexo-tj7Bj_743JA-unsplash-2.jpg
---

_This article was originally posted on [my personal blog](https://blog.shahednasser.com/how-to-style-an-audio-element/)_

Audio elements can be tricky to style. There is no straightforward way to style them, as applying CSS styles on `audio` directly does not work.

In this tutorial, we'll learn 2 ways of styling audios. We'll check how we can style audio elements with their pseudo-element selectors, then we'll see how we can style them completely from scratch.

This tutorial uses CodePens to show examples on the go. You can check out the [full collection](https://codepen.io/collection/pgvvxz), as well.

The audio used in this tutorial is free audio from [ZapSplat](https://www.zapsplat.com).

## Using Pseudo-Element Selectors

Audio elements, by default, are not visible. You need to add the `controls` attribute for their controls to be visible.

This is how a basic audio player looks like:

{% codepen https://codepen.io/shahednasser/pen/JjJdeqM %}

Audio elements have the following pseudo-element selectors in CSS:

```
audio::-webkit-media-controls-panel
audio::-webkit-media-controls-mute-button
audio::-webkit-media-controls-play-button
audio::-webkit-media-controls-timeline-container
audio::-webkit-media-controls-current-time-display
audio::-webkit-media-controls-time-remaining-display
audio::-webkit-media-controls-timeline
audio::-webkit-media-controls-volume-slider-container
audio::-webkit-media-controls-volume-slider
audio::-webkit-media-controls-seek-back-button
audio::-webkit-media-controls-seek-forward-button
audio::-webkit-media-controls-fullscreen-button
audio::-webkit-media-controls-rewind-button
audio::-webkit-media-controls-return-to-realtime-button
audio::-webkit-media-controls-toggle-closed-captions-button
```

Using these selectors, you can give basic styling to audio elements. However, these only work on select browsers like Chrome.

We'll see a few examples of how we can use some of these selectors to style the audio element.

All the examples below will only work on Chrome. So, if you want to see how the audio element's style changes, please use Chrome.

### Styling the Control Panel

To style the control panel, which is the container of all the audio's controls, you can use the selector `audio::-webkit-media-controls-panel`. In the example below, we use the selector to change the background color.

{% codepen https://codepen.io/shahednasser/pen/gORpZby %}

### Styling the Mute Button

To style the mute button, you can use the selector `audio::-webkit-media-controls-mute-button`. In the example below, we change the background color of the mute button as well as add a border-radius.

{% codepen https://codepen.io/shahednasser/pen/YzQXdwR %}

### Styling the Play Button

To style the play button, you can use the selector `audio::-webkit-media-controls-play-button`. In the example below, we change the background color of the play button as well as add a border-radius.

{% codepen https://codepen.io/shahednasser/pen/eYRNbzR %}

### Style the Current Time

To style the current time you can use the selector `audio::-webkit-media-controls-current-time-display`. In the example below, we change the color of the text.

{% codepen https://codepen.io/shahednasser/pen/YzQXdQg %}

### Style the Remaining Time

To style the remaining time you can use the selector `audio::-webkit-media-controls-time-remaining-display`. In the example below, we change the color of the text.

{% codepen https://codepen.io/shahednasser/pen/NWgqevN %}

### Style the Timeline

To style the timeline you can use the selector `audio::-webkit-media-controls-timeline`. In the example below, we add a background color and a border radius.

{% codepen https://codepen.io/shahednasser/pen/NWgqeaN %}

### Styling the Volume Slider

To style the volume slider, which on Chrome appears after hovering the mute button, you can use the selector `audio::-webkit-media-controls-volume-slider`. In the example below, we add a background color, a border radius, and some padding.

{% codepen https://codepen.io/shahednasser/pen/ZEyGVaX %}

## Styling a Custom Audio Player

In this section, we'll create our own custom audio player. We'll a nice looking player that uses different elements to achieve a good style. Then with the help of Javascript bind the audio element's functionalities to these elements.

All the icons used in this section are from [Heroicons](https://heroicons.com/).

You can see the full demo on CodePen at the end of the section.

### Create the Track Image

Usually, audio players have an image of the track playing. It gives a nice style to the audio player. We'll just an icon from Heroicons to simulate that.

We'll start by adding in the HTML the container `.audio-player`. Inside that container, we'll add the track "image" element.

```
<div class="audio-player">
  <div class="icon-container">
    <svg xmlns="http://www.w3.org/2000/svg" class="audio-icon" viewBox="0 0 20 20" fill="currentColor">
  <path d="M18 3a1 1 0 00-1.196-.98l-10 2A1 1 0 006 5v9.114A4.369 4.369 0 005 14c-1.657 0-3 .895-3 2s1.343 2 3 2 3-.895 3-2V7.82l8-1.6v5.894A4.37 4.37 0 0015 12c-1.657 0-3 .895-3 2s1.343 2 3 2 3-.895 3-2V3z" />
</svg>
       <audio src="https://www.zapsplat.com/wp-content/uploads/2015/sound-effects-61905/zapsplat_multimedia_alert_chime_short_musical_notification_cute_child_like_001_64918.mp3?_=1"></audio>
  </div>
</div>
```

Then, we'll add some CSS to style these elements.

```
.audio-player {
  width: 15rem;
  height: 15rem;
}

.icon-container {
  width: 100%;
  height: 100%;
  background-color: #DE5E97;
  color: #fff;
  display: flex;
  justify-content: center;
  align-items: center;
}

.audio-icon {
   width: 90%;
   height: 90%;
}
```

This will create the following audio track image.

![How to Style an Audio Element](https://backend.shahednasser.com/content/images/2021/08/Screen-Shot-2021-08-27-at-5.57.19-PM.png)

This has nothing to do with the actual functionality of the audio. It's just to make the visual nice.

### Add the Play Button

Next, we'll add the play button. There are 3 phases of adding the play button: adding the HTML elements, adding the CSS styling, then implementing the Javascript functionality.

**Add the HTML elements**

Add the following inside the `.audio-player` element:

```
<div class="controls">
    <button class="player-button">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
  <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd" />
</svg>
    </button>
</div>
```

This will add a container `.controls` element, then inside it, we're adding a button that has a play icon inside.

**Add the CSS styles**

Next, we'll add the CSS styles for the `.controls` element and the button.

First, add the following [CSS Variable](https://blog.shahednasser.com/css-variables-and-how-to-use-them) inside `.audio-player`:

```
.audio-player {
  --player-button-width: 3em;
    ...
}
```

Then, add the following CSS to style the `.controls` and `.player-button` elements:

```
.controls {
  display: flex;
  flex-direction: row;
  align-items: center;
  width: 100%;
  margin-top: 10px;
}

.player-button {
  background-color: transparent;
  border: 0;
  width: var(--player-button-width);
  height: var(--player-button-width);
  cursor: pointer;
  padding: 0;
}
```

This will style the `.controls` element to be a flexbox element. This will allow us to align the controls (which we will add more later) inside nicely.

The player button just has a transparent background and no border, as we just want to show the icon inside.

This will produce the following UI:

![How to Style an Audio Element](https://backend.shahednasser.com/content/images/2021/08/Screen-Shot-2021-08-27-at-5.57.42-PM.png)

However, clicking the button now does nothing. We need to use Javascript to bind the functionalities to the audio.

**Bind the Functionality with Javascript**

In Javascript, we'll first define some variables:

```
const playerButton = document.querySelector('.player-button'),
      audio = document.querySelector('audio'),
      playIcon = `
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
    <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z" clip-rule="evenodd" />
  </svg>
      `,
      pauseIcon = `
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
  <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z" clip-rule="evenodd" />
</svg>
      `;
```

We've defined `playerButton` which is the player button element, `audio` which is the audio this player is for, `playIcon` and `pauseIcon` which we will use to toggle the icon of the button.

Then, we'll create the function that should be triggered when the button is clicked:

```
function toggleAudio () {
  if (audio.paused) {
    audio.play();
    playerButton.innerHTML = pauseIcon;
  } else {
    audio.pause();
    playerButton.innerHTML = playIcon;
  }
}
```

This function checks whether the audio is paused or playing, then it either plays or pauses it. It also changes the icon of `playerButton`.

Next, add the function as an event listener to the click event of `playerButton`:

```
playerButton.addEventListener('click', toggleAudio);
```

We also need to update the icon of `playerButton` when the audio ends. To do that, we can use the audio element's event [ended](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/ended_event) and in the listener change the icon back to the play icon:

```
function audioEnded () {
  playerButton.innerHTML = playIcon;
}

audio.onended = audioEnded;
```

You can try to play the audio by clicking on the play button, and the audio will work!

### Add the Timeline Track

Next, we need to add the timeline track, which will allow us to see the progress of the audio, as well as seek through the audio.

To implement the audio timeline track, the easiest approach is to use a [range input](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwiw5PmPxdHyAhUC4BoKHbV2DzgQFnoECAkQAQ&url=https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FWeb%2FHTML%2FElement%2Finput%2Frange&usg=AOvVaw3-3hJWlge4BGAI_YzitUwT). Using the range input, we'll first style it with CSS, then bind the functionalities in Javascript.

**Add the HTML elements**

Inside `.controls` add the following input range:

```
<input type="range" class="timeline" max="100" value="0">
```

**Add the CSS styles**

To style a range input, there are two elements to take into account: the thumb, which allows us to change the value of the input, and the track that the thumb resides on.

To style the thumb, the following cross-browser selectors are used:

```
::-webkit-slider-thumb
::-moz-range-thumb
::-ms-thumb
```

and the following cross-browser selectors are used to style the track:

```
::-webkit-slider-runnable-track 
::-moz-range-track
::-ms-track
```

For the simplicity of this tutorial and to avoid repetition, we'll just show the code for `-webkit` selectors. You can find the full, cross-browser code in the demo CodePen.

We'll first style the input range itself:

```
.timeline {
  -webkit-appearance: none;
  width: calc(100% - var(--player-button-width));
  height: .5em;
  background-color: #e5e5e5;
  border-radius: 5px;
  background-size: 0% 100%;
  background-image: linear-gradient(#DE5E97, #DE5E97);
  background-repeat: no-repeat;
}
```

Using `-webkit-appearance: none;` is necessary to be able to apply the styling.

Using `linear-gradient(#DE5E97, #DE5E97);` for `background-image` allows us to easily add the progress track of a different color based on the current progress of the audio.

To change the size of the background image, which means the position of the current progress in the audio, we use `background-size: 0% 100%;`. The first value is the width. It will be the value we'll update through Javascript to show the progress of the audio.

Next, we'll add the styling of the thumb:

```
.timeline::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 1em;
  height: 1em;
  border-radius: 50%;
  cursor: pointer;
  opacity: 0;
  transition: all .1s;
  background-color: #a94672;
}

.timeline::-webkit-slider-thumb:hover {
  background-color: #943f65;
}

.timeline:hover::-webkit-slider-thumb {
  opacity: 1;
}
```

We're just adding some styling to the thumb, and we're hiding it and showing it on hover.

Then, we'll basically hide the track as we'll just use the styling in `.timeline` to show the track and the progress of the audio:

```
.timeline::-webkit-slider-runnable-track {
  -webkit-appearance: none;
  box-shadow: none;
  border: none;
  background: transparent;
}
```

The track will look like this:

![How to Style an Audio Element](https://backend.shahednasser.com/content/images/2021/08/Screen-Shot-2021-08-27-at-5.58.03-PM.png)

### Bind the Javascript Functionality

We just need to add the Javascript functionality now. The track should show the progress of the audio, and it should allow changing the progress of the audio by moving the thumb.

First, we'll define the `timeline` variable for the element:

```
const timeline = document.querySelector('.timeline');
```

Then, we'll add the function that will listen to the [timeupdate](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/timeupdate_event) event. The `timeupdate` event is triggered whenever the audio's time changes. So, it's triggered continuously as the audio is playing, and it's triggered when the audio [currentTime](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/currentTime) attribute is updated.

The function will calculate the progress of the audio in percentage using audio's currentTime attribute and audio's [duration](https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/duration) attribute. Then, will set the `backgroundSize` CSS property of the `timeline` element based on the calculation:

```
function changeTimelinePosition () {
  const percentagePosition = (100*audio.currentTime) / audio.duration;
  timeline.style.backgroundSize = `${percentagePosition}% 100%`;
  timeline.value = percentagePosition;
}

audio.ontimeupdate = changeTimelinePosition;
```

Next, we need to add the function that will handle the change event of the input range button, then change the progress of the audio as well as the `backgroundSize` CSS property:

```
function changeSeek () {
  const time = (timeline.value * audio.duration) / 100;
  audio.currentTime = time;
}

timeline.addEventListener('change', changeSeek);
```

You can now play the audio and see how the track shows the progress of the audio. You can also try changing the progress by moving the thumb.

### Add the Sound Button

The last thing we'll do is add a sound button. This button will just toggle the sound of the audio, muting and unmuting it.

**Add the HTML elements**

Add the following HTML elements inside `.controls`:

```
<button class="sound-button">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
  <path fill-rule="evenodd" d="M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM14.657 2.929a1 1 0 011.414 0A9.972 9.972 0 0119 10a9.972 9.972 0 01-2.929 7.071 1 1 0 01-1.414-1.414A7.971 7.971 0 0017 10c0-2.21-.894-4.208-2.343-5.657a1 1 0 010-1.414zm-2.829 2.828a1 1 0 011.415 0A5.983 5.983 0 0115 10a5.984 5.984 0 01-1.757 4.243 1 1 0 01-1.415-1.415A3.984 3.984 0 0013 10a3.983 3.983 0 00-1.172-2.828 1 1 0 010-1.415z" clip-rule="evenodd" />
</svg>
    </button>
```

This is just a button with an icon.

**Add the CSS Styles**

Next, we need to add the CSS styles.

First, add 2 new variables inside `.audio-player`:

```
.audio-player {
  --player-button-width: 3em;
  --sound-button-width: 2em;
  --space: .5em;
    ...
}
```

The `--sound-button-width` will be used for the width of the sound button, and `--space` will be used to add space between the track and the button.

Next, change the `width` of the `.timeline` element and add a `margin-right` property as well:

```
.timeline {
    width: calc(100% - (var(--player-button-width) + var(--sound-button-width) + var(--space)));
margin-right: var(--space);
    ...
}
```

Finally, add the CSS styling for the sound button:

```
.sound-button {
  background-color: transparent;
  border: 0;
  width: var(--sound-button-width);
  height: var(--sound-button-width);
  cursor: pointer;
  padding: 0;
}
```

We'll now have a sound button next to the track:

![How to Style an Audio Element](https://backend.shahednasser.com/content/images/2021/08/Screen-Shot-2021-08-27-at-5.58.19-PM.png)

**Bind the Javascript Functionality**

Lastly, we just need to bind the functionality of the sound button to the audio element. Clicking the sound button should mute or unmute the sound of the audio.

First, add the following new variable definitions:

```
const soundButton = document.querySelector('.sound-button'),
      soundIcon = `
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
  <path fill-rule="evenodd" d="M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM14.657 2.929a1 1 0 011.414 0A9.972 9.972 0 0119 10a9.972 9.972 0 01-2.929 7.071 1 1 0 01-1.414-1.414A7.971 7.971 0 0017 10c0-2.21-.894-4.208-2.343-5.657a1 1 0 010-1.414zm-2.829 2.828a1 1 0 011.415 0A5.983 5.983 0 0115 10a5.984 5.984 0 01-1.757 4.243 1 1 0 01-1.415-1.415A3.984 3.984 0 0013 10a3.983 3.983 0 00-1.172-2.828 1 1 0 010-1.415z" clip-rule="evenodd" />
</svg>`,
      muteIcon = `
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="#3D3132">
  <path fill-rule="evenodd" d="M9.383 3.076A1 1 0 0110 4v12a1 1 0 01-1.707.707L4.586 13H2a1 1 0 01-1-1V8a1 1 0 011-1h2.586l3.707-3.707a1 1 0 011.09-.217zM12.293 7.293a1 1 0 011.414 0L15 8.586l1.293-1.293a1 1 0 111.414 1.414L16.414 10l1.293 1.293a1 1 0 01-1.414 1.414L15 11.414l-1.293 1.293a1 1 0 01-1.414-1.414L13.586 10l-1.293-1.293a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>`;
```

This will add a `soundButton` variable, which will be the sound button element. It will also create two variables `soundIcon` and `muteIcon` to be used to change the icon of the button based on whether the audio is muted or not.

Next, add the function which will listen to the click event on the sound button:

```
function toggleSound () {
  audio.muted = !audio.muted;
  soundButton.innerHTML = audio.muted ? muteIcon : soundIcon;
}

soundButton.addEventListener('click', toggleSound);
```

### Final Demo

This will be the final result of creating the custom audio player:

{% codepen https://codepen.io/shahednasser/pen/XWgbGBN %}

The player can play, pause, seek, mute and unmute the audio, all while looking great.

## Conclusion

Using the pseudo-element selectors, you can do simple design changes to the audio element.

For more complex design changes, it's best to implement a custom audio player, then bind it with Javascript to the audio element to provide the necessary functionalities.