Skip to content

Instantly share code, notes, and snippets.

@mohammed-ghouse
Created October 29, 2018 09:07
Show Gist options
  • Save mohammed-ghouse/35f082af913047643a7b510e6091ea4e to your computer and use it in GitHub Desktop.
Save mohammed-ghouse/35f082af913047643a7b510e6091ea4e to your computer and use it in GitHub Desktop.
YouTube Video Modal
<main>
<section class="column left banner">
<a
href="https://www.youtube.com/watch?v=ze_ie8Ctp60"
data-youtube-id="ze_ie8Ctp60"
class="video-banner js-trigger-video-modal"
>
<img
class="video-banner-img"
src="http://i3.ytimg.com/vi/ze_ie8Ctp60/maxresdefault.jpg"
alt=""
/>
<span class="video-banner-headline">
Launch From A Banner
</span>
<!-- Play bttn - converted to a data URI just so i can avoid the need for external asset hosting w/ this demo -->
<img
class="video-banner-icon-play"
alt="Play Video"
src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyAKCXZlcnNpb249IjEuMSIgCgl4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIAoJeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiCgl4PSIwIgoJeT0iMCIKCXZpZXdCb3g9IjAgMCA3MiA3MiIgCglzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCA3MiA3MjsiIAoJeG1sOnNwYWNlPSJwcmVzZXJ2ZSIgCgl3aWR0aD0iIiAKCWhlaWdodD0iIiAKPgogICAgICAgIDxwYXRoIGQ9Ik0zNiw3MiBDNTUuOSw3MiA3Miw1NS45IDcyLDM2IEM3MiwxNi4xIDU1LjksMCAzNiwwIEMxNi4xLDAgMCwxNi4xIDAsMzYgQzAsNTUuOSAxNi4xLDcyIDM2LDcyIFogTTM2LDggQzUxLjQsOCA2NCwyMC42IDY0LDM2IEM2NCw1MS40IDUxLjQsNjQgMzYsNjQgQzIwLjYsNjQgOCw1MS40IDgsMzYgQzgsMjAuNiAyMC42LDggMzYsOCBaIiBpZD0iU2hhcGUiIGZpbGw9IiNGRkZGRkYiIGZpbGwtcnVsZT0ibm9uemVybyI+PC9wYXRoPgogICAgICAgIDxwYXRoIGQ9Ik0yNiw1MS43IEMyNi4zLDUxLjkgMjYuNyw1MiAyNyw1MiBDMjcuMyw1MiAyNy43LDUxLjkgMjgsNTEuNyBMNTIsMzcuNyBDNTIuNiwzNy4zIDUzLDM2LjcgNTMsMzYgQzUzLDM1LjMgNTIuNiwzNC42IDUyLDM0LjMgTDI4LDIwLjMgQzI3LjQsMTkuOSAyNi42LDE5LjkgMjYsMjAuMyBDMjUuNCwyMC43IDI1LDIxLjMgMjUsMjIgTDI1LDUwIEMyNSw1MC43IDI1LjQsNTEuNCAyNiw1MS43IFoiIGlkPSJTaGFwZSIgZmlsbD0iI0ZGRkZGRiIgZmlsbC1ydWxlPSJub256ZXJvIj48L3BhdGg+Cjwvc3ZnPg=="
/>
</a>
</section>
<section class="column right">
<article class="content">
<h1>
YouTube<br/>
Video Modal
</h1>
<p>
In this demo I worked out how to leverage just the YouTube video’s unique ID, and pass it in to a reusable modal component that takes advantage of YouTube’s embed&nbsp;method.
</p>
<h2>
Launch From Thumbnails
</h2>
<div class="video-thumb-grid">
<!-- Daft Punk - Human After All -->
<a
href="https://www.youtube.com/watch?v=hrB-_nIer88"
data-youtube-id="hrB-_nIer88"
class="video-thumb js-trigger-video-modal"
>
<img
class="video-banner-img"
src="http://i3.ytimg.com/vi/hrB-_nIer88/maxresdefault.jpg"
alt=""
/>
</a>
<!-- M83 - Midnight City -->
<a
href="https://www.youtube.com/watch?v=dX3k_QDnzHE"
data-youtube-id="dX3k_QDnzHE"
class="video-thumb js-trigger-video-modal"
>
<img
class="video-banner-img"
src="http://i3.ytimg.com/vi/dX3k_QDnzHE/hqdefault.jpg"
alt=""
/>
</a>
<!-- Death Cab for Cutie - You Are A Tourist -->
<a
href="https://www.youtube.com/watch?v=EcKinnMXuKg"
data-youtube-id="qkk5wViJo-I"
class="video-thumb js-trigger-video-modal"
>
<img
class="video-banner-img"
src="http://i3.ytimg.com/vi/qkk5wViJo-I/hqdefault.jpg"
alt="Death Cab for Cutie - You Are A Tourist"
/>
</a>
<!-- José Gonzales - Heartbeats -->
<a
href="https://www.youtube.com/watch?v=HxJhYpTIrl8"
data-youtube-id="HxJhYpTIrl8"
class="video-thumb js-trigger-video-modal"
>
<img
class="video-banner-img"
src="http://i3.ytimg.com/vi/HxJhYpTIrl8/hqdefault.jpg"
alt=""
/>
</a>
</div>
<h2>
Launch From Buttons &amp; Links
</h2>
<p>
Buttons and links are fair game too, since the method uses anchor tags.
</p>
<div class="button-group">
<a
href="https://www.youtube.com/watch?v=Ahglrb_z7wQ"
data-youtube-id="Ahglrb_z7wQ"
class=" button primary js-trigger-video-modal"
>
Let's Rock
</a>
<a
href="https://www.youtube.com/watch?v=dQw4w9WgXcQ"
data-youtube-id="dQw4w9WgXcQ"
class=" button js-trigger-video-modal"
>
Nah, Let's Rick
</a>
</div>
<h2>
Note
</h2>
<p>
Auto-play is disabled for certain interaction paradigms, and on certain OS's—Like most touch screen devices that are behaving according to spec. The trade-off here is the user will need to tap the play button once the modal pops on touch-screen devices like iPhones. Depending on your use-case and project that trade-off is likely acceptable.
</p>
</article>
</section>
</main>
<!-- video modal -->
<section class="video-modal">
<!-- Modal Content Wrapper -->
<div
id="video-modal-content" class="video-modal-content"
>
<!-- iframe -->
<iframe
id="youtube"
width="100%"
height="100%"
frameborder="0"
allowfullscreen
src=
></iframe>
<a
href="#"
class="close-video-modal"
>
<!-- X close video icon -->
<svg
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
x="0"
y="0"
viewBox="0 0 32 32"
style="enable-background:new 0 0 32 32;"
xml:space="preserve"
width="24"
height="24"
>
<g id="icon-x-close">
<path fill="#ffffff" d="M30.3448276,31.4576271 C29.9059965,31.4572473 29.4852797,31.2855701 29.1751724,30.980339 L0.485517241,2.77694915 C-0.122171278,2.13584324 -0.104240278,1.13679247 0.52607603,0.517159487 C1.15639234,-0.102473494 2.17266813,-0.120100579 2.82482759,0.477288136 L31.5144828,28.680678 C31.9872448,29.1460053 32.1285698,29.8453523 31.8726333,30.4529866 C31.6166968,31.0606209 31.0138299,31.4570487 30.3448276,31.4576271 Z" id="Shape"></path>
<path fill="#ffffff" d="M1.65517241,31.4576271 C0.986170142,31.4570487 0.383303157,31.0606209 0.127366673,30.4529866 C-0.12856981,29.8453523 0.0127551942,29.1460053 0.485517241,28.680678 L29.1751724,0.477288136 C29.8273319,-0.120100579 30.8436077,-0.102473494 31.473924,0.517159487 C32.1042403,1.13679247 32.1221713,2.13584324 31.5144828,2.77694915 L2.82482759,30.980339 C2.51472031,31.2855701 2.09400353,31.4572473 1.65517241,31.4576271 Z" id="Shape"></path>
</g>
</svg>
</a>
</div><!-- end modal content wrapper -->
<!-- clickable overlay element -->
<div class="overlay"></div>
</section>
<!-- end video modal -->
$(document).ready(function(){
/* Toggle Video Modal
-----------------------------------------*/
function toggle_video_modal() {
// Click on video thumbnail or link
$(".js-trigger-video-modal").on("click", function(e){
// prevent default behavior for a-tags, button tags, etc.
e.preventDefault();
// Grab the video ID from the element clicked
var id = $(this).attr('data-youtube-id');
// Autoplay when the modal appears
// Note: this is intetnionally disabled on most mobile devices
// If critical on mobile, then some alternate method is needed
var autoplay = '?autoplay=1';
// Don't show the 'Related Videos' view when the video ends
var related_no = '&rel=0';
// String the ID and param variables together
var src = '//www.youtube.com/embed/'+id+autoplay+related_no;
// Pass the YouTube video ID into the iframe template...
// Set the source on the iframe to match the video ID
$("#youtube").attr('src', src);
// Add class to the body to visually reveal the modal
$("body").addClass("show-video-modal noscroll");
});
// Close and Reset the Video Modal
function close_video_modal() {
event.preventDefault();
// re-hide the video modal
$("body").removeClass("show-video-modal noscroll");
// reset the source attribute for the iframe template, kills the video
$("#youtube").attr('src', '');
}
// if the 'close' button/element, or the overlay are clicked
$('body').on('click', '.close-video-modal, .video-modal .overlay', function(event) {
// call the close and reset function
close_video_modal();
});
// if the ESC key is tapped
$('body').keyup(function(e) {
// ESC key maps to keycode `27`
if (e.keyCode == 27) {
// call the close and reset function
close_video_modal();
}
});
}
toggle_video_modal();
});
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
/* Embed google fonts for demo layout
-----------------------------------------*/
@import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,600,700,900');
/* Main Page Layout
-- NOTE: Just for the demo page, and not
required for the video modal... Video Modal
styles are down below --
-----------------------------------------*/
* {
box-sizing: border-box;
}
html {
background: #fcfcfc;
}
@media (min-width: 641px) {
html {
background: #4b4b4b;
}
}
body {
font-family: 'Source Sans Pro', sans-serif;
}
.noscroll {
overflow: hidden;
}
main {
font-size: 0;
}
main .column.left,
main .column.right {
background: #fcfcfc;
display: block;
position: relative;
font-size: 1rem;
width: 100%;
min-height: 0;
vertical-align: top;
}
@media (min-width: 641px) {
main .column.left,
main .column.right {
display: inline-block;
width: 50%;
min-height: 100vh;
}
main .column.left {
position: fixed;
}
main .column.right {
margin-left: 50%;
}
}
.video-banner {
display: block;
}
@media (min-width: 641px) {
.video-banner {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
z-index: 0;
}
}
.video-banner .video-banner-img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
object-position: 50% 50%;
}
.video-banner-headline {
position: absolute;
left: 1.5rem;
bottom: 1.5rem;
font-family: 'Source Sans Pro', sans-serif;
font-size: 1.25em;
font-weight: 900;
line-height: 1.0em;
color: #fff;
text-transform: uppercase;
letter-spacing: 0.045em;
}
@media (min-width: 641px) {
.video-banner-headline {
left: 2em;
bottom: 2.75em;
font-size: 1.5em;
line-height: 1.5em;
}
}
.video-banner-icon-play {
position: absolute;
left: 50%;
top: 50%;
display: block;
width: 2.5em;
height: 2.5em;
-webkit-transform: translateX(-50%) translateY(-50%) scale(1.0);
-moz-transform: translateX(-50%) translateY(-50%) scale(1.0);
-ms-transform: translateX(-50%) translateY(-50%) scale(1.0);
-o-transform: translateX(-50%) translateY(-50%) scale(1.0);
transform: translateX(-50%) translateY(-50%) scale(1.0);
-webkit-transition:
all 0.2s ease-out 0.05s;
transition:
all 0.2s ease-out 0.05s;
}
@media (min-width: 641px) {
.video-banner-icon-play {
width: 4.5em;
height: 4.5em;
}
}
.video-banner-icon-play:hover {
-webkit-transform: translateX(-50%) translateY(-50%) scale(1.2);
-moz-transform: translateX(-50%) translateY(-50%) scale(1.2);
-ms-transform: translateX(-50%) translateY(-50%) scale(1.2);
-o-transform: translateX(-50%) translateY(-50%) scale(1.2);
transform: translateX(-50%) translateY(-50%) scale(1.2);
backgound: #330099;
}
.content {
display: block;
min-height: 100vh;
max-width: 40rem;
margin: 2.5rem auto;
padding: 1.5rem;
}
@media (min-width: 641px) {
.content {
margin: 5.75rem auto;
padding: 2.5rem;
}
}
.content h1,
.content h2,
.content p {
font-family: 'Source Sans Pro', sans-serif;
font-size: 1em;
font-weight: 300;
line-height: 1.5em;
color: #0D013D;
}
.content h1 {
font-size: 3.25em;
font-weight: 200;
line-height: 1.0em;
margin: 0 0 0.5rem 0;
}
@media (min-width: 641px) {
.content h1 {
font-size: 4em;
}
}
.content h2 {
font-size: 1em;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.155em;
margin-top: 3em;
}
/* buttons */
.content .button-group {
margin-top: 1em;
}
.content .button {
display: inline-block;
padding: 1em 2em;
min-width: 8em;
text-align: center;
font-weight: 900;
text-decoration: none;
border-radius: 1.5em;
box-shadow: 0 1px 1px rgba(0,0,0,0.25);
/* button theme - secondary is default */
background: #f0f0f0;
color: #2B2B2B;
-webkit-transition:
all 0.2s ease-out 0.05s;
transition:
all 0.2s ease-out 0.05s;
}
.content .button ~ .button {
margin-left: 0.5em;
}
.content .button:hover {
background: #e5e5e5;
}
/* primary button overrides */
.content .button.primary {
background: #E50055;
color: #fff;
}
.content .button.primary:hover {
background: #9D00E5;
}
/* video thumbnail grid */
.content .video-thumb-grid {
position: relative;
font-size: 0; /* collapse the white-space */
width: calc(100% + 2rem);
margin: 0 -1rem;
}
.content .video-thumb {
display: inline-block;
vertical-align: top;
text-decoration: none;
/* calculate the width, gutters, and aspect ratio */
width: calc((100% - 4rem) / 2);
height: 0;
padding-top: calc(((100% - 4rem) / 2) * 0.5625); /* 16:9 calc */
margin: 1rem 1rem; /* gutters */
overflow: hidden; /* clipping */
position: relative; /* enable positioning for inner content */
font-size: 1rem; /* reset the font size */
-webkit-transform: scale(1.0);
transform: scale(1.0);
box-shadow: 0 0 0 rgba(0,0,0,0.0);
-webkit-transition:
all 0.2s ease-out 0.05s;
transition:
all 0.2s ease-out 0.05s;
}
.content .video-thumb:hover {
-webkit-transform: scale(1.05);
transform: scale(1.05);
box-shadow: 0 2px 4px rgba(13,1,61,0.35);
}
.content .video-thumb img {
display: block;
width: 100%;
height: 100%;
/* position inside the 16:9 container */
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
/* clipping for source images that are letterboxed */
object-fit: cover;
object-position: 50% 50%;
background: #2b2b2b;
}
/* Video Modal
-----------------------------------------*/
.video-modal,
.video-modal .overlay {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 3000;
}
.video-modal {
overflow: hidden;
position: fixed;
opacity: 0.0;
-webkit-transform: translate(500%,0%);
transform: translate(500%,0%);
-webkit-transition: -webkit-transform 0s linear 0s;
transition: transform 0s linear 0s;
/* using flexbox for vertical centering */
/* Flexbox display */
display: -webkit-box;
display: -webkit-flex;
display: flex;
/* Vertical alignment */
-webkit-box-align: center;
-moz-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
-webkit-transform-style: preserve-3d;
-moz-transform-style: preserve-3d;
transform-style: preserve-3d;
}
.video-modal .overlay {
z-index: 0;
background: rgba(13,1,61,0.82); /* overlay color */
opacity: 0.0;
-webkit-transition: opacity 0.2s ease-out 0.05s;
transition: opacity 0.2s ease-out 0.05s;
}
.video-modal-content {
position: relative;
top: auto;
right: auto;
bottom: auto;
left: auto;
z-index: 1;
margin: 0 auto;
overflow-y: visible;
background: #000;
width: calc(100% - 12em);
height: 0;
padding-top: calc((100% - 12em) * 0.5625); /* 16:9 calc */
}
/* Scaling to fit within the current Viewport size:
When viewport aspect ratio is greater than 16:9
work off the height instead of the width for calc */
@media (min-aspect-ratio: 16/9) {
.video-modal-content {
width: 0;
height: calc(100vh - 10em);
padding-top: 0;
padding-left: calc((100vh - 10em) * 1.7778); /* 16:9 calc */
}
}
/* Mobile Layout Tweaks - side margins reduced */
@media (max-width: 640px) {
.video-modal-content {
width: calc(100% - 1em);
padding-top: calc((100% - 1em) * 0.5625); /* 16:9 calc */
}
}
/* modal close button */
.close-video-modal {
display: block;
position: absolute;
left: 0;
top: -40px;
text-decoration: none;
font-size: 20px;
font-weight: bold;
color: #fff;
}
/* set the iframe element to stretch to fit its parent element */
iframe#youtube {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
background: #000;
box-shadow: 0px 2px 16px rgba(0,0,0,0.5);
}
/* show the modal:
add class to the body to reveal */
.show-video-modal .video-modal {
opacity: 1.0;
transform: translate(0%,0%);
-webkit-transform: translate(0%,0%);
}
.show-video-modal .video-modal .overlay {
opacity: 1.0;
}
.show-video-modal .video-modal-content {
transform: translate(0%,0%);
-webkit-transform: translate(0%,0%);
}

YouTube Video Modal

I worked out a way to use just a YouTube video's ID in the main page's markup, so it can be passed in to a YouTube video modal / overlay template when a link or thumbnail is clicked. The video modal maintains its 16:9 aspect ratio no matter what the viewport size is, making it properly responsive.

A Pen by Matt Amyot on CodePen.

License.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment