Position Sticky: Scrollable, When Longer Than Viewport

Don't use sticky if element is larger than screen height

Hope this pen helps

Some explanations:

  • in js we use .offsetHeight&.clientHeight to get height we check weather this height(493px) + 50px offset is more than screen height or not.
  • When screen size is small we set position to static
  • Also we set margin-top: 50px instead of top: 50px

    because top works only for sticky and margin-top works for static

position: sticky not working after some amount of scroll

One way to solve this:

.slider {
overflow: auto;
display: grid; /* main element as grid */
grid-auto-columns: 20%; /* width of the items */
}
.header,
.body {
display: contents; /* remove the parent boundary to make sticky works */
}
.header > * {
grid-row: 1; /* all header elements in first row */
}
.body > * {
grid-row: 2; /* all body elements in second row */
}
.item {
height: 100px;
background: yellow;
border: 1px solid black;
}

.sticky-item-left {
position: sticky;
left: 0;
background: red;
}

.sticky-item-right {
position: sticky;
right: 0;
background: green;
}
<div class="slider">
<div class="header">
<div class="item sticky-item-left"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item sticky-item-right"></div>
</div>
<div class="body">
<div class="item sticky-item-left"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item sticky-item-right"></div>
</div>
</div>

How does the position: sticky; property work?

Sticky positioning is a hybrid of relative and fixed positioning. The element is treated as relative positioned until it crosses a specified threshold, at which point it is treated as fixed positioned.

...

You must specify a threshold with at least one of top, right, bottom, or left for sticky positioning to behave as expected. Otherwise, it will be indistinguishable from relative positioning.
[source: MDN]

So in your example, you have to define the position where it should stick in the end by using the top property.

html, body {
height: 200%;
}

nav {
position: sticky;
position: -webkit-sticky;
top: 0; /* required */
}

.nav-selections {
text-transform: uppercase;
letter-spacing: 5px;
font: 18px "lato", sans-serif;
display: inline-block;
text-decoration: none;
color: white;
padding: 18px;
float: right;
margin-left: 50px;
transition: 1.5s;
}

.nav-selections:hover {
transition: 1.5s;
color: black;
}

ul {
background-color: #B79b58;
overflow: auto;
}

li {
list-style-type: none;
}
<nav>
<ul align="left">
<li><a href="#/contact" class="nav-selections" style="margin-right:35px;">Contact</a></li>
<li><a href="#/about" class="nav-selections">About</a></li>
<li><a href="#/products" class="nav-selections">Products</a></li>
<li><a href="#" class="nav-selections">Home</a></li>
</ul>
</nav>

How to stop DIV larger than viewport from scrolling?

There is probably no way to really - in a more natural kind of way - prevent a div which uses position: fixed - or even position: sticky (which uses relative positioning at first and later when it sticks fixed positioning) - and has a larger size than viewport from scrolling when you want it to at a certain point.

Still, the goal of my question (stop scrolling to fade some div elements) I can answer myself with some lines of code. In summary: use marginTop of a div to pull up some div child elements of a div which uses fixed positioning.

I do have at least one other question (maybe two) relating to this code (but not to the prevention of scrolling). But that are other questions which I can ask as new questions.

I will accept my own answer for now. If someone has a better or more 'natural' idea concerning this question - which I somehow doubt - I will happily change my acceptance to that answer.

var $window = $(window);var $document = $(document);// Element which needs to fade in and out.var $fadingblack = $("#fadingblack");var $scrolldistract = $("#scrolldistract");var $scrollsviascrolldistract = $("#scrollsviascrolldistract");// Pulls up the child divs of #scrollsviascrolldistract, under it.var $puller = $("#puller");

// Start of fading area (Y-value).var scrollTopStart = $fadingblack.position().top;// And of course the Y-value of the end of the fading area.var scrollTopEnd = scrollTopStart + $fadingblack.height();
// Maximum scrollTop-value (when scrollbar is at 100%).var lastScrollTop = $document.height() - $window.height();
// Amount of scrolled pixels (vertically) including amount scrolled while// the fading element is fading.var scrollAmountWithFadeAmount = $document.height + $fadingblack.height();// Setting height does not quite work for an empty div,// so we are using some padding.$scrolldistract.css("paddingTop", scrollAmountWithFadeAmount);// Percentage of which we have scrolled (1 = 100%).var currentScrollTopP;// Current scrollTop value.var realCurY;
$(function() { // Off you go code...
function doScrollOrFade() { currentScrollTopP = Math.ceil($window.scrollTop() / lastScrollTop * 100) / 100; realCurY = currentScrollTopP * lastScrollTop;
if (realCurY >= scrollTopStart && realCurY <= scrollTopEnd) { // Current realCurY dictates we are in fade area. // So scroll the fading area into view at top of browser viewport. $puller.css("marginTop", -scrollTopStart); // Determine opacity percentage. var fadePercent = (realCurY - scrollTopStart) / (scrollTopEnd - scrollTopStart); // Fade to current opacity immediately. $fadingblack.fadeTo(0, fadePercent); } else { // We are outside of the fading area and in scroll-mode. if (realCurY < scrollTopStart) { // We are somewhere before the fading area, so set opacity to 0. $fadingblack.fadeTo(0, 0); } else { // We are somewhere after the fading area, so set opacity to 1. $fadingblack.fadeTo(0, 1); }
if (realCurY > scrollTopEnd) { // We have passed the fading area. So we have an amount // of pixels we wasted on the opacity changes. // Correct it here. $puller.css("marginTop", -realCurY + $fadingblack.height()); } else { $puller.css("marginTop", -realCurY); } } window.requestAnimationFrame(doScrollOrFade); }
window.requestAnimationFrame(doScrollOrFade);
$window.on('resize orientationchange', function(e) { // On resize or orientation change recalculate some stuff. lastScrollTop = $document.height() - $window.height(); scrollAmountWithFadeAmount = $document.height + $fadingblack.height(); $scrolldistract.css("paddingTop", scrollAmountWithFadeAmount); window.requestAnimationFrame(doScrollOrFade); });});
body {  background-color: whitesmoke;}
#scrollsviascrolldistract { position: fixed; left: 0px; top: 0px; width: 100%;}
#scrolldistract { position: absolute; left: 0px; top: 0px; width: 100%; padding-top: 2100px; height: 0px;}
#puller { position: relative; margin-top: 0px; left: 0px; top: 0px;}
img { display: block;}
.black,.red,.blue { border: solid 1px yellow; font-size: 32pt; position: relative; width: 100%; height: 300px;}
.red { background-color: red;}
.blue { background-color: blue;}
.black { background-color: black;}
<!--For mobile support use viewport meta-tag inside <head>:<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=yes">-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><div id="scrolldistract"></div>
<div id="scrollsviascrolldistract"> <!-- For pulling up the red, blue and fading area --> <div id="puller"></div> <div class="red">BEGIN</div> <div class="blue">Fading black area is ahead...</div> <div id="fadingblack" class="black"> </div> <div class="blue"> </div> <div class="red"> </div> <div class="blue">END</div></div>


Related Topics



Leave a reply



Submit