Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent event bubbling when clicking on HTML5 video controls in Firefox

In Firefox when a video tag is wrapped in an a tag, using the standard video controls when clicking on the video to pause it also re-directs. How can I make it behave like the other browsers where for example clicking on pause only pauses the video and does NOT re-direct as well. This is what I need.

Here is a simple demo: http://jsfiddle.net/me2loveit2/cSTGM/

<a href="http://www.google.com" target="_blank">
    <video controls="" muted="" preload="auto" id="testid" width="500">
        <source src="http://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4"/>
        <source src="http://www.w3schools.com/html/mov_bbb.ogg" type="video/ogg"/>
        <source src="http://www.w3schools.com/html/mov_bbb.webm" type="video/webm"/>
        <img src="http://dummyimage.com/1044x585/000/fff"/>
    </video>
</a>
like image 773
Philipp Werminghausen Avatar asked Jul 23 '14 16:07

Philipp Werminghausen


3 Answers

What you've got there is invalid markup, the HTML5 spec clearly states that

The a element may be wrapped around entire paragraphs, lists, tables, and so forth, even entire sections, so long as there is no interactive content within (e.g. buttons or other links).

and the video navigation is in fact interactive content containing buttons.

For some reason clicking the controls in Chrome does not trigger the anchor, while in Firefox it does.
This is dependant on how the browser constructs the controls with the Shadow DOM, and as the markup is invalid and there is no real standard for this, it's anyone's guess.

What you should have done is to remove the anchor and use javascript to redirect when the video is clicked, something like this

$('#testid').on('click', function() {
    var win = window.open('http://www.google.com', '_blank');
    win.focus();
});

That would have given you valid markup as you could just remove the wrapping anchor, but it doesn't solve the problem with not redirecting when clicking the controls either, it's exactly the same, as the controls are still inside the video and triggers the click handler in Firefox, but not in Chrome.

In webkit the controls could potentially have been targeted somehow with the -webkit-media-controls pseudo class, however Firefox doesn't seem to have any such pseudo class, so that won't work either.

What you're left with is relying on the fact that the controls seem to always be at the bottom, and they are around 30 pixels high, so you can just overlay the anchor on top of the video and leave out a little part of the bottom.
This will work in all browsers, and you'll have valid markup.

<video controls="" muted="" autoplay preload="auto" id="testid" width="500">
    <!-- stuff -->
</video>
<a href="http://www.google.com" class="overlay" target="_blank"></a>

To make sure the anchor is placed correctly and has the correct size, a little javascript can be used

$('.overlay').each(function() {
    var vid = $(this).prev('video');
    $(this).css({
        position : 'fixed',
        top      : vid.offset().top + 'px',
        left     : vid.offset().left + 'px',
        width    : vid.width() + 'px',
        height   : (vid.height() - 30) + 'px',
    });
});

FIDDLE

like image 179
adeneo Avatar answered Oct 24 '22 17:10

adeneo


Other than using custom controls, I am not sure it's possible to get around the control behavior in a truly elegant way, given that the video events (play, pause, etc) trigger after the click events. This is a solution that hardcodes the approximate height of the default controls. I don't like the hardcoding, but in other respects I think it is OK. It applies to all a and video elements and doesn't do any excessive iterating through elements. The setTimeout bit is a workaround for event.preventDefault() killing both the link behavior and the play/pause behavior.

$(document).on('click', 'a', function(event) {
    var video = $('video:hover').first();
    if (video.length && video.offset().top + video.height() - event.pageY < 35) {
        var anchor = $(this);
        var href = anchor.attr('href');
        var target = anchor.attr('target');
        anchor.attr('href', 'javascript:;');
        anchor.attr('target', null);
        setTimeout(function() {
            anchor.attr('href', href);
            anchor.attr('target', target);
        }, 1);
    }
});
like image 21
Jason S Avatar answered Oct 24 '22 16:10

Jason S


You can accomplish this by creating custom controls for your video and wrap only the video tag with the a tag and not the controls. This gives you the option of having consistent looking controls for your video across browsers, but you have to have a good understanding of CSS to make it look good and consistent across browsers. I have included a CodePen project of what you wanted, with some custom controls. The controls don't look very good across browsers, but I think you can get the idea.

http://codepen.io/anon/pen/dtHsb

like image 26
Vivek Avatar answered Oct 24 '22 17:10

Vivek