A CSS style guide for the default WordPress media player

As theme authors we’re always striving to give our themes a unique design and marry them to the WordPress ecosystem by trying to provide a unified user experience, to the best possible extent. As WordPress comes with its own widgets, shortcodes, and other components, it’s important for any theme to take them into consideration and style them accordingly to its look and feel.

Most of WordPress’s native components (i.e. widgets or shortcodes) do not come with their own predefined styles (i.e. the Gallery shortcode), but other ones (especially JavaScript based ones) do so (i.e. the Audio player). In this post we’ll see how we can visually customize the default WordPress media player and make it feel at home on our theme.

The WordPress media player

The WordPress media player is a wrapper on top of MediaElement.js, a powerful, customizable audio and video player that’s powered by HTML5 features. By default, in WordPress, it looks like this:

What we’ll achieve in this tutorial is to generate a set of predefined selectors for the player (along with WordPress’s audio playlist) and better match it on our theme. Here’s what we’ll be achieving to start with:

At first we’ll convert the player into light-skinned themed, suitable for more themes which are already on a dark-on-white mode.

Scripts and styles

First, let’s create the file my-theme-player.css to host our media player custom styles and enqueue it appropriately (in our theme’s functions.php file):

<?php
add_action( 'wp_footer', 'ci_theme_footer_scripts' );

function ci_theme_footer_scripts() {
	if ( wp_style_is( 'wp-mediaelement', 'enqueued' ) ) {
		wp_enqueue_style( 'my-theme-player', get_template_directory_uri() . '/css/my-theme-player.css', array(
			'wp-mediaelement',
		), '1.0' );
	}
}

The above snippet will ensure that our custom stylesheet will only load when MediaElement’s styles load (i.e. when there’s a media player on the page) and always after them (we need our custom styles to load after the default ones due to the cascade).

And because we’re good citizens, we need a way to isolate our theme’s styles from the rest of the WordPress ecosystem, i.e. assigning a unique class on the player so that we can nest every selector that we’ll use. This is always a good idea, as we’ve discussed previously in Writing effective CSS for WordPress, as it will limit the scope of the new styles just for our theme without possibly breaking other plugins relying on the WordPress media player.

<?php
/**
 * Add an HTML class to MediaElement.js container elements to aid styling.
 *
 * Extends the core _wpmejsSettings object to add a new feature via the
 * MediaElement.js plugin API.
 */
add_action( 'wp_print_footer_scripts', 'mytheme_mejs_add_container_class' );

function mytheme_mejs_add_container_class() {
	if ( ! wp_script_is( 'mediaelement', 'done' ) ) {
		return;
	}
	?>
	<script>
	(function() {
		var settings = window._wpmejsSettings || {};
		settings.features = settings.features || mejs.MepDefaults.features;
		settings.features.push( 'exampleclass' );
		MediaElementPlayer.prototype.buildexampleclass = function( player ) {
			player.container.addClass( 'mytheme-mejs-container' );
		};
	})();
	</script>
	<?php
}
functions.php

The code was kindly borrowed by cedaro. It will add the class .mytheme-mejs-container in the wrapper element of the media player. Feel free to change the prefix (mytheme) to anything you like (but make sure you replace it in the styles as well).

Styling the player

For this tutorial we’ll be changing the player’s theme to a light-skinned one, which is more suitable for most dark-on-white designs, plus adding a touch of character with an accent color.

/* Player background */
.mytheme-mejs-container.mejs-container,
.mytheme-mejs-container .mejs-controls,
.mytheme-mejs-container .mejs-embed,
.mytheme-mejs-container .mejs-embed body {
  background-color: #efefef;
}

/* Player controls */
.mytheme-mejs-container .mejs-button > button {
  background-image: url("images/mejs-controls-dark.svg");
}

.mytheme-mejs-container .mejs-time {
  color: #888888;
}

/* Progress and audio bars */

/* Progress and audio bar background */
.mytheme-mejs-container .mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-total,
.mytheme-mejs-container .mejs-controls .mejs-time-rail .mejs-time-total {
  background-color: #fff;
}

/* Track progress bar background (amount of track fully loaded)
  We prefer to style these with the main accent color of our theme */
.mytheme-mejs-container .mejs-controls .mejs-time-rail .mejs-time-loaded {
  background-color: rgba(219, 78, 136, 0.075);
}

/* Current track progress and active audio volume level bar */
.mytheme-mejs-container .mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-current,
.mytheme-mejs-container .mejs-controls .mejs-time-rail .mejs-time-current {
  background: #db4e88;
}

