Gap appearing down the middle - javascript

To Reproduce, To be able to see the gap, the code has to be viewed in these viewports in Chromium based browsers. The gap does not appear in Firefox.
You can set it to different viewports inside jsitor.
Also, By increasing and decreasing the browser you're able to see the Gap in the snippet provided. I just checked.
Click Run, not update to test code:
Further investigating finds:
Gap Visible
https://jsitor.com/ublt2Y43V8
With YouTube Code Removed, No Gap Visible.
https://jsitor.com/XT3U947ICr
Is there a solution to fix this gap issue?
Gap appearing down the middle
From The Snippet:
const cover = document.querySelector(".jacket");
(function manageCurtain() {
"use strict";
function hide(el) {
el.classList.add("hide");
}
function coverClickHandler(evt) {
const cover = evt.currentTarget;
hide(cover);
const curtain = document.querySelector(".curtain-ratio-keeper");
curtain.classList.add("slide");
}
const cover = document.querySelector(".jacket");
cover.addEventListener("click", coverClickHandler);
})();
const videoPlayer = (function makeVideoPlayer() {
"use strict";
let player = null;
const tag = document.createElement("script");
tag.src = "https://www.youtube.com/iframe_api";
const firstScriptTag = document.getElementsByTagName("script")[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
function onPlayerReady(event) {
player = event.target;
player.setVolume(100); // percent
}
let hasShuffled = false;
function onPlayerStateChange(event) {
const player = event.target;
const shufflePlaylist = true;
if (!hasShuffled) {
player.setShuffle(shufflePlaylist);
player.playVideoAt(0);
hasShuffled = true;
}
}
function addPlayer(video) {
const playlist = "M7lc1UVf-VE";
new YT.Player(video, {
width: 640,
height: 360,
host: "https://www.youtube-nocookie.com",
playerVars: {
autoplay: 0,
controls: 1,
loop: 1,
rel: 0,
iv_load_policy: 3,
cc_load_policy: 0,
fs: 0,
disablekb: 1,
playlist
},
events: {
onReady: onPlayerReady,
onStateChange: onPlayerStateChange
}
});
}
return {
addPlayer
};
})();
function onYouTubeIframeAPIReady() {
const wrapper = cover.parentElement;
const frameContainer = wrapper.querySelector(".video");
videoPlayer.addPlayer(frameContainer);
}
(function iife() {
"use strict";
function show(el) {
el.classList.remove("hide");
}
function coverClickHandler(evt) {
const wrapper = evt.currentTarget.parentElement;
show(wrapper);
}
cover.addEventListener("click", coverClickHandler);
})();
html,
body {
padding: 0;
margin: 0;
}
body {
height: 100vh;
background: url(https://picsum.photos/id/1015/1500/1500) no-repeat;
background-attachment: fixed;
background-size: cover;
}
.outer {
display: flex;
min-height: 100vh;
padding:8px 6px;
box-sizing:border-box;
}
.inner{
min-width: 40%;
max-width: 640px;
margin: auto;
}
.curtain-ratio-keeper {
position: relative;
padding-top: 56.25%;
border-radius: 25px;
height:0;
overflow: hidden;
border: 3px solid red;
}
.video-frame {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.jacket {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: auto;
cursor: pointer;
z-index: 3;
}
.play {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
margin: auto;
min-width: 70px;
min-height: 70px;
max-width: 30%;
max-height: 30%;
fill: red;
filter: drop-shadow(3px 3px 3px rgba(0, 0, 0, 0.7));
cursor: pointer;
}
.wrap iframe {
position: absolute;
top: -3px;
left: -3px;
width: calc(100% + 6px);
height: calc(100% + 6px);
}
.wrap,
.jacket {
position: absolute;
top: -3px;
left: -3px;
width: calc(100% + 6px);
height: calc(100% + 6px);
}
.hide {
display: none;
}
.slide-wrap:before,
.slide-wrap:after {
content: "";
position: absolute;
top: 0;
width: 50%;
height: 100%;
transition: transform 5s linear;
display: flex;
align-items: center;
background: url(https://picsum.photos/id/1015/1500/1500) no-repeat;
background-attachment: fixed;
background-size: cover;
z-index: 2;
}
.slide-wrap:before {
left: 0;
justify-content: flex-end;
}
.slide-wrap:after {
right: 0;
justify-content: flex-start;
}
.slide .slide-wrap::before {
transform: translateX(-100%);
}
.slide .slide-wrap::after {
transform: translateX(100%);
}
<div class="outer">
<div class="inner">
<div class="curtain-ratio-keeper">
<div class="video-wrapper">
<div class="video-ratio-keeper slide-wrap">
<div class="wrap">
<div class="video video-frame"></div>
</div>
</div>
</div>
<div class="jacket" title="Play">
<svg class="play" width="100%" height="100%" viewBox="0 0 64 64">
<path d="M25.6,46.4L44.8,32L25.6,17.6V46.4z M32,0C14.3,0,0,14.3,0,32s14.3,32,32,32s32-14.3,32-32S49.7,0,32,0z
M32,57.6C17.9,57.6,6.4,46.1,6.4,32S17.9,6.4,32,6.4S57.6,17.9,57.6,32S46.1,57.6,32,57.6z" />
</svg>
</div>
</div>
</div>
</div>

This is a rounding error with floating points when the width of your container is a non-integer (for example, 241.118px). The :before and :after elements will fill 50% of the container, but floating point math is imperfect and may round the result incorrectly, so rather than being 120.559px, it may be something like 120.554px. This causes the widths of the two pseudo-elements to not quite fill the container all the way, resulting in the gap you're seeing.
A simple, albeit "band-aid-ish" fix is to just increase the width of the two pseudo-elements to something greater than 50% so even if there is a rounding error, the whole container will be covered. I originally suggested 51%, but since the gap will always be less than 1px, you are correct in using calc(50% + 1px) as well.
.slide-wrap:before,
.slide-wrap:after {
width: calc(50% + 1px);
}

Related

Can I use requestAnimationFrame to smooth out scroll behaviour?

I have a small scroll effect which simulate that a logo will disappear if a lower div will scroll over it.
Currently I'm checking if two divs are intersecting. If this is true, then the height of the div of the logo will decrease with the scroll position of the div beneath.
Unfortunately, my demo is not foolproof and some fragments of the logo are still visible.
Is there a way to do this jank-free? Maybe with requestAnimationFrame?
function elementsOverlap(el1, el2) {
const domRect1 = el1.getBoundingClientRect();
const domRect2 = el2.getBoundingClientRect();
return !(
domRect1.top > domRect2.bottom ||
domRect1.right < domRect2.left ||
domRect1.bottom < domRect2.top ||
domRect1.left > domRect2.right
);
}
const el1 = document.querySelector(".logo");
const el2 = document.querySelector(".clickblocks");
let scrollPositionEl2;
let heightDifference;
const logoHeight = el1.offsetHeight;
document.addEventListener("DOMContentLoaded", () => {
var scrollDirectionDown;
scrollDirectionDown = true;
window.addEventListener("scroll", () => {
if (this.oldScroll > this.scrollY) {
scrollDirectionDown = false;
} else {
scrollDirectionDown = true;
}
this.oldScroll = this.scrollY;
// test
if (scrollDirectionDown) {
if (elementsOverlap(el1, el2) === true) {
scrollPositionEl2 = el2.getBoundingClientRect().top;
heightDifference = logoHeight - scrollPositionEl2 + 100;
//console.log(logoHeight - heightDifference);
el1.style.height = `${logoHeight - heightDifference}px`;
}
} else {
//scrolling up
scrollPositionEl2 = el2.getBoundingClientRect().top - 100;
el1.style.height = `${scrollPositionEl2}px`;
//console.log(logoHeight);
}
});
});
#import url("https://fonts.googleapis.com/css2?family=Inter:wght#900&display=swap");
.wrapper {
max-width: 100vw;
margin: 0 auto;
background-image: url("https://picsum.photos/1920/1080");
background-size: cover;
background-attachment: fixed;
height: 1200px;
position: relative;
&::after {
content: "";
position: absolute;
background: rgba(0, 0, 0, 0.3);
width: 100%;
height: 100%;
inset: 0;
}
}
body {
margin: 0;
}
main {
width: 100%;
height: 100vh;
position: relative;
z-index: 1;
}
.clickblocks {
width: 100%;
height: 200px;
display: grid;
grid-template-columns: repeat(12, (minmax(0, 1fr)));
}
.clickblock {
transition: all ease-in-out 0.2s;
backdrop-filter: blur(0px);
border: 1px solid #fff;
height: 100%;
grid-column: span 6 / span 6;
font-size: 54px;
font-weight: 700;
padding: 24px;
font-family: "Inter", sans-serif;
color: white;
text-transform: uppercase;
&:hover {
backdrop-filter: blur(10px);
}
}
.logo {
background: url("https://svgshare.com/i/ivR.svg");
width: 100%;
background-repeat: no-repeat;
background-position: top;
position: fixed;
top: 100px;
}
.logo-wrapper {
position: relative;
}
<div class="wrapper">
<main>
<div class="logo-wrapper" style="height: 390px">
<div class="logo" style="height: 300px">
</div>
</div>
<div class="clickblocks">
<div class="clickblock">
Some Content
</div>
</div>
</main>
</div>
Few things here to optimize your performance.
getBoundingClientRect() is a rather expensive calculation. If there are NO other options it's fine.
The Intersection Observer API is a lot more performant, and you can set the root element on the API. Then observe the element that is moving. This should be able to telly you if their are colliding.
Whenever you do scroll based logic, you should really try and throttle the logic so that the scroll any fires ever 16.6ms. That will reduce the number of times the calculations are made, and speed things up on the FE.
Learn how to use Google Chrome's performance tab. It can be overwhelming at first, but it gives you the ability to drill into the exact piece of code that's slowing your site down.
Learn about JS's event loop, and what's really going on under the hood. This video by Jake Archibald really help me understand it.
Hope this helped, sorry that I didn't give you an actual solution.

Translation animation when moving child from one parent to another parent

I am trying to make connect4 HTML game and I know I will be better off using canvas elements instead of a grids of divs but is it possible to make transition translate type of css animation when moving HTML elements around like this (using appendChild)
const row1 = document.getElementById("row1")
const row2 = document.getElementById("row2")
const ball = document.getElementById("TheBall")
ball.addEventListener("click", (event, element) => {
let rowNum = parseInt(ball.dataset.row)
if(rowNum==1) {
row2.appendChild(ball)
ball.dataset.row = 2
} else {
row1.appendChild(ball)
ball.dataset.row = 1
}
})
#main {
left:100px;
width: 100px;
height: 100px;
display: flex;
flex-direction: column;
}
#main div {
margin: 50px 0;
width: 50px;
height: 50px;
}
#TheBall {
width: auto;
height: auto;
background-color: red;
border-radius: 100%;
}
<div id="main">
<div id="row1"> </div>
<div id="row2">
<div id="TheBall" data-row=2></div>
</div>
</div>
Click on the red dot to toggle position of ball
You can use animationend to check when the animation end and move the ball element between the divs
const row1 = document.getElementById("row1")
const row2 = document.getElementById("row2")
const ball = document.getElementById("TheBall")
ball.addEventListener('animationend', () => {
ball.classList.remove("animate-ball");
ball.style.animation = "";
let rowNum = parseInt(ball.dataset.row)
if (rowNum == 1) {
row2.appendChild(ball)
ball.dataset.row = 2
} else {
row1.appendChild(ball)
ball.dataset.row = 1
}
});
ball.addEventListener("click", (event, element) => {
let rowNum = parseInt(ball.dataset.row)
if (rowNum == 1) {
ball.style.animation = "MoveDown 1s linear";
} else {
ball.style.animation = "MoveUp 1s linear";
}
ball.classList.add("animate-ball");
})
#main {
left: 100px;
width: 100px;
height: 100px;
display: flex;
flex-direction: column;
}
#main div {
margin: 50px 0;
width: 50px;
height: 50px;
}
#TheBall {
position: relative;
width: auto;
height: auto;
background-color: red;
border-radius: 100%;
}
.animate-ball {
animation-iteration-count: 1;
position: absolute;
bottom: 0;
}
#keyframes MoveUp {
0% {
top: -50px;
}
100% {
top: -100px;
}
}
#keyframes MoveDown {
0% {
top: 0;
}
100% {
top: 50px;
}
}
<div id="main">
<div id="row1"> </div>
<div id="row2">
<div id="TheBall" data-row=2></div>
</div>
</div>

