У меня есть одностраничный сайт с пятью полноэкранными «проблемными» картами (#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
JavaScript/CSS Smooth «Iris» Переход прокрутки: кружок растет, но не будет сокращаться на прокрутке ⇐ Javascript
Форум по Javascript
1750266044
Anonymous
У меня есть одностраничный сайт с пятью полноэкранными «проблемными» картами (#problems) и фиксированный раздел «время решения» (#solutions< /code>).
Когда пользователь прокручивает прошлое задача 5 Проблема 5 Круглая маска должна расти из центра (Radius 0 → Full Viewport) раскрывая #Solutions < /code>. Прокрутка работает отлично. < /P>
[b] проблема < /strong>
Когда круг достигает полноразмерного, и я прокручиваю обратно, страница мгновенно прыгает в проблему 5, а кружок закрывает-нет плавного, пропорционального сжимания при протест. /> [*] Scroll Down: [/b] Circle Растет 0 → Макс. Раскрытие «время решения».
[b] Прокрутка: [/b] Круг должен сократить макс. /> Сохранить три файла ниже в одной папке. />
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;
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79671057/javascript-css-smooth-iris-scroll-transition-circle-grows-but-won-t-shrink-on[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия