HiveBrain v1.2.0
Get Started
← Back to all entries
debugjavascriptMinor

Keep div fixed when it is inside it's container on scroll

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
containerkeepdivscrollwhenfixedinside

Problem

The required behaviour is :

  • The yellow span must be positioned relatively to viewport (position:fixed;) when it is inside the pink div.



  • The height of yellow span must always be the same as viewport height minus 100px. It has a fixed width in px.



  • The yellow span must be verticaly centered in the viewport (this rule is modified by rule 4).



  • On scroll, the yellow span must never be outside the boundaries of the pink div. If the page is scrolled further than the pink div, the yellow span must be absolutely positionned to the bottom of the pink div and scroll up with it



  • If the page is scrolled back up to the pink div, the yellow span must go back to fixed position (as in rule 1 and 2).



I know sticky positioning does exaclty that but I can't use it because of poor browser support. So I made this snippet and would like to know if it can be optimized or shortened :



$(document).scroll(function() {
var span = $('span'),
div = $('div'),
spanHeight = span.outerHeight(),
divHeight = div.height(),
spanOffset = span.offset().top + spanHeight,
divOffset = div.offset().top + divHeight;

if (spanOffset >= divOffset) {
span.addClass('bottom');
var windowScroll = $(window).scrollTop() + $(window).height() - 50;
if (spanOffset > windowScroll) {
span.removeClass('bottom');
}
}
});

*{margin:0;}
div {
position: relative;
background: pink;
height: 800px;
margin-bottom: 800px;
}
span {
position: fixed;
right: 0;
bottom: 50px;
width: 10%;
height: calc(100vh - 100px);
background: gold;
}
.bottom {
position: absolute;
bottom: 0;
right: 0;
}



some content

Solution

This is not really a full answer yet, but after correcting my interpretation of your question (as reflected by comments under it) I keep having some incertainties, and a comment is not wide enough to clearly express them.

Anyway I can already notice some possible improvements, not depending on any further precision:

  • Cosmetic: the right: 0; property can be suppressed from span.bottom rule, since it doesn't change compared to span one.



  • Performance:



  • since their value never changes, declaration of span, div, and divHeight can be moved outside of the scroll() event.



  • we also can fix $(window) by declaring it as var win at the same level.



-
Operation: depending on the window size, the initial state may not follow your requirements, e.g.:

  • When running the code snippet and immediately switching to full page the yellow span should have the bottom class, while it doesn't.



  • The same happens when toggling between full page and reduced iframe: if the state should change when reaching the new window size, it doesn't till scrolling happens.



Then to avoid that, the computation for affecting/dropping bottom class should occur not only when document.scroll() but also window.resize() event happens.

Additionally, each of those events should be initially fired (although in practice only one is enough).

Here is the so modified snippet:



var span = $('span'),
div = $('div'),
win = $(window),
divHeight = div.height();
$(document).scroll(compute).scroll();
$(window).resize(compute).resize();

function compute() {
var spanHeight = span.outerHeight(),
spanOffset = span.offset().top + spanHeight,
divOffset = div.offset().top + divHeight;

if (spanOffset >= divOffset) {
span.addClass('bottom');
var windowScroll = win.scrollTop() + win.height() - 50;
if (spanOffset > windowScroll) {
span.removeClass('bottom');
}
}
console.log('spanOffset='+spanOffset, 'windowScroll='+($(window).scrollTop() + $(window).height() - 50));
}

*{margin:0;}
div {
position: relative;
background: pink;
height: 800px;
margin-bottom: 800px;
}
span {
position: fixed;
right: 0;
bottom: 50px;
width: 10%;
height: calc(100vh - 100px);
background: gold;
}
.bottom {
position: absolute;
bottom: 0;
}



some content




Now let me explain what keeps puzzling me.

Both snippets (yours and mine) have the following wrong behaviour: as of a certain window height (couldn't precisely figure out yet), once switched to bottom the yellow span will never go back when scrolling up.

So before thinking further I'd want to be certain of what is precisely your need. Expressed independently from the current implementation, it seems to me that it is like follows:

  • as a fundamental requirement, the yellow span height must always be equal to window height minus a given height (say X, in this case 100px), and must not change



  • if not upset by the rule #3 below, the yellow span must be vertically centered in the window (its bottom is half the above given X)



  • taking over the rule #2, the yellow span must never cross the pink div (the bottom of the former can't move lower than the latter's one)



For now I remain pending. Thanks for confirming or correcting me.

Context

StackExchange Code Review Q#118267, answer score: 4

Revisions (0)

No revisions yet.