Freeze selected item when scrolling - javascript

I have a requirement, where I need to freeze the selected item from list of items in a container to top, when the selected item is in top fold of the container. and when the selected item is in bottom fold of the container, I need to stick it to the bottom.
If the selected item is in visible fold, nothing should happen. I mean the selected item should be in normal flow with other adjacent items.
I somehow managed to solve this to some extent. But when I scroll up, when the selected item is sticked above of the container, the selected item is hiding. This behavior is happening even when I scroll down, when the selected item is sticked to the bottom of the container.
Here is the Fiddle
$('.item').click(function () {
$('.item').removeClass('select').removeClass('pAbsolute');
$(this).addClass('select');
});
$('.parent').scroll(function () {
var $selected = $('.item.select');
var cTop = $selected.offset().top;
var cHeight = $selected.height();
var pHeight = $(this).height();
if (cTop < 0) {
$selected.css({
'top': $(this).scrollTop(),
'bottom': ''
}).addClass('pAbsolute');
} else if (cTop > pHeight - cHeight) {
$selected.css({
'bottom': -$(this).scrollTop(),
'top': ''
}).addClass('pAbsolute');
} else {
$selected.css({
'top': '',
'bottom': ''
}).removeClass('pAbsolute');
}
});

You have to use a consistent value to keep the initial offset relative to the container when you select it.
Then, calculate the offset and scroll value,
If cTop < 0, which means its top out of box, stick to top.
If cTop + cHeight > pHeight, which means its view is out of bottom block, set to bottom.
Else stay in position.
Edit:
When selecting a new Item, as the previous item may have .pAbsolute attr, the relative position of current item may change, but we can get the offset change by track the offset before and after those class add/remove actions.
Then we can add the missing height by change the scrollTop of the container manually.
var offset;
$('.item').click(function () {
// This is the offset in container before class change.
offset = this.offsetTop;
$('.item').removeClass('select').removeClass('pAbsolute');
$(this).addClass('select');
// Calculate the difference
var distortion = offset - this.offsetTop;
// Remove the distortion by manual scroll.
var $parent = $(this).parent();
$parent.scrollTop($parent.scrollTop() - distortion);
offset = this.offsetTop;
});
$('.parent').scroll(function () {
var $selected = $('.item.select');
var cTop = offset - $(this).scrollTop();
var cHeight = $selected.height();
var pHeight = $(this).height();
if (cTop < 0) {
$selected.css({
'top': $(this).scrollTop(),
'bottom': ''
}).addClass('pAbsolute');
} else if (cTop + cHeight > pHeight) {
$selected.css({
'bottom': -$(this).scrollTop(),
'top': ''
}).addClass('pAbsolute');
} else {
$selected.css({
'top': '',
'bottom': ''
}).removeClass('pAbsolute');
}
});
body, html {
padding: 0;
margin: 0;
}
.parent {
overflow: auto;
height: 200px;
position: relative;
}
.item {
padding: 10px 15px;
background-color: tomato;
width: 100%;
}
.item.select {
background-color: beige;
}
.pAbsolute {
position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="parent">
<div class="item select">1</div>
<div class="item">2</div>
<div class="item">3</div>
<div class="item">4</div>
<div class="item">5</div>
<div class="item">6</div>
<div class="item">7</div>
<div class="item">8</div>
<div class="item">9</div>
<div class="item">10</div>
<div class="item">11</div>
<div class="item">12</div>
<div class="item">13</div>
<div class="item">14</div>
<div class="item">15</div>
<div class="item">16</div>
<div class="item">17</div>
<div class="item">18</div>
<div class="item">19</div>
<div class="item">20</div>
<div class="item">21</div>
<div class="item">22</div>
<div class="item">23</div>
<div class="item">24</div>
<div class="item">25</div>
<div class="item">26</div>
<div class="item">27</div>
<div class="item">28</div>
<div class="item">29</div>
<div class="item">30</div>
<div class="item">31</div>
<div class="item">32</div>
<div class="item">33</div>
<div class="item">34</div>
<div class="item">35</div>
<div class="item">36</div>
<div class="item">37</div>
<div class="item">38</div>
<div class="item">39</div>
<div class="item">40</div>
<div class="item">41</div>
</div>

This solution uses a bottom and top header who are filled in with the selected values and showed/hidden when necessary:
Working Fiddle
Javascript:
function stickItems($parent, itemClass, selectClass) {
// Attach dummy element items
$parent.prepend('<div class="' + itemClass + ' sticky top"></div>');
$parent.append('<div class="' + itemClass + ' sticky bottom"></div>');
var $items = $('.' + itemClass),
$stickyTop = $('.' + itemClass + '.sticky.top'),
$stickyBottom = $('.' + itemClass + '.sticky.bottom');
// Click event registering
$items.click(function (e) {
if (!$(e.target).hasClass('sticky')) {
$items.removeClass(selectClass);
$stickyTop.css('display', 'none');
$stickyBottom.css('display', 'none');
$(this).addClass(selectClass);
}
});
// Scroll event
$parent.scroll(function () {
var $self = $(this);
var $selected = $('.' + itemClass + '.' + selectClass);
var cTop = $selected.offset().top;
var pTop = $self.offset().top;
var cHeight = $selected.height();
var pHeight = $self.height();
if (cTop - pTop <= 0) {
$stickyTop.html($selected.html()).css({
'display': 'block',
'top': $(this).scrollTop()
});
$stickyBottom.css('display', 'none');
} else if (cTop > pTop && cTop < pTop + pHeight) {
$stickyTop.css('display', 'none');
$stickyBottom.css('display', 'none');
} else {
$stickyTop.css('display', 'none');
$stickyBottom.html($selected.html()).css({
'display': 'block',
'bottom': -$(this).scrollTop()
});
}
});
}
stickItems($('.parent'), 'item', 'select');
Css:
body, html {
padding: 0;
margin: 0;
}
body {
padding-top: 200px;
}
.parent {
overflow-x: hidden;
overflow-y: auto;
height: 200px;
position: relative;
}
.item {
padding: 10px 15px;
background-color: tomato;
}
.item.select {
background-color: beige;
}
.item.sticky {
background-color: beige;
display: none;
position: absolute;
left: 0;
right: 0;
z-index: 1;
}
Html:
<div class="parent">
<div class="item sticky top"></div>
<div class="item select">1</div>
<div class="item">2</div>
<!-- ... -->
<div class="item">39</div>
<div class="item">40</div>
<div class="item">41</div>
<div class="item sticky bottom"></div>
</div>

Related

Multiple sticky sections with horizontal scrolling

I'm trying to make a page with multiple sticky sections with horizontal scrolling (so when you're scrolling vertically as normal, you're forced to go through the horizontal gallery)
I'm referencing this codepen (https://codepen.io/johnhubler/pen/RwoPRBG) as my JS knowledge is very poor. But, as you can see in the codepen, it is only working in the first sticky section, and the second one stays still.
var windowWidth = window.innerWidth;
var horLength = document.querySelector(".element-wrapper").scrollWidth;
var horLength2 = document.querySelector(".element-wrapper2").scrollWidth;
var distFromTop = document.querySelector(".horizontal-section").offsetTop;
var distFromTop2 = document.querySelector(".horizontal-section2").offsetTop;
var scrollDistance = distFromTop + horLength - windowWidth;
var scrollDistance2 = distFromTop2 + horLength2 - windowWidth;
document.querySelector(".horizontal-section").style.height = horLength + "px";
document.querySelector(".horizontal-section2").style.height = horLength2 + "px";
window.onscroll = function(){
var scrollTop = window.pageYOffset;
if (scrollTop >= distFromTop && scrollTop <= scrollDistance) {
document.querySelector(".element-wrapper").style.transform = "translateX(-"+(scrollTop - distFromTop)+"px)";
}
if (scrollTop >= distFromTop2 && scrollTop <= scrollDistance2) {
document.querySelector(".element-wrapper2").style.transform = "translateX(-"+(scrollTop - distFromTop2)+"px)";
}
}
I'm planning to add around 4 of the same sticky sections, so I'd like to know how to make it work in all of them. If there is a better alternative/resource/etc.(if possible, vanilla JS or something very easy to follow) please let me know.
Thank you
I made an optimized and working version of your code.
This array lists the classes of packaging elements. This way you can add as many galleries as you want by simply adding a new class to the array.
var array = ['.horizontal-section', '.horizontal-section2'];
Example:
var array = ['.horizontal-section', '.horizontal-section2'];
window.onscroll = function () {
var windowWidth = window.innerWidth;
var scrollTop = window.pageYOffset;
array.forEach(el => {
var wrap = document.querySelector(el);
var elWrap = wrap.querySelector(".element-wrapper");
var horLength = elWrap.scrollWidth;
var distFromTop = wrap.offsetTop;
var scrollDistance = distFromTop + horLength - windowWidth;
wrap.style.height = horLength + "px";
if (scrollTop >= distFromTop && scrollTop <= scrollDistance) {
elWrap.style.transform = "translateX(-" + (scrollTop - distFromTop) + "px)";
}
});
}
* {
box-sizing: border-box;
}
body {
padding: 0;
margin: 0;
}
.bumper {
width: 100%;
height: 1800px;
background-color: #f3f3f3;
}
.horizontal-section,
.horizontal-section2 {
padding: 100px 0;
background-color: pink;
}
.sticky-wrapper,
.sticky-wrapper2 {
position: sticky;
top: 100px;
width: 100%;
overflow: hidden;
}
.element-wrapper,
.element-wrapper2 {
position: relative;
display: flex;
}
.element {
width: 500px;
height: 400px;
background-color: purple;
margin: 0 20px 0 0;
flex-shrink: 0;
}
<div class="bumper"></div>
<div class="horizontal-section">
<div class="sticky-wrapper">
<div class="element-wrapper">
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
</div>
</div>
</div>
<div class="bumper"></div>
<div class="horizontal-section2">
<div class="sticky-wrapper">
<div class="element-wrapper">
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
</div>
</div>
</div>
<div class="bumper"></div>

How detect which child element is visible after scrolling the parent div?

I would like to emulate something like "current page" using divs (like a PDF reader)
document.addEventListener("DOMContentLoaded", function(event) {
var container = document.getElementById("container");
container.onscroll = function() {
let position = container.scrollTop;
let divs = document.querySelectorAll('.page');
for (div of divs) {
//???
}
}
});
#container {
width: 400px;
height: 600px;
overflow: auto;
}
.page {
width: 400px;
}
.red {
background-color: red;
height: 600px;
}
.blue {
background-color: blue;
height: 400px;
}
Current page: <span id="page-counter">1</span>
<div id='container'>
<div id="div-1" class="page red"></div>
<div id="div-2" class="page blue"></div>
<div id="div-3" class="page red"></div>
<div id="div-4" class="page blue"></div>
</div>
So, I would like to know the best way to, for example, change span page-counter text to "3" when the third div "appears".
Something like this: https://i.imgur.com/rXQ2Bw8.png
Thanks in advance
Celso
Since this question never tagged jQuery, here's a pure Javascript solution that simulates the behavior you're looking for to the best of my knowledge. The solution calculates the amount of pixels of each child element currently visible within the container. If the amount is bigger or equal to half the size of the container, it assumes this is the page your visitor is looking at.
function getVisibleHeight(element){
const container = document.getElementById("container");
let scrollTop = container.scrollTop;
let scrollBot = scrollTop + container.clientHeight;
let containerRect = container.getBoundingClientRect();
let eleRect = element.getBoundingClientRect();
let rect = {};
rect.top = eleRect.top - containerRect.top,
rect.right = eleRect.right - containerRect.right,
rect.bottom = eleRect.bottom - containerRect.bottom,
rect.left = eleRect.left - containerRect.left;
let eleTop = rect.top + scrollTop;
let eleBot = eleTop + element.offsetHeight;
let visibleTop = eleTop < scrollTop ? scrollTop : eleTop;
let visibleBot = eleBot > scrollBot ? scrollBot : eleBot;
return visibleBot - visibleTop;
}
document.addEventListener("DOMContentLoaded", function(event) {
const container = document.getElementById("container");
const divs = document.querySelectorAll('.page');
container.addEventListener("scroll", () => {
for(let i=0; i<divs.length; i++){
const containerHeight = container.clientHeight;
// Gets the amount of pixels currently visible within the container
let visiblePageHeight = getVisibleHeight(divs[i]);
// If the amount of visible pixels is bigger or equal to half the container size, set page
if(visiblePageHeight >= containerHeight / 2){
document.getElementById('page-counter').innerText = i+1;
}
}
}, false);
});
#container {
width: 400px;
height: 300px;
overflow: auto;
}
.page {
width: 380px;
}
.red {
background-color: red;
height: 300px;
}
.blue {
background-color: blue;
height: 200px;
}
Current page: <span id="page-counter">1</span>
<div id='container'>
<div id="div-1" class="page red"></div>
<div id="div-2" class="page blue"></div>
<div id="div-3" class="page red"></div>
<div id="div-4" class="page blue"></div>
</div>
The general approach here would be to write a function that determines if a given HTML element is in the viewport. You could run the check as the user scrolls. See the snippet below for an example with jQuery. I'm not necessarily saying this is the best way to do this, but it seems to be working. Start scrolling to see the IDs appear.
function isInViewPort(element) {
// Function will determine if any part of the element is in the viewport.
let $el = $("#" + element);
let windowScrollTop = $(window).scrollTop();
let windowHeight = $(window).height();
let windowBottom = windowScrollTop + windowHeight;
let elementTop = $el.offset().top;
let elementOuterHeight = $el.outerHeight();
let elementBottom = elementTop + elementOuterHeight;
let isAboveViewPort = elementBottom < windowScrollTop;
let isBelowViewPort = windowBottom < elementTop;
return !(isAboveViewPort || isBelowViewPort);
}
let currentDiv;
$("#container").on("scroll", function() {
$("#container").find("div").each(function() {
if (isInViewPort(this.id) && currentDiv !== this.id) {
$("#page").html("Current ID is " + this.id)
currentDiv = this.id;
}
});
});
#container {
overflow: auto;
height: 300px;
}
.red {
background-color: red;
height: 600px;
}
.blue {
background-color: blue;
height: 400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<span id="page"></span>
<div id='container'>
<div id="div-1" class="page red"></div>
<div id="div-2" class="page blue"></div>
<div id="div-3" class="page red"></div>
<div id="div-4" class="page blue"></div>
</div>
you can use the is visible feature in jQuery. Just give each div a unique ID or class.
if( $("#uniqueIdHere").is(':visible'))
$(".page3Selector").addClass('active');
and then to remove the active class you could pair it up with an else statement to remove the class of the inactive div.

testimonials previous button jquery

I'm trying to make testimonials and next button works fine but the back(previous) button when i click first click work but when click next and click back again the code stop working and i don't know what is the problem.........:/
here is my code..
$(document).ready(function() {
var peopleOpinion = $(".people-opinion:first");
var peopleCount = $(".people-opinion").length; // 9 items(div)
// one row have 3 items(div)
// 4.5 = one click
var clicksNum = Math.round(peopleCount / 4.5);
var pre = $(".previous");
var next = $(".next");
var marginLeft = -300;
var clicks = 1;
next.on('click', function() {
if (clicks <= clicksNum && !(marginLeft == 0)) {
peopleOpinion.css({"margin-left" : marginLeft + "px"});
marginLeft += -300;
clicks++;
} else if (marginLeft == 0) {
peopleOpinion.css({"margin-left" : "-300px"});
clicks++;
} else {
peopleOpinion.css({"margin-left" : "0px"});
marginLeft = -300;
clicks = 1;
}
});
pre.on('click', function() {
if (!(marginLeft == 0)) {
marginLeft += 300;
peopleOpinion.css({"margin-left" : marginLeft + "px"});
}
});
});
.container {
display: flex;
overflow: hidden;
width: 290px;
border: 2px solid #DDD;
}
.container .people-opinion {
display: inline-block;
max-width: 29%;
flex: 0 0 100%;
padding: 3px;
margin: 10px 0px 10px 10px;
transition: all 1s ease-in-out;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="people-opinion">Hello world111</div>
<div class="people-opinion">Hello world222</div>
<div class="people-opinion">Hello world333</div>
<div class="people-opinion">Hello world444</div>
<div class="people-opinion">Hello world555</div>
<div class="people-opinion">Hello world666</div>
<div class="people-opinion">Hello world777</div>
<div class="people-opinion">Hello world888</div>
<div class="people-opinion">Hello world999</div>
</div>
<button class="next">Next</button>
<button class="previous">previous</button>
Ok This is the code you need .. but let me explain somethings first
first of all you'll need to know that working with % in css needs no margins and no padding .. it will be better to control the percentages without margins and paddings
$(document).ready(function() {
var containerWidth = $('.container').width();
var peopleOpinion = $(".people-opinion:first");
var peopleCount = $(".people-opinion").length; // 9
var clicksNum = peopleCount / 3;
var pre = $(".previous");
var next = $(".next");
var clicks = 1;
next.on('click', function() {
if (clicks < clicksNum) {
peopleOpinion.css({"margin-left" : - containerWidth * clicks + "px"});
clicks++;
}
});
pre.on('click', function() {
var pclicks = clicksNum - clicks - 1;
if (clicks <= clicksNum && clicks !== 1) {
peopleOpinion.css({"margin-left" : + containerWidth * pclicks + "px"});
clicks--;
}
});
// if you working on a responsive website you may need to use `resize` and update the container width
$(window).on('resize' , function(){
containerWidth = $('.container').width();
});
});
.container {
display: flex;
overflow: hidden;
width: 100%;
border: 2px solid #DDD;
}
.container .people-opinion {
display: inline-block;
transition: all 1s ease-in-out;
max-width : 33.33333333%;
flex: 0 0 100%;
}
.people-opinion > div{
margin : 4px;
padding : 2px;
background : red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div class="people-opinion"><div>Hello world111</div></div>
<div class="people-opinion"><div>Hello world111</div></div>
<div class="people-opinion"><div>Hello world111</div></div>
<div class="people-opinion"><div>Hello world111</div></div>
<div class="people-opinion"><div>Hello world111</div></div>
<div class="people-opinion"><div>Hello world111</div></div>
<div class="people-opinion"><div>Hello world111</div></div>
<div class="people-opinion"><div>Hello world111</div></div>
<div class="people-opinion"><div>Hello world111</div></div>
</div>
<button class="next">Next</button>
<button class="previous">previous</button>
-Explanation
while you have margins and padding on people-opinion that makes you use 290px and 29% and its totally wrong .. use the exact width you need which should be 300px and because of that I wrapped another div .people-opinion > div inside people-opinion and set style to it .. in my code I made it responsive so I set the container width to 100%
In the previous button you need to use var pclicks = clicksNum - clicks - 1; which gives you the right number of clicks you need to go to the previous step ..
Once marginLeft is 0 and clicks is greater than 2, the only operation that is allowed to happen is:
peopleOpinion.css({"margin-left" : "-300px"});
clicks++;
I simplified your logic a bit, and this seems to work:
var slot = 0;
next.on('click', function() {
slot++;
slot=slot%3;
peopleOpinion.css({"margin-left": (slot*-300)+ "px"});
});
pre.on('click', function() {
slot--;
if (slot < 0)
slot = 2;
peopleOpinion.css({"margin-left": (slot*-300)+ "px"});
});
This can even be generalized further if we have a variable like pages = Math.ceil(people/3) and work with that instead of constants above.

Loop Carousel horizontaly javascript/jquery

I was wondering if somebody could help me write a loop for this carousel? at the moment the carousel just scrolls to the right every 3 seconds then scrolls back to the left afterwards and resets itself, I would just like it to contiuously loop infinitly so it looks cleaner, could somebody point me in the right direction or help me? i know its simpler but i'm not much of a js developer! (this is for google sites html box otherwise i would have used a jquery plugin)
<style>
.carousel {
width: 1080px;
height: 220px;
position: relative;
overflow: hidden;
background-color:white;
margin-bottom: 20px;
margin-top: 20px;
margin-left: 70px;
}
.items {
width: 1080px;
position: absolute;
}
.items > div {
font-size: 20px;
display: table-cell;
vertical-align: middle;
text-align: center;
}
.items > div > img {
padding: 10px;
}
.nav {
position: absolute;
bottom: 5px;
right: 15px;
}
.button {
cursor: pointer;
font-weight: bold;
color: #fff;
}
</style>
<div class="carousel" style="display:none;">
<div class="items">
<div>
<img src="http://i59.tinypic.com/etisye.png" border="0" alt="Alkamai Logo">
</div>
<div>
<img src="http://i59.tinypic.com/ouukxu.png" border="0" alt="AWS Logo">
</div>
<div>
<img src="http://i61.tinypic.com/16k3t43.png" border="0" alt="cover-it-live">
</div>
<div>
<img src="http://i60.tinypic.com/23wljxh.png" border="0" alt="escenic">
</div>
<div>
<img src="http://i58.tinypic.com/sbiqu1.png" border="0" alt="Livefire">
</div>
<div>
<img src="http://i58.tinypic.com/do9wep.jpg" border="0" alt="ooyala">
</div>
<div>
<img src="http://i61.tinypic.com/24werue.png" border="0" alt="varnish">
</div>
<div>
<img src="http://i60.tinypic.com/2ij14rd.png" border="0" alt="wordpress">
</div>
</div>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"> </script>
<script>
var current_slide = 0; // zero-based
var slide_count = 4;
var slide_size = 1080;
var Direction = {
LEFT: -1,
RIGHT: 1
};
/**
* Moves to the next slide using the direction (dx) parameter.
*/
var nextSlide = function(dx) {
current_slide = (current_slide + slide_count + dx) % slide_count;
// Calculate the new value for css 'left' property and animate.
var left_offset = '-' + (current_slide * slide_size) + 'px';
$('.items').animate({'left': left_offset}, 1080);
};
$('.carousel').show();
setInterval(function(){
nextSlide(Direction.RIGHT);
}, 3000);
</script>
A slight modification to your current script can make it move forward continuously.
The changes are:
current_slide is always 1 (so as to always move forward only)
When we move .items X pixels to the left, we move the corresponding number of items to the end (the number that fits inside X pixels in width)
Updated Demo: http://jsfiddle.net/techfoobar/dWy9R/4/
Code:
var parent = $('.items');
var nextSlide = function (dx) {
// NOTE: always move forward only
current_slide = 1; //(current_slide + slide_count + dx) % slide_count;
// Calculate the new value for css 'left' property and animate.
var ileft_offset = current_slide * slide_size,
left_offset = '-' + ileft_offset + 'px',
iWidth = 0;
parent.animate({
'left': left_offset
}, 'slow', function() { // called when animation is done
iWidth = parent.find('> div:first').width();
while(ileft_offset > iWidth) {
parent.find('> div:first').appendTo(parent);
ileft_offset -= iWidth;
parent.css('left', '-' + ileft_offset + 'px');
}
});
};
A modified version that doesn't pause in between. Just goes on.
Demo: http://jsfiddle.net/techfoobar/dWy9R/5/
var nextSlide = function () {
parent.animate({
'left': '-' + slide_size + 'px'
}, 4000, 'linear', function() { // called when animation is done
var ileft_offset = slide_size,
iWidth = parent.find('> div:first').width();
while(ileft_offset > iWidth) {
parent.find('> div:first').appendTo(parent);
ileft_offset -= iWidth;
parent.css('left', '-' + ileft_offset + 'px');
iWidth = parent.find('> div:first').width();
}
nextSlide();
});
};
nextSlide(); // start it off!

Sticky div on scroll

See this: http://jsfiddle.net/3yx5C/1/
I am trying to make a DIV(the green DIV) from the right column:
1. to be fixed when it meets the HEADER;
2. to be NOT-fixed when you scroll to the top and it meets the other DIVs above(*the grey DIVs);
What I can't achieve is the second part. Any ideas?
I have to mention that the grey DIVs on the right might be more than two, with flexible heights, and they can't be wrapped.
<div id="HEADER"></div>
<div id="WRAPPER">
<div class="layout_right">
<div style="height: 80px; background: gray;"></div>
<div style="height: 80px; background: gray;"></div>
<div id="right_ads">I am sticky!</div>
</div>
<div class="layout_middle">
<div style="width: 300px; height: 200px; background: beige;"></div>
<div style="width: 300px; height: 200px; background: pink;"></div>
<div style="width: 300px; height: 200px; background: blue;"></div>
</div>
</div>
<script type='text/javascript'>
window.addEvent('domready', function() {
function sticky_AD() {
var headerHeight2 = $('HEADER').getSize().y;
var window_top = $(window).getScroll().y + headerHeight2 + 20;
var div_top = $('right_ads').getPosition().y;
if (window_top > div_top){
$('right_ads').addClass('fixed_AD').setStyles({'top': headerHeight2 + 20});
} else {
$('right_ads').removeClass('fixed_AD').setStyles({'top':'auto'});
}
}
$(window).addEvent('scroll', function(){
sticky_AD();
});
sticky_AD();
});
</script>
Check this:
Demo here
I added a new variable var dist = $('right_ads').getPosition().y; to store the original position and use it later and changed your else to a new if : if (window_top < dist) {
Code:
function sticky_AD() {
var headerHeight2 = $('HEADER').getSize().y;
var window_top = $(window).getScroll().y + headerHeight2 + 20;
var div_top = $('right_ads').getPosition().y;
if (window_top > div_top) {
$('right_ads').addClass('fixed_AD').setStyles({
'top': headerHeight2 + 20
});
}
if (window_top < dist) {
$('right_ads').removeClass('fixed_AD').setStyles({
'top': 'auto'
});
}
}
$(window).addEvent('scroll', function () {
sticky_AD();
});
var dist = $('right_ads').getPosition().y;
sticky_AD();

Categories

Resources