2

How to embed YouTube and Vimeo the light way

 1 year ago
source link: https://dev.to/madsstoumann/how-to-embed-youtube-and-vimeo-the-light-way-2pek
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

You've probably embedded YouTube and Vimeo-videos dozens of times, using the standard <iframe>-embed-code.

While this works great out-of-the-box, services like Youtube loads a lot of Javascript, even if your users do not click on the embedded video.

I did a test with 3 embedded YouTube-videos. In this case, more than one megabyte of extra data was loaded.

That's a lot of unnecessary bandwidth. We can do better!


Lite Loaders

There are a lot of "lite loaders" out there, like lite-youtube or lite-youtube-embed.

If you're in a hurry, just npm install one of these.

Otherwise, hang on — it can be even lighter!


The Manual Way

We want to prevent YouTube or Vimeo loading anything, so we'll add the thumbnail-image for the video manually.

YouTube has an image-service, ytimg.com:

<img loading="lazy" src="https://i.ytimg.com/vi/[VIDEOID]/hqdefault.jpg">

The important part here is the [VIDEOID]. Replace this with the actual id.


Vimeo does not have a service like this, but we can use the (free for now) Vumbnail-service:

<img loading="lazy" src="vumbnail.com/[VIDEOID].jpg">

Vumbnail detects the video-provider automatically from the id/src.

Cool! Now, let's add a wrapper around the image, where we'll also add a dummy <iframe> and a play-<button>:

<youtube-embed>
  <img loading="lazy" src="https://i.ytimg.com/vi/[VIDEOID]/hqdefault.jpg" alt="Video Description">
  <iframe allow="autoplay" src="" data-src="https://www.youtube.com/embed/[VIDEOID]?autoplay=1"></iframe>
  <button aria-label="Play video"></button>
</youtube-embed>

It does not have to be a custom element, it's just a bit more readable, and we can use <vimeo-embed> for Vimeo-videos.


Styling

For styling, we're going to use our custom elements tags directly, instead of class’es:

:is(vimeo-embed, youtube-embed) {
  aspect-ratio: 16 / 9;
  border-radius: var(--video-embed-bdrs, 0.25em);
  display: grid;
  inline-size: 100%;
  position: relative;
}
:is(vimeo-embed, youtube-embed) :is(iframe, img) { 
  block-size: 100%;
  border: 0;
  border-radius: inherit;
  inline-size: 100%;
  inset: 0;
  object-fit: cover;
  position: absolute;
}

For the play-button, we'll add a bunch of CSS Custom Properties — allowing us to easily change colors etc:

:is(vimeo-embed, youtube-embed) button {
  background-color: var(--button-bgc, #F00);
  block-size: var(--button-h, 50px);
  border: 0;
  border-radius: var(--button-bdrs, 14%);
  display: grid;
  inline-size: var(--button-w, 75px);
  opacity: var(--button-op, 0.8);
  position: absolute;
  place-self: center;
  transition: all .2s ease-in;
}
:is(vimeo-embed, youtube-embed) button::before {
  aspect-ratio: 1;
  background: #FFF;
  block-size: 1.5em;
  clip-path: polygon(20% 0%, 20% 100%, 100% 50%);
  content: '';
  place-self: center;
}

vimeo-embed button { --button-bgc: #00adef; }

To hide the play-button when the <iframe> is loaded, we'll check if the src-attribute contains something else than an empty string:

:is(vimeo-embed, youtube-embed) iframe:not([src=""]) + button {
  display: none;
}

Now, to load the real <iframe>, all we have to do is replace src with data-src:

document.querySelectorAll(':is(vimeo-embed, youtube-embed) button').forEach(button => button.addEventListener('click', () => {
  const video = button.previousElementSibling;
  video.src = video.dataset.src;
}))

And that's it! We've replaced one megabyte of data with a few bytes.

Here's a Codepen-demo, with a short disclaimer: The videos don't autoplay directly from the Codepen-iframe, but will on your own site:


The Javascript Way

If you don't want to handle all that markup, a simpler way could be:

<youtube-embed id="5b4YcLB4DVI" title="Text">
<vimeo-embed id="70591644" title="Text">

All we need is the id of the video and a title for the thumbnail alt-attribute. Then in JavaScript, we can create the <img> and <button>-elements:

document.querySelectorAll('vimeo-embed, youtube-embed').forEach(v => {
  const [poster, src] = v.tagName === 'VIMEO-EMBED' ?
    [`vumbnail.com/${v.id}.jpg`, 'player.vimeo.com/video'] :
    [`i.ytimg.com/vi/${v.id}/hqdefault.jpg`, 'www.youtube.com/embed'];

  v.innerHTML = `<img loading="lazy" src="https://${poster}" alt="${v.title}"><button aria-label="Play"></button>`;
  v.children[1].addEventListener('click', () => v.innerHTML = `<iframe allow="autoplay" src="https://${src}/${v.id}?autoplay=1"></iframe>`)
})

That's 335 bytes gzipped, so it's not going to break your performance-budget.

Happy coding!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK