Horizontally scrollable gallery of videos that play on hover - javascript

I'm trying to create a gallery of images that, when hovered upon, the image disappears and a video begins playing, similar to Netflix. I was able to create a gallery that did what I want here:
.container {
display: flex;
overflow-x: auto;
width: 600px;
margin-left: 300px;
}
.container img {
margin-right: 15px;
width: 150px
}
<div class="container">
<img src=https://image.shutterstock.com/image-vector/check-back-soon-hand-lettering-600w-1379832464.jpg>
and the image disappearing and video playing on hover that I want here:
const videos = document.querySelectorAll(".polystar");
for (const video of videos) {
video.addEventListener('mouseover', function() {
video.play()
}, false);
video.addEventListener('mouseout', function() {
video.pause()
}, false);
}
.gallery-cv {
display: flex;
z-index: 1;
overflow-x: auto;
width: 1200px;
margin: 0;
}
.polystar {
width: 300px;
z-index: 2;
opacity: 0;
}
.top-img {
position: absolute;
width: 300px;
height: 535px;
z-index: 1;
}
.polystar:hover {
opacity: 1;
}
.second {
margin-left: 150px;
position: absolute;
z-index: 3;
}
<h1> headline </h1>
<div class="gallery-cv">
<img class="top-img first" src="https://source.unsplash.com/random">
<video class='polystar' muted src="https://player.vimeo.com/external/432406907.hd.mp4?s=f35b5f202d573efa75d9293d213fc3be0927fd85&profile_id=172&oauth2_token_id=57447761" type="video/mp4">
<img class="top-img second" src="https://source.unsplash.com/random">
<img class="top-img third" src="https://source.unsplash.com/random">
</div>
But when I try to combine these (as I've attempted in the above codepen), my gallery disappears and I'm left with only one image, despite having others present in the html. I'm guessing this has something to do with me losing my gallery when I try to have the images inside it absolutely positioned, but I'm not sure how else to achieve my hover effect without absolutely positioning them.

There are multiple problems we have to solve. Lets start with the image that should be displayed by default and disappear for the video on hover:
We need a wrapping element that contains the video and the image like a <div>.
We apply position: relative; to the parent element (wrapper)
We apply position: absolute; inset: 0; (inset: 0 = top + right + bottom + left: 0;) to have the image span the entire wrapping element and elevate it layer-wise above the video with a positive z-index: z-index: 1;
to hide the image on hover we use: div:hover img { display: none; }
The next issue is to start playing the video on hover. For that we need JS which we also can do with the onmouseover-attribute: onmouseover="element.play();"
To pause the video when you not hovering we can use JS or the onmouseout-attribute: onmouseout="element.pause();"
Both the onmouseover and onmouseout trigger/attribute must be added to the wrapping parent element.
div {
position: relative;
}
video {
width: 100%;
}
img {
width: 100%;
object-fit: cover;
position: absolute;
inset: 0;
z-index: 1;
}
div:hover img {
display: none;
}
<div onmouseover="document.querySelector('video').play();" onmouseout="document.querySelector('video').pause();">
<video>
<source src="https://www.tacoshy.de/stackoverflow/testvideo.mp4" type="video/mp4">
</video>
<img src="https://via.placeholder.com/1920x1080.jpg">
</div>

Related

How to align and clip overlay to match iframe video?

I'm trying to align to make some custom ''video player'' thingy based around two iframes acting as double buffers and an overlay that will allow users to perform custom actions, similar to Coursera's modal questions.
All this will be exposed later through and uri that will be used in an external iframe (yea, i know)
The issue i'm facing is that i need the overlay to always match the video inside the iframes but the iframes themselves seem to be bigger than the actual video. For example, by assigning width: 100% to the iframes i manage to get a consistent result accessing this component through another iframe (the one that will be used in the website).
Current html structure using VueJs
<div id="action-player">
<!-- Interactive layer -->
<div class="a-overlay-layer">
<slot name="overlay-layer"></slot>
</div>
<!-- iFrame double buffer -->
<div class="a-iframe-layer">
<div id="buffer0" :class="['a-frame-buffer', { 'a-frame-buffer__active': bufferState.active === 0 }]"></div>
<div id="buffer1" :class="['a-frame-buffer', { 'a_frame-buffer__active': bufferState.active === 1 }]"></div>
</div>
</div>
Both buffers are being instanced by vimeo player. Currently in the slot for the overlay i just have a background:red element covering the screen;insira o código aqui
.a_player {
position: relative;
width: 100%;
height: 100%;
// padding-top: 56.25%; // //Aspect ratio 16:9
}
.a-overlay-layer {
position: absolute;
display: block;
float: right;
height: 100%;
width: 100%;
z-index: 2147483647;
pointer-events: none;
// background: transparent;
}
.a-iframe-layer {
position: relative;
width: 100%;
height: 100%;
}
.a-frame-buffer {
position: absolute;
z-index: 99;
display: block;
height: 100%;
width: 100%;
// vimeo iframe
iframe {
height: 100%;
width: 100%;
}
}
.a-frame-buffer__active {
z-index: 100 !important;
animation: smoothTransition 0.425s linear 0s 1 normal both;
}
The double buffer works fine, i just need to find a way to keep the overlay matching the video size not the whole iframe, which i thin, i defaulting to the whole screen cause of width: 100%.
Appreciate the help! o/

Could background-color have different z-index than img?

I need to one image overlap an another. But the second image have background color and I need the first image between the second and second's background-color. It is possible? Already tried to made a new "div class" instead of style="background-color". Now i am stuck with this:
.mainRunner {
position: relative;
}
.firstimage {
position: relative;
z-index: 2;
}
.secondimage {
position: relative;
z-index: 3;
top: -75px;
}
.background {
position: relative;
z-index: 1
}
<div class="firstimage" style="max-width: 1170px;"><img src="" alt="" title="" style="width: 100%;" max-width="1168" height="399" caption="false" /></div>
<div class="background" style="background-color: #f2e5df;">
<div class="secondimage">
<img src="" alt="" title="" />
</div></div>
You can't give certain properties of an element different z-index values. However for certain elements like a div you can use ::before and ::after pseudo elements. And you can set a z-index on those, effectively creating three layers. More information here.
In this case you can create a div with the middle img inside. Then add a ::before and ::after to that div. Giving one a background color and a z-index of -1. And the other a background image and a z-index of 1.
In the example below I also added some margin and a border around the inital div so you can better see what is going on.
.image {
margin: 20px 0 0 20px;
position: relative;
border: 3px solid coral;
width: 200px;
height: 300px;
}
.image::before,
.image::after {
content: '';
display: block;
width: 200px;
height: 300px;
position: absolute;
}
.image::before {
z-index: -1;
background: cornflowerblue;
top: 20px;
left: 20px;
}
.image::after {
z-index: 1;
background: url("https://www.fillmurray.com/200/300");
top: -20px;
left: -20px;
}
<div class="image"><img src="https://www.fillmurray.com/200/300" /></div>
If I understand right what you're trying to achieve, you probably should be placing the images within background div and placing the second image with position: absolute:
<style>
.mainRunner {
position: relative;
}
.firstimage {
position: relative;
z-index: 2;
}
.secondimage {
position: absolute;
z-index: 3;
top: 20px; /* use top and left values to place the image exactly where you want it over the first image */
left: 20px
}
.background {
position: relative;
z-index: 1;
background-color: #f2e5df;
}
</style>
<div class="mainRunner">
<div class="background">
<img src="image1.png" class="firstimage" />
<img src="image2.png" class="secondimage " />
</div>
</div>
It sets the background color as the back-most element, then on top of it the secondimage and the firstimage.
Thank everyone for their ideas. In the end the solution was simple. In the style was the double definition of second image. And the first of them was just partly commented. So my first post working right like this:
.secondimage img{
max-width: 100%;
height: auto;
position: relative;
top: -75px;
margin: 5px;
margin-bottom: 10px;
}
Now just need to find out how to close this question...
Thank you :)
The answer is simply no... there is no way to address a z-index to specifically a background of an element, z-index and all the other CSS properties work on the entire element, not on only its background.
You're going to have to find another way to do this, have you thought of using a div with not content, and the same size of the image, and then just setting a background color to that specific div?

