How to remove the overlay image on only the selected lazyloaded video? - javascript
In the script below, I'm lazyloading two videos. My script is designed to remove the overlay image from the selected video when clicked. However, it's also removing the overlay image from the second video and placing it above it. Another click removes the duplicate image, and a third click plays the video.
How do I remove only the image for the selected video in a way that doesn't affect a second video on the page?
const getVideoId = (wistia_vid) => {
const classes = Array.from(wistia_vid.querySelector(".wistia_embed").classList);
const idClass = classes.find((cls) => cls.startsWith("wistia_async_"));
const id = idClass.replace("wistia_async_", "");
return id;
};
const removeElems = (wistia_vid) => {
const toRemove = Array.from(
wistia_vid.querySelectorAll(".wistia__overlay, .embed-youtube__play, .embed-video__play")
);
toRemove.forEach((node) => node.remove());
};
Array.from(document.querySelectorAll(".wistia")).forEach((node) => {
node.addEventListener("click", () => {
const videoId = getVideoId(node);
let wistiaSupportScripts = [
//adds jsonp file to provide security over requests
`https://fast.wistia.com/embed/medias/${videoId}.jsonp`
];
removeElems(node);
//Checks if above scripts are already loaded, and if they are... they won't be loaded again
const id = 'script-ev1';
if (!document.getElementById(id)) {
// const id = 'script-ev1';
var script = document.createElement('script');
script.id = id;
script.onload = () => {
console.log('Ev-1.js loaded and ready to go!');
};
script.src = `https://fast.wistia.com/assets/external/E-v1.js` ;
document.getElementsByTagName('head')[0].appendChild(script);
} else {
console.log(`Ev-1.js script with id: ${videoId} already loaded.`);
}
//loads supporting scripts into head
for (var i = 0; i < wistiaSupportScripts.length; i++) {
let wistiaSupportScript = document.createElement("script");
wistiaSupportScript.src = wistiaSupportScripts[i];
let complete = false;
if (
!complete &&
(!this.readyState ||
this.readyState == "loaded" ||
this.readyState == "complete")
) {
complete = true;
console.log(`JSONP script was added.`);
}
let wistiaContainers = document.querySelector(".wistia");
wistiaContainers ? document.getElementsByTagName("head")[0].appendChild(wistiaSupportScript) : console.log("No Wistia videos here.");
}
window._wq = window._wq || [];
_wq.push({
//globally scoped
id: videoId,
options: {
autoPlay: true,
volume: 0.5
},
onReady: function (video) {
playedOnce = true;
video.popover.show();
video.play();
}
});
});
});
.wistia {
position: relative;
display: block;
width: 100%;
max-width: 500px;
padding: 0;
overflow: hidden;
cursor: pointer;
}
.wistia__overlay {
width: 100%;
height: auto;
}
.wistia::before {
display: block;
content: "";
}
.wistia button.embed-youtube__play {
background: url("https://nextiva.com/assets/svg/play-button.svg") no-repeat center center, rgba(33, 33, 33, 0.8);
background-size: 40%;
background-position: 55%;
border: 0;
border-radius: 50%;
position: absolute;
transition: all 0.2s ease;
-webkit-transition: background 0.2s;
width: 10%;
aspect-ratio: 1/1;
max-height: 15%;
cursor: pointer;
z-index: 10;
display: flex;
justify-content: center;
align-items: center;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
}
.wistia:hover button.embed-youtube__play,
.wistia button.embed-youtube__play:focus-visible,
.wistia button.embed-youtube__play:focus {
background: url("https://nextiva.com/assets/svg/play-button.svg") no-repeat center center, #005fec;
background-size: 40%;
background-position: 55%;
}
.wistia_embed,
.wistia embed,
.wistia iframe {
width: 100%;
max-height: 100%;
}
<div class="wistia">
<picture>
<source srcset="https://embedwistia-a.akamaihd.net/deliveries/48f1d62d1ceddb4284ad9cf67c916235.jpg?auto=format&w=640" media="(min-width: 1200px)">
<source srcset="https://embedwistia-a.akamaihd.net/deliveries/48f1d62d1ceddb4284ad9cf67c916235.jpg?auto=format&w=310" media="(min-width: 768px)">
<img src="https://embedwistia-a.akamaihd.net/deliveries/48f1d62d1ceddb4284ad9cf67c916235.jpg?auto=format&w=310" alt="some text" class="wistia__overlay lazy" loading="lazy">
</picture>
<div class="wistia_embed wistia_async_vhkqhqhzyq videoFoam=true"></div>
<button class="embed-youtube__play"></button>
</div>
<div class="wistia">
<picture>
<source srcset="https://embed-fastly.wistia.com/deliveries/2eab84ad71cf5acd9c7572d36667d255.jpg?auto=format&w=640" media="(min-width: 1200px)">
<source srcset="https://embed-fastly.wistia.com/deliveries/2eab84ad71cf5acd9c7572d36667d255.jpg?auto=format&w=310" media="(min-width: 768px)">
<img src="https://embed-fastly.wistia.com/deliveries/2eab84ad71cf5acd9c7572d36667d255.jpg?auto=format&w=310" alt="Some text" class="wistia__overlay lazy" loading="lazy">
</picture>
<div class="wistia_embed wistia_async_8ei13wuby7 videoFoam=true"></div>
<button class="embed-youtube__play"></button>
</div>
Put this in your CSS:
.wistia_embed {
display: none;
}
.wistia.shown .wistia_embed {
display: block;
}
Then, put this in your JS:
if (!node.classList.contains("shown")) {
node.classList.add("shown");
} else {
return;
}
Right in the beginning of the event listener function.
Explanation
The E-v1.js script shows all the videos at once, when you load this script by the first click with this piece of code:
const id = 'script-ev1';
if (!document.getElementById(id)) {
// const id = 'script-ev1';
var script = document.createElement('script');
script.id = id;
script.onload = () => {
console.log('Ev-1.js loaded and ready to go!');
};
script.src = `https://fast.wistia.com/assets/external/E-v1.js`;
document.getElementsByTagName('head')[0].appendChild(script);
} else {
console.log(`Ev-1.js script with id: ${videoId} already loaded.`);
}
Before you load this script, there are no videos as is, just the <source> elements. You never indicate with you CSS that videos should be invisible; henceforth, they are visible by default, once the E-v1.js script loads them.
Now, when you add this CSS snippet above, you indicate that .wistia_embed elements, which are basically the loaded videos, have to be invisible from the beginning.
With this single line of JS code, only one video will be revealed on click (setting .shown class, which contains display: block; attribute for the .wistia_embed).
Undefined video.popover
I don't know Wistia API that much, but the browser tells that there is no video.popover.show() function. Remove this from your code as well, otherwise the second video won't auto-play by clicking on it.
onReady: function (video) {
playedOnce = true;
video.popover.show(); // remove
video.play();
}
Full working code
const getVideoId = (wistia_vid) => {
const classes = Array.from(wistia_vid.querySelector(".wistia_embed").classList);
const idClass = classes.find((cls) => cls.startsWith("wistia_async_"));
const id = idClass.replace("wistia_async_", "");
return id;
};
const removeElems = (wistia_vid) => {
const toRemove = Array.from(
wistia_vid.querySelectorAll(".wistia__overlay, .embed-youtube__play, .embed-video__play")
);
toRemove.forEach((node) => node.remove());
};
Array.from(document.querySelectorAll(".wistia")).forEach((node) => {
node.addEventListener("click", () => {
if (!node.classList.contains("shown")) {
node.classList.add("shown");
} else {
return;
}
const videoId = getVideoId(node);
let wistiaSupportScripts = [
//adds jsonp file to provide security over requests
`https://fast.wistia.com/embed/medias/${videoId}.jsonp`
];
removeElems(node);
//Checks if above scripts are already loaded, and if they are... they won't be loaded again
const id = 'script-ev1';
if (!document.getElementById(id)) {
// const id = 'script-ev1';
var script = document.createElement('script');
script.id = id;
script.onload = () => {
console.log('Ev-1.js loaded and ready to go!');
};
script.src = `https://fast.wistia.com/assets/external/E-v1.js`;
document.getElementsByTagName('head')[0].appendChild(script);
} else {
console.log(`Ev-1.js script with id: ${videoId} already loaded.`);
}
//loads supporting scripts into head
for (var i = 0; i < wistiaSupportScripts.length; i++) {
let wistiaSupportScript = document.createElement("script");
wistiaSupportScript.src = wistiaSupportScripts[i];
let complete = false;
if (
!complete &&
(!this.readyState ||
this.readyState == "loaded" ||
this.readyState == "complete")
) {
complete = true;
console.log(`JSONP script was added.`);
}
let wistiaContainers = document.querySelector(".wistia");
wistiaContainers ? document.getElementsByTagName("head")[0].appendChild(wistiaSupportScript) : console.log("No Wistia videos here.");
}
window._wq = window._wq || [];
_wq.push({
//globally scoped
id: videoId,
options: {
autoPlay: true,
volume: 0.5
},
onReady: function (video) {
playedOnce = true;
video.play();
}
});
});
});
.wistia {
position: relative;
display: block;
width: 100%;
max-width: 500px;
padding: 0;
overflow: hidden;
cursor: pointer;
}
.wistia__overlay {
width: 100%;
height: auto;
}
.wistia::before {
display: block;
content: "";
}
.wistia button.embed-youtube__play {
background: url("https://nextiva.com/assets/svg/play-button.svg") no-repeat center center, rgba(33, 33, 33, 0.8);
background-size: 40%;
background-position: 55%;
border: 0;
border-radius: 50%;
position: absolute;
transition: all 0.2s ease;
-webkit-transition: background 0.2s;
width: 10%;
aspect-ratio: 1/1;
max-height: 15%;
cursor: pointer;
z-index: 10;
display: flex;
justify-content: center;
align-items: center;
top: 50%;
left: 50%;
transform: translate3d(-50%, -50%, 0);
}
.wistia:hover button.embed-youtube__play,
.wistia button.embed-youtube__play:focus-visible,
.wistia button.embed-youtube__play:focus {
background: url("https://nextiva.com/assets/svg/play-button.svg") no-repeat center center, #005fec;
background-size: 40%;
background-position: 55%;
}
.wistia_embed,
.wistia embed,
.wistia iframe {
width: 100%;
max-height: 100%;
}
.wistia_embed {
display: none;
}
.wistia.shown .wistia_embed {
display: block;
}
<div class="wistia">
<picture>
<source
srcset="https://embedwistia-a.akamaihd.net/deliveries/48f1d62d1ceddb4284ad9cf67c916235.jpg?auto=format&w=640"
media="(min-width: 1200px)">
<source
srcset="https://embedwistia-a.akamaihd.net/deliveries/48f1d62d1ceddb4284ad9cf67c916235.jpg?auto=format&w=310"
media="(min-width: 768px)">
<img src="https://embedwistia-a.akamaihd.net/deliveries/48f1d62d1ceddb4284ad9cf67c916235.jpg?auto=format&w=310"
alt="some text" class="wistia__overlay lazy" loading="lazy">
</picture>
<div class="wistia_embed wistia_async_vhkqhqhzyq videoFoam=true"></div>
<button class="embed-youtube__play"></button>
</div>
<div class="wistia">
<picture>
<source
srcset="https://embed-fastly.wistia.com/deliveries/2eab84ad71cf5acd9c7572d36667d255.jpg?auto=format&w=640"
media="(min-width: 1200px)">
<source
srcset="https://embed-fastly.wistia.com/deliveries/2eab84ad71cf5acd9c7572d36667d255.jpg?auto=format&w=310"
media="(min-width: 768px)">
<img src="https://embed-fastly.wistia.com/deliveries/2eab84ad71cf5acd9c7572d36667d255.jpg?auto=format&w=310"
alt="Some text" class="wistia__overlay lazy" loading="lazy">
</picture>
<div class="wistia_embed wistia_async_8ei13wuby7 videoFoam=true"></div>
<button class="embed-youtube__play"></button>
</div>
Related
Why is my HTML-5 video playback so much smoother on Safari and how can I get it to run smoothly on other browsers?
I'm working with a collaborator on a scrolling video animation where the video should play as you scroll down the page. We've gone through a number of iterations of video compression to get the video to play smoothly, and in the process have noticed that while even the biggest files play really well on Safari (mobile and desktop), even the smallest files are pretty choppy on other browsers. Our goal was to have our video running as smoothly as this Scrolling Controls for HTML5 Video codepen example. Why is this so much smoother on safari? We're trying to get it that smooth on other browsers, but are wondering if the requestAnimationFrame (which enter-view.js relies on) function is more optimized for safari and if we should be opting for some other animation strategy. Here's our code: const container = d3.select('#scrolly-overlay'); const stepSel = container.selectAll('.step'); const progressCounter = d3.select('#progress'); let vid = document.getElementById('v0'); const containerHeightMultiplier = 300;; const vidUrls = [{ format: 'webm', name: '10FPS_CQ_35', file: 'TestVidLowRes_VP8_10FPS_CQ35', size: "6.5MB" }, { format: 'webm', name: '10FPS_CQ_45', file: 'TestVidLowRes_VP8_10FPS_CQ45', size: "4.8MB" }, { format: 'mp4', name: '10FPS_RF_27', file: 'TestVidLowRes_H264_10FPS_RF27', size: "4.7MB" }, { format: 'mp4', name: '10FPS_RF_40', file: 'TestVidLowRes_H264_10FPS_RF40', size: "0.5MB" }, { format: 'webm', name: '5FPS_RF_40', file: 'testVidLowRes_VP8_5FPS_CQ35', size: '3.4MB' } ] d3.select('#vid-selection').selectAll('button').data(vidUrls).join('button') .text(d => d.name + '.' + d.format + '-' + d.size) .on('click', (event, d) => { d3.select('#vid-source') .attr('type', 'video/' + d.format) .attr('src', "https://s3.us-west-1.amazonaws.com/tao.mo.2021/" + d.file + '.' + d.format) d3.select('#selected-vid') .text(d.format + ': ' + d.name + ' (' + d.size + ')') vid.load() vid.addEventListener('loadedmetadata', function() { console.log(vid.fileSize) d3.select('#scrolly-overlay .scrolly article .step').style('min-height', Math.floor(vid.duration) * containerHeightMultiplier + "px") }); }) function updateChart(index) { stepSel.classed('is-active', (d, i) => i === index); } function updateVid(progress) { progressCounter.text(progress); } function init() { Stickyfill.add(d3.select('.sticky').node()); enterView({ selector: stepSel.nodes(), offset: 0.5, enter: el => { const index = +d3.select(el).attr('data-index'); updateChart(index); }, progress: (el, progress) => { progressCounter.text(progress); vid.currentTime = progress * vid.duration }, exit: el => { let index = +d3.select(el).attr('data-index'); index = Math.max(0, index - 1); updateChart(index); } }) /* enterView({ selector: container.selectAll('.v0'), offset: 0.5, progress: (el, progress)=> { progressCounter.text(progress); vid.currentTime = progress*vid.duration } }); */ } init(); .filler { height: 20rem; text-align: center; } #scrolly-overlay .scrolly { max-width: 60rem; margin: 3rem auto; background-color: #f4f4f4; padding: 1rem; } #scrolly-overlay .scrolly article { padding: 0; max-width: 30rem; margin: 0 auto; position: relative; } #scrolly-overlay .scrolly article .step { /* min-height: 500vh; now set dynamically */ margin-bottom: 1rem; } #scrolly-overlay .scrolly article .step:last-of-type { margin-bottom: 0; } #scrolly-overlay .scrolly article .step.is-active p { background-color: #008080; } #scrolly-overlay .scrolly article .step p { margin: 0; padding: 1rem; text-align: center; font-weight: 400; background-color: #5b5b5b; transition: background-color 250ms ease-in-out; color: #f4f4f4; } #scrolly-overlay .scrolly figure.sticky { position: sticky; width: 100%; height: 75vh; margin: 0; top: 3vh; left: 0; } #scrolly-overlay .scrolly figure.sticky video { position: absolute; top: 1%; left: 0.5%; width: 99%; background-color: #fff; } #scrolly-overlay .scrolly figure.sticky #progress { position: absolute; background-color: #fff; } <section class='filler'> <p> Scroll </p> <div id='vid-selection'></div> <h2 style='margin-top:10px;font-weight:bold;' id='selected-vid'></h2> </section> <section id='scrolly-overlay'> <div class='scrolly'> <!-- sticky graphic --> <figure class='sticky'> <video id="v0" playsinline tabindex="0" autobuffer="autobuffer" preload="preload"> <!-- <source type="video/webm; codecs="vp8, vorbis"" src="https://static.observableusercontent.com/files/3e8f13f77456ac7c630d81e395bec55a90b9ab508d4602e2e11e5b3890fa8681b13ec1cc846cfc2e27b44989ca60536d448ee7d63f945eeca91301ca2a0bdce3"></source> <source type="video/mp4" src="https://static.observableusercontent.com/files/503c7cf52dcf3efaf653791a8919f2f4e186aba59d6e264fd22e46b589c7348b536fa23cc348a62a12e33b5dbcb5d258e4205150326297de0f7842105cab67a2"></source> <source type="video/webm; codecs="vp8, vorbis"" src="https://www.html5rocks.com/tutorials/video/basics/Chrome_ImF.webm"></source> <source type="video/webm" src="https://s3.us-west-1.amazonaws.com/tao.mo.2021/testVid2.webm"></source> <source type="video/webm" src="https://s3.us-west-1.amazonaws.com/tao.mo.2021/testVid.webm"></source> <source type="video/webm" src="https://s3.us-west-1.amazonaws.com/tao.mo.2021/testVid3.webm"></source> --> <source id='vid-source'></source> </video> <div id='progress'>0</div> </figure> <!-- step text --> <article> <div class='step' data-width='10%' data-index='0'> <p>Text to Trigger Scroll</p> </div> </article> </div> </section> <section class='filler'> <p> End </p> </section> And here it is on codepen (it uses elements from The Pudding’s enter-view.js examples, and that "Scrolling Controls" example): https://codepen.io/ossermans/pen/LYLbPJd
CSS class add/remove no longer working || vanilla JS
So previously I asked your help to execute a behaviour for when clicking a container div, said div would change height, clicking it again would revert it back to normal, as would clicking a sibling container div. I also added code for when clicking said div, the img inside would change data-src. This img div (not the container) has a sibling that is just text. It would change state through css, when the container div is clicked, a bit like the container div itself. When adding the code for the data-src change, I lost this ability and cant find out why. Can you help me? This is my code: const allImages = document.querySelectorAll('.containertira .imgclasstosize'); const allContainers = document.querySelectorAll('.containertira'); allContainers.forEach(el => { el.addEventListener('click', function(event) { const thisImg = el.querySelector('.imgclasstosize'); const thisTxt = el.querySelector('.centered'); const sibling = thisImg.nextElementSibling; // Get the next sibiling const bigSrc = thisImg.dataset.srcBig; const allOtherImages = Array.from(allImages).filter(img => { return img !== thisImg; }); const isBig = thisImg.classList.contains('big'); 1 if (isBig) { thisImg.classList.remove('big'); thisTxt.classList.remove('left'); // reset to the small image URL thisImg.src = thisImg.dataset.smallSrc; } else { // save the small image URL first: if (!thisImg.dataset.smallSrc) { thisImg.dataset.smallSrc = thisImg.src; } // change to the big image URL: thisImg.src = bigSrc; thisImg.classList.add('big'); thisTxt.classList.add('left'); sibling.classList.remove('hide'); } allOtherImages.forEach(img => { img.classList.remove('big'); // reset to the small image URL if (img.dataset.smallSrc) { img.src = img.dataset.smallSrc; } img.nextElementSibling.classList[isBig ? 'remove' : 'add']("hide"); }); }); } ); .imgclasstosize{ width: 100%; object-fit: cover; position: relative; } img.imgclasstosize { height: 80px; border: 1px solid gray; transition : 1.5s all ease; } img.imgclasstosize.big { height: 100%; transition: 1.5s all ease; width: 70vw; margin-left: auto; } .containertira { position: relative; text-align: center; color: white; display: flex; justify-content: space-between; } .imgclasstosize { transition: all ease 0.5s; } .imgclasstosize.big { /* transform: scale(1.1); */ } .centered { opacity: 1; transition: all ease 0.5s; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-family: 'blacker_pro_displayregular'; padding-top: 10px; /* background: linear-gradient(90deg, rgba(33,37,41,1) 0%, rgba(255,255,255,0) 50%); */ color: white; padding-left: 10px; padding-bottom: 6.5px; font-size: 5vh; display:block; pointer-events: none; } #media screen and (max-width: 960px) {.centered {font-size: 4.6vh;}} #media screen and (max-width: 500px) {.centered {font-size: 3.5vh;}} #media screen and (max-width: 375px) {.centered {font-size: 3vh;}} .centered.left{ top: 0%; left: 0%; transform: translate(0%, 0%); color: black; padding-left: 10px; padding-bottom: 6.5px; transition: all ease 0.5s; font-size: 7vh; } .imgclasstosize.big+.centered.hide { opacity: 0; } <div class="containertira"> <img id="primeiraimagem" class="imgclasstosize" src="//images.impresa.pt/expresso/2021-07-23-1---Minho.png-0c586cc8" data-src-big="//images.impresa.pt/expresso/2021-07-23-960px_minho.png-3938db2f"> <div class="centered">Minho</div> </div> <br> <div class="containertira"> <img id="primeiraimagem" class="imgclasstosize" src="//images.impresa.pt/expresso/2021-07-23-1---Minho.png-0c586cc8" data-src-big="//images.impresa.pt/expresso/2021-07-23-960px_minho.png-3938db2f"> <div class="centered">Minho</div> </div> Best regards everyone.
I can't seem to reproduce your error. Tried copying your code and pasting it on a separated HTML file and everything worked. If you execute this snippet and look at the console, you will see that the classes and properties are changing accordingly to your code. Maybe your code is executing before some library causing it to not execute something? const allImages = document.querySelectorAll('.containertira .imgclasstosize'); const allContainers = document.querySelectorAll('.containertira'); allContainers.forEach(el => { el.addEventListener('click', function(event) { const thisImg = el.querySelector('.imgclasstosize'); const thisTxt = el.querySelector('.centered'); const sibling = thisImg.nextElementSibling; // Get the next sibiling const bigSrc = thisImg.dataset.srcBig; const allOtherImages = Array.from(allImages).filter(img => { return img !== thisImg; }); const isBig = thisImg.classList.contains('big'); 1 if (isBig) { thisImg.classList.remove('big'); thisTxt.classList.remove('left'); // reset to the small image URL thisImg.src = thisImg.dataset.smallSrc; } else { // save the small image URL first: if (!thisImg.dataset.smallSrc) { thisImg.dataset.smallSrc = thisImg.src; } // change to the big image URL: thisImg.src = bigSrc; thisImg.classList.add('big'); thisTxt.classList.add('left'); sibling.classList.remove('hide'); } allOtherImages.forEach(img => { img.classList.remove('big'); // reset to the small image URL if (img.dataset.smallSrc) { img.src = img.dataset.smallSrc; } img.nextElementSibling.classList[isBig ? 'remove' : 'add']("hide"); }); }); } ); .containertira {border:1px black solid;} <div class="containertira"> <img id="primeiraimagem" class="imgclasstosize" src="img/Tiras/1 - Minho.png" data-src-big="img/INFO joao/joao 2/joao 2/960 px/960px_minho.png"> <div class="centered">Minho</div> </div> <div class="containertira"> <img id="primeiraimagem" class="imgclasstosize" src="img/Tiras/1 - Minho.png" data-src-big="img/INFO joao/joao 2/joao 2/960 px/960px_minho.png"> <div class="centered">Minho2</div> </div> <div class="containertira"> <img id="primeiraimagem" class="imgclasstosize" src="img/Tiras/1 - Minho.png" data-src-big="img/INFO joao/joao 2/joao 2/960 px/960px_minho.png"> <div class="centered">Minho3</div> </div> <div class="containertira"> <img id="primeiraimagem" class="imgclasstosize" src="img/Tiras/1 - Minho.png" data-src-big="img/INFO joao/joao 2/joao 2/960 px/960px_minho.png"> <div class="centered">Minho4</div> </div>
Fetch loading in data for HTML
So I'm making a simple pokemon app where the front-end makes fetch calls to grab the Pokemon from PokeAPI and displays it, but when loading a pokemon you can see that the fetch info gets loaded at different rates. For example the pokemon loads then the name loads then the background loads then the type loads. Is there anyway to have it so the HTML fills all at one time? This is what my Javascript fetch function looks like, additionally here is the app so you can see how the information loads slowly / not all at once : https://bui-pokemon.herokuapp.com/ pokeButton.addEventListener('click', (e)=> { e.preventDefault(); const pokeNameSearch = pokeSearch.value.toLowerCase(); fetch(`https://pokeapi.co/api/v2/pokemon/${pokeNameSearch}`) .then((response) => response.json()) .then(data => { if(pokeCard.classList.value === 'poke_card'){ pokeCard.classList.add('border'); }; //If a pokemon was normal / flying type then flying should be shown in the background isntead of normal //because flying type is more of a defining characteristic of that pokemon rather than normal if(data.types.length > 1 && data.types[0].type.name === "normal" && data.types[1].type.name === "flying"){ pokeCard.className = `poke_card border ${data.types[1].type.name}_background` } else { pokeCard.className = `poke_card border ${data.types[0].type.name}_background`; } pokeImg.src = data.sprites.front_default; pokeName.innerHTML = data.name; // Fill in Pokemon Type pokeTypeIcon1.src = ""; pokeTypeIcon2.src = ""; pokeTypeIcon1.className = ''; pokeTypeIcon2.className = ''; pokeTypeIcon2.style.display = "none"; pokeType.innerHTML = `${data.types[0].type.name}`; pokeNumDisplay.innerHTML = `#${fillInZero(data.id.toString())}` pokeTypeIcon1.src = `img/icons/${data.types[0].type.name}.svg` pokeTypeIcon1.className = `type_icon_1 ${data.types[0].type.name}` if(data.types.length > 1){ pokeType.innerHTML += `/${data.types[1].type.name}` pokeTypeIcon2.src = `img/icons/${data.types[1].type.name}.svg` pokeTypeIcon2.style.display = "inline-block"; pokeTypeIcon2.className = `type_icon_2 ${data.types[1].type.name}` } else { pokeType.innerHTML = `${data.types[0].type.name}` } })
Seems the font and images loading causes the issue. What you could do, is listen for the load event on each image and transition the opacity. Then, use document.fonts.ready and transition the color: const container = document.querySelector(".container"); const background = document.getElementById("background") const imgOne = document.getElementById("img-one") const imgTwo = document.getElementById("img-two") const fadeIn = (el) => { el.addEventListener("load", () => el.style.opacity = "1") } document.fonts.ready.then(() => container.style.color = "#fff") fadeIn(background) fadeIn(imgOne) fadeIn(imgTwo) background.src = "https://ak.picdn.net/shutterstock/videos/9589454/thumb/2.jpg" imgOne.src = "https://toppng.com/public/uploads/thumbnail/ikachu-8-bits-8-bit-pokemon-grid-11563233054e4sqfqyl2l.png" imgTwo.src = "https://icons.iconarchive.com/icons/paomedia/small-n-flat/1024/lightning-icon.png" #import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap'); body { background: #43464b; font-family: "Press Start 2P", Arial, Helvetica, sans-serif; } .container { display: flex; align-items: center; justify-content: center; flex-direction: column; position: relative; margin: 0 auto; width: 200px; height: 300px; color: transparent; overflow: hidden; transition: color 0.25s; } .container>*:not(#background) { z-index: 1; } img { opacity: 0; transition: opacity 0.25s; } #background { position: absolute; top: 0; left: 0; } #img-one, #img-two { height: 80px; } <div class="container"> <img id="background" /> <img id="img-one" /> <p>#25 Pikachu</p> <img id="img-two" /> <p>Electric</p> </div> However, it could still be uneven this way if one thing takes longer to load than the other. Another solution is to push values to an array once loaded, and check the length of the array before setting the opacity of the container: const container = document.querySelector(".container"); const background = document.getElementById("background") const imgOne = document.getElementById("img-one") const imgTwo = document.getElementById("img-two") const loaded = [] const setLoadState = (el) => { loaded.push(el) if (loaded.length === 4) container.style.opacity = "1" } const imgLoad = (img) => { img.addEventListener("load", () => setLoadState(img.id)) } document.fonts.ready.then(() => setLoadState('font')) imgLoad(background) imgLoad(imgOne) imgLoad(imgTwo) background.src = "https://ak.picdn.net/shutterstock/videos/9589454/thumb/2.jpg" imgOne.src = "https://toppng.com/public/uploads/thumbnail/ikachu-8-bits-8-bit-pokemon-grid-11563233054e4sqfqyl2l.png" imgTwo.src = "https://icons.iconarchive.com/icons/paomedia/small-n-flat/1024/lightning-icon.png" #import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap'); body { background: #43464b; font-family: "Press Start 2P", Arial, Helvetica, sans-serif; } .container { display: flex; align-items: center; justify-content: center; flex-direction: column; position: relative; margin: 0 auto; width: 200px; height: 300px; color: #fff; overflow: hidden; opacity: 0; transition: opacity 0.25s; } .container>*:not(#background) { z-index: 1; } #background { position: absolute; top: 0; left: 0; } #img-one, #img-two { height: 80px; } <div class="container"> <img id="background" /> <img id="img-one" /> <p>#25 Pikachu</p> <img id="img-two" /> <p>Electric</p> </div>
Recursive custom thumbnail for embedded YouTube API won't replay
I have an embedded YouTube video, but I want to use my own custom image for the face (thumbnail) of the video before and after the video plays. I have it working successfully up to where it shows the custom image in place of the video, and when the image is clicked, the image is removed and the video is loaded and played. Once the video is complete, the image is restored back to what appears to be the video's ready-to-play state. However, once the image is clicked again to replay the video, the video won't play again. I was hoping that every time my playYouTubeVideo() function is called from the click event listener, that the YT.Player object would reset and load again, but this isn't working. Any help you can give would be appreciated. The stackoverflow snippet I created as a demo doesn't actually play the YouTube embed, and you kind of need to be able to see the video end to know what I mean, so I've included and link to a fiddle as well: https://jsfiddle.net/MichaelVanEs/otq74r3w/3/ $(document).ready(function() { handleYouTubePlayer(); }); // function handleYouTubePlayer() { // YouTube iPlayer API var tag = document.createElement("script"); tag.src = "https://www.youtube.com/iframe_api"; var firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); // var player; var playerContainer = document.getElementById("player"); var iFrameVideo = document.getElementById("iFrameVideo"); var thumbnailWrap = document.getElementById("thumbnailWrap"); // thumbnailWrap.addEventListener("click", playYouTubeVideo, false); // function playYouTubeVideo() { console.log("Comes into playYouTubeVideo"); iFrameVideo.style.display = "block"; thumbnailWrap.style.display = "none"; // player = null; // player = new YT.Player("iFrameVideo", { playerVars: { mute: 1, autoplay: 1, }, events: { "onReady": onPlayerReady, 'onStateChange': onPlayerStateChange } }); // function onPlayerReady(event) { console.log("Comes into onPlayerReady"); event.target.mute(); event.target.playVideo(); } // function onPlayerStateChange(event) { if (event.data == YT.PlayerState.ENDED) { // Video has finished playing console.log("Comes into PlayerState.ENDED"); thumbnailWrap.style.display = "block"; iFrameVideo.style.display = "none"; // event.target.pauseVideo(); event.target.seekTo(0, true); } } } } .imgBrd { box-shadow: 0 0 0 1px #ccc; } .vid { display: block; width: 550px; height: 309px; margin: 0 auto; } #player { position: relative; } #iFrameVideo { display: none; } #thumbnailWrap { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } #thumbnail { position: absolute; top: 0; left: 0; } #youtubeBtn { position: absolute; top: 0; left: 0; display: flex; justify-content: center; align-items: center; font-size: 70px; color: rgba(40, 40, 40, 0.95); height: 100%; width: 100%; z-index: 2; } #youtubeBtn:hover { cursor: pointer; color: rgba(255, 0, 0, 0.95); } <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> <div id="player" class="vid"> <div id="thumbnailWrap"> <img id="thumbnail" class="vid imgBrd" src="https://libapps-au.s3-ap-southeast-2.amazonaws.com/customers/4753/images/dragArticleToGroup-thumb.png" alt="Video thumbnail" /> <div id="youtubeBtn"> <i class="fa fa-youtube-play" aria-hidden="true"></i> </div> </div> <iframe id="iFrameVideo" class="vid" src="https://www.youtube-nocookie.com/embed/tgbNymZ7vqY?rel=0&vq=hd720&enablejsapi=1" frameborder="0" allow="accelerometer; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe> </div>
Do not create a second YT.Player. Reuse the first player you created when the thumbnail is clicked. function playYouTubeVideo() { ... // remove `player = null` if (player) { player.playVideo(); return; } player = new YT.Player("iFrameVideo", { ... }
Full screen pop up window for multiple embedded videos
I'm new to js and I found a codepen that does exactly what I want to do except it currently only works for one embedded video. What i am trying to achieve is the same but with 6 videos. (function ($) { 'use strict'; $.fn.fitVids = function (options) { var settings = { customSelector: null, ignore: null }; if (!document.getElementById('fit-vids-style')) { // appendStyles: https://github.com/toddmotto/fluidvids/blob/master/dist/fluidvids.js var head = document.head || document.getElementsByTagName('head')[0]; var css = '.fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}'; var div = document.createElement("div"); div.innerHTML = '<p>x</p><style id="fit-vids-style">' + css + '</style>'; head.appendChild(div.childNodes[1]); } if (options) { $.extend(settings, options); } return this.each(function () { var selectors = [ 'iframe[src*="player.vimeo.com"]', 'iframe[src*="youtube.com"]', 'iframe[src*="youtube-nocookie.com"]', 'iframe[src*="kickstarter.com"][src*="video.html"]', 'object', 'embed' ]; if (settings.customSelector) { selectors.push(settings.customSelector); } var ignoreList = '.fitvidsignore'; if (settings.ignore) { ignoreList = ignoreList + ', ' + settings.ignore; } var $allVideos = $(this).find(selectors.join(',')); $allVideos = $allVideos.not('object object'); // SwfObj conflict patch $allVideos = $allVideos.not(ignoreList); // Disable FitVids on this video. $allVideos.each(function (count) { var $this = $(this); if ($this.parents(ignoreList).length > 0) { return; // Disable FitVids on this video. } if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; } if ((!$this.css('height') && !$this.css('width')) && (isNaN($this.attr('height')) || isNaN($this.attr('width')))) { $this.attr('height', 9); $this.attr('width', 16); } var height = (this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10)))) ? parseInt($this.attr('height'), 10) : $this.height(), width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(), aspectRatio = height / width; if (!$this.attr('id')) { var videoID = 'fitvid' + count; $this.attr('id', videoID); } $this.wrap('<div class="fluid-width-video-wrapper"></div>').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100) + '%'); $this.removeAttr('height').removeAttr('width'); }); }); }; // Works with either jQuery or Zepto })(window.jQuery || window.Zepto); // Init style shamelessly stolen from jQuery http://jquery.com var Froogaloop = (function () { // Define a local copy of Froogaloop function Froogaloop(iframe) { // The Froogaloop object is actually just the init constructor return new Froogaloop.fn.init(iframe); } var eventCallbacks = {}, hasWindowEvent = false, isReady = false, slice = Array.prototype.slice, playerDomain = ''; Froogaloop.fn = Froogaloop.prototype = { element: null, init: function (iframe) { if (typeof iframe === "string") { iframe = document.getElementById(iframe); } this.element = iframe; // Register message event listeners playerDomain = getDomainFromUrl(this.element.getAttribute('src')); return this; }, /* * Calls a function to act upon the player. * * #param {string} method The name of the Javascript API method to call. Eg: 'play'. * #param {Array|Function} valueOrCallback params Array of parameters to pass when calling an API method * or callback function when the method returns a value. */ api: function (method, valueOrCallback) { if (!this.element || !method) { return false; } var self = this, element = self.element, target_id = element.id !== '' ? element.id : null, params = !isFunction(valueOrCallback) ? valueOrCallback : null, callback = isFunction(valueOrCallback) ? valueOrCallback : null; // Store the callback for get functions if (callback) { storeCallback(method, callback, target_id); } postMessage(method, params, element); return self; }, /* * Registers an event listener and a callback function that gets called when the event fires. * * #param eventName (String): Name of the event to listen for. * #param callback (Function): Function that should be called when the event fires. */ addEvent: function (eventName, callback) { if (!this.element) { return false; } var self = this, element = self.element, target_id = element.id !== '' ? element.id : null; storeCallback(eventName, callback, target_id); // The ready event is not registered via postMessage. It fires regardless. if (eventName != 'ready') { postMessage('addEventListener', eventName, element); } else if (eventName == 'ready' && isReady) { callback.call(null, target_id); } return self; }, /* * Unregisters an event listener that gets called when the event fires. * * #param eventName (String): Name of the event to stop listening for. */ removeEvent: function (eventName) { if (!this.element) { return false; } var self = this, element = self.element, target_id = element.id !== '' ? element.id : null, removed = removeCallback(eventName, target_id); // The ready event is not registered if (eventName != 'ready' && removed) { postMessage('removeEventListener', eventName, element); } } }; /** * Handles posting a message to the parent window. * * #param method (String): name of the method to call inside the player. For api calls * this is the name of the api method (api_play or api_pause) while for events this method * is api_addEventListener. * #param params (Object or Array): List of parameters to submit to the method. Can be either * a single param or an array list of parameters. * #param target (HTMLElement): Target iframe to post the message to. */ function postMessage(method, params, target) { if (!target.contentWindow.postMessage) { return false; } var url = target.getAttribute('src').split('?')[0], data = JSON.stringify({ method: method, value: params }); if (url.substr(0, 2) === '//') { url = window.location.protocol + url; } target.contentWindow.postMessage(data, url); } /** * Event that fires whenever the window receives a message from its parent * via window.postMessage. */ function onMessageReceived(event) { var data, method; try { data = JSON.parse(event.data); method = data.event || data.method; } catch (e) { //fail silently... like a ninja! } if (method == 'ready' && !isReady) { isReady = true; } // Handles messages from moogaloop only if (event.origin != playerDomain) { return false; } var value = data.value, eventData = data.data, target_id = target_id === '' ? null : data.player_id, callback = getCallback(method, target_id), params = []; if (!callback) { return false; } if (value !== undefined) { params.push(value); } if (eventData) { params.push(eventData); } if (target_id) { params.push(target_id); } return params.length > 0 ? callback.apply(null, params) : callback.call(); } /** * Stores submitted callbacks for each iframe being tracked and each * event for that iframe. * * #param eventName (String): Name of the event. Eg. api_onPlay * #param callback (Function): Function that should get executed when the * event is fired. * #param target_id (String) [Optional]: If handling more than one iframe then * it stores the different callbacks for different iframes based on the iframe's * id. */ function storeCallback(eventName, callback, target_id) { if (target_id) { if (!eventCallbacks[target_id]) { eventCallbacks[target_id] = {}; } eventCallbacks[target_id][eventName] = callback; } else { eventCallbacks[eventName] = callback; } } /** * Retrieves stored callbacks. */ function getCallback(eventName, target_id) { if (target_id) { return eventCallbacks[target_id][eventName]; } else { return eventCallbacks[eventName]; } } function removeCallback(eventName, target_id) { if (target_id && eventCallbacks[target_id]) { if (!eventCallbacks[target_id][eventName]) { return false; } eventCallbacks[target_id][eventName] = null; } else { if (!eventCallbacks[eventName]) { return false; } eventCallbacks[eventName] = null; } return true; } /** * Returns a domain's root domain. * Eg. returns http://vimeo.com when http://vimeo.com/channels is sbumitted * * #param url (String): Url to test against. * #return url (String): Root domain of submitted url */ function getDomainFromUrl(url) { if (url.substr(0, 2) === '//') { url = window.location.protocol + url; } var url_pieces = url.split('/'), domain_str = ''; for (var i = 0, length = url_pieces.length; i < length; i++) { if (i < 3) { domain_str += url_pieces[i]; } else { break; } if (i < 2) { domain_str += '/'; } } return domain_str; } function isFunction(obj) { return !!(obj && obj.constructor && obj.call && obj.apply); } function isArray(obj) { return toString.call(obj) === '[object Array]'; } // Give the init function the Froogaloop prototype for later instantiation Froogaloop.fn.init.prototype = Froogaloop.fn; // Listens for the message event. // W3C if (window.addEventListener) { window.addEventListener('message', onMessageReceived, false); } // IE else { window.attachEvent('onmessage', onMessageReceived); } // Expose froogaloop to the global object return (window.Froogaloop = window.$f = Froogaloop); })(); //////////////////////////////////////// // Our Script //////////////////////////////////////// $(document).ready(function () { // Initiate FitVid.js $(".containiframeCeleb2").fitVids(); $(".containiframeRiver2").fitVids(); $(".containiframeBach").fitVids(); $(".containiframeLouie").fitVids(); $(".containiframeRiver1").fitVids(); $(".containiframeCeleb1").fitVids(); $(".containiframe").fitVids(); // Iframe/player variables var iframe = $('#videoCeleb1')[0]; var iframe = $('#videoRiver1')[0]; var iframe = $('#videoLouie')[0]; var iframe = $('#videoBach')[0]; var iframe = $('#videoRiver2')[0]; var iframe = $('#videoCeleb2')[0]; var iframe = $('#video')[0]; var player = $f(iframe); // Open on play $('.play').click(function () { $('.content').css('left', 0) $('.content').addClass('show') player.api("play"); }) $('.playcelebrity1').click(function () { $('.content').css('left', 0) $('.content').addClass('show') player.api("playcelebrity1"); }) $('.playcottage1').click(function () { $('.content').css('left', 0) $('.content').addClass('show') player.api("playcottage1"); }) $('.playLouie').click(function () { $('.content').css('left', 0) $('.content').addClass('show') player.api("playLouie"); }) $('.playbachelourette').click(function () { $('.content').css('left', 0) $('.content').addClass('show') player.api("playbachelourette"); }) $('.playcottage2').click(function () { $('.content').css('left', 0) $('.content').addClass('show') player.api("playcottage2"); }) $('.playcelbrity2').click(function () { $('.content').css('left', 0) $('.content').addClass('show') player.api("playcelbrity2"); }) // Closes on click outside $('.content').click(function () { $('.content').removeClass('show') setTimeout(function () { $('.content').css('left', '-100%') }, 300); player.api("pause"); }) }); /* Lazy-man Reset */ * { margin: 0; padding: 0; box-sizing: border-box; } /* Fullscreen Section */ header { width: 100%; /* 100% height */ height: 100vh; color: white; background: #2980b9; text-align: center; padding: 20px; /* Fancy flex-box centering */ display: flex; align-items: center; justify-content: center; -webkit-display: flex; -webkit-align-items: center; -webkit-justify-content: center; } header h1 { font-size: 40px; font-family: 'Roboto'; font-weight: 700; max-width: 700px; margin-bottom: 10px; } header p { font-family: 'Roboto Slab'; font-weight: 400; font-size: 20px; max-width: 700px; margin-bottom: 20px; opacity: .65; } .play { background-image: url(https://img.youtube.com/vi/YDHFM2HmYe0/default.jpg); display: block; width: 120px; height: 90px; margin: 0 auto; /* Important for :after */ position: relative; } .play:hover { background: #333; cursor: pointer; } .play:after { position: absolute; /* Centering */ /* CSS Triangle */ } .playcelebrity1 { background-image: url(https://img.youtube.com/vi/ebB0eoSY4yU/default.jpg); display: block; /* width: 500px; height: 297px;*/ margin: 0 auto; /* Important for :after */ position: relative; } .playcelebrity1:hover { background: #333; cursor: pointer; } .playcelebrity1:after { position: absolute; /* Centering */ /* CSS Triangle */ } .playcottage1 { background-image: url(https://img.youtube.com/vi/YDHFM2HmYe0/default.jpg); display: block; width: 120px; height: 90px; margin: 0 auto; /* Important for :after */ position: relative; } .playcottage1:hover { background: #333; cursor: pointer; } .playcottage1:after { position: absolute; /* Centering */ /* CSS Triangle */ } .playLouie { background-image: url(https://img.youtube.com/vi/ol43MqHED9c/default.jpg); display: block; width: 120px; height: 90px; margin: 0 auto; /* Important for :after */ position: relative; } .playLouie:hover { background: #333; cursor: pointer; } .playLouie:after { position: absolute; /* Centering */ /* CSS Triangle */ } .playbachelourette { background-image: url(https://img.youtube.com/vi/qXy5sCJj2wI/default.jpg); display: block; width: 120px; height: 90px; margin: 0 auto; /* Important for :after */ position: relative; } .playbachelourette:hover { background: #333; cursor: pointer; } .playbachelourette:after { position: absolute; /* Centering */ /* CSS Triangle */ } .playcottage2 { background-image: url(https://img.youtube.com/vi/7OeoQqPqxBg/default.jpg); display: block; width: 120px; height: 90px; margin: 0 auto; /* Important for :after */ position: relative; } .playcottage2:hover { background: #333; cursor: pointer; } .playcottage2:after { position: absolute; /* Centering */ /* CSS Triangle */ } .playcelbrity2 { background-image: url(https://img.youtube.com/vi/lk9tse44BMc/default.jpg); display: block; width: 120px; height: 90px; margin: 0 auto; /* Important for :after */ position: relative; } .playcelbrity2:hover { background: #333; cursor: pointer; } .playcelbrity2:after { position: absolute; /* Centering */ /* CSS Triangle */ } /* Fullscreen Overlay */ .content { width: 100%; height: 100vh; /* 50% opacity black */ background: rgba(0, 0, 0, .5); /* Stays locked on scroll */ position: fixed; /* On top of the rest*/ z-index: 2; /* Hidden */ opacity: 0; /* No interference */ left: -100%; /* CSS3 Transition */ transition: opacity .5s; -webkit-transition: opacity .5s; } /* 90% width container */ .containiframeCeleb2 { width: 90%; /* Centering */ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); -webkit-transform: translate(-50%, -50%); } .containiframeRiver2 { width: 90%; /* Centering */ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); -webkit-transform: translate(-50%, -50%); } .containiframeLouie { width: 90%; /* Centering */ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); -webkit-transform: translate(-50%, -50%); } .containiframeCeleb1 { width: 90%; /* Centering */ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); -webkit-transform: translate(-50%, -50%); } .containiframe { width: 90%; /* Centering */ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); -webkit-transform: translate(-50%, -50%); } .close { width: 20px; fill: white; position: absolute; right: 0; /* Bring above video */ top: -30px; } .close:hover { /* 50% opacity white */ fill: rgba(255, 255, 255, 0.5); cursor: pointer; } /* Class to fade in overlay */ .show { opacity: 1; } <title>FullScreen Vimeo Popup with Autoplay and CSS3 Transitions</title> <body> <div class="content"> <!--End of the new--> <div class="containiframeCeleb2"> <!-- SVG Close (X) Icon --> <svg class="close" xmlns="http://www.w3.org/2000/svg" viewBox="39.2 22.3 25 24.5"><path d="M39.5,46.4c0.2,0.2,0.6,0.4,0.9,0.4c0.3,0,0.6-0.1,0.9-0.4l10.3-10.3L62,46.4c0.2,0.2,0.6,0.4,0.9,0.4c0.3,0,0.6-0.1,0.9-0.4c0.5-0.5,0.5-1.3,0-1.8L53.5,34.3l9.8-9.8c0.5-0.5,0.5-1.3,0-1.8c-0.5-0.5-1.3-0.5-1.8,0l-9.8,9.8l-9.8-9.8c-0.5-0.5-1.3-0.5-1.8,0c-0.5,0.5-0.5,1.3,0,1.8l9.8,9.8L39.5,44.6C39,45.1,39,45.9,39.5,46.4z"/></svg> <!-- Embedded video --> <iframe id="videoCeleb2" src="https://www.youtube.com/embed/lk9tse44BMc?ecver=1" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> </div> <div class="containiframeRiver2"> <!-- SVG Close (X) Icon --> <svg class="close" xmlns="http://www.w3.org/2000/svg" viewBox="39.2 22.3 25 24.5"><path d="M39.5,46.4c0.2,0.2,0.6,0.4,0.9,0.4c0.3,0,0.6-0.1,0.9-0.4l10.3-10.3L62,46.4c0.2,0.2,0.6,0.4,0.9,0.4c0.3,0,0.6-0.1,0.9-0.4c0.5-0.5,0.5-1.3,0-1.8L53.5,34.3l9.8-9.8c0.5-0.5,0.5-1.3,0-1.8c-0.5-0.5-1.3-0.5-1.8,0l-9.8,9.8l-9.8-9.8c-0.5-0.5-1.3-0.5-1.8,0c-0.5,0.5-0.5,1.3,0,1.8l9.8,9.8L39.5,44.6C39,45.1,39,45.9,39.5,46.4z"/></svg> <!-- Embedded video --> <iframe id="videoRiver2" src="https://www.youtube.com/embed/7OeoQqPqxBg?ecver=1" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> </div> <div class="containiframeBach"> <!-- SVG Close (X) Icon --> <svg class="close" xmlns="http://www.w3.org/2000/svg" viewBox="39.2 22.3 25 24.5"><path d="M39.5,46.4c0.2,0.2,0.6,0.4,0.9,0.4c0.3,0,0.6-0.1,0.9-0.4l10.3-10.3L62,46.4c0.2,0.2,0.6,0.4,0.9,0.4c0.3,0,0.6-0.1,0.9-0.4c0.5-0.5,0.5-1.3,0-1.8L53.5,34.3l9.8-9.8c0.5-0.5,0.5-1.3,0-1.8c-0.5-0.5-1.3-0.5-1.8,0l-9.8,9.8l-9.8-9.8c-0.5-0.5-1.3-0.5-1.8,0c-0.5,0.5-0.5,1.3,0,1.8l9.8,9.8L39.5,44.6C39,45.1,39,45.9,39.5,46.4z"/></svg> <!-- Embedded video --> <iframe id="videoBach" src="https://www.youtube.com/embed/qXy5sCJj2wI?ecver=1" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> </div> <div class="containiframeLouie"> <!-- SVG Close (X) Icon --> <svg class="close" xmlns="http://www.w3.org/2000/svg" viewBox="39.2 22.3 25 24.5"><path d="M39.5,46.4c0.2,0.2,0.6,0.4,0.9,0.4c0.3,0,0.6-0.1,0.9-0.4l10.3-10.3L62,46.4c0.2,0.2,0.6,0.4,0.9,0.4c0.3,0,0.6-0.1,0.9-0.4c0.5-0.5,0.5-1.3,0-1.8L53.5,34.3l9.8-9.8c0.5-0.5,0.5-1.3,0-1.8c-0.5-0.5-1.3-0.5-1.8,0l-9.8,9.8l-9.8-9.8c-0.5-0.5-1.3-0.5-1.8,0c-0.5,0.5-0.5,1.3,0,1.8l9.8,9.8L39.5,44.6C39,45.1,39,45.9,39.5,46.4z"/></svg> <!-- Embedded video --> <iframe id="videoLouie" src="https://www.youtube.com/embed/ol43MqHED9c?ecver=1" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> </div> <div class="containiframeRiver1"> <!-- SVG Close (X) Icon --> <svg class="close" xmlns="http://www.w3.org/2000/svg" viewBox="39.2 22.3 25 24.5"><path d="M39.5,46.4c0.2,0.2,0.6,0.4,0.9,0.4c0.3,0,0.6-0.1,0.9-0.4l10.3-10.3L62,46.4c0.2,0.2,0.6,0.4,0.9,0.4c0.3,0,0.6-0.1,0.9-0.4c0.5-0.5,0.5-1.3,0-1.8L53.5,34.3l9.8-9.8c0.5-0.5,0.5-1.3,0-1.8c-0.5-0.5-1.3-0.5-1.8,0l-9.8,9.8l-9.8-9.8c-0.5-0.5-1.3-0.5-1.8,0c-0.5,0.5-0.5,1.3,0,1.8l9.8,9.8L39.5,44.6C39,45.1,39,45.9,39.5,46.4z"/></svg> <!-- Embedded video --> <iframe id="videoRiver1" src="https://www.youtube.com/embed/YDHFM2HmYe0?ecver=1" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> </div> <div class="containiframeCeleb1"> <!-- SVG Close (X) Icon --> <svg class="close" xmlns="http://www.w3.org/2000/svg" viewBox="39.2 22.3 25 24.5"><path d="M39.5,46.4c0.2,0.2,0.6,0.4,0.9,0.4c0.3,0,0.6-0.1,0.9-0.4l10.3-10.3L62,46.4c0.2,0.2,0.6,0.4,0.9,0.4c0.3,0,0.6-0.1,0.9-0.4c0.5-0.5,0.5-1.3,0-1.8L53.5,34.3l9.8-9.8c0.5-0.5,0.5-1.3,0-1.8c-0.5-0.5-1.3-0.5-1.8,0l-9.8,9.8l-9.8-9.8c-0.5-0.5-1.3-0.5-1.8,0c-0.5,0.5-0.5,1.3,0,1.8l9.8,9.8L39.5,44.6C39,45.1,39,45.9,39.5,46.4z"/></svg> <!-- Embedded video --> <iframe id="videoCeleb1" src="https://www.youtube.com/embed/ebB0eoSY4yU?ecver=1" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> </div> <div class="containiframe"> <!-- SVG Close (X) Icon --> <svg class="close" xmlns="http://www.w3.org/2000/svg" viewBox="39.2 22.3 25 24.5"><path d="M39.5,46.4c0.2,0.2,0.6,0.4,0.9,0.4c0.3,0,0.6-0.1,0.9-0.4l10.3-10.3L62,46.4c0.2,0.2,0.6,0.4,0.9,0.4c0.3,0,0.6-0.1,0.9-0.4c0.5-0.5,0.5-1.3,0-1.8L53.5,34.3l9.8-9.8c0.5-0.5,0.5-1.3,0-1.8c-0.5-0.5-1.3-0.5-1.8,0l-9.8,9.8l-9.8-9.8c-0.5-0.5-1.3-0.5-1.8,0c-0.5,0.5-0.5,1.3,0,1.8l9.8,9.8L39.5,44.6C39,45.1,39,45.9,39.5,46.4z"/></svg> <!-- Embedded video --> <iframe id="video" src="https://www.youtube.com/embed/YDHFM2HmYe0?ecver=1" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe> </div> </div> <header> <div> <span class="play"> </span> </div> <div> <span class="playcelebrity1"> </span> </div> <div> <span class="playcottage1"> </span> </div> <div> <span class="playLouie"> </span> </div> <div> <span class="playbachelourette"> </span> </div> <div> <span class="playcottage2"> </span> </div> <div> <span class="playcelbrity2"> </span> </div> </header> <script src='http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script> <script src="js/index.js"></script> </body> </html> Here is my progress so far (jsfiddle)
I had a project which I should embed multi videos. this is how I done it : I used Bootstrap modal : <div id="videoModal" class="modal"> <!-- Modal content --> <div class="modal-content"> <span class="close">×</span> <iframe id="videoIframe" class="full-width height-480" src="https://www.youtube.com/watch?v=UM-ZPAF2Dpw" frameborder="0" allowfullscreen></iframe> </div> </div> add this one only once, and in your button pass the youtube video ID like this : <button onclick="showVideo('UM-ZPAF2Dpw')"><span class="glyphicon glyphicon-triangle-right"></span> Show Video 1</button> you can have as many as button you like with different video ID and in your script file you need to have this : function showVideo(youtubeID){ var url = 'https://www.youtube.com/embed/' + youtubeID document.getElementById('videoIframe').src = url; // Get the modal var modal = document.getElementById('videoModal'); // Get the <span> element that closes the modal var span = document.getElementsByClassName("close")[0]; modal.style.display = "block"; // When the user clicks on <span> (x), close the modal span.onclick = function() { modal.style.display = "none"; document.getElementById('videoIframe').src = ''; } // When the user clicks anywhere outside of the modal, close it window.onclick = function(event) { if (event.target == modal) { modal.style.display = "none"; document.getElementById('videoIframe').src = ''; } } }