disable scrolling untill animation is done

I have a simple animation and I want to disable scrolling on the website
until this animation is done, it should be like a loader basically
UPDATE
thank you so much, but I have an issue with that sorry for not mention because I'm using a fixed position on a container to be fixed to do smooth scrolling, so when I use 'fixed' position for any element it doesn't seem to stick in the same place here is the full code
html
<main id="app">
<div id="scroll-container" class="scroll-container">
<div class="loader">
<div class="loader__block"></div>
</div>
</div>
</main>
CSS
body {
overflow-x: hidden;
overflow-y: scroll;
background: $bg-color;
user-select: none;
font-family: 'Platform Regular';
}
#app {
overflow: hidden;
position: fixed;
height: 100vh;
width: 100vw;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.scroll-container {
position: absolute;
overflow: hidden;
z-index: 10;
display: flex;
justify-content: center;
backface-visibility: hidden;
}
.loader {
width: 100vw;
height: 100vh;
position: absolute;
z-index: 999999;
overflow: hidden;
}
.loader__block {
position: absolute;
width: 0%;
height: 100vh;
background: #111111;
animation: go-left 4s cubic-bezier(.74, .06, .4, .92) forwards;
}
#keyframes go-left {
0% {
left: 0;
width: 0%;
}
50% {
left: 0;
width: 100%;
}
100% {
left: 100%;
width: 0;
}
these containers have a fixed position and overflow hidden because I'm making smooth page transition while scrolling and moving the 'y' position
here is also the js if it's going to help
function smoothScrolling() {
const html = document.documentElement;
const { body } = document;
const scroller = {
target: document.querySelector('#scroll-container'),
ease: 0.06, // <= scroll speed
endY: 0,
y: 0,
resizeRequest: 1,
scrollRequest: 0,
};
let requestId = null;
TweenLite.set(scroller.target, {
rotation: 0.01,
force3D: true,
});
function updateScroller() {
const resized = scroller.resizeRequest > 0;
if (resized) {
const height = scroller.target.clientHeight;
body.style.height = `${height}px`;
scroller.resizeRequest = 0;
}
const scrollY = window.pageYOffset || html.scrollTop || body.scrollTop || 0;
scroller.endY = scrollY;
scroller.y += (scrollY - scroller.y) * scroller.ease;
if (Math.abs(scrollY - scroller.y) < 0.05 || resized) {
scroller.y = scrollY;
scroller.scrollRequest = 0;
}
TweenLite.set(scroller.target, {
y: -scroller.y,
});
requestId = scroller.scrollRequest > 0 ? requestAnimationFrame(updateScroller) : null;
}
function onScroll() {
scroller.scrollRequest += 1;
if (!requestId) {
requestId = requestAnimationFrame(updateScroller);
}
}
function onResize() {
scroller.resizeRequest += 1;
if (!requestId) {
requestId = requestAnimationFrame(updateScroller);
}
}
function onLoad() {
updateScroller();
window.focus();
window.addEventListener('resize', onResize);
document.addEventListener('scroll', onScroll);
}
window.addEventListener('load', onLoad);
}
Use the CSS rule position: fixed; on your div with class loader which makes it to always stay in the same place even if the page is scrolled.
as so:
.loader {
width: 100vw;
height: 100vh;
position: absolute;
z-index: 999999;
overflow: hidden;
position: fixed;
}
.loader__block {
position: absolute;
width: 0%;
height: 100vh;
background: #111111;
animation: go-left 4s cubic-bezier(.74, .06, .4, .92) forwards;
}
#keyframes go-left {
0% {
left: 0;
width: 0%;
}
50% {
left: 0;
width: 100%;
}
100% {
left: 100%;
width: 0;
}
}
<main id="app">
<div id="scroll-container" class="scroll-container">
<div class="loader">
<div class="loader__block"></div>
</div>
</div>