/* Reduce height of the progress and audio bars */
.mytheme-mejs-container .mejs-time-buffering,
.mytheme-mejs-container .mejs-time-current,
.mytheme-mejs-container .mejs-time-float,
.mytheme-mejs-container .mejs-time-float-corner,
.mytheme-mejs-container .mejs-time-float-current,
.mytheme-mejs-container .mejs-time-hovered,
.mytheme-mejs-container .mejs-time-loaded,
.mytheme-mejs-container .mejs-time-marker,
.mytheme-mejs-container .mejs-time-total,
.mytheme-mejs-container .mejs-horizontal-volume-total,
.mytheme-mejs-container .mejs-time-handle-content {
  height: 3px;
}

.mytheme-mejs-container .mejs-time-handle-content {
  top: -6px;
}

.mytheme-mejs-container .mejs-time-total {
  margin-top: 8px;
}

.mytheme-mejs-container .mejs-horizontal-volume-total {
  top: 19px;
}
my-theme-player.css

The styles above will make the player look like this:

Pretty nifty. We’ve changed the background color, text color, the progress / audio bars pigment to the theme’s accent color, and the buttons. For the buttons, you’ll need to create a new SVG icon-set with darker icons, as the default ones are totally white. You can download the one I’ve prepared here. Add it to an /images directory and you’ll be good to go.

As an additional note, you’ve probably noticed that there’s a lot of nesting. Unfortunately that’s how it has to be, since MediaElement.js is styled that way already and we also need our own container class on top. Using a pre-processor like Sass or LESS would help a lot with readability if you’re comfortable with it.

Styling for media playlists

Every time you create an audio playlist in a post or page and you select more than one audio file, WordPress will create the player in a playlist mode for you. By default it looks like this:

WordPress wraps playlists with a different container (its own, unrelated to MediaElement.js), and the following styles will help give a better visual:

.wp-playlist-light {
  box-shadow: 3px 3px 0 #e2e2e2;
}

/* Captions - Track titles / subtitles, time */
.wp-playlist-light .wp-playlist-caption,
.wp-playlist-light .wp-playlist-item-length {
  color: #787878;
}

/* Captions - Current track */
.wp-playlist-light .wp-playlist-current-item .wp-playlist-item-title {
  font-size: 16px;
}

.wp-playlist-light .wp-playlist-item-album {
  font-style: normal;
}

.wp-playlist-light .wp-playlist-item-artist {
  text-transform: none;
  opacity: .8;
}

/* Playlist items */
.wp-playlist-light .wp-playlist-item {
  padding: 10px 0;
  border-bottom-color: #efefef;
}

.wp-playlist-light .wp-playlist-item:last-child {
  padding-bottom: 0;
}

.wp-playlist-light .wp-playlist-playing {
  font-weight: normal;
  border-bottom-color: #db4e88;
}

.wp-playlist-light .wp-playlist-item-length {
  top: 10px;
}
my-theme-player.css

And here’s how our playlist looks now:

Much better! Be aware that we’re not changing any kind of font-family as we’d generally like them to be the same as our theme, but of course you’re free to do so!

Here’s the full CSS code supporting both a standalone player and the audio playlist:

/* Media Element Player styles */

/* Player background */
.mytheme-mejs-container.mejs-container,
.mytheme-mejs-container .mejs-controls,
.mytheme-mejs-container .mejs-embed,
.mytheme-mejs-container .mejs-embed body {
  background-color: #efefef;
}

/* Player controls */
.mytheme-mejs-container .mejs-button > button {
  background-image: url("images/mejs-controls-dark.svg");
}

.mytheme-mejs-container .mejs-time {
  color: #888888;
}

/* Progress and audio bars */

/* Progress and audio bar background */
.mytheme-mejs-container .mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-total,
.mytheme-mejs-container .mejs-controls .mejs-time-rail .mejs-time-total {
  background-color: #fff;
}

/* Track progress bar background (amount of track fully loaded)
  We prefer to style these with the main accent color of our theme */
.mytheme-mejs-container .mejs-controls .mejs-time-rail .mejs-time-loaded {
  background-color: rgba(219, 78, 136, 0.075);
}

/* Current track progress and active audio volume level bar */
.mytheme-mejs-container .mejs-controls .mejs-horizontal-volume-slider .mejs-horizontal-volume-current,
.mytheme-mejs-container .mejs-controls .mejs-time-rail .mejs-time-current {
  background: #db4e88;
}

