Video modal

video-img
No media found

Note: Transition is not good in IE

Html


<!-- video section -->
<div class="video-section" data-toggle-video-modal>
	<div data-iframe-id="ahCwqrYpIuM"></div>
	<img src="https://picsum.photos/id/1021/2048/1206" alt="video-img" />
	<svg class="video-section__icon" style="enable-background:new 0 0 512 512;" version="1.1" viewBox="0 0 512 512" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><path d="M405.2,232.9L126.8,67.2c-3.4-2-6.9-3.2-10.9-3.2c-10.9,0-19.8,9-19.8,20H96v344h0.1c0,11,8.9,20,19.8,20  c4.1,0,7.5-1.4,11.2-3.4l278.1-165.5c6.6-5.5,10.8-13.8,10.8-23.1C416,246.7,411.8,238.5,405.2,232.9z" /></svg>
</div>

<!-- video modal -->
<div class="video-modal" data-video-modal>
	<div class="video-modal__backdrop" data-video-modal-close></div>
	<div class="video-modal__close" data-video-modal-close>
		<svg class="video-modal__close-icon" enable-background="new 0 0 357 357" version="1.1" viewBox="0 0 357 357" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
		<polygon points="357 35.7 321.3 0 178.5 142.8 35.7 0 0 35.7 142.8 178.5 0 321.3 35.7 357 178.5 214.2 321.3 357 357 321.3 214.2 178.5" />
		</svg>
	</div>
	<div class="video-modal__content-wrap">
		<div class="video-modal__video-wrap-backdrop"></div>
		<div class="video-modal__video-wrap" data-video-modal-content>
			<div class="video-modal__error-message" data-video-modal-error>
				<span class="video-modal__error-message-text">No media found</span>
			</div>
		</div>
	</div>
</div>

Scss

 
		
// local var
$modal-height: 80vh;
$modal-width: 80vw;
$modal-height--devices: 40vh;
$modal-width--devices: 90vw;
// video section
.video-section {
	position: relative;
	cursor: pointer;
	overflow: hidden;
	margin-bottom: 1.8rem;
	// video section backdrop
	&:after {
		content: "";
		background-color: $color-black;
		@include position-all-sides;
		opacity: .4;
		transition: opacity $transition;
	}
	// img
	img {
		min-width: 100%;
		display: block;
		transform: scale(1.01);
		transition: transform $transition;
	}
	// icon
	&__icon {
		@include position-center;
		width: 6rem;
		height: 6rem;
		z-index: 1;
		fill: $color-white;
		transition: transform $transition;
	}
}
// hide ifram id
[data-iframe-id] {
	display: none;
}
// video section hover transition
.video-section:hover {
	img {
		transform: scale(1.08);
	}

	&:after {
		opacity: 0;
	}

	.video-section__icon {
		transform: scale(1.2) translate(-50%,-50%);
	}
}
// video modal
.video-modal {
	@include position-all-sides;
	position: fixed;
	overflow: hidden;
	opacity: 0;
	pointer-events: none;
	transition: opacity $transition--slow;
	transition-delay: .6s;
	z-index: 5;
	// backdrop
	&__backdrop {
		cursor: pointer;
		position: relative;
		height: 100%;
		width: 100%;
		background-color: rgba($color-black, .7);
		z-index: 5;
	}
	// close icon
	&__close {
		position: absolute;
		top: 0;
		right: 0;
		background-color: $color-white;
		padding: 1.6rem 4rem;
		cursor: pointer;
		z-index: 5;
		transform: translate3d(0,-100%,0);
		visibility: hidden;
		transition: $transition--slow;
		transition-delay: .4s;
	}
	// close hover effect
	&__close:hover {
		.video-modal__close-icon {
			transform: rotate(180deg);
		}
	}

	&__close-icon {
		fill: $color-black;
		height: 1.4rem;
		width: 1.4rem;
		transition: transform $transition;
	}
	//content wrap
	&__content-wrap, &__video-wrap {
		position: absolute;
		z-index: 6;
	}

	&__content-wrap {
		height: $modal-height;
		width: $modal-width;
		top: (100 - $modal-height) / 2;
		left: (100 - $modal-width) / 2;
		overflow: hidden;
	}
	// video wrap
	&__video-wrap {
		height: 100%;
		width: 100%;
	}

	&__video-wrap iframe {
		position: relative;
		z-index: 5;
		height: $modal-height;
		width: $modal-width;
		background-color: $color-black;
	}
	// video wrap background
	&__video-wrap-backdrop {

		@include position-all-sides;
		z-index: 7;
		background-color: $color-black;
		opacity: 1;
		transition: opacity $transition;
		transition-delay: .6s;
	}
}

