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;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div>
<span>some content</span>
</div>
1 Answer 1
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 fromspan.bottom
rule, since it doesn't change compared tospan
one. - Performance:
- since their value never changes, declaration of
span
,div
, anddivHeight
can be moved outside of thescroll()
event. - we also can fix
$(window)
by declaring it asvar win
at the same level.
- since their value never changes, declaration of
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 whendocument.scroll()
but alsowindow.resize()
event happens.
Additionally, each of those events should be initially fired (although in practice only one is enough).- When running the code snippet and immediately switching to full page the yellow span should have the
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;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<div>
<span>some content</span>
</div>
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.
-
\$\begingroup\$ Thanx for your review, you got some nice improvements I didn't think of in there. I was concerned about the window resize event but didn't include it in question to focus on the scroll event but it definetly is necessary. For the requirments you gave, you got them right and I'll add them in the question to clarify. For the wrong behaviour, Ill need to test some more as I haven't noticed it yet. \$\endgroup\$web-tiki– web-tiki2016年01月31日 16:45:37 +00:00Commented Jan 31, 2016 at 16:45
position: fixed
. Then once moved to the bottom it'll never go back, since henceforthspanOffset
will always keep >=divOffset
when scrolling up. \$\endgroup\$position:absolute
and moves up with the pink div. When you scroll bac up, higher thant the bottom of the pink div, goes back toposition:fixed
here is a gif to demonstrate: i.imgur.com/7NU3oAO.gifv \$\endgroup\$