/* Reduce height of the progress and audio bars */
.mytheme-mejs-container .mejs-time-buffering,
.mytheme-mejs-container .mejs-time-current,
.mytheme-mejs-container .mejs-time-float,
.mytheme-mejs-container .mejs-time-float-corner,
.mytheme-mejs-container .mejs-time-float-current,
.mytheme-mejs-container .mejs-time-hovered,
.mytheme-mejs-container .mejs-time-loaded,
.mytheme-mejs-container .mejs-time-marker,
.mytheme-mejs-container .mejs-time-total,
.mytheme-mejs-container .mejs-horizontal-volume-total,
.mytheme-mejs-container .mejs-time-handle-content {
  height: 3px;
}

.mytheme-mejs-container .mejs-time-handle-content {
  top: -6px;
}

.mytheme-mejs-container .mejs-time-total {
  margin-top: 8px;
}

.mytheme-mejs-container .mejs-horizontal-volume-total {
  top: 19px;
}

/* WordPress audio playlist styles */

.wp-playlist-light {
  box-shadow: 3px 3px 0 #e2e2e2;
}

/* Captions - Track titles / subtitles, time */
.wp-playlist-light .wp-playlist-caption,
.wp-playlist-light .wp-playlist-item-length {
  color: #787878;
}

/* Captions - Current track */
.wp-playlist-light .wp-playlist-current-item .wp-playlist-item-title {
  font-size: 16px;
}

.wp-playlist-light .wp-playlist-item-album {
  font-style: normal;
}

.wp-playlist-light .wp-playlist-item-artist {
  text-transform: none;
  opacity: .8;
}

/* Playlist items */
.wp-playlist-light .wp-playlist-item {
  padding: 10px 0;
  border-bottom-color: #efefef;
}

.wp-playlist-light .wp-playlist-item:last-child {
  padding-bottom: 0;
}

.wp-playlist-light .wp-playlist-playing {
  font-weight: normal;
  border-bottom-color: #db4e88;
}

.wp-playlist-light .wp-playlist-item-length {
  top: 10px;
}
my-theme-player.css

Restyling everything

In case you don’t want to override the default styles (as is the approach of this tutorial) you can always completely dequeue WordPress’s default styles and re-write everything as you see fit:

<?php
add_action( 'wp_enqueue_scripts', 'mytheme_deregister_media_element_styles' );

function mytheme_deregister_media_element_styles() {
	wp_deregister_style( 'mediaelement' );
	wp_deregister_style( 'wp-mediaelement' );
}
Dequeueing WordPress media element styles

Doing this will remove the default stylesheet WordPress loads with media element (but the player will still work) and you’d have to completely rewrite them as you see fit, layout and all. An amazing starting point if you’d like to go through this endeavour is Justin Tadlock’s Media Element base stylesheet, which provides the basic structure and layout boilerplate.

And that’s it! Let us know in the comments how you’ve customized the media player in your themes and what’s your approach, we’d love to exchange ideas!

Related Articles

