JavaScript/CSS Smooth «Iris» Переход прокрутки: кружок растет, но не будет сокращаться на прокруткеHtml

Программисты Html
Ответить
Anonymous
 JavaScript/CSS Smooth «Iris» Переход прокрутки: кружок растет, но не будет сокращаться на прокрутке

Сообщение Anonymous »

У меня есть одностраничный сайт с пятью полноэкранными картами «проблемы» (

Код: Выделить всё

#problems
) и фиксированный раздел «время решения» (

Код: Выделить всё

#solutions
). Когда пользователь прокручивает прошлую проблему 5, круговая маска должна расти из центра (радиус 0 → полный просмотр), раскрывающего #Solutions . Прокрутка работает отлично. max, revealing 'Solution time'.
[*]Scroll-up: circle should shrink max → 0, smoothly revealing Problem 5 again (no jump).


Код: Выделить всё

(() => {
// Get the two sections: the problems you scroll past and the solutions you reveal
const problems = document.getElementById('problems');
const solutions = document.getElementById('solutions');
const body = document.body;
const html = document.documentElement;

/* -------- Robust way to read the current vertical scroll position -------- */
const getScrollY = () =>
window.pageYOffset ||
html.scrollTop ||
body.scrollTop ||
window.visualViewport?.offsetTop ||
0;

/* -------- Calculate the vertical boundaries where the clip animation starts/ends -------- */
let viewportHeight = window.innerHeight;
// The top position of the solutions section
let topOfSolutions = problems.offsetTop + problems.offsetHeight;
// When to start revealing solutions: one viewportHeight before the section
let startReveal = topOfSolutions - viewportHeight;
// When to be fully revealed
let endReveal = topOfSolutions;

let revealRatio = 0; // Will go from 0 (hidden) to 1 (fully revealed)
let isLocked = false; // Are we locking the page scroll to control the reveal?

/* Maximum radius for the circular clip: half the diagonal of the viewport */
const maxRadius = () => Math.hypot(window.innerWidth / 2, window.innerHeight / 2);

/* Apply the circular clip with given radius (in pixels) */
const setRadius = (r) => {
const clip = `circle(${r}px at 50% 50%)`;
solutions.style.clipPath = clip;
solutions.style.webkitClipPath = clip;
};

/* -------- Functions to lock/unlock the normal page scroll -------- */
const lockScroll = (yPos) => {
isLocked = true;
body.style.overflow = 'hidden';
window.scrollTo(0, yPos);
};
const unlockScroll = (yPos) => {
isLocked = false;
body.style.overflow = 'auto';
window.scrollTo({
top: yPos,
behavior: 'auto'
});
};

/* ---------- Main scroll handler: controls the clip during scrolling ---------- */
window.addEventListener('scroll', () => {
if (isLocked) return; // if we're locked, ignore normal scroll events

const currentY = getScrollY();

if (currentY < startReveal) {
// Above the start zone: keep circle closed
revealRatio = 0;
setRadius(0);
return;
}
if (currentY > endReveal) {
// Below the end zone: circle fully open
revealRatio = 1;
setRadius(maxRadius());
return;
}

// Inside the transition zone: compute how far we are in it
revealRatio = (currentY - startReveal) / (endReveal - startReveal);
setRadius(revealRatio * maxRadius());

// Lock the scroll so we can use wheel/touch to drive the reveal
// Decide which edge to snap to if the user reverses direction
const midpoint = (startReveal + endReveal) / 2;
lockScroll(currentY < midpoint ? startReveal : endReveal);
}, {
passive: true
});

/* ---------- Helper to advance the reveal by a delta, then release lock if done ---------- */
const advanceReveal = (deltaY) => {
// convert delta scroll into a change in ratio
revealRatio = Math.max(0, Math.min(1, revealRatio + deltaY / viewportHeight));
setRadius(revealRatio * maxRadius());

if (revealRatio === 1) unlockScroll(endReveal); // fully revealed → resume normal scroll down
if (revealRatio === 0) unlockScroll(startReveal); // fully hidden → resume normal scroll up
};

/* ---------- Mouse wheel while locked: drive the reveal ---------- */
window.addEventListener('wheel', (e) => {
if (!isLocked) return; // only intercept if we're in the locked state
e.preventDefault(); // prevent the page from scrolling
advanceReveal(e.deltaY);
}, {
passive: false
});

/* ---------- Touch drag while locked: similar to wheel ---------- */
window.addEventListener('touchmove', (e) =>  {
if (!isLocked) return;
e.preventDefault();
const touch = e.touches[0];
if (touch._prevY === undefined) {
touch._prevY = touch.clientY;
}
const dy = touch._prevY - touch.clientY;
touch._prevY = touch.clientY;
advanceReveal(dy);
}, {
passive: false
});

/* ---------- Recalculate dimensions on resize ---------- */
window.addEventListener('resize', () => {
viewportHeight = window.innerHeight;
topOfSolutions = problems.offsetTop + problems.offsetHeight;
startReveal = topOfSolutions - viewportHeight;
endReveal = topOfSolutions;
if (!isLocked) {
// update current clip if not locked
setRadius(revealRatio * maxRadius());
}
});
})();< /code>
html,
body {
height: 100%;
margin: 0;
font-family: sans-serif
}

/* Problems */
#problems {
scroll-snap-type: y mandatory;
position: relative
}

#problems h1 {
position: sticky;
top: 0;
background: #fff;
padding: 1rem;
text-align: center;
z-index: 1
}

.card {
height: 100vh;
scroll-snap-align: start;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
color: #fff
}

.card:nth-child(2) {
background: #90caf9
}

.card:nth-child(3) {
background: #a5d6a7
}

.card:nth-child(4) {
background: #ce93d8
}

.card:nth-child(5) {
background: #ffcc80
}

/* Solutions (masked) */
#solutions {
position: fixed;
inset: 0;
background: #000;
color: #fff;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
clip-path: circle(0px at 50% 50%);
-webkit-clip-path: circle(0px at 50% 50%);
pointer-events: none;
z-index: 50;
}< /code>

Do you know these problems?
Problem 1
Problem 2
Problem 3
Problem 4
Problem 5




Solution



Подробнее здесь: https://stackoverflow.com/questions/796 ... -shrink-on
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Html»