Пересчитать положение прокрутки div при использовании в обтравочном контуре
Я использую обтравочные контуры, чтобы изменить цвет моего логотипа на цвет фона.
В дополнение к этому логотип прокручивается сверху вниз в зависимости от вертикального положения пользователя на странице. Верхняя часть страницы = логотип сверху, нижняя часть страницы = логотип снизу и т.д.
К сожалению, когда я добавил обтравочные контуры, логотипы потеряли свое положение прокрутки и после первого не работают вообще.
Это можно обойти? Кроме того, с самого начала положение логотипа было немного неправильным, поэтому есть ли возможность решить эту проблему одновременно.
Вы можете увидеть оригинальный вопрос здесь:
положение дел на основе позиции прокрутки
Я пробовал это, но я не могу заставить его работать.
Положение прокрутки потеряно при скрытии div
Я использую Расширенные пользовательские поля, и каждый раздел PHP файла содержит это в заголовке как часть обтравочного контура, используя соответственно белую или темную версию логотипа. Его родитель позиционируется относительно, а его ребенок абсолютно.
div class="logo-scroll">
<div class="scroll-text">
<a href="/home"><img width="53px" height="260px" src="/wp-content/uploads/2019/07/sheree-walker-web-design-edinburgh-vertical-01.svg"/></a>
</div>
</div>
Javascript
const docHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
const logo = document.querySelector('.scroll-text');
const logoHeight = logo.offsetHeight;
// to get the pseudoelement '#page::before' top we use getComputedStyle method
const barTopMargin = parseInt(getComputedStyle(document.querySelector('#page'), '::before').top);
let viewportHeight, barHeight, maxScrollDist, currentScrollPos, scrollFraction;
logo.style.top = barTopMargin + 'px';
window.addEventListener('load', update);
window.addEventListener('resize', setSizes);
document.addEventListener('scroll', update);
setSizes();
function update() {
currentScrollPos = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
scrollFraction = currentScrollPos / (docHeight - viewportHeight);
logo.style.top = barTopMargin + (scrollFraction * maxScrollDist) + 'px';
}
function setSizes() {
viewportHeight = window.innerHeight;
// to get the pseudoelement '#page::before' height we use getComputedStyle method
barHeight = parseInt(getComputedStyle(document.querySelector('#page'), '::before').height);
maxScrollDist = barHeight - logoHeight;
update();
}
CSS
.logo-scroll .scroll-text img {
padding: 0 6px 0 17px;
}
#page::before {
content: "";
position: fixed;
top: 30px;
bottom: 30px;
left: 30px;
right: 30px;
border: 2px solid white;
pointer-events: none;
-webkit-transition: all 2s; /* Safari prior 6.1 */
transition: all 2s;
}
.logo-scroll {
position: fixed;
left: 30px;
top: 30px;
bottom: 30px;
border-right: 2px solid white;
width: 75px;
z-index: 10;
}
.scroll-text {
position: fixed;
}
Ответы
Ответ 1
let logos, logoHeight, barTopMargin;
let viewportHeight;
window.addEventListener('load', init);
window.addEventListener('resize', setSizes);
document.addEventListener('scroll', update);
function init(lockUpdate) {
logos = document.querySelectorAll('.scroll-text');
setSizes(lockUpdate);
}
function update() {
// ensure initialization and prevent recursive call
if (!logos) init(true);
//*************************************************
/**************************************************
THIS LINE MUST BE HERE.
**************************************************/
let maxScrollDist = document.documentElement.scrollHeight - viewportHeight;
//*************************************************
let currentScrollPos = document.documentElement.scrollTop;
let newTop;
let middle = currentScrollPos + viewportHeight/2;
let middleY = maxScrollDist/2;
if (middle >= (maxScrollDist+viewportHeight)/2) {
let p = (middleY - Math.floor(middle - (maxScrollDist+viewportHeight)/2))*100/middleY;
newTop = viewportHeight/2 - logoHeight/2;
newTop += (100-p)*(viewportHeight/2)/100;
newTop -= (100-p)*(barTopMargin +logoHeight/2)/100;
newTop = Math.max(newTop, viewportHeight/2 - logoHeight/2); /*fix*/
} else {
let p = (middleY - Math.floor(-middle + (maxScrollDist+viewportHeight)/2))*100/middleY;
newTop = barTopMargin*(100-p)/100+(viewportHeight/2 - (logoHeight/2)*p/100 )*p/100;
newTop = Math.min(newTop, viewportHeight/2 - logoHeight/2); /*fix*/
}
logos.forEach(function(el) {
el.style.top = newTop + "px";
});
}
function setSizes(lockUpdate) {
logoHeight = logos[0].offsetHeight;
barTopMargin = parseInt(getComputedStyle(document.querySelector('#page'), '::before').top);
viewportHeight = window.innerHeight;
if (lockUpdate === true) return;
update();
}
обновлено и проверено.
чтобы проверить, поместите этот код в консоль:
document.removeEventListener('scroll', update);
document.onscroll = function() {
let _logoHeight = logos[0].offsetHeight;
let _barTopMargin = parseInt(getComputedStyle(document.querySelector('#page'), '::before').top);
let _viewportHeight = window.innerHeight;
let _maxScrollDist = document.documentElement.scrollHeight - _viewportHeight;
let currentScrollPos = document.documentElement.scrollTop;
let percent100 = currentScrollPos + _viewportHeight;
let scrolledPercent = currentScrollPos * 100/_maxScrollDist;
let newTop = ((_viewportHeight - _logoHeight/2)*scrolledPercent/100);
let middle = currentScrollPos + _viewportHeight/2;
let middleY = _maxScrollDist/2; // 100
if (middle >= (_maxScrollDist+_viewportHeight)/2) {
let y1 = middleY - Math.floor(middle - (_maxScrollDist+_viewportHeight)/2);
let p = y1*100/middleY;
newTop = _viewportHeight/2 - _logoHeight/2;
newTop += (100-p)*(_viewportHeight/2)/100;
newTop -= (100-p)*(30 +_logoHeight/2)/100;
newTop = Math.max(newTop, _viewportHeight/2 - _logoHeight/2); /*fix*/
} else {
let y2 = middleY - Math.floor(-middle + (_maxScrollDist+_viewportHeight)/2);
let p = y2*100/middleY;
newTop = 30*(100-p)/100+(_viewportHeight/2 - (_logoHeight/2)*p/100 )*p/100;
newTop = Math.min(newTop, _viewportHeight/2 - _logoHeight/2); /*fix*/
}
logos.forEach(function(el) {
el.style.top = newTop + "px";
});
}
CSS исправить:
custom.css :: line 767
@media (max-width: 1000px)...
.scroll-text {
padding-left: 13px;
/*width: 27px;*/
}
.scroll-text img {
/* remove it. but if necessary move it to .scroll-text rule above
width: 27px; */
}
custom.css :: line 839
@media (max-width: 599px)...
.logo-scroll {
/*display: none; why! remove it*/
}
custom.css :: строка 268
.scroll-text {
position: fixed;
/* height: 280px; remove it*/
padding-left: 20px;
}
см. этот снимок
наконец, хорошего дня и до свидания.
Ответ 2
Вы выбираете только первый "логотип-текст". Вместо:
const logo = document.querySelector('.scroll-text');
Вы должны использовать querySelectorAll
:
const logos = document.querySelectorAll('.scroll-text');
Затем в обработчике прокрутки вы должны переместить их все.
Таким образом, каждый экземпляр использования логотипа можно заменить циклом всех элементов логотипа:
logos.forEach(logo => logo.style.top = ...);
Помните, что вы делаете довольно дорогие вещи в обработчике прокрутки, что не очень хорошо для производительности рендеринга. Вы также можете использовать requestAnimationFrame
для улучшения производительности рендеринга. Посетите справочную страницу в MDN. На самом деле я быстро выбрал версию, используя requestAnimationFrame
, но заметного улучшения производительности не произошло. Вероятно, это связано с тем, что очевидно, что rAF срабатывает примерно с той же скоростью, что и событие scroll
. Во всяком случае, я удалил его, чтобы избежать путаницы. Если вы обнаружите проблемы с производительностью, дайте мне знать.
Тем не менее, я предлагаю вам переместить логотип, используя transform: translate()
, а не top
. Здесь у вас есть полное решение. Я попробовал это в Chrome.
const docHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
const logos = document.querySelectorAll('.scroll-text');
const logoHeight = logos[0].offsetHeight;
// to get the pseudoelement '#page::before' top we use getComputedStyle method
const barTopMargin = parseInt(getComputedStyle(document.querySelector('#page'), '::before').top);
let viewportHeight, barHeight, maxScrollDist, currentScrollPos, scrollFraction;
window.addEventListener('load', update);
window.addEventListener('resize', setSizes);
document.addEventListener('scroll', update);
setSizes();
function update() {
currentScrollPos = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
scrollFraction = currentScrollPos / (docHeight - viewportHeight);
const translateDelta = barTopMargin + (scrollFraction * maxScrollDist);
logos.forEach(logo => logo.style.transform = 'translateY(${translateDelta}px)');
}
function setSizes() {
viewportHeight = window.innerHeight;
// to get the pseudoelement '#page::before' height we use getComputedStyle method
barHeight = parseInt(getComputedStyle(document.querySelector('#page'), '::before').height);
maxScrollDist = barHeight - logoHeight;
update();
}