Change z-index of stacked divs when scrolling - javascript

I have 2 divs with position:fixed, top:0, left: 0 and 100% in height and width on top of each other.
I'm trying to be able to scroll through the divs by changing the z-index, as I scroll. I have no idea how to achieve this.
In other words, trying to create a scrollable page without having to visually scroll vertically or horizontally. Instead staying on the same spot and reveal the content by changing z-index, if that makes sense.
Thank you in advance.

You can do it as you asked:
const sections = document.querySelectorAll('section');
let active = 0,
delayTimer = null;
addEventListener('wheel', e => {
// If we just scrolled, don't do anything
if (delayTimer !== null) return;
// Apply the section change
const upwards = e.deltaY < 0;
if ((upwards && active > 0) || (!upwards && active < sections.length - 1)) {
// Make the current one go one level below
const previous = sections[active];
previous.classList.add('previous');
previous.classList.remove('active');
// In 500ms, the animation will be over, hide it
setTimeout(() => previous.classList.remove('previous'), 500);
// Move the new current one to the front
active += upwards ? -1 : 1;
sections[active].classList.add('active');
}
// Prevent that from happening again during the next 500ms
// so that we don't scroll multiple sections at once
delayTimer = setTimeout(() => { delayTimer = null; }, 500);
});
body { background: #222; }
section {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
background: #555; color: #fff;
font-family: Arial, Helvetica, sans-serif;
text-align: center;
display: none;
}
section:nth-child(1) { background: #6A46F2; }
section:nth-child(2) { background: #F28B77; }
section:nth-child(3) { background: #A1BA44; }
section:nth-child(4) { background: #52bc93; }
section.previous, section.active {
display: block;
z-index: 1;
}
section.active {
z-index: 2;
animation: fadeIn .4s ease;
}
#keyframes fadeIn {
from { opacity: 0; transform: scale(.6); }
to { opacity: 1; transform: scale(1); }
}
<section class="active"><h1>Section A</h1><p>Some content A</p></section>
<section><h1>Section B</h1><p>Some content B</p></section>
<section><h1>Section C</h1><p>Some content C</p></section>
<section><h1>Section D</h1><p>Some content D</p></section>

Related

How to add text to cursor on hover

I have managed to put together a custom cursor that changes when hovering on different data-type. For this example, when you hover on the first image the cursor changes to a pause icon, when you hover on the second image the cursor changes to a play icon, I would like to change the play icon to just the text "play" instead of the icon.
const cursor = document.getElementById("cursor");
const animateCursor = (e, interacting) => {
const x = e.clientX - cursor.offsetWidth / 2,
y = e.clientY - cursor.offsetHeight / 2;
const keyframes = {
transform: `translate(${x}px, ${y}px) scale(${interacting ? 8 : 1})`
}
cursor.animate(keyframes, {
duration: 800,
fill: "forwards"
});
}
const getCursorClass = type => {
switch(type) {
case "video":
return "fa-solid fa-play";
case "image":
return "fa-solid fa-pause";
default:
return "fa-solid fa-arrow-up-right";
}
}
window.onmousemove = e => {
const interactable = e.target.closest(".interactable"),
interacting = interactable !== null;
const icon = document.getElementById("cursor-icon");
animateCursor(e, interacting);
cursor.dataset.type = interacting ? interactable.dataset.type : "";
if(interacting) {
icon.className = getCursorClass(interactable.dataset.type);
}
}
body {
background-color: rgb(20, 20, 20);
height: 100vh;
margin: 0px;
display: flex;
align-items: center;
justify-content: center;
gap: clamp(10px, 4vw, 100px);
}
body:hover > #cursor {
opacity: 1;
}
#cursor {
height: 20px;
width: 20px;
background-color: white;
border-radius: 20px;
position: fixed;
left: 0px;
top: 0px;
z-index: 10000;
pointer-events: none;
opacity: 0;
transition: opacity 500ms ease;
display: grid;
place-items: center;
}
#cursor:not([data-type=""]) > #cursor-icon {
opacity: 1;
}
#cursor-icon {
font-size: 6px;
line-height: 0px;
opacity: 0;
transition: opacity 400ms ease;
}
.interactable {
aspect-ratio: 1 / 1.5;
width: clamp(120px, 40vmin, 600px);
background-position: center 50%;
background-size: 100%;
opacity: 0.4;
transition: background-size 400ms ease, opacity 400ms ease;
}
.interactable:hover {
background-size: 105%;
opacity: 0.8;
}
<script src="https://kit.fontawesome.com/944eb371a4.js"></script>
<div id="cursor">
<i id="cursor-icon" class="fa-solid fa-arrow-up-right"></i>
</div>
<div
class="interactable"
data-type="image"
style="background-image: url(https://images.unsplash.com/photo-1657739774592-14c8f97eaece?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwyfHx8ZW58MHx8fHw%3D&auto=format&fit=crop&w=500&q=60)">
</div>
<div
class="interactable"
data-type="video"
style="background-image: url(https://images.unsplash.com/photo-1657779582398-a13b5896ff19?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxlZGl0b3JpYWwtZmVlZHwzNXx8fGVufDB8fHx8&auto=format&fit=crop&w=500&q=60)">
</div>
Add a new class named play in the css file
.play::after {
content: "Play";
font-style: normal;
}
Then add the new class name in the following portion of the JS file.
const getCursorClass = type => {
switch(type) {
case "video":
return "play"; // <--- add the class name here
case "image":
return "fa-solid fa-pause";
default:
return "fa-solid fa-arrow-up-right";
}
}
Codepen URL
There is no built-in way to do this, but it is possible with a little bit of CSS.
First, you need to add a span element after the cursor. This will be the element that contains the text that you want to display on hover.
<span class="cursor-text">Text that appears on hover</span>
Then, you need to add some CSS to position the span element and to hide it by default.
.cursor-text { position: absolute; top: 0; left: 0; opacity: 0; }
Finally, you need to add a CSS rule to show the span element on hover.
.cursor:hover .cursor-text { opacity: 1; }

