I came across this website's work page and would like to recreate the xray effect of each of the card element.
Here's my code for the xray effect: https://codepen.io/carljustineoyales/pen/yLMEVYd
HTML
<section class="banner">
<h1>this is a banner page</h1>
</section>
<section class="projects" id="projects">
<div class="cardlist" >
<div class="cardlist__grid" >
<div class="card" id="card" onmouseover="setSize()" onmouseout="resetSize()">
<div class="card__category">
category
</div>
<div class="card__thumbnail">
</div>
<div class="card__info">
<div class="card__title">title</div>
<div class="card__date">date</div>
</div>
</div>
<div class="card" id="card">
<div class="card__category">
category
</div>
<div class="card__thumbnail">
</div>
<div class="card__info">
<div class="card__title">title</div>
<div class="card__date">date</div>
</div>
</div>
</div>
</div>
<div class="cardlist--skeleton" id="skeleton">
<div class="cardlist--skeleton--bg"></div>
<div class="cardlist__grid">
<div class="card">
<div class="card__category">
category
</div>
<div class="card__thumbnail card__thumbnail--black">
</div>
<div class="card__info">
<div class="card__title">title</div>
<div class="card__date">date</div>
</div>
</div>
<div class="card">
<div class="card__category">
category
</div>
<div class="card__thumbnail card__thumbnail--black">
</div>
<div class="card__info">
<div class="card__title">title</div>
<div class="card__date">date</div>
</div>
</div>
</div>
</div>
</section>
</body>
SCSS
* {
margin: 0;
padding: 0;
}
.banner {
height: 100vh;
}
.projects {
max-width: 1440px;
width: 100%;
margin: 100px auto;
// padding: 100px 0;
position: relative;
}
.cardlist {
width: 100%;
color: #000;
&__grid {
display: flex;
flex-direction: row;
justify-content: space-between;
}
&--skeleton {
--x: 0;
--y: 0;
--size: 0px;
clip-path: circle(var(--size) at var(--x) var(--y));
user-select: none;
pointer-events: none;
// clip-path: circle(100px at 0 0);
// clip-path: circle(300px at 0% 0%);
transition: clip-path 0.1s ease;
&--bg {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: #838383;
z-index: -1;
}
width: 100%;
position: absolute;
top: 0;
left: 0;
color: #fff;
z-index: 1;
background-color: #838383;
}
}
.card {
padding: 50px;
&__thumbnail {
width: 500px;
height: 644px;
background-color: #838383;
&--black {
background-color: #000;
}
}
}
JS
let mouseX=0
let mouseY=0
let size = 0;
const projects = document.querySelector('#projects');
function setSize() {
size = 200
skeleton.style.setProperty('--size', size + "px");
}
function resetSize() {
size = 0
skeleton.style.setProperty('--size', size + "px");
}
function updateCoordinates(event) {
mouseX = event.pageX - projects.offsetLeft ;
mouseY = event.pageY - projects.offsetTop ;
skeleton.style.setProperty('--x', mouseX + "px");
skeleton.style.setProperty('--y', mouseY+ "px");
}
The problem is that I can't seem to find a solution for the updating cursor position while scrolling, also the hover animation became laggy when you open the console. Is there a way to update the cursor position on scroll and why the animation became laggy when the console is open.
Related
I want to use scroll to add and remove a class of Tabs
When I scroll down the page, then all tab switch to active. Then, when I scroll up the page, the all tab switched to inactive.
In the current condition, when I scroll down the page, it removes the current tab class, and when I scroll up the page, it adds the active class to the first tab. But, it's not what I want. I want it when I scroll down it moves to the next tab, when I scroll up it moves to the previous tab. I think I should use the if else tab.
//Add & remove class tab, contents, & menu on click
window.addEventListener('DOMContentLoaded', ()=> {
let tabs = document.querySelectorAll('.tab');
let content = document.querySelectorAll('.content-item');
let firstTab = function(tabs) {tabs.classList.add('tab-active')};
let firstContent = function(content) {content.classList.add('content-active')};
firstTab(tabs[0]); //Already remove the ready and callback
firstContent(content[0]);
for (let i = 0; i < tabs.length; i++) {
tabs[i].addEventListener('click', () => tabClick(i));
}
for (let i = 0; i < tabs.length; i++) {
window.addEventListener('scroll', () => tabScroll(i)); //Already remove the multiple scroll listeners in a loop. But, idk whether it's right or not
}
function tabClick(currentTab) {
//Remove Active Class
let prevt = document.querySelectorAll('.tab-active')[0];
let prevc = document.querySelectorAll('.content-active')[0];
prevc.classList.remove('content-active');
prevc.classList.add('content-show');
prevc.querySelector('iframe').removeAttribute('src');
setTimeout(function() {
prevc.classList.remove('content-show');
},1500);
prevt.classList.remove('tab-active');
//Add Active Class
const iframe = content[currentTab].querySelector('iframe');
tabs[currentTab].classList.add('tab-active');
content[currentTab].classList.add('content-active');
iframe.setAttribute('src', iframe.getAttribute('data-src'));
}
function tabScroll(currentTab) {
if(document.documentElement.scrollTop > 0) {
let prevt = document.querySelectorAll('.tab-active')[0];
let prevc = document.querySelectorAll('.content-active')[0];
prevc.classList.remove('content-active');
prevc.classList.add('content-show');
prevc.querySelector('iframe').removeAttribute('src');
setTimeout(function() {
prevc.classList.remove('content-show');
},1500);
prevt.classList.remove('tab-active');
//Add Active Class
const iframe = content[currentTab].querySelector('iframe');
tabs[currentTab].classList.add('tab-active');
content[currentTab].classList.add('content-active');
iframe.setAttribute('src', iframe.getAttribute('data-src'));
}
}
})
.container {
width: 100vw;
height: 400px;
}
.tabs {
display: flex;
height: 65px;
overflow: hidden;
align-items: center;
justify-content: center;
width: 100%;
}
.tab {
font-size: 16px;
padding: 5px 10px;
cursor: pointer;
}
.tab-active {
background-color: rgb(250, 97, 9);
}
.content {
width: 100%;
margin-top: 5px;
height: calc(100% - 65px);
}
.content-item {
width: 100%;
height: 100%;
display: none;
padding: 0px;
border: none;
position: absolute;
}
.content-wrapper1 {
width: 100%;
height: 100%;
}
.content-wrapper2 {
width: 100%;
height: 100%;
}
.content-wrapper3 {
width: 100%;
height: 100%;
}
.content-iframe {
height: 100%;
width: 100%;
}
.content-show {
display: flex;
animation-name: fade-out;
animation-duration: 2.5s;
}
#keyframes fade-out {
0% {
opacity: 1;
display: flex;
}
99% {
opacity: 0;
display: flex;
}
100% {
opacity: 0;
display: none;
}
}
.content-active {
display: flex;
border: none;
justify-content: center;
height: 100%;
animation-name: fade-in;
animation-duration: 2.5s;
}
#keyframes fade-in {
0% {
display: none;
opacity: 0;
}
1% {
display: block;
opacity: 0.01;
}
100%{
display: block;
opacity: 1;
}
}
.content-iframe {
border: none;
padding: 0px;
margin: 0px;
width: 100vw;
height: 50vh;
}
<div class="container">
<div class="tabs">
<div class="tab">Tokyo</div>
<div class="tab">Paris</div>
<div class="tab">Washington</div>
<div class="tab">Jakarta</div>
<div class="tab">London</div>
</div>
<div class="content">
<div class="content-item">
<div class="content-wrapper1">
<div class="content-wrapper2">
<div class="content-wrapper3">
<iframe class= "content-iframe" data-src="https://en.wikipedia.org/wiki/Tokyo" src="https://en.wikipedia.org/wiki/Tokyo" loading="lazy"></iframe>
</div>
</div>
</div>
</div>
<div class="content-item">
<div class="content-wrapper1">
<div class="content-wrapper2">
<div class="content-wrapper3">
<iframe class= "content-iframe" data-src="https://en.wikipedia.org/wiki/Paris" loading="lazy"></iframe>
</div>
</div>
</div>
</div>
<div class="content-item">
<div class="content-wrapper1">
<div class="content-wrapper2">
<div class="content-wrapper3">
<iframe class= "content-iframe" data-src="https://en.wikipedia.org/wiki/Washington" loading="lazy"></iframe>
</div>
</div>
</div>
</div>
<div class="content-item">
<div class="content-wrapper1">
<div class="content-wrapper2">
<div class="content-wrapper3">
<iframe class= "content-iframe" data-src="https://en.wikipedia.org/wiki/Jakarta" loading="lazy"></iframe>
</div>
</div>
</div>
</div>
<div class="content-item">
<div class="content-wrapper1">
<div class="content-wrapper2">
<div class="content-wrapper3">
<iframe class= "content-iframe" data-src="https://en.wikipedia.org/wiki/London" loading="lazy"></iframe>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
Please help me to solve this guys. Thank you so much..
I am currently creating a horizontal image slider which will be used more than once with different amount of images.
At the moment, the parent div needs to be bigger than 100% to fit all images in, so I calculate the width by adding all widths of the child divs (which include the images) manually in a calculator and then add it to the css, but I want to be able to calculate it automatically with the help of either CSS or JS/jQuery.
window.onload = function(){
let images = [...document.querySelectorAll('.bild')];
let slider = document.querySelector('.slider');
let sliderWidth;
let imageWidth;
let current = 0;
let target = 0;
let ease = .05;
window.addEventListener('resize', init);
function lerp(start, end, t){
return start * (1-t) + end * t;
}
function setTransform (el, transform){
el.style.transform = transform;
}
function init(){
sliderWidth = slider.getBoundingClientRect().width;
imageWidth = sliderWidth / images.length;
document.body.style.height = `${sliderWidth - (window.innerWidth - window.innerHeight)}px`
}
function animate(){
current = parseFloat(lerp(current, target, ease)).toFixed(2);
target = window.scrollY;
setTransform(slider, `translateX(-${current}px)`);
requestAnimationFrame(animate);
}
init();
animate();
console.log(sliderWidth)
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
}
.slider {
position: absolute;
top: 0;
left: 0;
width: 3900px; /* this should be calculated automatically by the amount of divs with the class "item" multiplied by the item width */
height: 100%;
}
.slider-inner {
position: absolute;
top: 5%;
height: 90%;
display: flex;
justify-content: space-around;
}
.item {
position: relative;
width: 455px;
height: 100%;
overflow: hidden;
z-index: 1;
background: #13271b;
}
.image {
position: absolute;
width: 435px;
height: 100%;
background-size: cover;
background-position: top center;
border: none;
}
/* example "images" */
#one, #four {
background-color: #aaaaaa;
}
#two, #five {
background-color: #222222;
}
#three, #six {
background-color: #777777;;
}
#zero {
background-color: #ee2277;;
}
<div class="container">
<div class="slider">
<div class="slider-inner">
<div class="item">
<div class="image" id="zero">
</div>
</div>
<div class="item">
<div class="image" id="one">
</div>
</div>
<div class="item" >
<div class="image" id="two">
</div>
</div>
<div class="item">
<div class="image" id="three">
</div>
</div>
<div class="item">
<div class="image" id="four">
</div>
</div>
<div class="item">
<div class="image" id="five">
</div>
</div>
<div class="item">
<div class="image" id="six">
</div>
</div>
</div>
</div>
</div>
Try something like this:
/** #param {HTMLElement} sliderEl */
function scaleSlider(sliderEl) {
let totalWidth = 0;
sliderEl.querySelectorAll(".item").forEach(item => totalWidth += item.getBoundingClientRect().width);
sliderEl.style.width = `${totalWidth}px`;
}
Here I have six different div on hover blue color div should appear and by default hidden. I have written code for this but it works only for the first div I merge all div's in a single variable. Can anyone suggest to me what I'm missing here
var tcpTooltip = $('.tp-cont-tech, tp-cont-b, tp-cont-m, tp-cont-t, tp-cont-i, tp-cont-e');
var tcpTooltipDiv = $('.tpc-tooltip-tech, tpc-tooltip-b, tpc-tooltip-m, tpc-tooltip-t, tpc-tooltip-i, tpc-tooltip-e');
tcpTooltipDiv.hide();
$(tcpTooltip).each(function() {
$(tcpTooltip).hover(function() {
$(tcpTooltipDiv).show();
}, function() {
$(tcpTooltipDiv).hide();
});
});
/* Tooltip */
.tp-cont-tech,
.tp-cont-e,
.tp-cont-t,
.tp-cont-m,
.tp-cont-i,
.tp-cont-b {
position: relative;
width: 200px;
height: 200px;
background-color: red;
margin-bottom: 20px;
}
.tpc-tooltip-tech,
.tpc-tooltip-e,
.tpc-tooltip-t,
.tpc-tooltip-m,
.tpc-tooltip-i,
.tpc-tooltip-b {
position: absolute;
top: 2%;
left: 5%;
z-index: 10;
width: 100px;
height: 100px;
background-color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div class="tpc-info">
<div class="tp-cont-tech">
<div class="tpc-tooltip-tech"></div>
</div>
<div class="tp-cont-b">
<div class="tpc-tooltip-b"></div>
</div>
<div class="tp-cont-m">
<div class="tpc-tooltip-m"></div>
</div>
<div class="tp-cont-t">
<div class="tpc-tooltip-t"></div>
</div>
<div class="tp-cont-e">
<div class="tpc-tooltip-e"></div>
</div>
</div>
As suggested already, I'd go by using pure CSS and the :hover pseudo.
If you really want jQuery for some reason this would be a remake of your code.
Basically (beside adding common classes to your elements [see code below]) you need the $(this) reference of the currently hovered element:
var $tpCont = $('.tp-cont');
var $tcpTooltip = $('.tcp-tooltip');
$tcpTooltip.hide();
$tpCont.hover(function() {
$(this).find($tcpTooltip).toggle();
});
.tp-cont {
position: relative;
width: 200px;
height: 200px;
background-color: red;
margin-bottom: 20px;
}
.tcp-tooltip {
position: absolute;
top: 2%;
left: 5%;
z-index: 10;
width: 100px;
height: 100px;
background-color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div class="tpc-info">
<div class="tp-cont tp-cont-tech">
<div class="tcp-tooltip tpc-tooltip-tech"></div>
</div>
<div class="tp-cont tp-cont-b">
<div class="tcp-tooltip tpc-tooltip-b"></div>
</div>
<div class="tp-cont tp-cont-m">
<div class="tcp-tooltip tpc-tooltip-m"></div>
</div>
<div class="tp-cont tp-cont-t">
<div class="tcp-tooltip tpc-tooltip-t"></div>
</div>
<div class="tp-cont tp-cont-e">
<div class="tcp-tooltip tpc-tooltip-e"></div>
</div>
</div>
You can achieve this far more effectively with CSS. If you add some common classes to the tp-cont-X and tpc-tooltip-X elements, then you can use the :hover pseudo-selector, like this:
.tp-cont {
position: relative;
width: 200px;
height: 200px;
background-color: red;
margin-bottom: 20px;
}
.tpc-tooltip {
position: absolute;
top: 2%;
left: 5%;
z-index: 10;
width: 100px;
height: 100px;
background-color: blue;
display: none;
}
.tp-cont:hover .tpc-tooltip {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div class="tpc-info">
<div class="tp-cont tp-cont-tech">
<div class="tpc-tooltip tpc-tooltip-tech"></div>
</div>
<div class="tp-cont tp-cont-b">
<div class="tpc-tooltip tpc-tooltip-b"></div>
</div>
<div class="tp-cont tp-cont-m">
<div class="tpc-tooltip tpc-tooltip-m"></div>
</div>
<div class="tp-cont tp-cont-t">
<div class="tpc-tooltip tpc-tooltip-t"></div>
</div>
<div class="tp-cont tp-cont-e">
<div class="tpc-tooltip tpc-tooltip-e"></div>
</div>
</div>
Try using index inside hover.
var tcpTooltip = $('.tp-cont-tech, .tp-cont-b, .tp-cont-m, .tp-cont-t, .tp-cont-i, .tp-cont-e');
var tcpTooltipDiv = $('.tpc-tooltip-tech, .tpc-tooltip-b, .tpc-tooltip-m, .tpc-tooltip-t, .tpc-tooltip-i, .tpc-tooltip-e');
tcpTooltipDiv.hide();
$(tcpTooltip).each(function() {
$(tcpTooltip).hover(function(index, item) {
$(tcpTooltipDiv).eq($(this).index()).show();
}, function() {
$(tcpTooltipDiv).hide();
});
});
/* Tooltip */
.tp-cont-tech,
.tp-cont-e,
.tp-cont-t,
.tp-cont-m,
.tp-cont-i,
.tp-cont-b {
position: relative;
width: 200px;
height: 200px;
background-color: red;
margin-bottom: 20px;
}
.tpc-tooltip-tech,
.tpc-tooltip-e,
.tpc-tooltip-t,
.tpc-tooltip-m,
.tpc-tooltip-i,
.tpc-tooltip-b {
position: absolute;
top: 2%;
left: 5%;
z-index: 10;
width: 100px;
height: 100px;
background-color: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<div class="tpc-info">
<div class="tp-cont-tech">
<div class="tpc-tooltip-tech"></div>
</div>
<div class="tp-cont-b">
<div class="tpc-tooltip-b"></div>
</div>
<div class="tp-cont-m">
<div class="tpc-tooltip-m"></div>
</div>
<div class="tp-cont-t">
<div class="tpc-tooltip-t"></div>
</div>
<div class="tp-cont-e">
<div class="tpc-tooltip-e"></div>
</div>
</div>
Im trying to achieve this example for my layout.
https://youtu.be/itV7jvKpWXc
when i scroll content horizontally, my sidebar should change in width for the same amount of horizontal scroll till i reach min-width of sidebar ?
Any easy way to approach it ?
Add to your main-content onscroll
<div class="main-content" onscroll="resizeSidebar()"></div>
In your javascript add the function:
function resizeSidebar(){
document.getElementById("sidebar").style.width = "50px";
}
you can add to the sidebar css:
.sidebar {
transition: 0.5s;
}
It makes the animation for open with slide
this is plus minus what i was trying to achieve, tho it have smull ugly bug when i use horizontal scroll when sidebar reduces in size it makes scrollbar jump also :D
$('.content').scroll(function() {
var scrolling = $(".content").scrollLeft();
console.log(scrolling);
if (scrolling >= 50) {
if(!$(".sidebar").hasClass('SmallSidebar')){
$(".sidebar").addClass("smallSidebar");
}
}
else{
$(".sidebar").removeClass("smallSidebar");
}
if (scrolling >= 50) {
if(!$(".content").hasClass('smallContent')){
$(".content").addClass("smallContent");
}
}
else{
$(".content").removeClass("smallContent");
}
});
$(function(){
var curDown = false,
curYPos = 0,
curXPos = 0;
$('.content').mousemove(function(m){
if(curDown === true){
$('.content').scrollTop($('.content').scrollTop() + (curYPos - m.pageY));
$('.content').scrollLeft($('.content').scrollLeft() + (curXPos - m.pageX));
}
});
$('.content').mousedown(function(m){
curDown = true;
curYPos = m.pageY;
curXPos = m.pageX;
});
$('.content').mouseup(function(){
curDown = false;
});
})
var width = 0;
$('.inner-content').each(function() {
width += $(this).outerWidth( true );
});
$('.block').css('width', width);
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
}
div {
box-sizing: border-box;
}
.wrapper {
width: 100%;
height: 100vh;
}
.sidebar {
width: 33.33333%;
float: left;
background: blue;
height: 100vh;
transition: width 0.2s;
}
.sidebar.smallSidebar {
width: 80px;
}
.content {
width: 66.66666%;
float: left;
background: #171717;
height:100%;
overflow-y:hidden;
height: 100vh;
transition: width 0.2s;
position: relative;
}
.content.smallContent {
width: calc(100% - 80px);
}
.inner-content {
height: 100%;
padding: 50px 0px;
box-sizing: border-box;
display: flex;
align-items: center;
transition: width 0.2s;
position: absolute;
}
.block {
background: yellow;
max-width: 320px;
height: 400px;
float: left;
width: 100%;
margin: 0 20px;
box-sizing: border-box;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="sidebar"></div>
<div class="content">
<div class="inner-content">
<div style="background: #c39eb2;" class="block"></div>
<div style="background: #a4af93" class="block"></div>
<div style="background: #0fe7ad;" class="block"></div>
<div style="background: #f75f31;" class="block"></div>
<div style="background: #9473c0;" class="block"></div>
<div style="background: #46087f;" class="block"></div>
<div style="background: #f59000;" class="block"></div>
<div style="background: #22e318;" class="block"></div>
<div style="background: #71454e;" class="block"></div>
<div style="background: #7eb544;" class="block"></div>
<div style="background: #2fe218;" class="block"></div>
<div style="clear: both;"></div>
</div>
</div>
<div style="clear: both;"></div>
</div>
I want the overlay div to take full container width (col-md-12). Now of course, it's only taking up col-md-4 width which is it's parent.
$(document).ready(function() {
$('button').click(function() {
$('#overlay').toggleClass('active');
// calcs bottom of button
var bottom = $(this).position().top + $(this).outerHeight(true);
$('#overlay').css({
'top': bottom + 'px',
});
});
$('#close').click(function() {
$('#overlay').removeClass('active');
});
});
#overlay {
z-index: 10;
margin-left: 15px;
position: absolute;
width: 100%;
background: #E5E5E5;
text-align: center;
min-height: 500px;
display: none;
left: 0;
}
#overlay.active {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<div class="row">
<div class="col-md-4">
<button type="button" class="btn btn-link">ADD GAME</button>
<div id="overlay">
X
<h2>This is an overlay</h2>
</div>
</div>
<div class="col-md-4"></div>
<div class="col-md-4"></div>
</div>
Set position: static; to .col-md-4 and position: relative; to .container
$(document).ready(function() {
$('button').click(function() {
$('#overlay').toggleClass('active');
// calcs bottom of button
var bottom = $(this).position().top + $(this).outerHeight(true);
$('#overlay').css({
'top': bottom + 'px',
});
});
$('#close').click(function() {
$('#overlay').removeClass('active');
});
});
#overlay {
z-index: 10;
margin-left: 15px;
position: absolute;
width: 100%;
background: #E5E5E5;
text-align: center;
min-height: 500px;
display: none;
left: 0;
}
#overlay.active {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<style>
.container {
position: relative;
}
.col-md-4 {
position: static;
}
</style>
<div class=container>
<div class="row">
<div class="col-md-4">
<button type="button" class="btn btn-link">ADD GAME</button>
<div id="overlay">
X
<h2>This is an overlay</h2>
</div>
</div>
<div class="col-md-4"></div>
<div class="col-md-4"></div>
</div>
</div>
Try this I think this may work for you. Am not sure because your Q is not that much clear.I have removed margin-left: 15px as you have put left:0; at the bottom.
#overlay {
z-index: 10;
position: absolute;
background: #E5E5E5;
text-align: center;
min-height: 500px;
display: none;
left: 0;
right:0;/*Added right attribut to make width 100%*/
top: 0;/*Added top attribut to make your div attach to the top of the parent div*/
}
#overlay.active {
display: inline-block;
}
This will only work if the parent of the #overlay is positioned as relative(position: relative;) because the absolute position div always depend on its relative parent if there is none then it will align according to the HTML Page.
How about adding overlay as sibling to row
<div class="row">
<div class="col-md-4">
<button type="button" class="btn btn-link">ADD GAME</button>
</div>
<div class="col-md-4"></div>
<div class="col-md-4"></div>
</div>
<div id="overlay">
X
<h2>This is an overlay</h2>
</div>