Delay random position jQuery

I have some code that displays 4 divs at a random hight at specified distances from the viewport sides, each div appears with a different delay speed and then moves around the page at random.
I want to add a delay to the movement of each div so they don't all start and stop moving at the same time but every time I add ad .delay() it breaks. Any help?
Thanks
HTML
<div class="content">
<div class="loopbox">
<div id="rand_pos" class="loop mobile box1">L</div>
<div id="rand_pos" class="loop mobile box2">O</div>
<div id="rand_pos" class="loop mobile box3">O</div>
<div id="rand_pos" class="loop mobile box4">P</div>
</div>
<div class="info">
<h1>COMING SOON</h1>
<p>info#loopstudio.uk</p>
</div>
</div>
*CSS
#import url('https://fonts.googleapis.com/css?family=Marcellus&display=swap');
*:focus {
outline: none;
}
html { overflow: hidden; }
body {
margin: 0;
background-color:#FFF9F3;
}
p,h1 {
font-family:sans-serif;
}
h1{
font-weight:100;
}
.loop {
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
font-size:22vw;
font-family:'Marcellus', serif;
font-weight:100;
color: black;
position: absolute;
}
.loop:hover {
animation: shake 0.82s cubic-bezier(.5,.01,.01,.05) 1;
transform: translate3d(0, 0, 0);
backface-visibility: hidden;
perspective: 1000px;
-webkit-animation-fill-mode:forwards;
-moz-animation-fill-mode:forwards;
animation-fill-mode:forwards;
}
.box1{
top:10vh;
left:8vw;
display:none;
}
.box2{
top:20vh;
left:30vw;
display:none;
}
.box3{
top:30vh;
right:35vw;
display:none;
}
.box4{
top:40vh;
right:10vw;
display:none;
}
.content {
position: relative;
height: 100vh;
width: 100vw;
margin: 0 auto;
resize: both;
}
.info {
width: 100%;
height:auto;
transform: translate(-50%, -50%);
position: fixed;
top: 50%;
left: 50%;
resize: both;
text-align:center;
z-index:-1000;
}
JS
$('document').ready(function(){
$('.box1').delay(500).fadeIn(850);
$('.box2').delay(1000).fadeIn(850);
$('.box3').delay(750).fadeIn(850);
$('.box4').delay(1250).fadeIn(850);
});
$('document').ready(function() {
var bodyHeight = document.body.clientHeight;
var randPosY = Math.floor((Math.random()*bodyHeight));
$('#rand_pos').css('top', randPosY);
});
$(document).ready(function(){
animateDiv('.box1');
animateDiv('.box2');
animateDiv('.box3');
animateDiv('.box4');
});
function makeNewPosition(){
var h = $(window).height() - 50;
var w = $(window).width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh,nw];
}
function animateDiv(myclass){
var newq = makeNewPosition();
$(myclass).animate({ top: newq[0], left: newq[1] }, 8000, function(){
animateDiv(myclass);
});
};