Display div based on scroll up and div from current position

I am working on small application
i want to display the div if the user scroll up to > 100px from the current position and hide div if the user scroll down to > 50 px from current postion
example code
myID = document.getElementById("myID");
var myScrollFunc = function() {
var y = window.scrollY;
if (y >= 200) {
myID.className = "bottomMenu show"
} else {
myID.className = "bottomMenu hide"
}
};
window.addEventListener("scroll", myScrollFunc);
body {
height: 2000px;
}
.bottomMenu {
position: fixed;
bottom: 0;
width: 100%;
height: 60px;
border-top: 1px solid #000;
background: red;
z-index: 1;
transition: all 1s;
}
.hide {
opacity: 0;
left: -100%;
}
.show {
opacity: 1;
left: 0;
}
<div id="myID" class="bottomMenu hide"></div>
can any one help with code in javascript
Finded the way to solve this
first we want to get the scroll direction
and create two counter 1.upcounter 2. down counter
and if we start scroll up increase the upcounter and set down counter
to 0
and if we start scroll dow increase the downcounter and set up
counter to 0
if the up counter value reaches your value for example if reaches 100
display the div
and if the down counter reaches your value for example if reaches 50
hide the div
code example
myID = document.getElementById("myID");
function showSmartMenu() {
// current scroll position
var st = window.pageYOffset || document.documentElement.scrollTop;
// scrolling up
if (st < lastScrollTop) {
upCounter += 1;
downCounter = 0;
if (upCounter == 100) {
myID.className = "bottomMenu show"
}
} else { // scrolling down
downCounter -= 1;
upCounter = 0;
if (downCounter == -50) {
myID.className = "bottomMenu hide"
}
}
lastScrollTop = st <= 0 ? 0 : st;
}
var lastScrollTop = 0;
var upCounter = 0
var downCounter = 0
window.addEventListener("scroll", showSmartMenu)
body {
height: 2000px;
}
.bottomMenu {
position: fixed;
bottom: 0;
width: 100%;
height: 60px;
border-top: 1px solid #000;
background: red;
z-index: 1;
transition: all 1s;
}
.hide {
opacity: 0;
left: -100%;
}
.show {
opacity: 1;
left: 0;
}
<div id="myID" class="bottomMenu hide"></div>

CSS Animation Won't Play Per Click

