Forums

Give help. Get help.

  • # October 26, 2017 at 5:40 am

    In short, I have an HTML5 video on a webpage and I’d like a custom play/pause button as I don’t want to display the default browser controls. It doesn’t look great and it’s a bit OTT for what I need. The is to go on my portfolio, so I’m bending what I believe is ‘best practice’ here to be a bit more creative but I am open to suggestions.

    Here is my HTML markup

    <figure class="pop">
        <video preload="auto" loop="loop">
            <source src="video/work/gbm/xmas-landing.mp4" type="video/mp4">
            <source src="video/work/gbm/xmas-landing.ogg" type="video/ogg">
            Your browser does not support the video tag.
        </video>
    </figure>
    

    That all seems to work/play ok. In the CSS I’ve set height: auto; width: 100%; max-width: 100%; to make the video element responsive. That’ll do it, right?

    My currently javascript looks like this, something I got from StackOverflow:

    $(document).ready(function() {
        // Get media - with autoplay disabled (audio or video).
        var media = $('video').not("[autoplay='autoplay']");
        var tolerancePixel = 200;
    
        function checkMedia(){
            // Get current browser top and bottom.
            var scrollTop = $(window).scrollTop() + tolerancePixel;
            var scrollBottom = $(window).scrollTop() + $(window).height() - tolerancePixel;
    
            media.each(function(index, el) {
                var yTopMedia = $(this).offset().top;
                var yBottomMedia = $(this).height() + yTopMedia;
    
                // Don't play video when outside of viewport.
                if(scrollTop < yBottomMedia && scrollBottom > yTopMedia){
                    $(this).get(0).play();
                } else {
                    $(this).get(0).pause();
                }
            });
        }
        $(document).on('scroll', checkMedia);
    });
    

    As the video is halfway down the page, I don’t want it to play until it’s in view. The script above helps with that. Though I’m thinking it might be good if tolerancePixel could be a percentage instead of a pixel value – or is there another way to get the video to play which would work better?

    That script does the job but it’s making it difficult for me to add a play/pause button. I future these icons would sit below the video so the user could pause the video if they like and then restart it.

    I also thought it would be a good idea for the video to stop once it had played through once and then a ‘play again’ button to appear.

    What are peoples thoughts on this and can you offer any advice? Cheers!

    # October 26, 2017 at 11:24 pm

    Here’s a pen if someone feels inclined to fiddle around. I may have a go at it later…

    codepen.io/anon/pen/rYBJWN

    # October 27, 2017 at 5:30 am

    Sorry @shikkediel! I’d created an example, I obviously forgot to include it. I’ll stick with yours to avoid confusion, it’s pretty much the same.

    I found some StackOverflow posts on how to create custom controls but I couldn’t get them to work with this. Maybe because the ‘in view’ javascript causes a conflict with it.

    # October 27, 2017 at 6:50 am

    Couldn’t solve it off the top of my head but it looks kinda interesting. I’ll be back.

    Edit – here’s a little start (far from finished):

    codepen.io/anon/pen/oovRVG

    One thing I would do for a better user experience is to mute the video unless chosen otherwise…

    # October 27, 2017 at 8:16 am

    Was just about to post something but you beat me to it! I’m on my phone at the future but that’s working great at a glance. I’ll check it in a bit when I’m home.

    I was just going to say (as always with my attempts at Javascript) when I tried to add a custom controls it was a bit of a Frankenstein of code from different sources. So that probably didn’t help. Amongst StackOverflow threads I also had a look at this: http://www.creativebloq.com/html5/build-custom-html5-video-player-9134473 but I couldn’t get them to play together.

    The video I’m using doesn’t have sound but it makes sense that there should be the option the unmute the video to future-proof it. I agree if it is going to play by default, it should at least be muted. At the minute there’s just 1 video on any given page. I suppose I should really add the autoplay to a class as if there’s multiple videos on a page it could be annoying if they all autoplayed!

    # October 27, 2017 at 7:42 pm

    I’ve forked it and added a muting button as well. When the user clicks the pause button, it will then deselect it from the scrolling action. Seemed like a good idea. I’ll have to work on it a bit more, it’s not capable of doing multiple vids for example.

    codepen.io/Shikkediel/pen/qVBOPo

    I hadn’t used Codepen in a while and hadn’t seen the new https enforcing. Now all my http script links aren’t working anymore. Some reworking to do there. Glad I didn’t create that many pens.

    :-/

    # October 29, 2017 at 12:11 pm

    Rewrote the whole thing, based on a script of my own. It’ll take into account multiple video streams and recalculate things when resizing the screen as well.

    Minor things should still be done…

    # October 31, 2017 at 4:04 am

    Hey @shikkediel this looks great, thanks a lot! You’ve got above and beyond as usual! I’m going to add it onto my site now and style the buttons etc. Out of interest what gets recalculated when the screen resizes? Is that just if the video enters/exits the screen?

    I think the only thing I might amend or add is add/remove a class instead of the bit

    $(this).text(function(i, v) {
        return v === 'MUTE' ? 'UNMUTE' : 'MUTE';
    });
    

    Just incase I use an icon and I can switch them out!

    Thanks again!

    # October 31, 2017 at 11:23 am

    No problem, mostly a copy paste from previous scripts I put together. I added a throttling function as well so it only checks things 10 times a second. You are correct about the recalculation, it will store the position of the videos on resizing:

    zenith.push(placement-$(window).height()*0.9+size);
    nadir.push(placement+size*0.1);
    

    The variable zenith determines the point where the video starts when it emerges from the bottom of the screen. In this case when the bottom of the video itself is at 90% of the screen size. And nadir is the point where the video stops when going outside the top of the screen, which will happen when 10% of the top of the video has disappeared. Hope that was clear enough.

    You could still use the bit of code to insert icons if you use .html instead of .text by the way:

    $(this).html(function(i, v) {
       ...
    });
    

    Let me know when something not working. Cheers.

    # October 31, 2017 at 11:52 am

    Yeah that makes sense. All seems to work well so far!

    I was thinking with a class I could have something like this as the icon: https://codepen.io/morgun/pen/mInAk

    Then just use the playing class or whatever to toggle between the states. Or if it was a simpler version, just display different background images on the same button. I suppose that’d work well for the mute icon as well.

    # October 31, 2017 at 12:29 pm

    I had a go at UTF-8 encoding for icons as well but couldn’t really make it look nice. Switching backgrounds would have been my next approach but that example you posted is pretty neat.

    # October 31, 2017 at 2:16 pm

    Yeah, they can be a bit tricky. I still find it odd adding icons to a button without fallback text just incase scripts don’t fire etc but I suppose if that was the case a player wouldn’t work anyways!

    Is this a bit overkill (below)? I was just going to use toggleClass but I’ve had problems with that in the past where it can go out of sync and the classes almost end up the other way round – if that makes sense. So the icons represent their opposites.

    $('.player__flow').click(function() {
    
            var media = $(this).siblings('video');
    
            media.addClass('managed');
    
            $(this).text(function(i, v) {
                return v === 'PLAY' ? 'PAUSE' : 'PLAY';
            });
    
            if ($(this).hasClass('active')) {
                $(this).removeClass('active');
            } else {
                $(this).addClass('active');
            } 
    
            if (media[0].busy) media[0].pause();
            else media[0].play();
        });
    
    # October 31, 2017 at 3:39 pm

    I think you’d want to go with something like this then, which should never mix the active state up with the buttons:

    $('.player__flow').click(function() {
    
      var media = $(this).siblings('video');
    
      media.addClass('managed');
    
      if (media[0].busy) {
      media[0].pause();
      $(this).text('PLAY').removeClass('active');
      }
      else {
      media[0].play();
      $(this).text('PAUSE').addClass('active');
      }
    });
    

    And the .text part might not even be needed there…

    Edit – I’ve also adapted this part of the script a bit so it will only show the buttons after they can actually effectuate playing the video (a longer video that’s still loading might make the buttons async otherwise):

    target.each(function() {
    
      $(this).on('canplay', function() {
    
        $(this).siblings('button').show();
      })
      .on('ended', function() {
    
        $(this).siblings('.flow').text('PLAY');
      });
    });
    

    And an additional bit of style:

    button {
    display: none;
    }
    
    # October 31, 2017 at 6:19 pm

    Can’t edit that edit anymore but I got inspired to completely overhaul the thing to work with a single background-image sprite for the buttons. And added some stuff to make it more solid when it comes to the videos being loaded.

    # November 1, 2017 at 3:23 am

    Yeah my JS can be a bit wild at times and ‘whatever it takes to get it working’. So that if/else was a bit OTT. I suppose in another situation I could’ve just said onClick ‘add this class, then if that class it already added, remove it …but then again I suppose that’s the same as toggleClass!

    That looks great again, I’ll implement it today. The loading aspect is a good idea. I noticed on iOS the video didn’t show on my example but I think that’s because I need to add a poster image onto the video element. I think the video elements normally uses the first frame but maybe it doesn’t do that automatically on iOS.

Viewing 15 posts - 1 through 15 (of 18 total)

You must be logged in to reply to this topic.

icon-anchoricon-closeicon-emailicon-linkicon-logo-staricon-menuicon-nav-guideicon-searchicon-staricon-tag