Adding content on top of webcam video i.e. color overlay

I'm trying to add a blue color overlay to my full screen video tag that's pulling the video feed from the users webcam (using JS to do this.) I'm unable to get the blue overlay to appear on top of the video, as it displays behind it, and if the div isn't set to absolute, the video stops being full screen - any thoughts?
<div class="fullscreen-bg">
<div class="overlay--blue">
<video id="videoElement" class="fullscreen-bg__video"autoplay="true"></video>
</div>
</div>
.fullscreen-bg {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: hidden;
z-index: -100;
}
.fullscreen-bg__video {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
#media (min-aspect-ratio: 16/9) {
.fullscreen-bg__video {
height: 300%;
top: -100%;
}
}
#media (max-aspect-ratio: 16/9) {
.fullscreen-bg__video {
width: 300%;
left: -100%;
}
}
.overlay--blue {
background-color:rgba(19, 186, 228, 0.8);
position: absolute;
width: 100%;
height: 100%;
}
Since #videoElement is a child of .overlay--blue, #videoElement will by default be shown on top of .overlay--blue.
If you want the video to be shown behind the overlay, you can either give it a negative z-index (z-index: -1;). You can also edit the HTML by moving the video outside the overlay, before it, like so:
<div class="fullscreen-bg">
<video id="videoElement" class="fullscreen-bg__video"autoplay="true"></video>
<div class="overlay--blue"></div>
</div>
Hope this helps