I built a carousel for some images. I need my 'next' and 'previous' buttons to use the CSS animation that I assigned them in my javascript function for their event listeners.The animation will only play for one click, and when the buttons are clicked again to navigate the carousel the animation doesn't play. I need the buttons to grow and shrink for every click.
Here's the CSS:
.carousel-actions {
position: absolute;
display: flex;
justify-content: space-between;
width: 105%;
top: 30%;
}
.carousel-actions button {
padding: 30px 50px;
background-color: rgba(255, 255, 255, 0.329);
font-weight: 900;
cursor: pointer;
border-radius: 100px;
border: 0;
font-size: 60px;
color: black;
outline: none;
}
#keyframes grow {
0% {
transform: scale(1);
}
50% {
transform: scale(1.3);
}
100% {
transform: scale(1);
}
}
Here's the HTML:
<div class="carousel-actions">
<button id="prev" aria-label="Previous Slide"><</button>
<button id="next" aria-label="Next Slide">></button>
</div>
Here's the JS:
const slides = document.querySelectorAll(".carousel-item");
const totalSlides = slides.length;
let slidePosition = 0;
console.log(totalSlides);
const next = document.getElementById("next");
const prev = document.getElementById("prev");
function hideAllSlides() {
for (const slide of slides) {
slide.classList.remove("carousel-item-visible") &&
slide.classList.add("carousel-item-hidden");
}
}
function nextSlide() {
hideAllSlides();
if (slidePosition === totalSlides - 1) {
slidePosition = 0;
} else {
slidePosition++;
}
slides[slidePosition].classList.add("carousel-item-visible");
next.style.animation = "grow 1s";
}
function prevSlide() {
hideAllSlides();
if (slidePosition === 0) {
slidePosition = totalSlides - 1;
} else {
slidePosition--;
}
slides[slidePosition].classList.add("carousel-item-visible");
prev.style.animation = "grow 1s";
}
next.addEventListener("click", nextSlide);
prev.addEventListener("click", prevSlide);
The problem is seen because once the system has played the animation it thinks 'well, I've played it'. Setting it to the same again does not make it play again.
To get round this you can unset the animation when it has finished.
In your code add an event listener for the animationend event.
Here's a simplified example:
const div = document.querySelector('div');
div.addEventListener('click', function() { div.style.animationName='grow';});
div.addEventListener('animationend', function() { div.style.animationName='';});
div {
width: 100px;
height: 100px;
background-color: blue;
animation-duration: 1s;
animation-iteration-count: 1;
}
#keyframes grow {
0% {
transform: scale(1);
}
50% {
transform: scale(1.3);
}
100% {
transform: scale(1);
}
<div></div>

Changing CSS parameters based on scroll position

In the example below, I have two invisible buttons – button in the right half, on click, horizontally scrolls to the next section, and the button in the left half to the previous section. Buttons show left and right arrow cursors when user hovers over them for displaying scroll direction.
I would like to toggle the cursor of goToPreviousSectionButton to default when scrollPosition === 0, and same for goToNextSectionButton when scrollPosition === maxScrollPosition.
To put it plainly: when you run the code snippet, hover your mouse cursor to the left of number 1. You can see that it’s a left arrow cursor now. I would like it to be a default cursor, since you can’t go left because you’re at the beginning. Same when you reach to the number 3, but this time for the right arrow, since you can’t go any further, so it’s pointless for the right arrow to be shown.
I’m having trouble getting this to work. Any help would be greatly appreciated.
let scrollPosition = 0
const maxScrollPosition = document.body.scrollWidth - window.innerWidth
const goToPreviousSectionButton = document.createElement("button")
const goToNextSectionButton = document.createElement("button")
document.body.appendChild(goToPreviousSectionButton)
document.body.appendChild(goToNextSectionButton)
if (scrollPosition === 0) {
// If scroll position is at the beginning
}
if (scrollPosition === maxScrollPosition) {
// If scroll position at the end
}
goToPreviousSectionButton.addEventListener("click", () => {
window.scrollBy(-window.innerWidth, 0)
})
goToNextSectionButton.addEventListener("click", () => {
window.scrollBy(window.innerWidth, 0)
})
* {
margin: 0;
padding: 0
}
html { height: 100% }
html, body, main {
display: flex;
flex-grow: 1
}
section {
display: grid;
place-items: center;
flex: 1 0 100%
}
section:nth-of-type(1) { background: orange }
section:nth-of-type(2) { background: limeGreen }
section:nth-of-type(3) { background: royalBlue }
h2 { color: white }
button {
background: transparent;
position: fixed;
top: 0;
width: 50%;
height: 100%;
border: none;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent
}
:focus { outline: none }
button:nth-of-type(1) { /* Left button */
left: 0;
cursor: w-resize
}
button:nth-of-type(2) { /* Right button */
right: 0;
cursor: e-resize
}
<main>
<section>
<h2>1</h2>
</section>
<section>
<h2>2</h2>
</section>
<section>
<h2>3</h2>
</section>
</main>
One idea is to add extra elements using pseudo-element that you will cover your invisible buttons and disable the action on them:
const goToPreviousSectionButton = document.createElement("button")
const goToNextSectionButton = document.createElement("button")
document.body.appendChild(goToPreviousSectionButton)
document.body.appendChild(goToNextSectionButton)
goToPreviousSectionButton.addEventListener("click", () => {
window.scrollBy(-window.innerWidth, 0)
})
goToNextSectionButton.addEventListener("click", () => {
window.scrollBy(window.innerWidth, 0)
})
* {
margin: 0;
padding: 0
}
html,body { height: 100% }
body, main {
display: flex;
flex-grow: 1
}
section {
display: grid;
place-items: center;
flex: 1 0 100%
}
section:nth-of-type(1) { background: orange }
section:nth-of-type(2) { background: limeGreen }
section:nth-of-type(3) { background: royalBlue }
h2 { color: white }
button {
background: transparent;
position: fixed;
top: 0;
width: 50%;
height: 100%;
border: none;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent
}
:focus { outline: none }
button:nth-of-type(1) { /* Left button */
left: 0;
cursor: w-resize
}
button:nth-of-type(2) { /* Right button */
right: 0;
cursor: e-resize
}
/* Added */
main:before,
main:after{
content:"";
z-index:9;
position:relative;
flex: 1 0 50%;
}
main:before {
margin-right:-50%;
}
main:after {
margin-left:-50%;
}
/**/
<main>
<section>
<h2>1</h2>
</section>
<section>
<h2>2</h2>
</section>
<section>
<h2>3</h2>
</section>
</main>
if (scrollPosition === 0) {
goToPreviousSectionButton.classList.add('default')
}
if (scrollPosition === maxScrollPosition) {
goToPreviousSectionButton.classList.add('default')
}
css:
.default {
cursor: default
}