Skrollr image flickers and some images doesnt load in chrome

I am using Skrollr librabry. In the start it works fine,but as I'm scrolling down,I am experiencing flickering and images do not load. The content of my website are just images. Works fine on firefox, but not on Chrome. Could you please help me. I am using approximately 190 images. Is that an issue?
I am using async calls to fetch the data,and every image is being loaded before the skrollr is rendered.
Here's my working example : https://jsfiddle.net/if_true/v1mLhutc/7/
html
<body>
<div id="fakeloader"></div>
<div style="transform: translate3d(0,0,0);"></div>
<div class="DESKScreen">
<div id="info" hidden="hidden">0</div>
<section id="slide">
<div class="bcg"></div>
</section>
</div>
</body>
CSS
*,:before,:after {
-moz-box-sizing:border-box;
-webkit-box-sizing:border-box;
box-sizing:border-box;
-webkit-backface-visibility:hidden;
backface-visibility: hidden;
}
#info{
position: fixed;
top: 20px;
left: 20px;
background-color: rgba(0, 0, 0, 0.5);
color: #fff;
padding: 20px;
z-index: 9999;
}
body {
margin: 0;
width: 100%;
height: 100%;
}
html{
width: 100%;
height: 100%;
}
section {
width: 100%;
max-width: 100%;
height: 100%;
position: fixed;
left: 0;
right: 0;
margin: auto;
}
#slide .bcg {
height: 100%;
width: 100%;
background-size: 100%;
background-position: center top;
background-attachment: fixed;
position: absolute;
transform:translateZ(0)
}
.img{
background-size: cover;
background-repeat: no-repeat;
background-position: center;
display: table;
margin: auto;
max-height: 100vh !important;
height: 100% !important;
}
.item {
width: 100%;
position: absolute;
opacity: 1;
}
`Js`
$(document).ready(function() {
DivImage("sup");
var s = skrollr.init({
render: function(data) {
console.log(data.curTop);
}
});
//Check the screen size.
(function() {
if (screen.width < 768) {
$("#fullpage").fullpage({
//scrollingSpeed: 0,
});
$(".DESKScreen").css("display", "none");
} else if (screen.width > 768) {
$(".MObileScreen").css("display", "none");
}
})();
//Fakeloader for the loadtime
function loader() {
$("#fakeloader").fakeLoader({
timeToHide: 4000,
bgColor: "#e74c3c",
spinner: "spinner2"
});
}
loader();
});
function DivImage(name) {
//console.log(name);
//a counter to set for div id
let counter = 0;
//create the urls based on a nr
var Images = makeUrls();
//first create the div and pass the counter to it
CreateDiv(Images);
}
function makeUrls() {
let base = "images/";
let rest = ".jpg";
let result = [];
for (let i = 0; i < 191; i++) {
let baseNr = 1 + i;
if (baseNr === 2000) {
console.log("base");
} else {
result.push(base + baseNr + rest);
}
}
return result;
}
function CreateDiv(images) {
// debugger;
var from = 0,
to = 0;
let result = [];
for (let i of images) {
var newDiv = $('<div class="img-div"></div>');
newDiv.css({
backgroundImage: `url(${i})`
});
newDiv.attr("data--" + from + "-top", "opacity: 0;");
from += 125;
newDiv.attr("data--" + from + "-top", "opacity: 0;");
from += 125;
newDiv.attr("data--" + from + "-top", "opacity: 1;");
newDiv.attr("data-anchor-target", "#slide");
newDiv.attr("data-skrollr-decks-speed", "300");
$("#slide").append($(newDiv));
}
}

Categories

Resources