I have a page with the following functionality: there is a large image that generates scoll (both horizontally and vertically) and a button in a fixed position (it remains in the top left corner, even with scroll) that, when clicked, fits the image to the client width.
Since position: fixed is not supported in Internet Explorer 8, I used a workaround - this is the function:
function setFixedPosition(jqueryWrapper, pixelsFromTop, pixelsFromLeft) {
jqueryWrapper.css('position', 'absolute');
var setOffsets = function() {
jqueryWrapper.css("top", (($(window).scrollTop() + pixelsFromTop) + "px"));
jqueryWrapper.css("left", (($(window).scrollLeft() + pixelsFromLeft) + "px"));
};
setOffsets();
$(window).scroll(function() {
setOffsets();
});
}
setFixedPosition($('#zoomFitButton'), 15, 15);
This is the button's action:
$('#zoomFitButton').click(function() {
$('img.preview').css('width', '100%');
});
The button remains fixed both in Firefox 13 and IE8.
But, under IE8, if I am scrolling somewhere, then I click the button, the button moves to a "strange" position:
If I scroll vertically, then click, it puts the button in the lower-left corner;
If I scroll horizontally, then click, it puts the button in the upper-right corner;
If I scroll both ways, then click, it puts the button somewhere in the center.
In Firefox, the button always remains in the upper-left corner (the place where I expect it to be), even after I click the fit to width button.
Here is a test page.
Is my code OK for this functionality (in principle), or I need to add something to the fit to width action (to fix my button positioning); or there is something wrong with IE (and I need a workaround - if so, any suggestions?)?
Thanks.
I found a solution that works in IE6 also.
I think the problem has something to do with IE not updating the scrollTop and scrollLeft positions after the document is resized.
So, after I resize the picture, I have to scroll to the upper-left corner (scrollTop(0) and scrollLeft(0)).
Unfortunately, if I have a large picture that needs vertical scrolling even when it's fit to width, the workaround brings me to the top of the page. So I added code to bring me back proportionally to the aproximate position I was before. I wrapped the logic in a more generic function:
function doSomethingThatAffectsScrollPosition(affectingScrollPositionFunction) {
var oldDocumentWidth = $(document).width();
var oldScrollFromLeft = $(window).scrollLeft();
var oldDocumentHeight = $(document).height();
var oldScrollFromTop = $(window).scrollTop();
affectingScrollPositionFunction();
var newDocumentWidth = $(document).width();
var widthRatio = (newDocumentWidth / oldDocumentWidth);
var newScrollFromLeft = (oldScrollFromLeft * widthRatio);
var newDocumentHeight = $(document).height();
var heightRatio = (newDocumentHeight / oldDocumentHeight);
var newScrollFromTop = (oldScrollFromTop * heightRatio);
$(window).scrollLeft(0); // Needed for button repositioning
$(window).scrollLeft(newScrollFromLeft);
$(window).scrollTop(0); // Needed for button repositioning
$(window).scrollTop(newScrollFromTop);
}
And I used the function in the fit to width button's action:
$('#zoomFitButton').click(function() {
doSomethingThatAffectsScrollPosition(function() {
$('img.preview').css('width', '100%');
});
});
Here is a test page.
Related
I have a weird issue where my div is not scrolling vertically in Chrome on my MacBook display. If I move the window (without resizing it or anything) to a different display vertical scrolling works. If I scroll horizontally first that "unlocks" the vertical scrolling. Only in Chrome, only on the MacBook display.
I can't share the page here, but I can try to re-produce it with some different content if that is helpful. Thought I would check if it is a known issue first. I have some jquery resizing things going on that might be a lead.
setTimeout(function() {
var table_p = $("#table");
var position = table_p.position();
var viewheight = $(window).height() - position.top - 10;
table_p.height(viewheight);
$(window).resize(function() {
var table_p = $("#table");
var position = table_p.position();
var viewheight = $(window).height() - position.top - 10;
table_p.height(viewheight);
});
}, 250);
Turns out setting a height in the css for #table fixed the problem, even though the height is replaced by js soon after.
I have a collapsible aside nav (so don't know the height of it) and a div under it, which should change position to fixed when scrolled at it's bottom.
I achieved this, but when I scroll back at top, the div stays fixed and I can't find solution to make it static again at the point where it was at the beginning, since I don't know where the exact point is.
Here is a fiddle (I explain my solution in js comments): https://jsfiddle.net/1krLnv7q/2/.
Could anybode help me, please? I am stuck.
EDIT
You can define your vars outside of the scroll() event, otherwise it will cause a buggy animation.
Like this
$(function(){
//top offset of static/fixed div
var staticOffset = $('.static').offset().top;
//window height
var wpHeight = $(window).height();
//point when the user scrolls at the bottom of div
//static/fixed div height + top offset - viewport height
var treshold = staticOffset + $('.static').height() - wpHeight;
$(window).scroll(function(){
//if user scrolls below the divs bottom (treshold) it becomes fixed
if ($(window).scrollTop() > treshold){
$('.static').addClass('fix');
}else{
$('.static').removeClass('fix');
}
});
});
I have a sticky sidebar that when you scroll becomes fixed when the bottom of the sidebar is in view.
If the sidebar exceeds the length of the page as it does in this demo all works fine when you scroll and is exactly what you would expect.
However if the sidebar is shorter than the window height as in this demo, it seems to be jumping when you scroll and I can't work out how to get it to stop jumping and to be smooth. In other words it should only be fixed when the base of the sidebar hits the base of the window.
I'm not great with jQuery so any help would be greatly appreciated.
$(function () {
if ($('.leftsidebar').offset()!=null) {
var top = $('.leftsidebar').offset().top - parseFloat($('.leftsidebar').css('margin-top').replace(/auto/, 0));
var height = $('.leftsidebar').height();
var winHeight = $(window).height();
var footerTop = $('#footer').offset().top - parseFloat($('#footer').css('margin-top').replace(/auto/, 0));
var gap = 7;
$(window).scroll(function (event) {
// what the y position of the scroll is
var y = $(this).scrollTop();
// whether that's below the form
if (y+winHeight >= top+ height+gap && y+winHeight<=footerTop) {
// if so, ad the fixed class
$('.leftsidebar').addClass('leftsidebarfixed').css('top', winHeight-height-gap +'px');
}
else if (y+winHeight>footerTop) {
// if so, ad the fixed class
$('.leftsidebar').addClass('leftsidebarfixed').css('top', footerTop-height-y-gap + 'px');
}
else {
// otherwise remove it
$('.leftsidebar').removeClass('leftsidebarfixed').css('top', '0px');
}
});
}
});
Is it possible to combine the two instances? So if its shorter stay relative till the sidebar reaches the bottom, then act as it is now if the sidebar is longer?
The code works just as intended. This is actually a conceptual problem.
Picture how it would work first. The way you described it working seems to be exactly how it's working in your demo. When the sidebar is longer than the page, the scrolling page reaches the bottom of the sidebar before the leftsidebarfixed is added. That would be impossible with a shorter sidebar.
You may want to consider fixing the sidebar to the top, instead of the bottom (as most websites with sticky sidebars do) or having a taller header, so that the sidebar starts at the bottom.
Update
I've just updated the jsFiddle so that you can see the "pop up" happening and how it's never centered. It's always 200px from top.
So if the user has scrolled down a long page and clicked to make the pop up happen, the pop up is back up at the top of the page - 200px instead of centered on the visible screen.
http://jsfiddle.net/JYgcj/40/
I'll try out the answer below and update with results of that
I have a hidden div included in my layout as a partial
Here is the partial
A javascript function shows this div for showing the result of ajax requests
function showResultPopUpDiv(divId, title) {
var popUpId = document.getElementById(divId);
var popUpHeader = title;
var originalDivHTML;
var topPos = 200;
var popUpWidth;
var midPos;
var leftPos;
var spinnerOpts;
//Insert header text & open pop up
popUpId.style.display = "block";
document.getElementById("ajaxResultPopUpHeaderText").innerHTML = popUpHeader;
//Set position dimensions
popUpWidth = popUpId.offsetWidth / 2;
midPos = $(document).width() / 2;
leftPos = midPos - popUpWidth;
//Position pop up (center)
popUpId.style.top = topPos + "px";
popUpId.style.left = leftPos + "px";
//Insert spinning loader code here
... //left out for brevity
}
If a view is longer than a single screen and the user has scrolled to the bottom and clicked the submit button, this div pops up but cannot be seen unless the user scrolls back to the top.
How do I get this to center on the window correctly wherever the page is currently scrolled to.
This question and others that I've investigated have not solved this for me. Any ideas?
It sounds like what you want is a CSS position of "Fixed" (CSS Positioning 101). This will keep the object fixed relative to the viewport (the browser) rather than relative to the document. This will affect the way top and left behave.
Make sure you have something like:
#ajaxResultPopUpHeaderText {
position: fixed; /* Make the position fixed to the viewport,
so it stays in the same place no matter how much the user scrolls */
}
To centre on the viewport you need to calculate positions relative to the viewport. The full JSFiddle (forked from your original, with added content for scrolling and styling to keep the button with you as you scroll) has all of the JavaScript, but since you're working with jQuery then you just need to use $(window) instead of $(document).
//Set position dimensions
var popUpHeight = popUpId.offsetHeight / 2;
var centrePos = $(window).height() / 2;
topPos = centrePos - popUpHeight;
popUpWidth = popUpId.offsetWidth / 2;
midPos = $(window).width() / 2;
leftPos = midPos - popUpWidth;
$(document) happens to work okay for width, because the document is generally 100% of the width, but you should use $(window) anyway.
When tabbing to a form field that is below the bottom of the viewport (or typing in a textarea that overlaps the bottom), browsers usually automatically scroll up enough so that you can see the field. Is there a way to set the position the browser moves to?
This is an issue because I have a fixed position bar at the bottom of the page and so it covers up where the browser scrolls to and would like it to scroll up further.
Cheers
Sure, you could add a focus event handler to your inputs and check their position onfocus. If it's too close to the bottom, just bump the window scroll a bit until it's acceptable.
Below is how you could do it in jQuery:
// Constant amount of padding an element should be from the bottom of the window
var padding = 50;
// Add focus event to all your different form elements
$("input, textarea, select").focus(function(){
// Check their position relative to the window's scroll
var elementBottom = $(this).offset().top + $(this).height();
var windowScroll = $(window).scrollTop();
var windowBottom = windowScroll + $(window).height();
if(elementBottom + padding > windowBottom){
$(window).scrollTop(windowScroll + padding);
}
});
You can see it in action here.
Edit: Typing in textarea
You could capture and check the position of the textarea during typing using the keydown event handler:
$('textarea').keydown(function(){
// same logic as above to check textarea position relative to window
});