htmlcssgoogle-chromecss-selectorspseudo-element

How to hide "/" character delimiter in total time when using the native audio player in Chromium using CSS only?


I'm styling a native browser element, <audio>, and to do so, it's necessary to work with native browser pseudo elements, such as:

.audio-message audio::-webkit-media-controls-current-time-display {
        display: none;
}

Hiding this element makes the total audio duration element appear with a "/" in front.

audio element

I wish to hide this slash, as it makes no sense in the context where the remaining time is hidden, but I cannot use :first-letter with native element selectors.

My question is, how can we apply something like:

.audio-message audio::-webkit-media-controls-current-time-display::first-letter {
    display: none;  
}

The example doesn't work, I tried :is(), using :first-letter instead of ::, and also changing to hover and adding important to test if the issue was the selector.

I'd rather a CSS only solution, I know it could be done in JS in a way or other, but there are several audio elements and it would hurt performance.

audio::-webkit-media-controls-current-time-display  {
    display: none;
}

audio::-webkit-media-controls-current-time-display::first-letter {
    /* Doesn't work */
    display: none;  
}
<audio controls="" src="https://www.w3schools.com/tags/horse.ogg"></audio>

Test the snippet using Chrome-based browser please.


Solution

  • The audio player is displayed differently in every browser. We could only address each of them with cumbersome coding, thus it's a better approach to create a custom audio player, like this for example:

    // scripts.js
    document.addEventListener('DOMContentLoaded', function() {
      var audio = document.getElementById('audio');
      var playPauseButton = document.getElementById('play-pause');
      var playIcon = document.getElementById('play-icon');
      var pauseIcon = document.getElementById('pause-icon');
      var volumeControl = document.getElementById('volume');
      var muteButton = document.getElementById('mute');
      var speakerIcon = document.getElementById('speaker-icon');
      var muteIcon = document.getElementById('mute-icon');
      var speedOptions = document.querySelectorAll('.speed-option');
      var timeline = document.getElementById('timeline');
      var currentTimeDisplay = document.getElementById('current-time');
    
      // Play/Pause functionality
      playPauseButton.addEventListener('click', function() {
        if (audio.paused) {
          audio.play();
          playIcon.style.display = 'none';
          pauseIcon.style.display = 'block';
        } else {
          audio.pause();
          playIcon.style.display = 'block';
          pauseIcon.style.display = 'none';
        }
      });
      // Revert to play icon when audio ends
      audio.addEventListener('ended', function() {
        playIcon.style.display = 'block';
        pauseIcon.style.display = 'none';
      });
      // Volume control functionality
      volumeControl.addEventListener('input', function() {
        audio.volume = volumeControl.value;
        if (audio.volume === 0) {
          speakerIcon.style.display = 'none';
          muteIcon.style.display = 'block';
        } else {
          speakerIcon.style.display = 'block';
          muteIcon.style.display = 'none';
        }
      });
    
      // Mute functionality
      muteButton.addEventListener('click', function() {
        if (audio.muted) {
          audio.muted = false;
          speakerIcon.style.display = 'block';
          muteIcon.style.display = 'none';
        } else {
          audio.muted = true;
          speakerIcon.style.display = 'none';
          muteIcon.style.display = 'block';
        }
      });
    
      // Playback speed control functionality
      speedOptions.forEach(function(option) {
        option.addEventListener('click', function() {
          audio.playbackRate = this.dataset.speed;
        });
      });
    
      // Update current time display and timeline
      audio.addEventListener('timeupdate', function() {
        var currentMinutes = Math.floor(audio.currentTime / 60);
        var currentSeconds = Math.floor(audio.currentTime % 60);
        if (currentSeconds < 10) {
          currentSeconds = '0' + currentSeconds;
        }
        currentTimeDisplay.textContent = currentMinutes + ':' + currentSeconds;
    
        // Update timeline
        var value = (audio.currentTime / audio.duration) * 100;
        timeline.value = value;
      });
    
      // Seek functionality for timeline
      timeline.addEventListener('input', function() {
        var time = (timeline.value / 100) * audio.duration;
        audio.currentTime = time;
      });
    });
    /* styles.css */
    .audio-player {
      display: flex;
      align-items: center;
      background: #f3f3f3;
      border-radius: 100px;
      padding: 5px;
      gap: 10px;
      width: 100%;
      max-width: 290px;
      margin: 0 auto;
    }
    
    button {
      padding: 10px 10px;
      background-color: transparent;
      border: none;
      border-bottom-right-radius: 20px;
      border-top-right-radius: 20px;
      font-size: 20px;
      line-height: 10px;
      z-index: 37;
      position: relative;
      cursor: pointer;
    }
    
    
    #play-pause {
      border-radius: 50px;
    }
    
    #play-pause:hover {
      background-color: #e0e0e0;
    }
    
    input[type="range"] {
      width: 100px;
    }
    
    #timeline {
      width: 80px;
    }
    
    .volume-control {
      display: flex;
      align-items: center;
      position: relative;
    }
    
    .volume-control input[type="range"] {
      position: relative;
      top: -2px;
      right: 50px;
      width: 47px;
    }
    
    .wrap {
      width: 0;
      overflow: hidden;
      position: absolute;
      float: right;
    }
    
    .volume-control:hover .wrap {
      overflow: visible;
    }
    
    #play-icon,
    #pause-icon,
    #speaker-icon,
    #mute-icon {
      width: 24px;
      height: 24px;
    }
    
    .dropdown {
      position: relative;
      display: inline-block;
    }
    
    .dropdown-content {
      display: none;
      position: absolute;
      background-color: #f9f9f9;
      min-width: 50px;
      box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
      z-index: 1;
    }
    
    .dropdown-content button {
      color: black;
      padding: 8px 12px;
      text-decoration: none;
      display: block;
      background: none;
      border: none;
      width: 100%;
      text-align: left;
      font-size: 14px;
    }
    
    .dropdown-content button:hover {
      background-color: #f1f1f1;
    }
    
    .dropdown:hover .dropdown-content {
      display: block;
    }
    
    .wrap::before {
      background-color: #e0e0e0;
      content: "";
      margin: 0 auto;
      position: absolute;
      right: -45px;
      width: 100px;
      height: 43px;
      border-radius: 50px;
      top: -17px;
      border: 5px solid #f3f3f3;
    }
    
    input[type="range"] {
      -webkit-appearance: none;
      width: 100%;
      height: 5px;
      border-radius: 5px;
      background: #595959;
      outline: none;
      opacity: 1;
      transition: opacity .2s;
    }
    
    input[type="range"]:hover {
      opacity: 1;
    }
    
    input[type="range"]::-webkit-slider-thumb {
      -webkit-appearance: none;
      appearance: none;
      width: 11px;
      height: 11px;
      border-radius: 50%;
      background: #000;
      cursor: pointer;
      box-shadow: 0 0 3px rgba(0, 0, 0, 0.1);
    }
    
    input[type="range"]::-moz-range-thumb {
      width: 11px;
      height: 11px;
      border-radius: 50%;
      background: #000;
      cursor: pointer;
      box-shadow: 0 0 3px rgba(0, 0, 0, 0.1);
      border: 0;
    }
    
    input[type="range"]::-ms-thumb {
      width: 11px;
      height: 11px;
      border-radius: 50%;
      background: #000;
      cursor: pointer;
      box-shadow: 0 0 3px rgba(0, 0, 0, 0.1);
    }
    
    /* For IE */
    input[type="range"]::-ms-track {
      width: 100%;
      height: 8px;
      border-color: transparent;
      color: transparent;
      background: transparent;
    }
    
    input[type="range"]::-ms-fill-lower {
      background: #f0f0f0;
      border-radius: 10px;
    }
    
    input[type="range"]::-ms-fill-upper {
      background: #f0f0f0;
      border-radius: 10px;
    }
    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Custom Audio Player</title>
      <link rel="stylesheet" href="styles.css">
    </head>
    
    <body>
      <div class="audio-player">
        <audio id="audio" src="https://www.w3schools.com/tags/horse.ogg"></audio>
        <button id="play-pause">
                <svg id="play-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                    <path d="M8 5v14l11-7L8 5z" fill="currentColor"/>
                </svg>
                <svg id="pause-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="display: none;">
                    <path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" fill="currentColor"/>
                </svg>
            </button>
        <span id="current-time">0:00</span>
        <input type="range" id="timeline" value="0" max="100">
        <div class="volume-control">
          <button id="mute">
                    <svg  id="speaker-icon" width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
                        <path d="M16 9C16.5 9.5 17 10.5 17 12C17 13.5 16.5 14.5 16 15M19 6C20.5 7.5 21 10 21 12C21 14 20.5 16.5 19 18M13 3L7 8H5C3.89543 8 3 8.89543 3 10V14C3 15.1046 3.89543 16 5 16H7L13 21V3Z" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
                        </svg>
                    <svg id="mute-icon"  width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" style="display: none;">
                        <path d="M10.6 5L13 3V8M3 3L21 21M13 18V21L7 16H5C3.89543 16 3 15.1046 3 14V10C3 9.63571 3.09739 9.29417 3.26756 9" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
                        </svg>
                </button>
          <span class="wrap"><input type="range" id="volume" min="0" max="1" step="0.01" value="1"></span>
    
        </div>
        <div class="dropdown">
          <button id="speed-menu">⋮</button>
          <div class="dropdown-content">
            <button class="speed-option" data-speed="0.5">0.5x</button>
            <button class="speed-option" data-speed="1">1x</button>
            <button class="speed-option" data-speed="1.5">1.5x</button>
            <button class="speed-option" data-speed="2">2x</button>
          </div>
        </div>
      </div>
      <script src="scripts.js"></script>
    </body>
    
    </html>

    EDIT:

    Here's a pure CSS approach (workaround):

    audio::-webkit-media-controls-current-time-display {
      display: none;
    }
    
    .wrap {
      position: relative;
    }
    
    /*essential part for the cover: */
    .wrap::before {
      content: '';
      background: #f3f3f3;
      width: 10px;
      height: 15px;
      position: absolute;
      top: 20px;
      left: 42px;
      z-index: 1;
    }
    
    /*to hide the cover in Firefox: */
    @-moz-document url-prefix() {
      .wrap::before {
        content: none;
      }
    }
    <div class="wrap"><audio controls="" src="https://www.w3schools.com/tags/horse.ogg"></audio>
      <div>

    This covers the "/" with the matching background color of the background it stands on.