// video modal transition
.video-modal.is-active {
	opacity: 1;
	transition-delay: 0s;
	pointer-events: initial;

	.video-modal__close {
		transform: translate3d(0,0,0);
		transition-delay: .2s;
		visibility: visible;
	}

	.video-modal__video-wrap-backdrop {
		transition-delay: .5s;
		opacity: 0;
	}
}
// video error message
.video-modal {
	&__error-message {
		@include position-center;
		visibility: hidden;
		opacity: 0;
		transition: $transition;
		text-align: center;
	}

	&__error-message-text {
		font-size: 5rem;
		color: $color-white;
	}
}
// video error active
.video-modal__error-message.is-active {
	visibility: visible;
	opacity: 1;
}

@include viewport-large {
	.video-section {
		&:after {
			opacity: 1;
		}

		img {
			transform: none;
		}
	}
}

@include viewport-medium {
	// video error message
	.video-modal {
		&__error-message-text {
			font-size: 2.6rem;
		}
	}
}

@include viewport-small {
	// video section
	.video-section {
		margin-bottom: 1rem;

		&__icon {
			width: 8rem;
			height: 8rem;
		}

		&__icon-item {
			width: 1.5rem;
			height: 1.4rem;
		}
	}
	// video modal
	.video-modal {
		transition-delay: 1s;

		&__content-wrap {
			height: $modal-height--devices;
			width: $modal-width--devices;
			top: (100 - $modal-height--devices) /2;
			left: (100 - $modal-width--devices) /2;
		}

		&__video-wrap iframe {
			height: $modal-height--devices;
			width: $modal-width--devices;
		}
	}
}

JavaScript

 
	
export class videoModalModule {
	videoModalToggle: NodeList = document.querySelectorAll("[data-toggle-video-modal]");
	videoModalToggleArray: Array< HTMLElement> = Array.prototype.slice.call(this.videoModalToggle);
	videoModal: HTMLElement = document.querySelector("[data-video-modal]");
	videoModalClose: NodeList = document.querySelectorAll("[data-video-modal-close]");
	videoModalCloseArray: Array< HTMLElement> = Array.prototype.slice.call(this.videoModalClose);
	videoModalError: HTMLElement = document.querySelector("[data-video-modal-error]");
	videoModalContent: HTMLElement = document.querySelector("[data-video-modal-content]");
	activeClass: string = "is-active";

	constructor() {
		this.appendUrl();
		this.toggleModal();
	}
	// append url to modal
	private appendUrl = () => {
		this.videoModalToggleArray.forEach((elem) => {
			elem.addEventListener("click", () => {
				let targetIframe: string = elem.firstElementChild.getAttribute("data-iframe-id");
				if (targetIframe !== '') {
					this.videoModalContent.innerHTML = '< iframe class="iframe-item" src="https://www.youtube.com/embed/' + targetIframe + '?autoplay=1' + '" frameborder="0" allowfullscreen="" allow="accelerometer; autoplay">< /iframe>';
				} else {
					this.videoModalError.classList.add(this.activeClass);
				}
			})
		});
	}

	private toggleModal = () => {
		// open modal
		this.videoModalToggleArray.forEach((elem) => {
			elem.addEventListener("click", () => {
				this.videoModal.classList.add(this.activeClass);
			})
		});
		// close modal
		let closeModal = () => {
			this.videoModal.classList.remove(this.activeClass);
			// clear iframe, so it dosent run in background
			setTimeout(() => {
				document.querySelector(".iframe-item").removeAttribute("src");
			}, 1200);
		}
		this.videoModalCloseArray.forEach(elem => elem.addEventListener("click", closeModal));
	}
}