Occasionally, a client will request a slider that contains YouTube videos. While having a video in a slider is a pretty cool feature, it can present a bit of a challenge for web developers. We’re happy to do it of course, but we’d like to show how much goes into a seemingly simple design.
One of the primary issues for developers is that sliders tend to be set to transition to the next slide at set intervals – such as every 5 seconds. So when a user plays a video in the slider, it will keep playing in the background even as it transitions out of view.
There is also the challenge of making the video responsive. Unfortunately, iframes don’t work well with traditional responsive layout techniques. In this post, we’ll set out to tackle the challenge of pausing the slider when the video is playing while making sure our video is responsive.
What We’ll Be Using for Our Example
- A typical YouTube iframe embed that you would get from any YouTube video page.
- Cycle2 slideshow plugin
- YouTube Iframe Player API.
- JQuery
Cycle 2 Slider
Cycle2 is a popular slideshow plugin with a well documented API that makes working with sliders a snap. We’ll utilize the Cycle2 plugin to create our slider. In the HTML code block below, I’ve created the base code for a simple slider that includes one image and one YouTube video iframe:
<div class="page-wrapper"> <div id="slider" class="slider"> <div class="slide"> <img src="http://via.placeholder.com/1600x650" width="600" height="650" class="slide-image" alt="Placeholder"> </div> <!-- slide --> <div class="slide"> <div class="video-wrap"> <iframe width="560" height="315" src="https://www.youtube.com/embed/Lscb4SL58X4" frameborder="0" allowfullscreen></iframe> </div> </div> <!-- slide --> </div> <!-- slider --> </div> <!-- page-wrapper →
I’ve also created some CSS (SASS) to style our slider.
.page-wrapper { max-width: 1600px; margin: 0 auto; } #slider { width: 100%; margin: 0; border: 0; .slide { width: 100%; display: none; position: relative; &:first-child { display: block; } img { width: 100%; } } }
There are a few ways to get our Cycle2 slider to function. You can initialize the plugin and set options programmatically using Javascript, or you can add the ‘.cycle-slideshow’ class to your container element and set options using data attributes. I’ll be using Javascript for this example, but I’ll provide a finished working example of the data attribute method at the end of the post.
$('#slider').cycle({ slides: '.slide', fx: 'scrollHorz', timeout: 6000, });
Let’s take a closer look at our code. We’re utilizing the jQuery library and invoking the cycle method on our containing div with the ID of ‘slider’. The ‘slides’ option sets the elements that should become slides. In our case, we’re using a div with the class name of “slides.” The ‘fx’ option is set to ‘scrollHorz’ so the the slides scroll horizontally. The timeout option defines the time in milliseconds between each slide.
Cycle2 has a pretty robust API with loads of options. You can view all the Cycle2 Options on their API page.
See the Pen Responsive Video Slider with Cycle2 That Pauses Rotation When the Video Plays – Step 1 by Andrew Gehman (@AndrewGehman) on CodePen.
At this point, we should have a functioning slider. However, we still have the same problems I mentioned above. If you play the video, the slider will continue to ‘slide’ out of view even while the video is playing. Also, the video is not responsive.
Making The Video Responsive
To make the video embed truly responsive, we need a bit of CSS magic.
Our iframe has a parent element with a class of ‘video-wrap.’ We need to set the containing element to have an aspect ratio that matches our slider. We can accomplish this by giving our containing element a height of 0 and setting the bottom padding to a percentage which is equal to our required aspect ratio.
Doing so allows the bottom padding to provide the proper height in response to the changing width. In our example, we’d like the slider to have a width of 1600px and a height of 650px. So, to get the proper ratio we divide 650 by 1600 and get .40625 or 40.625%. If we wanted our ratio to be 16:9, we would divide 9 by 16 and get 56.25%.
We are also going to remove the inline height and width from our iframe so it doesn’t conflict with our CSS.
.video-wrap { position: relative; //slider resolution = 1600 x 650, so this percentage is from 650/1600=0.40625 padding-bottom: 40.625%; height: 0; overflow: hidden; }
See the Pen Responsive Video Slider with Cycle2 That Pauses Rotation When the Video Plays – Step 2 by Andrew Gehman (@AndrewGehman) on CodePen.
Finally, we’ll deal with the issue of the slider continuing to advance slides even when the video is playing. Cycle2 has ‘pause’ and ‘resume’ commands that we can utilize to pause and resume our slider. We’ll also need a way to execute those commands when the video is paused or resumed. Enter the YouTube Iframe Player API.
YouTube Iframe Player API
We’re going to add an id of “player” to our YouTube iframe and append “?enablejsapi=1” to the end of the src attribute. We’ll need both of these when working with the YouTube Iframe Player API. Adding the enablejsapi parameter allows the video to be controlled by the YouTube IFrame Player API. Adding an id will allow us to reference the specific video in our code.
So, now our iframe should look like this:
<iframe id="player" src="https://www.youtube.com/embed/Lscb4SL58X4?enablejsapi=1" frameborder="0" allowfullscreen></iframe>
Now, we’ll create the Javascript using the YouTube IFrame Player API that will interact with our video.
var player function onYouTubeIframeAPIReady() { player = new YT.Player('player', { events: { 'onStateChange': onPlayerStateChange, } }); } function onPlayerStateChange(event) { if (event.data == YT.PlayerState.PLAYING) { $('#slider').cycle('pause'); } if (event.data == YT.PlayerState.ENDED){ $('#slider').cycle('resume'); } } function stopVideo() { player.stopVideo(); }
The onYouTubeIframeAPIReady() function will run when the JavaScript for the YouTube Iframe Player API has finished loading. With this function, we create a new YouTube player (with the id of ‘player’, that we’ve already added to our HTML code) and set an event of onStateChange that will run onPlayerStateFunction(). As the name suggests, this function will look for any change in state of the YouTube player. When the state of the player changes, the onPlayerStateFunction() checks if the state of the player is “PLAYING” or “ENDED.” If the video is playing, we tell the cycle slider to ‘pause.’ If the the video has finished, we tell the cycle slider to resume sliding.
See the Pen Responsive Video Slider with Cycle2 That Pauses Rotation When the Video Plays – Final by Andrew Gehman (@AndrewGehman) on CodePen.
Data Attributes Rather Than JavaScript for Cycle2
As promised, here’s a look at the same example using HTML5 data attributes with Cycle2.
<div class="page-wrapper"> <div id="slider" class="cycle-slideshow" data-cycle-timeout="6000" data-cycle-fx="scrollHorz" data-cycle-slides=">.slide"> <!-- slide --> <div class="slide"> <img src="http://via.placeholder.com/1600x650" width="600" height="650" class="slide-image" alt=""> </div><!-- slide --> <div class="slide"> <div class="video-wrap"> <iframe id="player" width="560" height="315" src="https://www.youtube.com/embed/Lscb4SL58X4?enablejsapi=1" frameborder="0" allowfullscreen></iframe> </div> </div><!-- slide --> </div> <!-- slider --> </div> <!-- page-wrapper -->
See the Pen Responsive Video Slider with Cycle2 That Pauses Rotation When the Video Plays – Final w/ Data Attributes by Andrew Gehman (@AndrewGehman) on CodePen.
Now, we should have a functional slider that is not only responsive, but stops sliding while the video is playing.