48

I'm trying to get the video to be able to play and pause like it does YouTube (Using both the play and pause button, and clicking the video itself.)

<video width="600" height="409" id="videoPlayer" controls="controls">
 <!-- MP4 Video -->
 <source src="video.mp4" type="video/mp4">
</video>


<script>
    var videoPlayer = document.getElementById('videoPlayer');

    // Auto play, half volume.
    videoPlayer.play()
    videoPlayer.volume = 0.5;

    // Play / pause.
    videoPlayer.addEventListener('click', function () {
        if (videoPlayer.paused == false) {
            videoPlayer.pause();
            videoPlayer.firstChild.nodeValue = 'Play';
        } else {
            videoPlayer.play();
            videoPlayer.firstChild.nodeValue = 'Pause';
        }
    });
</script>

Do you have any ideas why this would break the play and pause control button?

Peter Badida
  • 10,502
  • 9
  • 40
  • 84
user2698522
  • 481
  • 1
  • 4
  • 4
  • 1
    possible duplicate of [Click the poster image the HTML5 video plays?](http://stackoverflow.com/questions/5278262/click-the-poster-image-the-html5-video-plays) – Daniel Golden Jan 29 '15 at 16:22
  • Keep in mind that the latest firefox versions have out-of-the-box support for pausing/playing the video on click on a `` tag. – ccpizza Sep 22 '17 at 23:02
  • you need not added controls it comes as part of the tag itself. – Nagappan Feb 05 '19 at 14:32

11 Answers11

112

The simplest form is to use the onclick listener:

<video height="auto" controls="controls" preload="none" onclick="this.play()">
 <source type="video/mp4" src="vid.mp4">
</video>

No jQuery or complicated Javascript code needed.

Play/Pause can be done with onclick="this.paused ? this.play() : this.pause();".

Demo:

<video height="200" controls="controls" preload="none" onclick="this.play()">
 <source type="video/webm" src="https://upload.wikimedia.org/wikipedia/commons/transcoded/5/54/Yawning_kitten.ogv/Yawning_kitten.ogv.480p.vp9.webm">
</video>

On Chromium 89:

  • onclick="this.play()" prevents the video from playing again by clicking on the body (rather than controls) after an initial play + pause (clicking on controls still works), which is generally undesirable. This is presumably because the callback makes it play, and then the event propagates and the browser immediately re-pauses it.
  • the default behavior without onclick="this.play()" would be: initial body click to play on body does not work, but after initial play clicks on body do toggle play/pause
  • onclick="this.paused ? this.play() : this.pause();" makes body clicks after the initial play not work neither to play nor pause, presumably for an analogous to what happens with onclick="this.play()"
oabarca
  • 10,186
  • 6
  • 56
  • 69
51

HTML:

<video class="video"><source src=""></video>

JAVASCRIPT: "JQUERY"

$('.video').click(function(){this.paused?this.play():this.pause();});
Mickey
  • 2,137
  • 5
  • 23
  • 36
16

Adding return false; worked for me:

jQuery version:

$(document).on('click', '#video-id', function (e) {
    var video = $(this).get(0);
    if (video.paused === false) {
        video.pause();
    } else {
        video.play();
    }

    return false;
});

Vanilla JavaScript version:

var v = document.getElementById('videoid');
v.addEventListener(
    'play', 
    function() { 
        v.play();
    }, 
    false);

v.onclick = function() {
    if (v.paused) {
        v.play();
    } else {
        v.pause();
    }

    return false;
};
Roberts126
  • 241
  • 3
  • 4
  • This worked for me except that the full-screen button stopped working... :( why? – ios-lizard Mar 12 '14 at 20:47
  • ios-lizard Are you using the jQuery or Vanilla JavaScript version. The full screen button works in my current implementation using the above jQuery version of the code. – Roberts126 Mar 29 '14 at 16:23
  • I was using jQuery 2.1.0 – ios-lizard Mar 30 '14 at 19:15
  • The jQuery code worked for me except on iPad. I changed `$(document).on('click', 'video',...` to `$('video').on('click',...` and strangely it started to work on iPad as well. – certainlyakey Nov 05 '14 at 23:13
5

I had countless issues doing this but finally came up with a solution that works.

Basically the code below is adding a click handler to the video but ignoring all the clicks on the lower part (0.82 is arbitrary but seems to work on all sizes).

    $("video").click(function(e){

        // get click position 
        var clickY = (e.pageY - $(this).offset().top);
        var height = parseFloat( $(this).height() );

        // avoids interference with controls
        if(y > 0.82*height) return;

        // toggles play / pause
        this.paused ? this.play() : this.pause();

    });
ios-lizard
  • 846
  • 1
  • 12
  • 19
4

I had this same problem and solved it by adding an event handler for the play action in addition to the click action. I hide the controls while playing to avoid the pause button issue.

    var v = document.getElementById('videoID');
    v.addEventListener(
       'play', 
          function() { 
             v.play();
          }, 
        false);

    v.onclick = function() {
      if (v.paused) {
        v.play();
        v.controls=null;
      } else {
        v.pause();
        v.controls="controls";
      }
    };

Seeking still acts funny though, but at least the confusion with the play control is gone. Hope this helps.

Anyone have a solution to that?

jkrz
  • 41
  • 3
2

Following up on ios-lizard's idea:

I found out that the controls on the video are about 35 pixels. This is what I did:

$(this).on("click", function(event) {
    console.log("clicked");
    var offset = $(this).offset();
    var height = $(this).height();
    var y = (event.pageY - offset.top - height) * -1;
    if (y > 35) {
        this.paused ? this.play() : this.pause();
    }
});

Basically, it finds the position of the click relative to the element. I multiplied it by -1 to make it positive. If the value was greater than 35 (the height of the controls) that means that the user click somewhere else than the controls Therefore we pause or play the video.

KatieK
  • 13,027
  • 17
  • 73
  • 87
Nathan
  • 1,161
  • 1
  • 15
  • 31
2

How about this one

<video class="play-video" muted onclick="this.paused?this.play():this.pause();">
   <source src="" type="video/mp4">
</video>
Abhi Burk
  • 1,702
  • 10
  • 20
2

On Chromium 89 and Firefox 86 click on body works, except the first click of preload="none" for Chromium

Of those browsers:

  • Firefox works perfectly: all clicks on video body toggle play/pause, just like corresponding clicks on controls. Furthermore it shows an intuitive placeholder that makes it clear to the user that clicking will work:

    enter image description here

  • Chromium has a bug where the first click no video body does not work for videos that have preload="none". Further clicks work however.

    And its placeholder does not make it clear that you can click to play anywhere (which you can't anyways, hopefully they will add a decent placeholder when the bug gets fixed):

    enter image description here

Therefore, the best option is to work around that bug minimally by only doing play on the first click:

<!doctype html>
<html lang=en>
<head>
<meta charset=utf-8>
<title>Min</title>
</head>
<body>
<video id="vid" height="200" controls="controls" preload="none">
 <source type="video/webm" src="https://upload.wikimedia.org/wikipedia/commons/transcoded/5/54/Yawning_kitten.ogv/Yawning_kitten.ogv.480p.vp9.webm">
</video>
<script>
let first = true;
document.getElementById('vid').addEventListener('click', (e) => {
  if (first) {
    e.target.play();
  }
  first = false;
});
</script>
</body>
</html>

This also does not break Firefox' correct behavior in any way.

TODO: make that workaround perfect by adding an overlay div that clearly indicates that the initial click to play will work, e.g. along the lines of: https://codepen.io/wizaRd_Mockingjay/pen/NVGpep but keeping the controls.

The JavaScript solution shown at: https://stackoverflow.com/a/35563612/895245 of doing onclick="this.play()" actually breaks the play after the first play + pause from working on those browsers, so I do not recommend it.

The evil part in me wants to think that Chromium behavior is worse because YouTube videos are the only videos that matter to them >:-)

  • Hi, some how when i remove controls attribute then onclick="this.paused ? this.play() : this.pause();" works fine but when it adds controls to shadow dom, chrome messes up the click on video and end up clicking somewhere in shadow dom and due to that it causes a bug. – Shashank Bhatt Mar 17 '22 at 11:23
1

The problem appears to be internal bubbling within the <video> element ... so when you click on the "Play" button the code triggers and then the play button itself get triggered :(

I couldn't find a simple (reliable) way to stop the click bubbling through (logic tells me there should be a way, but... it escapes me right now)

Anyway, the solution I found to this was to put a transparent <div> over the video sized to fit down to where the controls appear... so if you click on the div then your script controls play/pause but if the user clicks on the controls themselves then the <video> element handles that for you.

The sample below was sized for my video so you may need to juggle sizes of the relative <div>s but it should get you started

<div id="vOverlay" style="position:relative; width:600px; height:300px; z-index:2;"></div>
<video style="position:relative; top:-300px; z-index:1;width:600px;height:340px;" width="600" height="409" id=videoPlayer controls="controls">
<source src="video.mp4" type="video/mp4">
</video>

<script>
    var v = document.getElementById('videoPlayer');
    var vv = document.getElementById('vOverlay');
    <!-- Auto play, Half volume -->
    v.play()
    v.volume = 0.5;
    v.firstChild.nodeValue = "Play";

    <!-- Play, Pause -->
    vv.addEventListener('click',function(e){
        if (!v.paused) {
            console.log("pause playback");
            v.pause();
            v.firstChild.nodeValue = 'Pause';
        } else {
            console.log("start playback")
            v.play();
            v.firstChild.nodeValue = 'Play';
        }
      });
</script>
Offbeatmammal
  • 7,581
  • 2
  • 31
  • 50
0

must separate this code to work well, or it well pause and play in one click !

 $('video').click(function(){this.played ? this.pause() ;});
  $('video').click(function(){this.paused ? this.play() ;});
0

For chrome as of now we can fix the native click on video on shadow elements by this lines.

video::-webkit-media-controls {
    pointer-events: none;
}

But due to this native controls stops working and then we have to even enable that pointer events on inner sub-tree for enabling volume, seekbar and fullscreen controls by setting it to auto.

video::-webkit-media-controls-timeline {
    pointer-events: auto
}

video::-webkit-media-controls-play-button {
    pointer-events: auto;
}

And then either as per above answer from ciro or oabarca, we can make a click on parent div or on the video itself and then it will work fine.

Shashank Bhatt
  • 613
  • 9
  • 22