debugjavascriptMinor
Keep div fixed when it is inside it's container on scroll
Viewed 0 times
containerkeepdivscrollwhenfixedinside
Problem
The required behaviour is :
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 :
- 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:
-
Operation: depending on the window size, the initial state may not follow your requirements, e.g.:
Then to avoid that, the computation for affecting/dropping
Additionally, each of those events should be initially fired (although in practice only one is enough).
Here is the so modified snippet:
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:
For now I remain pending. Thanks for confirming or correcting me.
Anyway I can already notice some possible improvements, not depending on any further precision:
- Cosmetic: the
right: 0;property can be suppressed fromspan.bottomrule, since it doesn't change compared tospanone.
- Performance:
- since their value never changes, declaration of
span,div, anddivHeightcan be moved outside of thescroll()event.
- we also can fix
$(window)by declaring it asvar winat 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
bottomclass, 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.