【问题标题】:Recalculate scrolling div position when used in a clipping path在剪切路径中使用时重新计算滚动 div 的位置
【发布时间】:2019-08-04 11:58:57
【问题描述】:

我正在使用剪切路径根据背景颜色更改我的徽标颜色。

除此之外,徽标会根据用户在页面上的垂直位置从上到下滚动。页面顶部 = 顶部徽标,页面底部 = 底部徽标等。

不幸的是,当我添加剪切路径时,徽标失去了滚动位置,在第一个之后,根本不起作用。

有没有办法解决这个问题?此外,徽标位置开始时有点偏离,所以如果有任何方法可以同时解决这个问题。

您可以在此处查看原始问题: div position based on scroll position

我已经尝试过了,但我似乎无法让它工作。

Scroll position lost when hiding 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's '#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's '#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;
}

【问题讨论】:

    标签: javascript jquery html css


    【解决方案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 :: 第 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 :: 第 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;
    }
    

    看到这个capture


    最后,祝你有美好的一天,再见。

    【讨论】:

    • 您好 - 谢谢,除了在开始移动之前有一点延迟并且由于某种原因它总是在底部短时停止,偏移量取决于在浏览器宽度上。我尝试从 SVG 徽标切换到 png,以防它与尺寸有关,但没有任何区别。您可以在原帖的链接中看到它
    • 更新了却一点动静都没有?对不起。谢谢!\
    • 请使用控制台再次检查。
    • 别忘了更新 setSizes 函数,让我看看你的更新。谢谢
    • 我的错...我使用了未定义的变量(_viewportHeight)!在 setSize 函数中。 [已修复] 对不起
    【解决方案2】:

    您只选择了第一个“logo-text”。而不是:

    const logo = document.querySelector('.scroll-text');
    

    你应该使用querySelectorAll:

    const logos = document.querySelectorAll('.scroll-text');
    

    然后,在您的滚动处理程序中,您应该将它们全部移动。

    因此,您可以用遍历所有徽标元素的循环替换每个徽标使用实例:

    logos.forEach(logo => logo.style.top = ...);
    

    请注意,您在滚动处理程序中执行了相当昂贵的操作,这对渲染性能不利。您可能还想使用requestAnimationFrame 来提高渲染性能。查看reference page on 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's '#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's '#page::before' height we use getComputedStyle method
      barHeight = parseInt(getComputedStyle(document.querySelector('#page'), '::before').height);
      maxScrollDist = barHeight - logoHeight;
      update();
    }
    

    【讨论】:

    • 您好。这次真是万分感谢。我更改了您建议的路线,但效果是它们现在都没有移动。在使用变换方面: translate() - 我熟悉这种用法是 CSS,但我不知道如何将它集成到 JS 中代替“top”,因为这里使用了原始 JS stackoverflow.com/questions/57129154/… 虽然我从来没有让它正常工作。
    • @MrToad 我已经用示例用法更新了我的答案。今天我会出去,但是当我回来时,我会尝试提供一个更好的实现,使用transforms 和requestAnimationFrame
    • 嗨@Emanuele - 谢谢你的时间。对不起,我是个白痴,但我似乎无法让这些更改生效,尽管我怀疑我可能编辑错了。
    • @MrToad 别担心,我们都去过那里。我将在今天或明天回家时提供完整的工作解决方案。干杯。
    • @MrToad 我添加了一个我在 Chrome 上测试过的工作 sn-p。希望对您有所帮助。
    猜你喜欢
    • 1970-01-01
    • 2019-01-14
    • 1970-01-01
    • 1970-01-01
    • 2012-03-14
    • 2013-10-29
    • 1970-01-01
    • 2011-05-10
    • 2021-01-14
    相关资源
    最近更新 更多