I have a simple on-hover CSS animation which makes slide transition between images.
When the user makes the hover on SECTION ONE and before the animation ends make hover on SECTION two, animation restart and make lagging move.
MY CODE:
var $circle = $('#circle');
function moveCircle(e) {
TweenLite.to($circle, 0.8, {
css: {
left: e.pageX,
top: e.pageY
}
});
}
$(window).on('mousemove', moveCircle);
#import "compass/css3";
#keyframes in {
from {
transform: translateY(-100%);
}
to {
transform: translateY(0);
}
}
#keyframes out {
from {
transform: translateY(0);
}
to {
transform: translateY(100%);
}
}
html {
background: #0E3741;
}
#circle {
position: absolute;
pointer-events : none;
width: 400px;
height: 200px;
top: 50%;
left: 50%;
margin: -50px 0 0 -50px;
}
#circle .circle-wrapper {
overflow: hidden;
width: 400px;
height: 200px;
position: relative;
}
#circle img {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 400px;
height: 200px;
object-fit: cover;
overflow: hidden;
}
#wrapper {
display: flex;
flex-direction: column;
}
.special-element {
width: 100%;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
}
#one {
background: blue;
}
#two {
background: red;
}
#one:hover ~ #circle .circle-wrapper #imgOne {
animation: in 1s ease-in-out;
z-index: 2;
}
#one:hover ~ #circle .circle-wrapper #imgTwo {
animation: out 1s ease-in-out;
}
#two:hover ~ #circle .circle-wrapper #imgTwo {
animation: in 1s ease-in-out;
z-index: 2;
}
#two:hover ~ #circle .circle-wrapper #imgOne {
animation: out 1s ease-in-out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.11.4/TweenMax.min.js"></script>
<section id="wrapper">
<section class="special-element" id="one">
section one
</section>
<section class="special-element" id="two">
section two
</section>
<div id="circle">
<div class="circle-wrapper">
<img id="imgOne" src="https://upload.wikimedia.org/wikipedia/commons/3/3b/Coca-cat.jpg">
<img id="imgTwo" src="https://staticcdn.sk/images/photoarchive/sized/700/2020/07/29/ohrozeny-vtak-krakla-belasa.jpg">
</div>
</div>
</section>
Is there any solution how I can prevent this lagging issue?
Maybe is there any solution to how I can solve it and make this animation smooth?
I'm looking for something like animation on this website.
Updated version
You can do a simplified version of it with gsap. It is probably best not to mix plain css too much with the gsap, unless you use css inside the gsap library. Because gsap will manipulate some of the props. E.g. the transformation. And it is better to use transform than just left/top because it is hardware accelerated.
I've done some improvements to the code I've posted before. It looks smoother now. In addition, I have added a little zoom and horizontal-shift effect - similar to the animation on the referenced website. Also, the animation now starts from the bottom.
The animation is really well done on the referenced page. It is done with WebGL. This is not your every-day animation and requires quite a bit of effort to make it work - at least for someone who is not a designer. It uses a 3d transformation matrix and some other effects together.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reset-css#5.0.1/reset.min.css" />
<script type="application/javascript" defer src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script>
<script type="application/javascript" defer src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/plugins/CSSPlugin.min.js"></script>
<style type="text/css">
.section {
display: block;
width: 100%;
height: 300px;
border-bottom: 1px solid red;
}
.overlay {
position: absolute;
top: 0;
left: 0;
display: none;
background: transparent;
z-index: -1;
}
.stack {
position: relative;
min-width: 300px;
min-height: 300px;
width: 480px;
height: 320px;
max-width: 480px;
max-height: 320px;
overflow: hidden;
z-index: 1;
}
.img {
position: absolute;
top: 0;
left: 0;
width: auto;
height: auto;
max-width: 100%;
object-fit: contain;
z-index: -1;
}
</style>
</head>
<body>
<main class="main">
<section class="section section-1" data-img="img-1">section 1</section>
<section class="section section-2" data-img="img-2">section 2</section>
<div class="overlay">
<div class="stack">
<img id="img-1" class="img" src="https://upload.wikimedia.org/wikipedia/commons/3/3b/Coca-cat.jpg">
<img id="img-2" class="img" src="https://staticcdn.sk/images/photoarchive/sized/700/2020/07/29/ohrozeny-vtak-krakla-belasa.jpg">
</div>
</div>
</main>
<script type="application/javascript">
window.onload = () => {
const overlay = document.querySelector(".overlay");
const stack = document.querySelector(".stack");
const s1 = document.querySelector(".section-1");
const s2 = document.querySelector(".section-2");
const main = document.querySelector(".main");
const overlaySize = {
width: 480,
height: 320
};
const easeFunc = "sine.inOut";
const easeDuration = 0.5;
let animation;
let activeSection;
let currentTarget;
function createAnimation() {
//console.log('create animation');
t1 = gsap.timeline({
paused: true
});
t1.to(currentTarget, {
zIndex: 2,
display: "block"
}, 0);
t1.fromTo(currentTarget, {
y: "100%"
}, {
y: 0,
duration: easeDuration,
ease: easeFunc
}, 0);
t1.to(currentTarget, {
scale: 1.25,
transformOrigin: "center",
duration: easeDuration,
ease: easeFunc
}, 0);
stack.querySelectorAll(".img").forEach((it) => {
if (it !== currentTarget) {
t1.to(it, {
zIndex: -1
}, 0);
t1.to(it, {
scale: 1,
transformOrigin: "center"
}, 0);
t1.to(it, {
display: "none"
}, easeDuration);
}
});
return t1;
}
function onMouseLeave(e) {
const target = e.target;
//console.log("leave", e.target);
if (target === activeSection) {
gsap.set(overlay, {
display: "none"
});
currentTarget = null;
}
}
function onMouseEnter(e) {
currentTarget = stack.querySelector(`#${e.target.dataset.img}`);
gsap.set(overlay, {
display: "block"
});
if (!animation) {
//console.log("undefined animation")
animation = createAnimation();
animation.play();
} else if (animation.isActive()) {
//console.log("still active");
animation.timeScale(10); // fast forward the rest of the animation
animation = createAnimation();
animation.timeScale(1).play();
} else {
//console.log("no longer active");
animation = createAnimation();
animation.play();
}
}
function onMouseMove(e) {
const hoveredEl = document.elementFromPoint(e.pageX, e.pageY);
if (hoveredEl.classList.contains("section")) {
if (activeSection !== hoveredEl) {
activeSection = hoveredEl;
}
} else if (hoveredEl.classList.contains("overlay") || hoveredEl.classList.contains("stack") || hoveredEl.classList.contains("pointer")) {
// do nothing
} else {
if (activeSection) {
activeSection = null;
}
}
if (currentTarget) {
// update overlay
gsap.set(overlay, {
x: e.pageX - overlaySize.width / 2,
y: e.pageY - overlaySize.height / 2
});
// add a little horizontal-shift effect
const dx = window.innerWidth / 2 - e.pageX;
const offsetX = dx / window.innerWidth / 2 * 100;
gsap.to(currentTarget, {
x: offsetX * 2,
duration: 2
}, 0);
}
}
gsap.set(overlay, {
x: 0,
y: 0
});
stack.querySelectorAll('.img').forEach((it) => gsap.set(it, {
x: 0,
y: "100%"
}));
window.addEventListener("mousemove", onMouseMove);
s1.addEventListener("mouseleave", onMouseLeave);
s2.addEventListener("mouseleave", onMouseLeave);
s1.addEventListener("mouseenter", onMouseEnter);
s2.addEventListener("mouseenter", onMouseEnter);
}
</script>
</body>
</html>
Old answer
I have been playing around a little bit with the gsap library today. I've honestly never done anything with or like it. Tried to do it with the x and y params that you may pass to gsap. It will take care of the transformations - also the TimeLine stuff
is quite handy. The result is not that great, also the animations look like it could be done better, but maybe it might still help you out. You could also improve some of the logic and animation probably. At least it runs quite stable - performance wise.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/reset-css#5.0.1/reset.min.css" />
<script type="application/javascript" defer src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script>
<script type="application/javascript" defer src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/plugins/CSSPlugin.min.js"></script>
<style type="text/css">
.section {
display: block;
width: 100%;
height: 200px;
border-bottom: 1px solid red;
}
.overlay {
position: absolute;
top: 0;
left: 0;
display: none;
border: none; // 1px dashed black;
background: transparent; // lavender;
overflow: hidden;
}
.stack {
position: relative;
left: 0;
right: 0;
top: 0;
bottom: 0;
min-width: 300px;
min-height: 300px;
width: 480px;
height: 320px;
z-index: 0;
}
.anim-img {
position: absolute;
top: 0;
left: 0;
width: auto;
height: auto;
max-width: 100%;
object-fit: contain;
z-index: 1;
}
</style>
</head>
<body>
<main class="main">
<section class="section section-1">section 1</section>
<section class="section section-2">section 2</section>
<div class="overlay">
<div class="stack">
<img id="img-1" class="anim-img" src="https://upload.wikimedia.org/wikipedia/commons/3/3b/Coca-cat.jpg">
<img id="img-2" class="anim-img" src="https://staticcdn.sk/images/photoarchive/sized/700/2020/07/29/ohrozeny-vtak-krakla-belasa.jpg">
</div>
</div>
</main>
<script type="application/javascript">
window.onload = () => {
const overlay = document.querySelector(".overlay");
const img1 = document.getElementById("img-1");
const img2 = document.getElementById("img-2");
const s1 = document.querySelector(".section-1");
const s2 = document.querySelector(".section-2");
const main = document.querySelector(".main");
let anim;
let isS1active = false;
let isS2active = false;
let showEl;
let hideEl;
let leaveTimeout;
function reverseFadeInOut(showEl, hideEl) {
console.log("create reverse timeline anim -> ", {
showEl,
hideEl
});
const tl = gsap.timeline({
paused: true
});
tl
.to(showEl, {
zIndex: 1
}, 0)
.to(hideEl, {
zIndex: 10
}, 0)
.to(hideEl, {
y: "-100%",
duration: 0.375
}, 0)
.to(hideEl, {
display: "none"
}, 0.375)
.to(hideEl, {
zIndex: 1
}, 0.375)
.to(showEl, {
display: "block",
zIndex: 10
}, 0.375)
.fromTo(showEl, {
y: "-100%"
}, {
y: 0,
duration: .375
}, 0.375)
.to(hideEl, {
display: "none"
});
return tl;
}
function fadeInOut(showEl, hideEl) {
console.log("create timeline anim -> ", {
showEl,
hideEl
});
const tl = gsap.timeline({
paused: true
});
tl
.to(hideEl, {
zIndex: 1
}, 0)
.to(showEl, {
display: "block",
zIndex: 10
}, 0)
.fromTo(showEl, {
y: "-100%"
}, {
y: 0,
duration: .75
}, 0)
.fromTo(hideEl, {
y: 0
}, {
y: "-100%",
duration: .75
}, 0)
.to(hideEl, {
display: "none"
}, 0.75);
return tl;
}
function animateImage() {
if (isS1active || isS2active) {
if (isS1active) {
showEl = img1;
hideEl = img2;
} else if (isS2active) {
showEl = img2;
hideEl = img1;
}
if (!anim) {
console.log("create new animation");
anim = fadeInOut(showEl, hideEl);
anim.play();
} else {
console.log("anim active:", anim.isActive());
if (anim.isActive()) {
console.log("reverse");
anim.kill();
anim = reverseFadeInOut(showEl, hideEl);
anim.play();
} else {
anim = fadeInOut(showEl, hideEl);
anim.play();
}
}
}
}
function moveOverlay(e) {
e.preventDefault();
e.stopPropagation();
gsap.set(overlay, {
x: e.pageX + 15,
y: e.pageY + 15,
display: isS1active || isS2active ? "block" : "none"
});
}
function mouseOver(e, el, isEntering) {
e.preventDefault();
e.stopPropagation();
el.classList.toggle("active");
isS1active = s1.classList.contains("active");
isS2active = s2.classList.contains("active");
if (isEntering) {
clearTimeout(leaveTimeout);
animateImage();
} else {
leaveTimeout = setTimeout(() => {
if (anim) {
console.log("kill anim");
anim.kill();
anim = null;
}
gsap.timeline({
onComplete: () => {
console.log("clear props");
gsap.set(".anim-img", {
clearProps: true
});
}
});
}, 500);
}
}
gsap.set(overlay, {
x: "0",
y: "0"
});
gsap.set(img1, {
x: "0",
y: "-100%"
});
gsap.set(img2, {
x: "0",
y: "-100%"
});
window.addEventListener("mousemove", moveOverlay);
s1.addEventListener("mouseenter", (e) => {
mouseOver(e, s1, true);
});
s1.addEventListener("mouseleave", (e) => {
mouseOver(e, s1, false);
});
s2.addEventListener("mouseenter", (e) => {
mouseOver(e, s2, true);
});
s2.addEventListener("mouseleave", (e) => {
mouseOver(e, s2, false);
});
}
</script>
</body>
</html>
I think that problem is because "moving circle function". Moving dom element with Left and right is not good for performance. You should move the circle with "transform". transform runs with GPU acceleration and it performs better and make move smooth.
Try this code.
function moveCircle(e) {
TweenLite.to($circle, 0.8, {
css: {
transform: `translate(${e.pageX}px, ${e.pageY}px)`
}
});
}
Yes, there is, by modifying the value of the second parameter of TweenLite.to, because that's the duration, see more here: http://www.tud.ttu.ee/im/Jaak.Henno/FlashDevelop/greensock-as3/greensock-as3/docs/com/greensock/TweenLite.html#to()
var $circle = $('#circle');
function moveCircle(e) {
TweenLite.to($circle, 0.1, {
css: {
left: e.pageX,
top: e.pageY
}
});
}
$(window).on('mousemove', moveCircle);
#import "compass/css3";
#keyframes in {
from {
transform: translateY(-100%);
}
to {
transform: translateY(0);
}
}
#keyframes out {
from {
transform: translateY(0);
}
to {
transform: translateY(100%);
}
}
html {
background: #0E3741;
}
#circle {
position: absolute;
pointer-events : none;
width: 400px;
height: 200px;
top: 50%;
left: 50%;
margin: -50px 0 0 -50px;
}
#circle .circle-wrapper {
overflow: hidden;
width: 400px;
height: 200px;
position: relative;
}
#circle img {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 400px;
height: 200px;
object-fit: cover;
overflow: hidden;
}
#wrapper {
display: flex;
flex-direction: column;
}
.special-element {
width: 100%;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
}
#one {
background: blue;
}
#two {
background: red;
}
#one:hover ~ #circle .circle-wrapper #imgOne {
animation: in 1s ease-in-out;
z-index: 2;
}
#one:hover ~ #circle .circle-wrapper #imgTwo {
animation: out 1s ease-in-out;
}
#two:hover ~ #circle .circle-wrapper #imgTwo {
animation: in 1s ease-in-out;
z-index: 2;
}
#two:hover ~ #circle .circle-wrapper #imgOne {
animation: out 1s ease-in-out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.11.4/TweenMax.min.js"></script>
<section id="wrapper">
<section class="special-element" id="one">
section one
</section>
<section class="special-element" id="two">
section two
</section>
<div id="circle">
<div class="circle-wrapper">
<img id="imgOne" src="https://upload.wikimedia.org/wikipedia/commons/3/3b/Coca-cat.jpg">
<img id="imgTwo" src="https://staticcdn.sk/images/photoarchive/sized/700/2020/07/29/ohrozeny-vtak-krakla-belasa.jpg">
</div>
</div>
</section>
The website is using canvas for the moving slideshow and they've used webgl for the smooth kind of reveal effects.
<div class="site-footer">
<div class="js-scroll-height"></div>
<canvas width="780" height="624" class="js-webgl" style="width: 1041px;height: 833px;opacity: 1;border: 1px solid brown;"></canvas>
</div>
We can create similar reveal effect using simple animation and z-index manipulation:
var $cursor = $('#cursor');
function movecursor(e) {
TweenLite.to($cursor, 0.8, {
css: {
left: e.pageX,
top: e.pageY
}
});
}
$(window).on('mousemove', movecursor);
let topImg = null;
$('.special-element').mouseenter((e) => {
//make all images at same level
$('.img-wrapper').css({ zIndex: '1' });
//make last focused image at second highest level
if (topImg) topImg.css({ zIndex: '2' });
//make current image as topImage
let atr = $(e.target).attr('data-img');
topImg = $('.img-wrapper[data-img="' + atr + '"]');
//make it topmost
topImg.css({ zIndex: '3' });
});
:root {
--cursor-img-height: 30vh;
--cursor-img-width: 30vw;
}
html,
body {
background: #0E3741;
}
#wrapper {
display: flex;
flex-direction: column;
}
.special-element {
width: 100%;
height: 33vh;
display: flex;
justify-content: center;
align-items: center;
font-size: 2rem;
}
.special-element:nth-child(1) {
background: lightblue;
}
.special-element:nth-child(2) {
background: lightcoral;
}
.special-element:nth-child(3) {
background: lightgreen;
}
#cursor {
position: absolute;
pointer-events: none;
margin: 0;
margin-top: calc(var(--cursor-img-height) * -0.5);
margin-left: calc(var(--cursor-img-width) * -0.5);
overflow: hidden;
width: var(--cursor-img-width);
height: var(--cursor-img-height);
}
.img-wrapper {
position: absolute;
bottom: 0;
left: 0;
width: var(--cursor-img-width);
height: var(--cursor-img-height);
overflow: hidden;
}
.img-wrapper>img {
position: absolute;
bottom: 0;
left: 0;
width: var(--cursor-img-width);
height: var(--cursor-img-height);
object-fit: fill;
z-index: 1;
}
.special-element[data-img="one"]:hover~#cursor [data-img="one"],
.special-element[data-img="two"]:hover~#cursor [data-img="two"],
.special-element[data-img="three"]:hover~#cursor [data-img="three"] {
animation: slide .8s ease-in-out;
}
#keyframes slide {
from {
height: 0px;
transform: scale(1.2);
}
to {
height: (--cursor-img-height);
transform: scale(1);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.11.4/TweenMax.min.js"></script>
<section id="wrapper">
<section class="special-element" data-img="one">food</section>
<section class="special-element" data-img="two">animal</section>
<section class="special-element" data-img="three">night</section>
<div id="cursor">
<div class="img-wrapper" data-img='one'>
<img src="https://picsum.photos/id/674/400/200">
</div>
<div class="img-wrapper" data-img='two'>
<img src="https://picsum.photos/id/433/400/200">
</div>
<div class="img-wrapper" data-img='three'>
<img src="https://picsum.photos/id/901/400/200">
</div>
</div>
</section>
View in full page mode.
Related
I have a horizontal slider with sections that scale when dragged using GSAP. The issue I have is the scaling is applied on click and the value is saved until after dragging. I need the scaling to only be applied while the mouse button is held down.
Here is a codepen.
var drag = Draggable.create(".horizontalContainer ", {
type: "x",
onPress() {
const scale = .6;
gsap.to('.section', {scale: scale, duration: .25});
},
onDragEnd() {
const xpos = this.target.getBoundingClientRect().left;
const winWidth = window.innerWidth;
gsap.to('.section', {scale: 1, duration: .25});
gsap.to(this.target, {x: Math.round(xpos / winWidth) * winWidth, duration: .5});
}
});
body {
margin: 0;
padding: 0;
overflow: hidden;
}
.horizontalContainer {
width: 600%;
display: flex;
flex-wrap: nowrap;
}
.section {
height: 100vh;
width: 100vw;
text-align: center;
font-size: 36px;
line-height: 90vh;
}
.section:nth-child(1) {
background-color: #deb887;
}
.section:nth-child(2) {
background-color: limegreen;
}
.section:nth-child(3) {
background-color: #b8860b;
}
.section:nth-child(4) {
background-color: #2f4f4f;
}
.proxy {
position: absolute;
visibility: hidden;
}
<script src="https://unpkg.com/gsap#3/dist/Draggable.min.js"></script>
<script src="https://unpkg.com/gsap#3/dist/ScrollTrigger.min.js"></script>
<script src="https://unpkg.co/gsap#3/dist/gsap.min.js"></script>
<div class='horizontalContainer'>
<div class='section'>ScrollTrigger with Draggable</div>
<div class='section'></div>
<div class='section'></div>
<div class='section'></div>
</div>
Use onRelease() callback to bring the scale back to 1.
onRelease() {
const scale = 1;
gsap.to('.section', {scale: scale, duration: .25});
}
Code Snippet:
var drag = Draggable.create(".horizontalContainer ", {
type: "x",
onPress() {
const scale = .6;
gsap.to('.section', {
scale: scale,
duration: .25
});
},
onRelease() {
const scale = 1;
gsap.to('.section', {
scale: scale,
duration: .25
});
},
onDragEnd() {
const xpos = this.target.getBoundingClientRect().left;
const winWidth = window.innerWidth;
gsap.to('.section', {
scale: 1,
duration: .25
});
gsap.to(this.target, {
x: Math.round(xpos / winWidth) * winWidth,
duration: .5
});
}
});
body {
margin: 0;
padding: 0;
overflow: hidden;
}
.horizontalContainer {
width: 600%;
display: flex;
flex-wrap: nowrap;
}
.section {
height: 100vh;
width: 100vw;
text-align: center;
font-size: 36px;
line-height: 90vh;
}
.section:nth-child(1) {
background-color: #deb887;
}
.section:nth-child(2) {
background-color: limegreen;
}
.section:nth-child(3) {
background-color: #b8860b;
}
.section:nth-child(4) {
background-color: #2f4f4f;
}
.proxy {
position: absolute;
visibility: hidden;
}
<div class='horizontalContainer'>
<div class='section'>ScrollTrigger with Draggable</div>
<div class='section'></div>
<div class='section'></div>
<div class='section'></div>
</div>
<script src="https://unpkg.com/gsap#3/dist/Draggable.min.js"></script>
<script src="https://unpkg.com/gsap#3/dist/ScrollTrigger.min.js"></script>
<script src="https://unpkg.co/gsap#3/dist/gsap.min.js"></script>
Somehow I can't get the following script to run.
The idea is to swap background images of a div, once the links with its corresponding data attributes are hovered. To be clear, both the links and the background images are listed separately.
Can someone help me with the solution??
Ps: Codepen example over here: https://codepen.io/eric-schakel/pen/qBXvgoM
!(function (t) {
class Bo {
constructor(t) {
const e = $$$(".capabilities__list a"),
i = $$(".capabilities__list");
e.forEach((t) => {
t.addEventListener("mouseover", function () {
const e = t.getAttribute("data-capability");
$$(".background__images img:nth-of-type(" + e + ")").classList.add("active");
}),
t.addEventListener("mouseout", function () {
const e = t.getAttribute("data-capability"),
i = $$(".background__images img:nth-of-type(" + e + ")");
i && i.classList.remove("active");
}),
t.addEventListener("click", function () {
window.capability = this.getAttribute("data-capability");
}),
i.addEventListener("mouseover", function () {
$$("#home__capabilities img.fill-background").classList.add("hidden");
}),
i.addEventListener("mouseout", function () {
const t = $$("#home__capabilities img.fill-background");
t && t.classList.remove("hidden");
});
});
}
}
});
#home__capabilities {
width: 100vw;
height: 60vh;
display: flex;
align-items: center;
}
img.fill-background {
width: 100%;
height: 100%;
object-fit: cover;
position: absolute;
top: 0;
left: 0;
}
img.fill-background.hidden {
opacity: 0;
}
.capabilities__list {
font-size: 50px;
z-index: 10;
}
.capabilities__list a:hover {
opacity: .5;
}
.background__images {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-size: cover;
z-index: 1;
}
.background__images img {
width: 100%;
height: 100%;
max-width: 100%;
object-fit: cover;
opacity: 0;
position: absolute;
top: 50%;
transform: translateY(-50%) translateZ(0) scale(1.01);
transform-origin: left center;
transition: opacity .2s ease-in-out,transform .4s ease;
}
.background__images img.active {
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section id="home__capabilities">
<img class="fill-background" src="https://images.unsplash.com/photo-1428606381429-22224991fb0c">
<div class="capabilities__list">
Link 01
Link 02
Link 03
Link 04
</div>
<div class="background__images">
<img src="https://images.unsplash.com/photo-1427830574887-32e5702033b0">
<img src="https://images.unsplash.com/photo-1427830180740-12146c79a1a3">
<img src="https://images.unsplash.com/photo-1415226181422-279a51ca056e">
<img src="https://images.unsplash.com/photo-1450885413713-176921f199b2">
</div>
</section>
Here
I changed a few things I would love to delegate more, but that would change your code too much.
Syntax error - script should end on }) and not ])
Instantiation of class was missing
Variable names and constants were not understandable
Missing helper functions for querySelector and querySelectorAll
!(function() {
class Bo {
constructor() {
const $$ = selector => document.querySelector(selector),
$$$ = selector => document.querySelectorAll(selector),
links = $$$(".capabilities__list a"),
list = $$(".capabilities__list");
links.forEach(link => {
link.addEventListener("mouseover", function() {
const capability = link.getAttribute("data-capability");
$$(".background__images img:nth-of-type(" + capability + ")").classList.add("active");
}),
link.addEventListener("mouseout", function() {
const capability = link.getAttribute("data-capability"),
image = $$(".background__images img:nth-of-type(" + capability + ")");
image && image.classList.remove("active");
}),
link.addEventListener("click", function() {
window.capability = this.getAttribute("data-capability");
}),
list.addEventListener("mouseover", function() {
$$("#home__capabilities img.fill-background").classList.add("hidden");
}),
list.addEventListener("mouseout", function() {
const image = $$("#home__capabilities img.fill-background");
image && image.classList.remove("hidden");
});
});
}
}
const list = new Bo()
})();
#home__capabilities {
width: 100vw;
height: 60vh;
display: flex;
align-items: center;
}
img.fill-background {
width: 100%;
height: 100%;
object-fit: cover;
position: absolute;
top: 0;
left: 0;
}
img.fill-background.hidden {
opacity: 0;
}
.capabilities__list {
font-size: 50px;
z-index: 10;
}
.capabilities__list a:hover {
opacity: .5;
}
.background__images {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-size: cover;
z-index: 1;
}
.background__images img {
width: 100%;
height: 100%;
max-width: 100%;
object-fit: cover;
opacity: 0;
position: absolute;
top: 50%;
transform: translateY(-50%) translateZ(0) scale(1.01);
transform-origin: left center;
transition: opacity .2s ease-in-out, transform .4s ease;
}
.background__images img.active {
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<section id="home__capabilities">
<img class="fill-background" src="https://images.unsplash.com/photo-1428606381429-22224991fb0c">
<div class="capabilities__list">
Link 01
Link 02
Link 03
Link 04
</div>
<div class="background__images">
<img src="https://images.unsplash.com/photo-1427830574887-32e5702033b0">
<img src="https://images.unsplash.com/photo-1427830180740-12146c79a1a3">
<img src="https://images.unsplash.com/photo-1415226181422-279a51ca056e">
<img src="https://images.unsplash.com/photo-1450885413713-176921f199b2">
</div>
</section>
I have some lightbox gallery code which works great. I've only ever needed to use 1 on a page at a time, but a client wants to include two different galleries on the same page. I've tried to do this a couple of ways:
The first thing I tried was just copy / pasting the same HTML into a different div using different pictures. That didn't work for me.
The second thing I did was I tried going through the CSS, renaming every single gallery class to gallery-two, then adjusting every class I could find in the javascript to match its CSS counterpart. What ended up happening was that when I clicked the second gallery, the original set of pictures/gallery came up instead of the photos belonging to the new gallery I clicked.
Here is the original lightbox gallery code:
https://codepen.io/Lancewalker/pen/JjjdbOZ
class AsyncGallery {
constructor(settings) {
this.settings = {
images: ".gallery__Image",
loop: true,
next: undefined,
prev: undefined,
dots: undefined,
close: undefined,
loader: undefined,
counter: undefined,
counterDivider: "/",
keyboardNavigation: true,
hiddenElements: []
};
Object.assign(this.settings, settings);
this.gallery = null;
this.index = 0;
this.items = [...document.querySelectorAll(this.settings.images)];
this.addedItems = {};
this.touch = {
endX: 0,
startX: 0
};
this.init();
}
get loading() {
return !this.settings.hiddenElements.includes("loader");
}
get dotsVisible() {
return !this.settings.hiddenElements.includes("dots");
}
init() {
this.clearUncomplete();
this.createElements();
this.bindEvents();
}
clearUncomplete() {
this.items = this.items.filter(item => {
return item.dataset.large;
});
}
createElements() {
this.gallery = document.createElement("DIV");
this.gallery.classList.add("asyncGallery");
this.createSingleElement({
element: "prev",
type: "BUTTON",
event: "click",
func: this.getPrevious
});
this.createSingleElement({
element: "next",
type: "BUTTON",
event: "click",
func: this.getNext
});
this.createSingleElement({
element: "close",
type: "BUTTON",
event: "click",
func: this.closeGallery
});
this.createSingleElement({
element: "loader",
type: "SPAN",
text: "Loading..."
});
this.createSingleElement({
element: "counter",
type: "SPAN",
text: "0/0"
});
this.createSingleElement({
element: "dots",
type: "UL",
text: ""
});
if (!this.settings.hiddenElements.includes("dots")) {
this.items.forEach((item, i) => {
let dot = document.createElement("LI");
dot.dataset.index = i;
let button = document.createElement("BUTTON");
button.innerHTML = i;
button.addEventListener("click", () => {
this.index = i;
this.getItem(i);
});
dot.append(button);
this.dots.append(dot);
});
}
window.document.body.append(this.gallery);
}
createSingleElement({ element, type, event = "click", func, text }) {
if (!this.settings.hiddenElements.includes(element)) {
if (!this.settings[element]) {
this[element] = document.createElement(type);
this[element].classList.add(
`asyncGallery__${this.capitalizeFirstLetter(element)}`
);
this[element].innerHTML = text !== undefined ? text : element;
this.gallery.append(this[element]);
} else {
this[element] = document.querySelector(this.settings[element]);
this.gallery.append(this[element]);
}
if (func) {
this[element].addEventListener(event, func.bind(this));
}
}
}
getItem(i, content = null) {
let contentObj = content;
if (contentObj === null) {
contentObj = {};
contentObj.src = this.items[i].dataset.large;
contentObj.description = this.items[i].dataset.description;
}
if (!this.settings.hiddenElements.includes("counter")) {
this.counter.innerHTML = `
<span class="asyncGallery__Current">${this.index + 1}</span>${
this.settings.counterDivider
}<span class="asyncGallery__Current">${this.items.length}</span>
`;
}
if (!this.addedItems.hasOwnProperty(i)) {
let image = document.createElement("IMG");
let galleryItem = document.createElement("DIV");
galleryItem.classList.add("asyncGallery__Item");
if (this.loading) {
this.loader.classList.add("is-visible");
}
this.clearVisible();
if (this.dotsVisible) {
this.gallery
.querySelector(`.asyncGallery__Dots li[data-index="${i}"]`)
.classList.add("is-active");
}
image.src = contentObj.src;
image.alt = contentObj.description ? contentObj.description : "";
galleryItem.innerHTML = `
<div class="asyncGallery__ItemImage">
${image.outerHTML}
</div>
`;
if (contentObj.description) {
galleryItem.innerHTML += `
<div class="asyncGallery__ItemDescription">
<p>${contentObj.description}</p>
</div>
`;
}
this.gallery.append(galleryItem);
this.addedItems[i] = galleryItem;
image.addEventListener("load", () => {
this.addedItems[i].loaded = true;
if (!this.gallery.querySelector(".asyncGallery__Item.is-visible")) {
this.addedItems[i].classList.add("is-visible");
}
if (this.loading) {
this.loader.classList.remove("is-visible");
}
});
} else {
this.clearVisible();
if (this.addedItems[this.index].loaded) {
this.addedItems[this.index].classList.add("is-visible");
if (this.loading) {
this.loader.classList.remove("is-visible");
}
} else if (this.loading) {
this.loader.classList.add("is-visible");
}
if (this.dotsVisible) {
this.gallery
.querySelector(`.asyncGallery__Dots li[data-index="${i}"]`)
.classList.add("is-active");
}
}
if (!this.settings.loop) {
if (this.index === 0) this.prev.setAttribute("disabled", true);
else this.prev.removeAttribute("disabled");
if (this.index === this.items.length - 1)
this.next.setAttribute("disabled", true);
else this.next.removeAttribute("disabled");
}
}
clearVisible() {
if (this.gallery.querySelector(".asyncGallery__Item.is-visible")) {
this.gallery
.querySelector(".asyncGallery__Item.is-visible")
.classList.remove("is-visible");
}
if (this.gallery.querySelector(".asyncGallery__Dots li.is-active")) {
this.gallery
.querySelector(".asyncGallery__Dots li.is-active")
.classList.remove("is-active");
}
}
closeGallery() {
this.gallery.classList.remove("is-visible");
this.clearVisible();
}
capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
handleGesure() {
if (this.touch.endX > this.touch.startX + 20) {
this.getPrevious();
} else if (this.touch.endX < this.touch.startX - 20) {
this.getNext();
}
}
getPrevious() {
if (this.settings.loop) {
this.index--;
if (this.index === -1) {
this.index = this.items.length - 1;
}
this.getItem(this.index);
} else if (this.index > 0) {
this.index--;
this.getItem(this.index);
}
}
getNext() {
if (this.settings.loop) {
this.index++;
if (this.index === this.items.length) {
this.index = 0;
}
this.getItem(this.index);
} else if (this.index < this.items.length - 1) {
this.index++;
this.getItem(this.index);
}
}
bindEvents() {
this.items.forEach((item, i) => {
item.addEventListener("click", e => {
this.gallery.classList.add("is-visible");
this.index = i;
this.getItem(i, {
src: e.target.dataset.large,
description: e.target.dataset.description
});
});
});
document.addEventListener("keyup", e => {
if (this.gallery.classList.contains("is-visible")) {
if (e.key === "Escape") this.closeGallery();
if (this.settings.keyboardNavigation) {
if (e.keyCode === 39) this.getNext();
else if (e.keyCode === 37) this.getPrevious();
}
}
});
this.gallery.addEventListener(
"touchstart",
e => {
this.touch.startX = e.changedTouches[0].screenX;
},
false
);
this.gallery.addEventListener(
"touchend",
e => {
this.touch.endX = e.changedTouches[0].screenX;
this.handleGesure();
},
false
);
}
}
new AsyncGallery();
.ec-container {
max-width: 98%;
margin: 1% auto;
}
.gallery {
display: flex;
flex-wrap: wrap;
align-items: center;
}
.gallery div {
max-width: calc(20% - 20px);
margin: 10px;
transition: opacity 200ms;
cursor: pointer;
}
.gallery div:hover {
opacity: 0.8;
}
.gallery div img {
max-width: 100%;
}
.asyncGallery {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0;
z-index: 10000;
visibility: hidden;
background-color: rgba(30, 30, 30, 0.95);
transition: opacity 200ms, visibility 200ms;
}
.asyncGallery.is-visible {
opacity: 1;
visibility: visible;
}
.asyncGallery__Item {
position: absolute;
top: 50%;
left: 50%;
opacity: 0;
visibility: hidden;
overflow: hidden;
transform: translate(-50%, -50%);
transition: opacity 200ms, visibility 200ms;
}
.asyncGallery__Item.is-visible {
opacity: 1;
visibility: visible;
}
.asyncGallery__ItemImage img {
max-height: 80vh;
display: block;
max-width: 95vw;
}
.asyncGallery__ItemDescription,
.asyncGallery__Loader {
color: #fff;
}
.asyncGallery__Loader {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: none;
color: #fff;
z-index: 100;
}
.asyncGallery__Loader.is-visible {
display: block;
}
.asyncGallery button {
background-color: transparent;
border: 0;
outline: 0;
padding: 0;
font-size: 0;
cursor: pointer;
}
.asyncGallery__Close {
position: absolute;
top: 3%;
right: 4%;
width: 30px;
height: 30px;
z-index: 1000;
background-repeat: no-repeat;
background-size: 30px 30px;
background-image: url("data:image/svg+xml;utf8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iNTEycHgiIHZlcnNpb249IjEuMSIgaGVpZ2h0PSI1MTJweCIgdmlld0JveD0iMCAwIDY0IDY0IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA2NCA2NCI+CiAgPGc+CiAgICA8cGF0aCBmaWxsPSIjRkZGRkZGIiBkPSJNMjguOTQxLDMxLjc4NkwwLjYxMyw2MC4xMTRjLTAuNzg3LDAuNzg3LTAuNzg3LDIuMDYyLDAsMi44NDljMC4zOTMsMC4zOTQsMC45MDksMC41OSwxLjQyNCwwLjU5ICAgYzAuNTE2LDAsMS4wMzEtMC4xOTYsMS40MjQtMC41OWwyOC41NDEtMjguNTQxbDI4LjU0MSwyOC41NDFjMC4zOTQsMC4zOTQsMC45MDksMC41OSwxLjQyNCwwLjU5YzAuNTE1LDAsMS4wMzEtMC4xOTYsMS40MjQtMC41OSAgIGMwLjc4Ny0wLjc4NywwLjc4Ny0yLjA2MiwwLTIuODQ5TDM1LjA2NCwzMS43ODZMNjMuNDEsMy40MzhjMC43ODctMC43ODcsMC43ODctMi4wNjIsMC0yLjg0OWMtMC43ODctMC43ODYtMi4wNjItMC43ODYtMi44NDgsMCAgIEwzMi4wMDMsMjkuMTVMMy40NDEsMC41OWMtMC43ODctMC43ODYtMi4wNjEtMC43ODYtMi44NDgsMGMtMC43ODcsMC43ODctMC43ODcsMi4wNjIsMCwyLjg0OUwyOC45NDEsMzEuNzg2eiIvPgogIDwvZz4KPC9zdmc+Cg==");
}
.asyncGallery__Counter {
position: absolute;
font-size: 20px;
font-weight: bold;
color: #fff;
right: 40px;
bottom: 40px;
}
.asyncGallery__Dots {
position: absolute;
left: 50%;
bottom: 40px;
display: flex;
margin: 0;
padding: 0;
transform: translateX(-50%);
list-style-type: none;
z-index: 1000;
}
.asyncGallery__Dots button {
padding: 0;
width: 10px;
height: 10px;
background-color: #fff;
border: 0;
outline: 0;
border-radius: 50%;
}
.asyncGallery__Dots li {
opacity: 0.2;
transition: opacity 200ms;
}
.asyncGallery__Dots li + li {
margin-left: 10px;
}
.asyncGallery__Dots li.is-active {
opacity: 1;
}
.asyncGallery__Next,
.asyncGallery__Prev {
position: absolute;
top: 50%;
width: 30px;
height: 30px;
z-index: 1000;
transition: transform 200ms, opacity 200ms;
transform: translateY(-50%);
}
.asyncGallery__Next:disabled,
.asyncGallery__Prev:disabled {
opacity: 0.2;
cursor: default;
}
.asyncGallery__Next:before,
.asyncGallery__Prev:before {
position: absolute;
content: "";
top: 50%;
left: 50%;
background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 129 129' xmlns:xlink='http://www.w3.org/1999/xlink' enable-background='new 0 0 129 129'%3E%3Cg%3E%3Cpath d='m40.4,121.3c-0.8,0.8-1.8,1.2-2.9,1.2s-2.1-0.4-2.9-1.2c-1.6-1.6-1.6-4.2 0-5.8l51-51-51-51c-1.6-1.6-1.6-4.2 0-5.8 1.6-1.6 4.2-1.6 5.8,0l53.9,53.9c1.6,1.6 1.6,4.2 0,5.8l-53.9,53.9z' fill='%23fff'/%3E%3C/g%3E%3C/svg%3E%0A");
width: 30px;
height: 30px;
background-repeat: no-repeat;
background-size: 30px 30px;
}
.asyncGallery__Next {
right: 40px;
}
.asyncGallery__Next:hover {
transform: translateX(2px) translateY(-50%);
}
.asyncGallery__Next:before {
transform: translate3d(-50%, -50%, 0);
}
.asyncGallery__Prev {
left: 40px;
}
.asyncGallery__Prev:hover {
transform: translateX(-2px) translateY(-50%);
}
.asyncGallery__Prev:before {
transform: translate3d(-50%, -50%, 0) scale(-1);
}
#media screen and (max-width: 800px) {
.gallery img {
max-width: calc(50% - 40px);
margin: 20px;
transition: opacity 200ms;
cursor: pointer;
}
.gallery-no-lb-2-items div {
max-width: 90%;
margin: 20px;
}
.asyncGallery__Dots {
bottom: 15px;
}
.asyncGallery__Counter {
right: 15px;
bottom: 15px;
font-size: 12px;
}
.asyncGallery__Item {
width: 100%;
}
.asyncGallery__ItemImage img {
max-height: none;
max-width: 100%;
}
.asyncGallery__ItemDescription {
padding: 0 20px;
}
.asyncGallery__Next,
.asyncGallery__Prev {
display: none;
}
.gallery {
display: inline-flex;
}
.gallery div {
max-width: 90%;
margin: 10px auto;
}
.gallery div img {
max-width: 100%;
margin: 0 auto;
}
<div class="ec-container" id="project-ec">
<div class="gallery">
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I8950.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I8950.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 1">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I89502.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I89502.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 2">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I89503.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I89503.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 3">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I89504.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I89504.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 4">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I89505.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I89505.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 5">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I89506.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I89506.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 6">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I89507.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I89507.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 7">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I89508.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I89508.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 8">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I89509.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I89509.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 9">
</div> <div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I895010.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I895010.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 10">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I895011.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I895011.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 11">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I895021.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I895021.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 12">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I895013.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I895013.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 13">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I895014.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I895014.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 14">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I895022.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I895022.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 15">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I895016.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I895016.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 16">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I895017.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I895017.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 17">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I895018.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I895018.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 18">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I895019.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I895019.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 19">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I895020.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I895020.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 20">
</div>
</div>
</div>
Any ideas?
I created a new setting where you can set your gallery content:
this.settings = {
myGallery: "gallery_1", // add this
images: ".gallery__Image",
loop: true,
next: undefined,
prev: undefined,
dots: undefined,
close: undefined,
loader: undefined,
counter: undefined,
counterDivider: "/",
keyboardNavigation: true,
hiddenElements: []
};
After that I changed these lines of code:
this.gallery = document.getElementById(this.settings.myGallery);
this.items = [...this.gallery.querySelectorAll(this.settings.images)];
To say at gallery that it has to take only the items in myGallery content.
Now you can create different istances of your gallery, simply change that new setting that I added (in this example I created a loop to start every gallery in project-ec block. Each gallery must have an ID and a class gallery.):
var allTags = document.getElementById('project-ec').getElementsByClassName("gallery");
for (var i = 0, len = allTags.length; i < len; i++) {
new AsyncGallery({
myGallery: String(allTags[i].id)
});
}
If you can't put your galleries in a same block or it is more simple for you, you can also start every gallery manually (by default, if you don't write any setting, the system search a gallery called gallery_1):
new AsyncGallery();
new AsyncGallery({
myGallery:"gallery_2"
});
The code in action:
class AsyncGallery {
constructor(settings) {
this.settings = {
myGallery: "gallery_1",
images: ".gallery__Image",
loop: true,
next: undefined,
prev: undefined,
dots: undefined,
close: undefined,
loader: undefined,
counter: undefined,
counterDivider: "/",
keyboardNavigation: true,
hiddenElements: []
};
Object.assign(this.settings, settings);
this.gallery = document.getElementById(this.settings.myGallery);
this.index = 0;
this.items = [...this.gallery.querySelectorAll(this.settings.images)];
this.addedItems = {};
this.touch = {
endX: 0,
startX: 0
};
this.init();
}
get loading() {
return !this.settings.hiddenElements.includes("loader");
}
get dotsVisible() {
return !this.settings.hiddenElements.includes("dots");
}
init() {
this.clearUncomplete();
this.createElements();
this.bindEvents();
}
clearUncomplete() {
this.items = this.items.filter(item => {
return item.dataset.large;
});
}
createElements() {
this.gallery = document.createElement("DIV");
this.gallery.classList.add("asyncGallery");
this.createSingleElement({
element: "prev",
type: "BUTTON",
event: "click",
func: this.getPrevious
});
this.createSingleElement({
element: "next",
type: "BUTTON",
event: "click",
func: this.getNext
});
this.createSingleElement({
element: "close",
type: "BUTTON",
event: "click",
func: this.closeGallery
});
this.createSingleElement({
element: "loader",
type: "SPAN",
text: "Loading..."
});
this.createSingleElement({
element: "counter",
type: "SPAN",
text: "0/0"
});
this.createSingleElement({
element: "dots",
type: "UL",
text: ""
});
if (!this.settings.hiddenElements.includes("dots")) {
this.items.forEach((item, i) => {
let dot = document.createElement("LI");
dot.dataset.index = i;
let button = document.createElement("BUTTON");
button.innerHTML = i;
button.addEventListener("click", () => {
this.index = i;
this.getItem(i);
});
dot.append(button);
this.dots.append(dot);
});
}
window.document.body.append(this.gallery);
}
createSingleElement({ element, type, event = "click", func, text }) {
if (!this.settings.hiddenElements.includes(element)) {
if (!this.settings[element]) {
this[element] = document.createElement(type);
this[element].classList.add(
`asyncGallery__${this.capitalizeFirstLetter(element)}`
);
this[element].innerHTML = text !== undefined ? text : element;
this.gallery.append(this[element]);
} else {
this[element] = document.querySelector(this.settings[element]);
this.gallery.append(this[element]);
}
if (func) {
this[element].addEventListener(event, func.bind(this));
}
}
}
getItem(i, content = null) {
let contentObj = content;
if (contentObj === null) {
contentObj = {};
contentObj.src = this.items[i].dataset.large;
contentObj.description = this.items[i].dataset.description;
}
if (!this.settings.hiddenElements.includes("counter")) {
this.counter.innerHTML = `
<span class="asyncGallery__Current">${this.index + 1}</span>${
this.settings.counterDivider
}<span class="asyncGallery__Current">${this.items.length}</span>
`;
}
if (!this.addedItems.hasOwnProperty(i)) {
let image = document.createElement("IMG");
let galleryItem = document.createElement("DIV");
galleryItem.classList.add("asyncGallery__Item");
if (this.loading) {
this.loader.classList.add("is-visible");
}
this.clearVisible();
if (this.dotsVisible) {
this.gallery
.querySelector(`.asyncGallery__Dots li[data-index="${i}"]`)
.classList.add("is-active");
}
image.src = contentObj.src;
image.alt = contentObj.description ? contentObj.description : "";
galleryItem.innerHTML = `
<div class="asyncGallery__ItemImage">
${image.outerHTML}
</div>
`;
if (contentObj.description) {
galleryItem.innerHTML += `
<div class="asyncGallery__ItemDescription">
<p>${contentObj.description}</p>
</div>
`;
}
this.gallery.append(galleryItem);
this.addedItems[i] = galleryItem;
image.addEventListener("load", () => {
this.addedItems[i].loaded = true;
if (!this.gallery.querySelector(".asyncGallery__Item.is-visible")) {
this.addedItems[i].classList.add("is-visible");
}
if (this.loading) {
this.loader.classList.remove("is-visible");
}
});
} else {
this.clearVisible();
if (this.addedItems[this.index].loaded) {
this.addedItems[this.index].classList.add("is-visible");
if (this.loading) {
this.loader.classList.remove("is-visible");
}
} else if (this.loading) {
this.loader.classList.add("is-visible");
}
if (this.dotsVisible) {
this.gallery
.querySelector(`.asyncGallery__Dots li[data-index="${i}"]`)
.classList.add("is-active");
}
}
if (!this.settings.loop) {
if (this.index === 0) this.prev.setAttribute("disabled", true);
else this.prev.removeAttribute("disabled");
if (this.index === this.items.length - 1)
this.next.setAttribute("disabled", true);
else this.next.removeAttribute("disabled");
}
}
clearVisible() {
if (this.gallery.querySelector(".asyncGallery__Item.is-visible")) {
this.gallery
.querySelector(".asyncGallery__Item.is-visible")
.classList.remove("is-visible");
}
if (this.gallery.querySelector(".asyncGallery__Dots li.is-active")) {
this.gallery
.querySelector(".asyncGallery__Dots li.is-active")
.classList.remove("is-active");
}
}
closeGallery() {
this.gallery.classList.remove("is-visible");
this.clearVisible();
}
capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
handleGesure() {
if (this.touch.endX > this.touch.startX + 20) {
this.getPrevious();
} else if (this.touch.endX < this.touch.startX - 20) {
this.getNext();
}
}
getPrevious() {
if (this.settings.loop) {
this.index--;
if (this.index === -1) {
this.index = this.items.length - 1;
}
this.getItem(this.index);
} else if (this.index > 0) {
this.index--;
this.getItem(this.index);
}
}
getNext() {
if (this.settings.loop) {
this.index++;
if (this.index === this.items.length) {
this.index = 0;
}
this.getItem(this.index);
} else if (this.index < this.items.length - 1) {
this.index++;
this.getItem(this.index);
}
}
bindEvents() {
this.items.forEach((item, i) => {
item.addEventListener("click", e => {
this.gallery.classList.add("is-visible");
this.index = i;
this.getItem(i, {
src: e.target.dataset.large,
description: e.target.dataset.description
});
});
});
document.addEventListener("keyup", e => {
if (this.gallery.classList.contains("is-visible")) {
if (e.key === "Escape") this.closeGallery();
if (this.settings.keyboardNavigation) {
if (e.keyCode === 39) this.getNext();
else if (e.keyCode === 37) this.getPrevious();
}
}
});
this.gallery.addEventListener(
"touchstart",
e => {
this.touch.startX = e.changedTouches[0].screenX;
},
false
);
this.gallery.addEventListener(
"touchend",
e => {
this.touch.endX = e.changedTouches[0].screenX;
this.handleGesure();
},
false
);
}
}
var allTags = document.getElementById('project-ec').getElementsByClassName("gallery");
for (var i = 0, len = allTags.length; i < len; i++) {
new AsyncGallery({
myGallery: String(allTags[i].id)
});
}
.ec-container {
max-width: 98%;
margin: 1% auto;
}
.gallery {
display: flex;
flex-wrap: wrap;
align-items: center;
}
.gallery div {
max-width: calc(20% - 20px);
margin: 10px;
transition: opacity 200ms;
cursor: pointer;
}
.gallery div:hover {
opacity: 0.8;
}
.gallery div img {
max-width: 100%;
}
.asyncGallery {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: 0;
z-index: 10000;
visibility: hidden;
background-color: rgba(30, 30, 30, 0.95);
transition: opacity 200ms, visibility 200ms;
}
.asyncGallery.is-visible {
opacity: 1;
visibility: visible;
}
.asyncGallery__Item {
position: absolute;
top: 50%;
left: 50%;
opacity: 0;
visibility: hidden;
overflow: hidden;
transform: translate(-50%, -50%);
transition: opacity 200ms, visibility 200ms;
}
.asyncGallery__Item.is-visible {
opacity: 1;
visibility: visible;
}
.asyncGallery__ItemImage img {
max-height: 80vh;
display: block;
max-width: 95vw;
}
.asyncGallery__ItemDescription,
.asyncGallery__Loader {
color: #fff;
}
.asyncGallery__Loader {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
display: none;
color: #fff;
z-index: 100;
}
.asyncGallery__Loader.is-visible {
display: block;
}
.asyncGallery button {
background-color: transparent;
border: 0;
outline: 0;
padding: 0;
font-size: 0;
cursor: pointer;
}
.asyncGallery__Close {
position: absolute;
top: 3%;
right: 4%;
width: 30px;
height: 30px;
z-index: 1000;
background-repeat: no-repeat;
background-size: 30px 30px;
background-image: url("data:image/svg+xml;utf8;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB3aWR0aD0iNTEycHgiIHZlcnNpb249IjEuMSIgaGVpZ2h0PSI1MTJweCIgdmlld0JveD0iMCAwIDY0IDY0IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCA2NCA2NCI+CiAgPGc+CiAgICA8cGF0aCBmaWxsPSIjRkZGRkZGIiBkPSJNMjguOTQxLDMxLjc4NkwwLjYxMyw2MC4xMTRjLTAuNzg3LDAuNzg3LTAuNzg3LDIuMDYyLDAsMi44NDljMC4zOTMsMC4zOTQsMC45MDksMC41OSwxLjQyNCwwLjU5ICAgYzAuNTE2LDAsMS4wMzEtMC4xOTYsMS40MjQtMC41OWwyOC41NDEtMjguNTQxbDI4LjU0MSwyOC41NDFjMC4zOTQsMC4zOTQsMC45MDksMC41OSwxLjQyNCwwLjU5YzAuNTE1LDAsMS4wMzEtMC4xOTYsMS40MjQtMC41OSAgIGMwLjc4Ny0wLjc4NywwLjc4Ny0yLjA2MiwwLTIuODQ5TDM1LjA2NCwzMS43ODZMNjMuNDEsMy40MzhjMC43ODctMC43ODcsMC43ODctMi4wNjIsMC0yLjg0OWMtMC43ODctMC43ODYtMi4wNjItMC43ODYtMi44NDgsMCAgIEwzMi4wMDMsMjkuMTVMMy40NDEsMC41OWMtMC43ODctMC43ODYtMi4wNjEtMC43ODYtMi44NDgsMGMtMC43ODcsMC43ODctMC43ODcsMi4wNjIsMCwyLjg0OUwyOC45NDEsMzEuNzg2eiIvPgogIDwvZz4KPC9zdmc+Cg==");
}
.asyncGallery__Counter {
position: absolute;
font-size: 20px;
font-weight: bold;
color: #fff;
right: 40px;
bottom: 40px;
}
.asyncGallery__Dots {
position: absolute;
left: 50%;
bottom: 40px;
display: flex;
margin: 0;
padding: 0;
transform: translateX(-50%);
list-style-type: none;
z-index: 1000;
}
.asyncGallery__Dots button {
padding: 0;
width: 10px;
height: 10px;
background-color: #fff;
border: 0;
outline: 0;
border-radius: 50%;
}
.asyncGallery__Dots li {
opacity: 0.2;
transition: opacity 200ms;
}
.asyncGallery__Dots li + li {
margin-left: 10px;
}
.asyncGallery__Dots li.is-active {
opacity: 1;
}
.asyncGallery__Next,
.asyncGallery__Prev {
position: absolute;
top: 50%;
width: 30px;
height: 30px;
z-index: 1000;
transition: transform 200ms, opacity 200ms;
transform: translateY(-50%);
}
.asyncGallery__Next:disabled,
.asyncGallery__Prev:disabled {
opacity: 0.2;
cursor: default;
}
.asyncGallery__Next:before,
.asyncGallery__Prev:before {
position: absolute;
content: "";
top: 50%;
left: 50%;
background-image: url("data:image/svg+xml,%3Csvg version='1.1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 129 129' xmlns:xlink='http://www.w3.org/1999/xlink' enable-background='new 0 0 129 129'%3E%3Cg%3E%3Cpath d='m40.4,121.3c-0.8,0.8-1.8,1.2-2.9,1.2s-2.1-0.4-2.9-1.2c-1.6-1.6-1.6-4.2 0-5.8l51-51-51-51c-1.6-1.6-1.6-4.2 0-5.8 1.6-1.6 4.2-1.6 5.8,0l53.9,53.9c1.6,1.6 1.6,4.2 0,5.8l-53.9,53.9z' fill='%23fff'/%3E%3C/g%3E%3C/svg%3E%0A");
width: 30px;
height: 30px;
background-repeat: no-repeat;
background-size: 30px 30px;
}
.asyncGallery__Next {
right: 40px;
}
.asyncGallery__Next:hover {
transform: translateX(2px) translateY(-50%);
}
.asyncGallery__Next:before {
transform: translate3d(-50%, -50%, 0);
}
.asyncGallery__Prev {
left: 40px;
}
.asyncGallery__Prev:hover {
transform: translateX(-2px) translateY(-50%);
}
.asyncGallery__Prev:before {
transform: translate3d(-50%, -50%, 0) scale(-1);
}
#media screen and (max-width: 800px) {
.gallery img {
max-width: calc(50% - 40px);
margin: 20px;
transition: opacity 200ms;
cursor: pointer;
}
.gallery-no-lb-2-items div {
max-width: 90%;
margin: 20px;
}
.asyncGallery__Dots {
bottom: 15px;
}
.asyncGallery__Counter {
right: 15px;
bottom: 15px;
font-size: 12px;
}
.asyncGallery__Item {
width: 100%;
}
.asyncGallery__ItemImage img {
max-height: none;
max-width: 100%;
}
.asyncGallery__ItemDescription {
padding: 0 20px;
}
.asyncGallery__Next,
.asyncGallery__Prev {
display: none;
}
.gallery {
display: inline-flex;
}
.gallery div {
max-width: 90%;
margin: 10px auto;
}
.gallery div img {
max-width: 100%;
margin: 0 auto;
}
<div class="ec-container" id="project-ec">
<div class="gallery" id="gallery_1">
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I8950.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I8950.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 1">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I89502.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I89502.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 2">
</div>
</div>
<div class="gallery" id="gallery_2">
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I89504.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I89504.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 4">
</div>
<div>
<img class="gallery__Image" src="https://www.lancewalker.life/images/ec/AL4I89505.jpg" data-description=""
data-large="https://www.lancewalker.life/images/ec/AL4I89505.jpg" alt="Eagle Class 53 - FAST FORWARD COMPOSITES Gallery Image 5">
</div>
</div>
</div>
I have some divs that the user can click on, and then they expand to cover the screen. In doing so, they become fixed position.
Everything works exactly as expected in all browsers except for Safari. When on Safari, once the div is expanded, the user cannot click anything inside the div. I have buttons and links that would take the user to other pages or close the div, but it behaves as if the user never clicked anything.
Here is a link: https://toucan-sam.firebaseapp.com/
Any insight would be appreciated.
I've created a snippet below using what I believe to be the relevant code, but the snippet actually displays the intended behavior.
let $body = $('body');
let $introduction = $('#introduction');
let $sidebar = $('#sidebar');
let griffen = {
viewportHeight: $introduction.height(),
viewportWidth: $introduction.width(),
preset: false,
extrasVisible: false,
projectVisible: false,
projectOpening: false,
projectClosing: false,
mobileSize: 900,
};
let openProject = (project) => {
'use strict';
let open = () => {
let containerPosition = project.article.offset().top - window.scrollY;
let containerWidth = project.article.width();
let containerHeight = project.article.height();
project.container.css({
'height': containerHeight + 'px',
'position': 'fixed',
'top': containerPosition + 'px',
'width': containerWidth + 'px',
'z-index': '100',
});
if (project.id === 'sdot') {
project.heading.css({
'background-position': 'center 25%',
});
project.header.animate({
'padding-left': '0',
'padding-top': '20%',
}, 1000);
} else {
project.header.animate({
'padding-left': '0',
}, 1000);
}
project.container.animate({
'height': '100vh',
'top': '0',
'width': '100%',
}, 1000, () => {
project.container.addClass('full');
griffen.projectOpening = false;
});
};
$body.addClass('stuck');
$('html').addClass('stuck');
project.tabButton.attr('aria-selected', 'true');
project.content.attr('aria-hidden', 'false');
let verticalPosition = project.article.offset().top - (griffen.viewportHeight / 2) + (project.article.height() / 2);
let diff = Math.round(verticalPosition) - window.scrollY;
console.log(diff);
if (Math.abs(diff) > 50) {
let doneScrolling = false;
$('html, body').animate({
'scrollTop': verticalPosition
}, 500, () => {
if (!doneScrolling) {
doneScrolling = true;
window.setTimeout(() => {
open();
}, 500);
}
});
} else {
open();
}
};
let closeProject = (project) => {
'use strict';
let close = () => {
let containerPosition = project.article.offset().top - window.scrollY;
let containerWidth = project.article.width();
let containerHeight = project.article.height();
project.container.removeClass('full');
project.container.animate({
'height': containerHeight + 'px',
'top': containerPosition + 'px',
'width': containerWidth + 'px',
}, 1000, () => {
project.container.css({
'height': '',
'position': '',
'top': '',
'width': '',
'z-index': '',
});
$body.removeClass('stuck');
$('html').removeClass('stuck');
griffen.projectClosing = false;
griffen.projectVisible = false;
});
if (project.id === 'sdot') {
project.heading.css({
'background-position': '',
});
if (griffen.viewportWidth >= griffen.mobileSize) {
project.header.animate({
'padding-left': '250px',
'padding-top': '0',
}, 1000, () => {
project.header.css({
'padding-left': '',
'padding-top': '',
});
});
} else {
project.header.animate({
'padding-left': '0',
'padding-top': '0',
}, 1000, () => {
project.header.css({
'padding-left': '',
'padding-top': '',
});
});
}
} else {
if (griffen.viewportWidth >= griffen.mobileSize) {
project.header.animate({
'padding-left': '250px',
}, 1000, () => {
project.header.css({
'padding-left': '',
});
});
}
}
};
if (project.container.scrollTop() !== 0) {
project.container.animate({
'scrollTop': 0,
}, 500, () => {
close();
});
} else {
close();
}
};
let toggleProject = (project) => {
'use strict';
if (griffen.projectVisible === false) {
if (griffen.projectOpening === false && griffen.projectClosing === false) {
griffen.projectOpening = true;
griffen.projectVisible = true;
openProject(project);
}
} else {
if (griffen.projectOpening === false && griffen.projectClosing === false) {
griffen.projectClosing = true;
closeProject(project);
}
}
};
let inciteWater = {
article: $('#incite-water'),
container: $('#incite-water-container'),
header: $('#incite-water-header'),
heading: $('#incite-water-heading'),
content: $('#incite-water-content'),
tabButton: $('#incite-water-button'),
id: 'incitewater',
};
console.log(inciteWater);
inciteWater.tabButton.click((e) => {
'use strict';
e.preventDefault();
$('.project-link').attr('aria-selected', 'false');
$('[role="tabpanel"]').attr('aria-hidden', 'true');
toggleProject(inciteWater);
});
let $closeInciteWater = $('#close-incite-water-button');
$closeInciteWater.click((e) => {
'use strict';
e.preventDefault();
$('.project-link').attr('aria-selected', 'false');
$('[role="tabpanel"]').attr('aria-hidden', 'true');
closeProject(inciteWater);
});
#introduction,
#sidebar {
box-sizing: border-box;
width: 100vw;
height: 100vh;
position: fixed;
opacity: 0;
z-index: -1;
}
.project,
.project-container {
overflow: hidden;
background-color: #fff
}
section>header {
text-align: center
}
section p {
font-size: 1.2em;
font-weight: 400;
line-height: 2;
margin: 1em 0
}
.project-date,
.project-header {
font-weight: 300;
text-transform: uppercase
}
.image {
font-size: 1em;
font-style: italic;
text-align: center
}
.icon,
.project-header {
-webkit-box-align: center;
display: -webkit-box
}
.project-content-title,
.project-header h3 {
font-family: "Krona One", "IBM Plex Sans", "Hiragino Maru Gothic ProN", sans-serif;
font-size: 1.6em
}
.project {
background-size: cover;
height: 40vh;
min-height: 250px;
position: relative;
width: 100%
}
.project-container,
.project-container>header {
height: 100%;
position: relative;
max-height: 100vh;
width: 100%
}
.project-container {
-webkit-overflow-scrolling: touch;
right: 0
}
.project-container>header {
overflow: hidden
}
.project-container.full .project-header,
.project-link {
position: absolute
}
.project-container.full {
/* overflow-x:hidden; */
;
overflow-y: scroll
}
.project-link {
clip: rect(auto, auto, auto, auto);
bottom: 0;
left: 0;
right: 0;
top: 0
}
.project-header {
-ms-flex-align: center;
align-items: center;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: #fff;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: reverse;
-ms-flex-direction: column-reverse;
flex-direction: column-reverse;
height: 60vh;
right: 0;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
max-height: 100vh;
position: fixed;
top: 50%;
-webkit-transform: translate3d(0, -50%, 0);
transform: translate3d(0, -50%, 0);
-webkit-transition: .25s opacity, .25s visibility, .25s top;
-o-transition: .25s opacity, .25s visibility, .25s top;
transition: .25s opacity, .25s visibility, .25s top;
width: 100%
}
#contact,
#contact-form {
-webkit-box-orient: vertical;
-webkit-box-direction: normal
}
.project-header h3 {
text-align: center
}
.project-pre-title {
margin: 0 0 2em;
position: relative
}
.project-pre-title::after {
background-color: #fff;
bottom: -1em;
content: '';
height: 1px;
left: 50%;
position: absolute;
-webkit-transform: translate3d(-50%, 0, 0);
transform: translate3d(-50%, 0, 0);
width: 8em
}
.project-content {
margin: 0 auto;
max-width: 960px;
padding: 2em;
position: relative;
z-index: 150;
}
.project-content-intro {
margin-bottom: 2em
}
.project-content-title {
text-transform: uppercase
}
.project-date {
margin: .5em 0
}
.close-project-button-dang {
cursor: pointer;
position: absolute;
right: 3em;
top: 3em;
width: 3em;
height: 3em;
background-image: url(../icons/cancel.svg);
background-size: cover;
opacity: 0;
-webkit-transition: .5s opacity;
-o-transition: .5s opacity;
transition: .5s opacity
}
#incite-water-heading {
background-image: url(https://toucan-sam.firebaseapp.com/assets/images/water-drops.jpeg);
background-position: center;
background-size: cover
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="introduction">
INTRODUCTION
</div>
<div id="sidebar">
SIDEBAR
</div>
<article class="project" id="incite-water">
<div class="project-container" id="incite-water-container">
<header id="incite-water-heading">
<a href="#incite-water" tabindex="0" class="project-link" id="incite-water-button" role="tab" aria-controls="incite-water-content" data-project="inciteWater">
<div class="project-header" id="incite-water-header">
<h3>Incite Water</h3>
<span class="project-pre-title">Web Design & Development</span>
</div>
</a>
</header>
<div class="project-content" tabindex="0" id="incite-water-content" aria-hidden="true" role="tabpanel" aria-labelledby="incite-water-button">
<div class="project-content-intro">
<div class="project-content-title">Incite Water</div>
<div class="project-date">October 2017 – March 2018</div>
</div>
<p>This year, for the Alaska Airlines Environmental Innovation Challenge, I worked on a project called Incite Water. Our team
was comprised of peers from various departments and the goal was to create a simple yet powerful interface that would encourage people to save water. We hoped to do this by demonstrating how much money people could personally save while mitigating
the potential environmental impacts of wasting water.</p>
<p>For this project, I worked as the sole web developer. I created the interface of the site as well as the background connections with our servers. In a small group, we programmed the “calculator” first using client-side JavaScript. I then implemented
the calculation using Node.js to run server-side to protect some sensitive information from exposure and to allow for easier implementation with the Firebase platform used to host the project.</p>
<p>My role went beyond web development and extended to providing direction for our technology-based decisions and assessing feasibility. I advised we use Google’s Firebase platform to take advantage the free low-traffic hosting and integration with
various database structures and cloud computing functions that enabled the quick prototyping of the product.</p>
<p>Though we chose to go with a high-fidelity prototype, it is still a prototype. We hoped that by presenting a more realized product to judges our vision would be more effectively conveyed. Because it is still an early prototype, we need to perform
additional user research and usability testing to determine our next course of action. I anticipate further adjustments to our calculator as well as increased outreach and awareness campaigns to involve more members of the public.</p>
<p>Visit Incite Water</p>
← Return<span class="sr-only"> to the main page</span>
</div>
</div>
</article>
I wanted to combine this function of showing a picture (our logo) on my Shopify frontage website fullscreen and make it fade away or vanish after seconds automatically so people can access to the website after the Image or our logo is gone (2 Sec).
Now I have these two parts of HTML, but they don't work together somehow.
Can someone help?
Thank you
<div id="makethisvanish"><img src="image"></div>
<div class="fixed-background">
<img src="image" class="myimg">
</div>
<script type="text/javascript">
window.onload = function () {
window.setTimeout( vanishText, 2000 ); // 2000 is 2 seconds
}
function vanishText() {
document.getElementById( 'makethisvanish' ).style.visibility = 'hidden';
}
</script>
<style>
body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
.fixed-background {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
overflow: hidden;
}
.myimg {
height: inherit;
}
</style>
Try the code below:
<head>
<script>
window.onload = function () {
window.setTimeout(vanishText,2000); // 2000 is 2 seconds
}
function vanishText() {
document.getElementById('makethisvanish').style.opacity = '0';
}
</script>
<style>
body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
#makethisvanish {
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
min-height: 100%;
height: auto;
opacity: 1;
z-index:1000;
margin: 0 auto;
transition: opacity .5s linear;
}
#makethisvanish img {
width: 100%;
height: auto;
}
.fixed-background {
position: relative;
top: 0;
left: 0;
height: 100%;
overflow: hidden;
}
.grid__item {
height: 50px;
}
.myimg {
height: 100%;
width: auto;
}
</style>
</head>
<body>
<div id="makethisvanish">
<img src="http://i65.tinypic.com/5nn1va.jpg">
</div>
<div class="grid__item">
<div class="fixed-background">
<img src="http://i65.tinypic.com/5nn1va.jpg" class="myimg">
</div>
</div>
</body>
I believe this should do?
Report back if you have a problem. I'll try to help you solve it ;)
EDIT
For only the full-screen picture you'll need even less:
<head>
<script>
window.onload = function () {
window.setTimeout(vanishText,2000); // 2000 is 2 seconds
}
function vanishText() {
document.getElementById('makethisvanish').style.opacity = '0';
}
</script>
<style>
#makethisvanish {
display: block;
position: fixed;
top: 0;
left: 0;
width: 100%;
min-height: 100%;
height: auto;
opacity: 1;
z-index:1000;
margin: 0 auto;
transition: opacity .5s linear;
}
#makethisvanish img {
width: 100%;
height: auto;
}
</style>
</head>
<body>
<div id="makethisvanish">
<img src="http://i65.tinypic.com/5nn1va.jpg">
</div>
</body>
Maybe you'll need another line in vanishText():
document.getElementById('makethisvanish').style.zIndex = "0";
But try with the code above first.
EDIT_2
replace the script in the head with the following:
window.onload = function () {
window.setTimeout(vanishText,2000); // 2000 is 2 seconds
}
var IDLE_TIMEOUT = 60; //seconds
var _idleSecondsCounter = 0;
window.setInterval(CheckIdleTime, 1000);
function CheckIdleTime() {
_idleSecondsCounter++;
if (_idleSecondsCounter >= IDLE_TIMEOUT) {
screensaver();
}
}
function vanishText() {
document.getElementById('makethisvanish').style.opacity = '0';
document.getElementById('makethisvanish').style.zIndex = '-1';
}
function screensaver() {
document.getElementById('makethisvanish').style.zIndex = "1000";
document.getElementById('makethisvanish').style.opacity = "1";
}
function resetTimer() {
if(_idleSecondsCounter >= IDLE_TIMEOUT) {
vanishText();
}
_idleSecondsCounter = 0;
}
document.onclick = function() {
resetTimer();
};
document.onmousemove = function() {
resetTimer();
};
document.onkeypress = function() {
resetTimer();
};
You'll probably have to adapt the IDLE_TIMEOUT. It's set to 5 seconds for testing. I would probably set it to one minute, maybe a bit more. The "screensaver" should dissappear if the mouse is moved, a mouseclick is done or a key on the keyboard is pressed.