-
-
Save isaacl/d25e88efae01d95599972e250f056ac8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div | |
@pointerover.once="warmConnections" | |
@click="isActive = true" | |
:class="{ activated: isActive }" | |
:style="{ backgroundImage: `url(${posterUrl})` }" | |
> | |
<button v-if="!isActive" type="button" :title="playlabel" /> | |
<iframe | |
v-else | |
width="560" | |
height="315" | |
frameborder="0" | |
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" | |
allowfullscreen | |
:src="`https://www.youtube-nocookie.com/embed/${encodedVideoId}?${paramString}`" | |
></iframe> | |
</div> | |
</template> | |
<script lang="ts"> | |
import LiteYTEmbedUtils from './LiteYTEmbedUtils'; | |
export default { | |
name: 'lite-youtube', | |
props: { | |
videoid: { | |
type: String, | |
required: true, | |
}, | |
playlabel: { | |
type: String, | |
default: 'Play', | |
}, | |
params: String, | |
}, | |
data() { | |
return { | |
isActive: false, | |
}; | |
}, | |
computed: { | |
encodedVideoId() { | |
return encodeURIComponent(this.videoid); | |
}, | |
posterUrl() { | |
return `https://i.ytimg.com/vi/${this.encodedVideoId}/hqdefault.jpg`; | |
}, | |
paramString() { | |
const parsedParams = new URLSearchParams(this.params); | |
parsedParams.set('autoplay', '1'); | |
return parsedParams.toString(); | |
}, | |
}, | |
methods: { | |
warmConnections() { | |
LiteYTEmbedUtils.warmConnections(); | |
}, | |
}, | |
created() { | |
LiteYTEmbedUtils.addPrefetch('preload', this.posterUrl, 'image'); | |
}, | |
}; | |
</script> | |
<style scoped> | |
div { | |
background-color: #000; | |
position: relative; | |
display: block; | |
contain: content; | |
background-position: center center; | |
background-size: cover; | |
cursor: pointer; | |
max-width: 720px; | |
} | |
/* gradient */ | |
div::before { | |
content: ''; | |
display: block; | |
position: absolute; | |
top: 0; | |
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAADGCAYAAAAT+OqFAAAAdklEQVQoz42QQQ7AIAgEF/T/D+kbq/RWAlnQyyazA4aoAB4FsBSA/bFjuF1EOL7VbrIrBuusmrt4ZZORfb6ehbWdnRHEIiITaEUKa5EJqUakRSaEYBJSCY2dEstQY7AuxahwXFrvZmWl2rh4JZ07z9dLtesfNj5q0FU3A5ObbwAAAABJRU5ErkJggg==); | |
background-position: top; | |
background-repeat: repeat-x; | |
height: 60px; | |
padding-bottom: 50px; | |
width: 100%; | |
transition: all 0.2s cubic-bezier(0, 0, 0.2, 1); | |
} | |
/* responsive iframe with a 16:9 aspect ratio | |
thanks https://css-tricks.com/responsive-iframes/ | |
*/ | |
div::after { | |
content: ''; | |
display: block; | |
padding-bottom: calc(100% / (16 / 9)); | |
} | |
div > iframe { | |
width: 100%; | |
height: 100%; | |
position: absolute; | |
top: 0; | |
left: 0; | |
} | |
/* play button */ | |
div > button { | |
width: 68px; | |
height: 48px; | |
position: absolute; | |
transform: translate3d(-50%, -50%, 0); | |
top: 50%; | |
left: 50%; | |
z-index: 1; | |
background-color: transparent; | |
/* YT's actual play button svg */ | |
background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 68 48"><path fill="%23f00" fill-opacity="0.8" d="M66.52,7.74c-0.78-2.93-2.49-5.41-5.42-6.19C55.79,.13,34,0,34,0S12.21,.13,6.9,1.55 C3.97,2.33,2.27,4.81,1.48,7.74C0.06,13.05,0,24,0,24s0.06,10.95,1.48,16.26c0.78,2.93,2.49,5.41,5.42,6.19 C12.21,47.87,34,48,34,48s21.79-0.13,27.1-1.55c2.93-0.78,4.64-3.26,5.42-6.19C67.94,34.95,68,24,68,24S67.94,13.05,66.52,7.74z"></path><path d="M 45,24 27,14 27,34" fill="%23fff"></path></svg>'); | |
filter: grayscale(100%); | |
transition: filter 0.1s cubic-bezier(0, 0, 0.2, 1); | |
border: none; | |
} | |
div:hover > button, | |
div button:focus { | |
filter: none; | |
} | |
/* Post-click styles */ | |
div.activated { | |
cursor: unset; | |
} | |
div.activated::before { | |
opacity: 0; | |
pointer-events: none; | |
} | |
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export default class LiteYTEmbedUtils { | |
static preconnected = false; | |
static addPrefetch(kind: string, url: string, as?: string) { | |
const linkElem = document.createElement('link'); | |
linkElem.rel = kind; | |
linkElem.href = url; | |
if (as) { | |
linkElem.as = as; | |
} | |
document.head.append(linkElem); | |
} | |
/** | |
* Begin pre-connecting to warm up the iframe load | |
* Since the embed's network requests load within its iframe, | |
* preload/prefetch'ing them outside the iframe will only cause double-downloads. | |
* So, the best we can do is warm up a few connections to origins that are in the critical path. | |
* | |
* Maybe `<link rel=preload as=document>` would work, but it's unsupported: http://crbug.com/593267 | |
* But TBH, I don't think it'll happen soon with Site Isolation and split caches adding serious complexity. | |
*/ | |
static warmConnections() { | |
if (this.preconnected) return; | |
// The iframe document and most of its subresources come right off youtube.com | |
this.addPrefetch( | |
'preconnect', | |
'https://www.youtube-nocookie.com', | |
); | |
// The botguard script is fetched off from google.com | |
this.addPrefetch('preconnect', 'https://www.google.com'); | |
// Not certain if these ad related domains are in the critical path. Could verify with domain-specific throttling. | |
this.addPrefetch( | |
'preconnect', | |
'https://googleads.g.doubleclick.net', | |
); | |
this.addPrefetch( | |
'preconnect', | |
'https://static.doubleclick.net', | |
); | |
this.preconnected = true; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment