简体   繁体   中英

div position based on scroll position

I would like my logo to scroll up and down vertically based on the scroll position on the website.

In exactly the same way a default scroll bar indicates your position on the site, I would like my logo to do the same. When you are at the top of the website page, the logo sits at the top, and when you are at the bottom it will sit at the bottom of the page in a vertical bar on the left hand side of the web page.

I have no idea how to approach this, I have looked at a few plugins but none offer the positioning based on the content and I can't find any other Stack Overflow results that are what I am looking for, though I may not be phrasing the question correctly.

My setup is

.logo-scroll {
    position: fixed;
    border: 2px solid white;
    top: 30px;
    left: 30px;
    height: calc(100vh - 60px);
    width: 75px;
}  

.scroll-text {
    height: auto;
} 

.logo-scroll .scroll-text img {
    padding: 0 6px 0 17px;
}

and my html

<div class="logo-scroll">

    <div class="scroll-text">
        <a href="/home">
            <img src="logo.svg"/>
        </a>
    </div>

</div>

Any help would be greatly appreciated

** Edit - to complicate things, I have a 30px border which is not to be included in the page height. So an offset of 30px on the top and bottom.

The size of the margin/border will need to change responsively at break points - 1 maybe 2, before I will hide it. Essentially the height of the scroll bar will always need to match the height of either the page with margins subtracted or the height of the :before element.

Alternatively if I can set offsets, I can reuse the JS and adjust based on screen size. Like media queries for JS?

You can see the web page here - which is still very under construction https://www.sheree-new.shereewalker.com/

You could give something like this a try.

window.addEventListener('scroll', e => {
  const logo = document.querySelector('.scroll-text');
  const logoHeight = logo.clientHeight;
  const viewHeight = window.innerHeight;
  const maxLogoOffset = viewHeight - logoHeight;
  const scrollFraction = getElementScrollFraction(document.querySelector('body'));
  logo.style.top = maxLogoOffset*scrollFraction;
});

function getElementScrollFraction(elem){
  return elem.scrollTop / (elem.scrollHeight - elem.clientHeight);
}

You'll also need to add position:fixed; to the .scroll-text css.

Here is a working example: https://jsbin.com/yuholihece/edit?html,css,js,console,output

Here is my solution.

Edited:

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();
}

And if I understand correctly, you want #page::before element to have like margins on its top, left, bottom and right. If so, then I think it would be better to use this styling rules:

#page::before {
    content: "";
    position: fixed;
    top: 30px;
    bottom: 30px;
    left: 30px;
    right: 30px;
    ...
}

When you use position: fixed property (or position: absolute ), you can stretch the element's width and height as you want by just setting top - bottom and left - right properties at the same time. PS: And also there is no sense in using display: inline-block , because position: fixed (and position: absolute ) automatically sets display to block :)

Hopefully, this helps you!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM