Custom video placeholder with lazy load for better performance
Features
- Full styling control of video placeholders
- An image/picture is used for the poster which allows the use of src-set
- Videos and embeds are lazy loaded to reduce page load
- Embeds are prefetched on user interaction to improve performance
- HTML Web Component version
Examples
Image
The default setup for the plugin with an image and a video.
The poster is the first frame of the video.
No image
The placeholder is styled instead of using an image.
Web component
Installation
$ npm install responsive-video-poster --save-dev
Usage
Import or add the JS into your project, add the elements to your HTML and initialize the plugin if needed.
JavaScript
import { ResponsiveVideoPoster, ResponsiveVideoPosterAuto } from 'responsive-video-poster.js';
OR
<script src="responsive-video-poster.js" type="module"></script>
Web Component
import { ResponsiveVideoPoster } from 'responsive-video-poster-wc.js';
OR
<script src="responsive-video-poster-wc.js" type="module"></script>
Initialize JS
// Initialize a single element
const responsiveVideoPosterDefault = ResponsiveVideoPoster({
selector: '#responsive-video-poster--default'
});
// Initialize all elements with default options, these can be overridden by reinitializing or by data attributes on the element.
ResponsiveVideoPosterAuto();
Markup
JS
<div class="responsive-video-poster">
<button class="rvp-placeholder" aria-label="Play video">
<span class="rvp-button" aria-hidden="true"><svg class="rvp-button-icon"> ... </svg></span>
<img srcset="images/720.jpg 720w, images/1080.jpg 1080w" src="images/1080.jpg" class="rvp-poster" width="1080" height="608" loading="lazy">
</button>
<video src="videos/video.mp4" class="rvp-video" preload="none" width="1080" height="608"></video>
</div>
Web Component
<responsive-video-poster>
...
</responsive-video-poster>
Options
The options can be set via initialization in the JS or by attributes on the element, which will be given the highest priority. The property is changed from camel case to dash case with with the prefix 'rvp' added for the JS version e.g. "activeClass" to "rvp-active-class".
<div class="responsive-video-poster" data-rvp-active-class="is-open">
<responsive-video-poster active-class="is-open">
Property | Default | Type | Description |
---|---|---|---|
selector |
'.responsive-video-poster' | String || Element | Container element selector. |
placeholderSelector |
'.rvp-placeholder' | String | Placeholder element selector. |
posterSelector |
'.rvp-poster' | String | Poster element selector. |
videoSelector |
'.rvp-video' | String | Video element selector. |
animClass |
'is-anim' | String | CSS class to transition the video placeholder between states. |
activeClass |
'is-active' | String | CSS class when placeholder is transitioned and the video is playing. |
playDelay |
'transition' | Integer(ms) || 'transition' | Delay playing the video by set time or wait for the placeholder transition to finish. |
playDelayOffset |
0 | Integer(ms) | Reduces playDelay to start loading the video before the placeholder has finished transitioning. |
hideControlsOnLoad |
true | Boolean | Hide video controls while transitioning placeholder. |
hideControlsOnFirstPlay |
false | Boolean | Hide video controls on first video play. |
preConnections |
[] | Array || Comma seperated list | Domains to preconnect to for loading an embed. Youtube and Vimeo are automatically preconnected. |
embedApi |
false | Boolean | Embed Youtube API, this is autmatically added on Safari to get around autoplay restrictions. |
API
Property | Type | Description |
---|---|---|
instance.playVideo() |
Method | Plays the video. |
instance.getInfo() |
Object | Returns the element and its properties. |
Performance optimizations
Responsive image techniques(srcset, sizes, source, etc) are used to load the most appropriate image. Native lazy loading is used on the responsive poster image to reduce initial page load. The plugin should also work normally with lazy load plugins.
The video element includes preload="metadata" or preload="none" so the video is not loaded until the user interacts with it. This will reduce the initial page load but may create lag in playback for some users. This can be removed if not needed.
The embedded video includes srcdoc="" so the video and third-party scripts are not loaded until the user interacts with it. The 'preConnections' option can be used to pass domains to start pre-connect connections for loading an embedded video. this happens when the user hovers/taps on the video using the pointerover event. For example Youtube could use ['https://www.youtube.com', 'https://www.google.com'].
Events
A 'playVideo' event is started once a user clicks the video placeholder. The event is ended once the placeholder has become inactive and the video starts playing.
document.querySelector('#responsive-video-poster--default').addEventListener('playVideo', (event) => {
console.log(`Action: ${event.detail.action}`);
});
You can also attach this to the document.
document.addEventListener('playVideo', (event) => {
console.log(`Target: ${event.target.matches('#responsive-video-poster--default')}`, `Action: ${event.detail.action}`);
});
Compatibility
Supports all modern browsers at the time of release.
Demo site
Clone the repo from Github and run the commands below.
$ npm install
$ npm run dev
References
Lazy loading of an embedded video by Arthur Corenzan. Lazy load third-party resources with facades. HTML Web Components by Jim Nielsen Lite YouTube Embed by Paul Irish.
Covverr videos of Lago di braies and Lofoten rocks. Youtube video of Tustan Karpaty mountains.