2

I want to divide my website into two parts: a header containing a large image, and a main part, containing other images, text, etc.

When I scroll the page, the large image on the header should scroll together with the main part. In a certain point, the image should become fixed, and the main part scroll behind it.

I have tried some different approaches, but I can't get the right combination of position, display, top, etc to work.

That's the closest I've got so far: https://jsfiddle.net/aor0abhf/

HTML

<body onscroll='scroll(event)'>
  <div class='top' id='top'><img src='http://www.vejanomapa.net.br/wp-content/uploads/2013/03/Maria-Fuma%C3%A7a-em-Tiradentes-MG.jpg'></div>
  <div class='bottom'>
    <div class='menu'>Menu</div>
    <div class='main'><img src='http://tvulavras.com.br/wp-content/uploads/2017/04/maria-fuma%C3%A7a.jpg'></div>
  </div>
</body>

Javascript

function scroll(e) {
    var T = document.getElementById('top');
    var imgH = T.clientHeight; // header image height
    var hH = 200; // fixed header height
    if (imgH-e.pageY > hH) { // image is scrolling
        T.style.top = '-'+e.pageY+'px';
        T.style.position = 'sticky';
    } else { // image should remain fixed
        T.style.top = '-'+(imgH-hH)+'px';
        T.style.position = 'fixed';
    }
}

CSS

html, body {
    margin:0;
}
body {
    overflow-y:scroll;
    overflow-x:hidden;
}
img {
    display:block;
}
.top {
    background:#FCC;
  display:block;
    top:0;
}
.bottom {
    display:flex;
    min-height:1500px;
    background:#CFC;
}
.menu {
    width:100px;
    background:#CCF;
}

But still there's a glitch in the transition between scroll/fixed positions. And if the left menu (in light blue) could stick together, that would be great! (Maybe subject to another question?)

Rodrigo
  • 4,706
  • 6
  • 51
  • 94
  • Instead of changing the css with javascript, you could add a class, then have your other content act differently when that class is there. For example, when active your top would be fixed, but you could also add a margin-top to your bottom equal to the height of your top & set your left menu to be fixed as well. If I have some time later and you're still working on it I'll help some more :) – Joe Lissner Aug 08 '17 at 16:16
  • @JoeLissner Change object class is faster than changing CSS properties? – Rodrigo Aug 08 '17 at 20:43
  • @JoeLissner Can you add a working jsfiddle example, please? – Rodrigo Aug 08 '17 at 21:17
  • Can you use jQuery? Not a big deal if not, just easier :P – Joe Lissner Aug 08 '17 at 21:23
  • well, either way, it's not perfect, but let me know if this is what you're looking for. Should at least give you an idea of what you're needing to do. https://jsfiddle.net/aor0abhf/2/ – Joe Lissner Aug 08 '17 at 21:34
  • @JoeLissner Thank you, that worked perfectly! And no, I don't want to use jQuery. Please add as an answer, so I can accept it. – Rodrigo Aug 08 '17 at 22:46

2 Answers2

1

I updated your fiddle to the following:

No Change to HTML

<body onscroll='scroll(event)'>
  <div class='top' id='top'><img src='http://www.vejanomapa.net.br/wp-content/uploads/2013/03/Maria-Fuma%C3%A7a-em-Tiradentes-MG.jpg'></div>
  <div class='bottom' id='bottom'>
    <div class='menu'>Menu</div>
    <div class='main'><img src='http://tvulavras.com.br/wp-content/uploads/2017/04/maria-fuma%C3%A7a.jpg'></div>
  </div>
</body>

CSS

html, body {
    margin:0;
}
body {
    overflow-y:scroll;
    overflow-x:hidden;
}
img {
    display:block;
}

.top {
    background:#FCC;
    display:block;
    top:0;
}

/* start new rules */

.active{
  position: fixed;
}

.active ~ .bottom {
  margin-top: 386px;
  padding-left: 100px;
}

.active ~ .bottom .menu {
  position: fixed;
  top: 200px;
  bottom: 0;
  left: 0;
}

/* end new rules */

.bottom {
    display:flex;
    min-height:1500px;
    background:#CFC;
}
.menu {
    min-width:100px;
    background:#CCF;
}

Javascript

function scroll(e) {
    var T = document.getElementById('top');
    var B = document.getElementById('bottom');
    var imgH = T.clientHeight; // header image height
    var hH = 200; // fixed header height

    if (imgH-e.pageY > hH) { // image is scrolling
        T.classList.remove('active') // remove class active as applicable
        T.style.top = '-'+e.pageY+'px';
        T.style.position = 'sticky';
        B.style['margin-top'] = '0';
    } else { // image should remain fixed
        T.classList.add('active') // add class active as applicable
        T.style.top = '-'+(imgH-hH)+'px';
    }
}
Joe Lissner
  • 2,181
  • 1
  • 15
  • 21
0

Remove

min-height:1500px;

The div height will stay 1500px; Try this one

.bottom {
    display:flex;
    background:#CFC;
}

This should work.

Add margin-top:200px; on <div class='bottom'> part on scroll.

Gene Sescon
  • 165
  • 12