Javascript/jQuery - replace a video iframe with a placeholder image

I've had one question involving this piece of code answered by the very helpful people here, but now I have another one which is slightly different. I have a placeholder image which sits in a carousel slide, which when clicked on gets replaced by a youtube video using the default youtube iframe embed.
What I would like to do is, after a user has clicked on the image and has played the video, when they click away from the carousel slide the video is embedded in (for example, by clicking on a carousel arrow or pagination dot) it resets it back to how it was before the video was displayed.
I hope that makes sense. Basically, I need help reverse engineering this code so that the video gets replaced again by it's placeholder image on a click of another element/div.
Here is the HTML:
<div class="youtube_video">
<img src="img/video_poster_carousel.jpg" width="986" height="308">
<!-- <iframe width="986" height="555" src="https://www.youtube.com/embed/Wt_Ruy_ejPY?enablejsapi=1&list=PL027E2B6D9900A88F&showinfo=0&controls=1" frameborder="0" allowfullscreen></iframe> -->
</div>
And the CSS:
/* video */
.youtube_video { position: relative; padding-bottom: 31.65%; height:0; }
.youtube_video img { position: absolute; display: block; top: 0; left: 0; /*width: 100%; height: 100%;*/ z-index: 20; cursor: pointer; }
.youtube_video:after { content: ""; position: absolute; display: block;
background: url(play-button.png) no-repeat 0 0;
top: 45%; left: 45%; width: 46px; height: 36px; z-index: 30; cursor: pointer; }
.youtube_video iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/* image poster clicked, player class added using js */
.youtube_video.player img { display: none; }
.youtube_video.player:after { display: none; }
And the Javascript:
$(function() {
var videos = $(".youtube_video");
videos.on("click", function(){
var elm = $(this),
conts = elm.contents(),
le = conts.length,
ifr = null;
for(var i = 0; i<le; i++){
if(conts[i].nodeType == 8) ifr = conts[i].textContent;
}
elm.addClass("player").html(ifr);
elm.off("click");
});
});
This below line actually does a innerHTML which means your img tag is lost
you may have to move the IMG tag out of the youtube_video container and do a hide and show toggle mechanism for the youtube_video container and the IMG tag
elm.addClass("player").html(ifr);

Absolute center an element with child elements (containing imgs/iframes) while keeping their aspect ratio on resize

I'm wondering how I can tackle these problems I'm facing.
DemoJS Bin Demo
What I'm trying to achieve is this:
.display and it's content should adapt to the size of the screen. If the viewport width is too narrow (same with viewport height) – .display
should shrink and all enclosed items should keep their ratio.
.display and all content should be centered, vertically and horizontally.
Let vimeo items have the same aspect ratio as the images (vimeo embed forces 16x9 aspect ratio, but I'd like the height of the video
to be the same as the images and let vimeo add black bars to fill
out).
And on a side note, as I have absolute positioned divs above the actual content (.cursor .left and .cursor .right) controlling the vimeo video will prove to be somewhat problematic. Are there any other solutions out there that could potentially work the same way as these divs do but enable interaction with the content underneath?
Here's a site that have absolute dead center and that keeps ratio of the enclosed items when resized, this is exactly what I'm trying to achieve. I could not figure out how they made this happen other than JS is involved.
Bureau Collective
HTML
<div class="display">
<div class="cursor left"></div>
<div class="cursor right"></div>
<div class="work-carousel">
<div class="item"><img src="http://lorempixel.com/output/abstract-q-c-1080-675-7.jpg"></div>
<div class="item"><img src="http://lorempixel.com/output/nightlife-q-c-1080-675-9.jpg"></div>
<div class="item"><iframe src="http://player.vimeo.com/video/57840967?title=0&byline=0&portrait=0&color=000000" width="1080" height="608" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe></div>
</div>
</div>
CSS
.display {
position: relative;
width: 1080px;
}
.cursor.left {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 45%;
z-index: 999;
}
.cursor.right {
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 45%;
z-index: 999;
}
.work-carousel {
margin:50px auto 60px;
padding:0;
}
.work-carousel item {
max-height: 100%;
max-width: 100%;
display: none;
}
.work-carousel item.first {
display: block
}
I thought I'd never use this technique!
The trick is in the padding:
.display {
position: relative;
width: 100%;
height:0;
padding:56.25% 0 0 0;
}
.item{
width: 100%;
height: 100%;
}
.item > * {
width: 100%;
height: 100%;
}
Here is the demo: http://jsbin.com/epeqar/7/edit

Categories