I'm trying to create a script that will keep divs fixed in their position no matter where they are on the screen when the page is scrolled... Basically, if a div is 50 px from the top, it will stay 50 px from the top of the current window. If a div is 0 px from the top, it will stay 0 px from the top.
I don't want a fixed div because of the cut-off problems they have... So please don't recommended changing the position to 'position: fixed;'...
A script I was working with was essentially doing the following:
window.onscroll = function() {
var elements = document.getElementsByClassName('sticky_div');
var doc = document.documentElement;
for (i = 0; i < elements.length; i++) {
rect = elements[i].getBoundingClientRect();
if (doc.scrollTop > rect.top) {
elements.style.top = doc.scrollTop + rect.top;
} else {
elements.style.top - doc.scrollTop - rect.top;
}
}
}
I'm sorry if that actually comes out wrong. I accidentally deleted my original code... Either way, the above method caused to be too laggy and it would jump the headers and divs. Are there any other ways of doing this using less over-the-top processing to do?
elements.style.top = doc.scrollTop; works very well but it won't allow for divs that are positioned elsewhere on the page...
Here's a JSFiddle for the reason why I don't want to use fixed divs (try scrolling horizontally):
https://jsfiddle.net/o27L3uss/
Related
I am trying to duplicate the left nav at http://www.kahuna-webstudio.fr/. If you take a look at http://www.kahuna-webstudio.fr/, and scroll down about 50 pixels or so, you will see a div appear off to the left of the screen that has some navigation in it. I have most of it working, thanks to the help of some of you at stackoverflow. But the one part I do not have working is that the content of my div, images, do not stay stationary in place (or always visible) as you scroll down.
So what I want to happen is: when the div appears at the left of the screen, when the user scrolls down, I want the content of the div to appear always in view.
Right now what I have working is: through animate() I set the height of my left nav div to the document height, and the width grows to 80 pixels, and then some images fadeIn(). But the page is fairly long and as the user scrolls down they are also able to scroll down the height of my left nav div; and I always want the content of my left nav to always appear in view to the user.
I think this person posted a similiar question (Keeping a header always in view) but I am finding it difficult to attach if to my example code. Can anyone help? I appreciate it a lot.
Here is my code:
$(window).scroll(function(){
var wintop = $(window).scrollTop();
var docheight = $(document).height();
var winheight = $(window).height();
var newwidthgrow = 80;
var smallheight = 0;
var smallwidth = 0;
if((wintop > 296)) {
$("#slidebottom").stop().animate({height:docheight +"px"},'fast',function(){
$("#slidebottom").stop().animate({width:newwidthgrow + "px"},'slow',function(){
$("#slidebottomContents").fadeIn();
});
});
}
if((wintop < 25))
{
$("#slidebottom").stop().animate({height:docheight +"px"},'fast',function(){
$("#slidebottomContents").fadeOut(function(){
$("#slidebottom").stop().animate({width:smallwidth + "px"});
});
});
}
});
As far as i'm concerned this can be covered by only css.
To keep the div in the same position you can apply the following css:
css:
div id {
position: fixed;
left: 0px
width: 'your width'
}
position fixed freezes the div in the position you want.
left keeps the div positioned on the left side of you page.
does this answer your question and solve your problem?
if not let me know!
I'm writing some javascript code to move all absolutely positioned elements down 60 pixels (below a 60 pixel heigh div I'm displaying at the top of other pages on my proxy). Here's the code I have right now (mostly borrowed from another question on stackoverflow):
function getStyle(el, prop)
{
var doc = el.ownerDocument;
var view = doc.defaultView;
if (view && view.getComputedStyle)
{
return view.getComputedStyle(el, '')[prop];
}
return el.currentStyle[prop];
}
function runAfterLoad()
{
var all = document.getElementsByTagName('*');
var i = all.length;
while (i--)
{
var topOffset = parseInt(all[i].offsetTop, 10);
if (getStyle(all[i], 'position') === 'absolute')
{
all[i].style.top = isNaN(topOffset) ? '60px' : (topOffset + 60) + 'px';
}
}
}
Unfortunately this moves all absolute positioned elements down 60 pixels. As it turns out, I found out that absolute positioning isn't actually absolute to the browser window, but absolute to a parent that meets some specific rules. Here's a quote from another answer on here:
This works because "position: absolute" means something like "use top, right, bottom, left" to position yourself in relation to the nearest ancestor who has "position: absolute" or "position: relative"."
So I'm looking for help on how to adjust my current code to only find the elements with absolute position that don't have a parent that is also absolute or relative positioned. Any help is highly appreciated.
Another option would be to use that fact to your advantage. If you were to wrap your entire page in a div which you positioned absolutely (or relatively) with top: 60px, you would essentially move the entire page down 60px at once.
This would also move non-absolute elements. If this is not desired then this won't work.
I'm having a beyond frustrating problem which I have no idea how to tackle.
My question: How do I determine how many elements exist between two positions in a viewport (a scrollable div in this occasion)?
Say I have a scrollable <div> that has a height of 150 px, but has a viewport at 450px with the majority of it being hidden. The div has children that are 30px high, 15 of them.
Question 2: How could I find out how many first children exist between n1 and n2, it seems pretty easy but it's proving not to be.
I've created a jsFiddle where I have partly solved the solution, it works if the top value is set to 0, but it doesn't work if it's anything else. For example, with this solution I am able to determine that there are 7 visible divs between 0 and 200px. But if I change it to determine how many are between 30px and 230px it tells me 0, when again it should be 7.
Help please!
Try this instead:
var $this = $(this),
topOffset = $this.offset().top;
if (topOffset >= top && topOffset <= bottom) {
elements++;
}
This checks to see if the current element's (in the each()) top offset is greater than the top variable's value and increases the elements only then. This way, you don't need to be constantly updating the height variable.
And this works, as you can see here.
Change it so that the 'height' starts equal to the top value.
Your javascript should be:
var container = $('div#container'),
top = 30,
bottom = 230,
height = top,
elements = 0;
container.find('div').each(function(n)
{
if (top <= height && height < bottom)
{
height = height + $(this).height();
elements++;
console.log(top, bottom, height, elements);
}
});
$('span.top').text(top);
$('span.btm').text(bottom);
$('span.num').text(elements);
That worked for me, Good luck!
Simple, I just would like to have it so when a user is dragging an item and they reach the very bottom or top of the viewport (10px or so), the page (about 3000px long) gently scrolls down or up, until they move their cursor (and thus the item being dragged) out of the region.
An item is an li tag which uses jquery to make the list items draggable. To be specific:
../jquery-ui-1.8.14.custom.min.js
http://code.jquery.com/jquery-1.6.2.min.js
I currently use window.scrollBy(x=0,y=3) to scroll the page and have the variables of:
e.pageY ... provides absolute Y-coordinates of cursor on page (not relative to screen)
$.scrollTop() ... provides offset from top of page (when scroll bar is all the way up, it is 0)
$.height()... provides the height of viewable area in the user's browser/viewport
body.offsetHeight ... height of the entire page
How can I achieve this and which event best accommodates this (currently its in mouseover)?
My ideas:
use a an if/else to check if it is in top region or bottom, scroll up if e.pageY is showing it is in the top, down if e.page& is in bottom, and then calling the $('li').mouseover() event to iterate through...
Use a do while loop... this has worked moderately well actually, but is hard to stop from scrolling to far. But I am not sure how to control the iterations....
My latest attempt:
('li').mouseover(function(e) {
totalHeight = document.body.offsetHeight;
cursor.y = e.pageY;
var papaWindow = window;
var $pxFromTop = $(papaWindow).scrollTop();
var $userScreenHeight = $(papaWindow).height();
var iterate = 0;
do {
papaWindow.scrollBy(0, 2);
iterate++;
console.log(cursor.y, $pxFromTop, $userScreenHeight);
}
while (iterate < 20);
});
Works pretty well now, user just needs to "jiggle" the mouse when dragging items sometimes to keep scrolling, but for scrolling just with mouse position its pretty solid. Here is what I finally ended up using:
$("li").mouseover(function(e) {
e = e || window.event; var cursor = { y: 0 }; cursor.y = e.pageY; //Cursor YPos
var papaWindow = parent.window;
var $pxFromTop = $(papaWindow).scrollTop();
var $userScreenHeight = $(papaWindow).height();
if (cursor.y > (($userScreenHeight + $pxFromTop) / 1.25)) {
if ($pxFromTop < ($userScreenHeight * 3.2)) {
papaWindow.scrollBy(0, ($userScreenHeight / 30));
}
}
else if (cursor.y < (($userScreenHeight + $pxFromTop) * .75)) {
papaWindow.scrollBy(0, -($userScreenHeight / 30));
}
}); //End mouseover()
This won't work as the event only fires while you're mouse is over the li.
('li').mouseover(function(e) { });
You need to be able to tell the position of the mouse relative to the viewport when an item is being dragged. When the users starts to drag an item attach an 'mousemove' event to the body and then in that check the mouse position and scroll when necessary.
$("body").on("mousemove", function(event) {
// Check mouse position - scroll if near bottom or top
});
Dont forget to remove your event when the user stops dragging.
$("body").off("mousemove", function(event) {
// Check mouse position - scroll if near bottom or top
});
This may not be exactly what you want, but it might help. It will auto-scroll when the mouse is over the 'border of the screen' (a user defined region). Say you have a 40px wide bar on the right of the screen, if the mouse reaches the first 1px, it will start scrolling. Each px you move into it, the speed will increase. It even has a nice easing animation.
http://www.smoothdivscroll.com/v1-2.htm
I get a weekly newsletter (email) from CodeProject, and it had some stuff that certainly looks like it will solve my problem... hopefully this can help others:
http://johnpolacek.github.com/scrollorama/ -- JQuery based and animates the scroll
https://github.com/IanLunn/jQuery-Parallax -- JQuery based, similar to above
http:// remysharp. com/2009/01/26/element-in-view-event-plugin/ -- JQuery, detects whether an element is currently in view of the user (super helpful for this issue!)
Also the site in #2 had some interesting code:
var windowHeight = $window.height();
var navHeight = $('#nav').height() / 2;
var windowCenter = (windowHeight / 2);
var newtop = windowCenter - navHeight;
//ToDo: Find a way to use these vars and my original ones to determine scroll regions
I've got a solution for keeping a sidebar in the viewport as you scroll up and down the page. Problem comes in when the sidebar is longer than the content area, and you keep scrolling you get this jittering effect as the sidebar keeps pushing the footer down.
I've got an example of this setup in jsFiddle: http://jsfiddle.net/U9F7w/2/ (full screen: http://jsfiddle.net/U9F7w/2/embedded/result/ )
My question is, is there a way to make the sidebar stop once it touches the bottom/footer area?
I've read some solutions about setting the sidebar to absolute, unfortunately it's an existing site and changing the position didn't work and messed with a lot of the existing page elements.
Here's the jQuery/js I'm working with:
// set the offset
var sidebarOffset = $(".sidebar").offset();
var sidebarPadding = 15;
// when the window scrolls, keep sidebar in view
$(window).scroll(function() {
if ($(window).scrollTop() > sidebarOffset.top) {
$(".sidebar").stop().animate({marginTop: $(window).scrollTop() - sidebarOffset.top + sidebarPadding });
}
else {
$(".sidebar").stop().animate({marginTop: 0});
};
});
edit
One thing I thought about was (not sure if this is possible) to detect if the bottom of one div was lower than the bottom of another, stop the scrolling. Is there a way to detect if the bottom of one div is lower than the other?
Check if the sidebar's height is greater then that of the content:
var ct = $(".content");
var sb = $(".sidebar");
var sbOffsetTop = sb.offset().top;
var sbPadding = 15;
$(window).scroll(function() {
if (sb.height() < ct.height()) {
if ($(window).scrollTop() > sbOffsetTop) {
sb.stop().animate({top: $(window).scrollTop() - sbOffsetTop + sbPadding });
}
else {
sb.stop().animate({top: 0});
};
};
});
See demo fiddle with large content and demo fiddle with large sidebar.
And I don't know why exactly, I would use top in conjunction with position: relative, but marginTop works also fine.