skip to Main Content

I have an html audio tag in my project, which in some situation I need to disable.
In order to do it I apply the following css by adding disabled class to the audio tag:

audio.disabled {
  pointer-events: none
}

I would like to add a layer with opacity 50% that will cover the audio element, in order to give a different view for it when it is disabled.
I thought to use the pseudo class ::before, but do not manage to have a visible element.

Here is a snippet with what I have already:

function toggleAudioDisable() {
  document.getElementById('myAudio').classList.toggle("disabled");
}
.disabled {
  pointer-events: none
}
<audio id="myAudio" controls="controls" src="https://commondatastorage.googleapis.com/codeskulptor-assets/Epoq-Lepidoptera.ogg"></audio> <br> 

<button onclick="toggleAudioDisable()">Toggle Audio Disable</button>

Any idea how to implement it?

5

Answers


  1. "I would like to add a layer with opacity 50% that will cover the audio element, in order to give a different view for it when it is disabled."

    You can do this by adding an ‘opacity’ declaration to your .disabled class.

    function toggleAudioDisable() {
      document.getElementById('myAudio').classList.toggle("disabled");
    }
    .disabled {
      pointer-events: none;
      opacity: 50%;
    }
    <audio id="myAudio" controls="controls" src="https://commondatastorage.googleapis.com/codeskulptor-assets/Epoq-Lepidoptera.ogg"></audio> <br> 
    
    <button onclick="toggleAudioDisable()">Toggle Audio Disable</button>
    Login or Signup to reply.
  2. Use disabled attribute to prevent user interaction with element.

    Updated toggleAudioDisable function:

    function toggleAudioDisable() {
      var audio = document.getElementById('myAudio');
      if(audio.hasAttribute('disabled')){
        audio.removeAttribute('disabled');
        audio.classList.remove('disabled');
      } else {
        audio.setAttribute('disabled', disabled);
        audio.classList.add('disabled');
      }
    }
    

    Updated style:

    audio.disabled {
      pointer-events: none;
      opacity: 0.5;
    }
    
    Login or Signup to reply.
  3. I added a layer with opacity: 0.5 and it will works as you want. Hope it helps you!

    function toggleAudioDisable() {
      const audio = document.getElementById('myAudio');
      const isDisabled = audio.classList.toggle("disabled");
    
      const blocker = document.getElementById('blocker');
      if (isDisabled) {
        blocker.style.display = 'block';
      } else {
        blocker.style.display = 'none';
      }
    }
    .audio-wrapper {
      position: relative;
    }
    
    audio.disabled {
      pointer-events: none;
    }
    
    .blocker {
      position: absolute;
      width: 100%;
      height: 100%;
      top: 0;
      left: 0;
      opacity: 0.5;
      cursor: not-allowed;
      display: none;
      z-index: 1000;
      background: #FFF;
    }
    <div class="audio-wrapper">
        <audio id="myAudio" controls src="https://commondatastorage.googleapis.com/codeskulptor-assets/Epoq-Lepidoptera.ogg"></audio>
        <div id="blocker" class="blocker"></div>
    </div>
    <br> 
    <button onclick="toggleAudioDisable()">Toggle Audio Disable</button>
    Login or Signup to reply.
  4. Why don’t you style the tag itself "audio"?

    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
    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
    

    If this option does not suit you, I recommend creating a div container where you can add .audio-container::before

    <div class="audio-container">
       <audio>
    </div>
    
    Login or Signup to reply.
  5. I second jerad.blair’s answer, but if you were wondering why it isn’t working your way (or need to specify other properties in the future like background-color or content), it is because <audio> acts like a "replaced element". This means the ::before and ::after pseudo-elements will not be displayed if the element loads/renders properly. Read more on the MDN Web Docs

    The solution using a ::before element would require you to layer a non-replaced element in the markup, such as a <div>. So something like this will work:

    <html>
    <body>
      <div>
        <audio id="myAudio" controls="controls" src="..."></audio>
      </div>
      <br />
      <button onclick="toggleAudioDisable()">Toggle Audio Disable</button>
    </body>
    <script>
      function toggleAudioDisable() {
        document.getElementById("myAudio").classList.toggle("disabled");
      }
    </script>
    <style>
      div:has(#myAudio) {
        display: inline-block;
        border-radius: 50%;
        position: relative;
      }
      div:has(.disabled) {
        pointer-events: none;
      }
      div:has(.disabled)::before {
        content: "";
        position: absolute;
        border-radius: 2rem;
        z-index: 1;
        width: 100%;
        height: 100%;
        opacity: 0.5;
        background-color: white; /* alternatively, use your container background color */
      }
    </style>
    </html>
    

    This is quite a lot of markup and style overhead for simply an extra opacity property, but if you need to do anything more complex with the pseudo-element (e.g., background-color, content), you may have to go this route.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search