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

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

Сообщение Anonymous »

У меня есть одностраничный сайт с пятью полноэкранными «проблемными» картами (#problems) и фиксированный раздел «время решения» (#solutions< /code>).

Когда пользователь прокручивает прошлое задача 5 Проблема 5 Круглая маска должна расти из центра (Radius 0 → Full Viewport) раскрывая #Solutions < /code>. Прокрутка работает отлично. < /P>
проблема < /strong>

Когда круг достигает полноразмерного, и я прокручиваю обратно, страница мгновенно прыгает в проблему 5, а кружок закрывает-нет плавного, пропорционального сжимания при протест. />
[*] Scroll Down: [/b] Circle Растет 0 → Макс. Раскрытие «время решения».
Прокрутка: Круг должен сократить макс. /> Сохранить три файла ниже в одной папке. />
script.js
(() => {
// 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>
index.html





Iris Demo





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




Solution





< /code>
style.css
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;
}


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

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

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

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

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

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