Perfectly positioned tooltips with position: fixed

I'm trying to create some very basic tooltips but I'm having trouble calculating the exact position these should go in with some JavaScript. The reason for wanting a fixed position is to make sure these work whenever there is overflow hidden and such.
This is my code so far:
var overflowTooltip = function (elem) {
let legendRow = elem.currentTarget.getBoundingClientRect();
let tooltip = elem.currentTarget.children[2];
let topPosition;
let leftPosition;
if ((elem.currentTarget.offsetWidth < elem.currentTarget.scrollWidth) && tooltip !== undefined) {
tooltip.classList.add('total-opacity');
$timeout(function () {
if (tooltip.offsetHeight > 35) {
topPosition = (legendRow.top - tooltip.offsetHeight / 4) - 65;
} else {
topPosition = legendRow.top - 65;
}
leftPosition = (legendRow.left + elem.currentTarget.offsetWidth) / 2;
tooltip.style.left = leftPosition + 'px';
tooltip.style.top = topPosition + 'px';
$timeout(function () {
tooltip.classList.remove('total-opacity');
}, 400)
}, 100);
} else {
elem.currentTarget.children[2].style.left = '-9999px';
}
}
And some SASS:
.custom-tooltip {
font-family: $brand-font-condensed;
font-size: 14px;
font-weight: 400;
position: fixed;
text-align: left;
overflow: visible !important;
background-color: rgba($dark-gray, 0.95);
color: #fff;
height: auto;
padding: 7px 10px;
z-index: 9000;
visibility: hidden;
opacity: 0;
border-radius: 2px;
box-shadow: 0 2px 5px 0 rgba(#000, 0.16), 0 2px 10px 0 rgba(#000, 0.12);
#include transition (.2s ease-in);
left: -9999px;
&:hover {
visibility: visible;
opacity: 1;
#include transition (.2s ease-out);
-webkit-transition-delay: .3s;
transition-delay: .3s;
}
}
The above works but it's not perfect. if I wanna change around the position for it to appear on the left, right, bottom. I'd have to so some refactoring. If the tooltip's height is bigger or smaller, the position changes, If I scroll up or down, the tooltip stays stuck on screen for a few seconds. etc. Lots of these little details which are pretty annoying.
Not interested in using a plugin at the moment nor jQuery. Thanks for any suggestion or feedback :)

Categories

Resources