57 comments

  1. michael says:

    Do you know the easiest and best way to set the WordPress built in audio player to set the default volume to 100% and not 80%? I know very little about website editing!

    Thanks!

    1. Vassilis Mastorostergios says:

      Heya, unfortunately I don’t think it’s possible. The only workaround I found is here and requires some custom code: https://github.com/mediaelement/mediaelement/issues/2449

  2. Naomi Janzen says:

    Hi, thanks for this! I want to hide my media player on selected blog posts (but still have its data readable to my podcasting plugin). My theme allows me to add CSS to each page so I am wondering if there is any CSS which can hide the media player.

    1. Vassilis Mastorostergios says:

      Hi, yes of course this should be easy!

      Let’s try adding the following rule:

      .mejs-container { display: none !important; }

      That should do the trick.

  3. Todd Jones says:

    Is it possible to use this tutorial for any theme that uses the default wordpress player? New to the process and I was wondering if these instructions would only work within the CI theme?

    1. Nik Vourvachis says:

      Hello Todd.

      Yes, this can be used in any WordPress theme, not just one of ours. Just keep in mind that if you see something wrong with the styling, it could be that the theme in use applies its own styles to the player which clash with your custom ones.

  4. mo says:

    hi, i want to make the sound audio as a small icon like this one for google translate

    1. Vassilis Mastorostergios says:

      Heya, you’d have to edit the SVG provided in this article with the app of your choice (i.e. Illustrator, Sketch, or some other vector design application) and replace it :)

  5. Mark says:

    Thanks for this guide Vassilis. I have a very long playlist that will be getting longer so I added:

    `.wp-playlist {
    max-height: 200px;
    overflow: auto;
    }`

  6. Mark says:

    I added the functions to Twenty Seventeen’s functions file and the css to its assets/css directory. All the styling is fine except that no play or volume icon displays on the player of the playlist.

    BTW, how do I change the image at the top left? I tried using display: none on the img tag and using a background image instead but failed with being unable to hide the music symbol but getting the background to show under a semi opaque layer of the symbol image.

    Thanks.

  7. Tekno Freek says:

    hi, is it possible that i can add custom title/caption in the default wordpress audio playlists? I am using the same audio file in multiple playlists – and I need the playlists to display different captions/titles.

    1. Vassilis Mastorostergios says:

      Hello, I’m afraid I don’t see WordPress allowing that, any time you change the title to a track it changes across all playlists.

  8. Kosiso says:

    This was very very helpful thank you

  9. Olamide says:

    Thats why i love this blog

  10. daniele says:

    Hallo, thanks a lot for the tutorial !! Do you know how may i insert a playlist audio that works like different players in sequence, instead of this compact version? ? ( Estetically like if i wanted to add one by one the files , with the thumnails on the left )

    1. Vassilis Mastorostergios says:

      Heya, glad you liked the tutorial. I’m not sure if I got the question right but you can add multiple tracks to the default WordPress audio player and it will look like a playlist. Alternatively you could look at our free audio player plugin AudioIgniter: https://www.cssigniter.com/plugins/audioigniter

  11. Kennedy says:

    This was very helpful thanks for sharing

  12. Godspower says:

    Nice tutorial admin great writeup. Thanks

  13. Tom says:

    Thank you very much! Do you know how to change the color of the time that appears on hover on the audio track progress bar? Right now it defaults to black.

    1. Vassilis Mastorostergios says:

      Hi, can you help me narrow down which element you’re talking about, the progress bar itself or the actual time digits (e.g. 00:34)? And on the main progress or in the track listing underneath?

  14. Annie says:

    Hello! I’ve used this awesome tutorial to style my theme’s players and everything was working great until I updated to WordPress v5. All audio / playlists added using the “Classic Block” are still styled correctly, but any audio added using the “Audio Block” is using the browser’s default audio player. Any ideas on how to extend the styling to work with the new audio block? Thanks!

    1. Vassilis Mastorostergios says:

      Heya, unfortunately I’m not aware of any good ways to style the default HTML5 audio player, this seems not to be possible right now so unless we want to use an external JS plugin (like mediaelementplayer) to override it we’re struck with it I’m afraid.

  15. RM says:

    Is there a way to add a scroll bar to the player to hide the long list of audios? thanks!

    1. Vassilis Mastorostergios says:

      Hello! Absolutely, it’s very simple, all you need is this code:

      .wp-playlist-tracks {
      max-height: 100px;
      overflow-y: scroll;
      }

      Feel free to adjust “100px” to the height of your liking.

  16. Jim says:

    Hi. This might sound like a really dumb question, but my audio player in wordpress doesn’t look like your first (black) example at all.

    And strangely enough, it looks different in every browser — Edge, Firefox, and Chrome.

    So it seems to me like for some reason the wordpress audio player is not loading, and it’s just passing it to the browser to load their own built-in audio players.

    How do I correct this, and get back to the wordpress audio player?

    Thanks!

    1. Vassilis Mastorostergios says:

      Heya, unfortunately since WP 5.0 WordPress has decided to use the native browser audio player for single audio files. I’m not aware of any good ways to style the default HTML5 audio player, this seems not to be possible right now so unless we want to use an external JS plugin (like mediaelementplayer) to override it we’re struck with it I’m afraid.

  17. AKA says:

    Thanks for this tip, been looking to style my media player

  18. T. Blanco says:

    Hey there, i wanted to style the wp audio player, but your guide says to put some inside functions.php. That doesn’t work right?

    Also i saw somewhere that wp 5.0 (with gutenberg) might not continue with this player?
    Any suggestions?

  19. T. Blanco says:

    actually i now found this: https://www.brianshim.com/webtricks/style-the-wordpress-3-6-media-player/ which gave me an much easier solution.
    what do you think?

  20. Hiphopza says:

    thanks for this update

  21. Kelvin says:

    Thanks for sharing

  22. Dharmendra k says:

    How to replace wordpress default video player with Fluid Player Or any other player which supports VAST …

    1. Vassilis Mastorostergios says:

      Hello, doesn’t seem like this is a question about the post but with some quick Googling I found this plugin here https://wordpress.org/plugins/fluid-player/

  23. Candy says:

    very detailed post, thank you!

  24. Ramona says:

    Thank you for this excellent work. I already use some styles for years and now add some additional ones from your suggestions. Nice!

    I like to share this post;)

  25. VirginSound says:

    I have read your tutorial concerning styling the default wordpress media player but I don’t really understand where to create the the file my-theme-player.css and how to enqueue it in my theme’s function.

    1. Nik says:

      Hello.
      It would be preferable to do all these in a child theme so you will be able to preserve changes during theme updates. If your theme author offers a child theme for your currently active theme, just download it, install and activate it. Then you can add the code in the child theme’s functions.php file and the styles in the child theme’s root folder. If your author does not offer a child theme you can create one yourself by checking out our article here.

  26. Lester G. says:

    Example simply breaks my site until I revert everything back!

    Quite complex and impractical example.

    Better would be if the player could be styled from within the style.css of the theme used unstead of tampering with the functions,php!

    1. Nik says:

      Hello Lester.
      Sorry to hear you are having a negative experience with the tutorial. Adding code to the theme’s functions.php is necessary because we need to add some custom classes to the media element. Perhaps what is wrong is that you need to omit the opening php tag from the first two code blocks to avoid disrupting the existing code. Of course this is just a guess, if there is a certain error you are getting you could let us know so we can assist further.
      Best regards.

  27. Alvaro says:

    Hi Nik,

    Thanks for the tutorial. I have copied the code into my child theme’s functions.php and the css in the my-theme-player.css file in the child theme’s root folder.
    However, nothing has changed in the actual website, could it be because I embedded the player inside a Divi module?

    This is the webpage in question:

    https://ciml.ch/musique/

    1. Nik says:

      Hello Alvaro.
      It appears that the media element styles are applied after your child theme styles and overwrite your changes. Try adding in your style like this
      .wp-playlist .wp-playlist-current-item {
      margin-bottom: 0px;
      }

      1. Alvaro says:

        Hi Nik,
        Thank you for your answer, it works now!
        However, the alignment of “current item title” and “current item artist” in mobile is screwed up for some reason. They are supposed to be aligned to the left and they just look off-centered.
        Do you have any idea why?

        1. Nik says:

          Hello again Alvaro.
          Sorry for this late reply, I’m guessing you have managed to fix this, correct?

  28. Alireza says:

    hi
    thanks for your useful article
    would it be possible to upload a video tutorial of this content in your youtube?

    1. Nik says:

      Hello Alireza.
      Thank you for the suggestion. We don’t have any plans to create such a video tutorial at the moment, but if more users are interested and we manage to find the time necessary perhaps we could do that.

  29. fakaza2019 says:

    Thank you for this post, i have copied the code to my site but i am yet to see any difference.

    1. Nik says:

      Hello there.
      Did you copy both the code in the functions.php and the my-theme-player.css?
      If yes is there a link where we can have a look?
      Thank you.

  30. yeyebrity says:

    will this still work on the latest version of wordpress.

    1. Nik says:

      Hello.
      It should work, yes. Did you try it and have different results?

  31. Reagan says:

    Can we add the code using code snippets plugin? If we can, how to copy the code? Will we copy all of those 3 codes into 1 code snippet?

    Thank you!

    1. Nik says:

      Hello Reagan.
      If you’d like to do this via plugin you should copy only the second bit of code to a snippet, without the first opening PHP tag if the snippet plugin provides it by default. Then you can place the third code block in your in the custom CSS in the WordPress Customizer, or if you are using a special plugin for style insertion.

  32. sterling says:

    thanks for sharing this… ive been searching for this article for long but thank God I found it here… thanks.

    the problem is that I’ve been trying to implement it on my website https://gidimack.com but its not showing as described in the main tutorial… any help please

    1. Nik says:

      Hello there!
      You are different results than what is expected due to the fact that your theme (Voice) has its own styling for the WordPress media player which overrides your new styles. I would suggest contacting your theme provider and ask them for information on how to disable the built in styles for the media player so you can apply your own.

  33. Krzysztof says:

    Hello, Great article. should I add this code to function.php or or elsewhere
    When i pass this code to function.php i have fatal error.

    “add_action( ‘wp_print_footer_scripts’, ‘mytheme_mejs_add_container_class’ “….

    1. Nik says:

      Hello Krzysztof.
      The code can go in the theme’s functions.php file, but if it’s not empty you should omit the opening PHP tag from the code blocks found in the article. If your functions.php is entirely empty (for example if you are doing this in a child theme) you will need to include the opening PHP tag once, on the top of the file, and omit the rest of them.
      If this still does not work please paste us the fatal error info so we can see if it’s something different.

Leave a Reply

Your email address will not be published. Required fields are marked *