Can any explain why this jQuery.offset() shifts each time its used? - javascript

Can anyone explain to me what is happening here?
I am trying to use jQuery to center wizard elements on a page. The first time showCentered() is called on an element, it is correctly centered on the page and all looks good. The second time however the element is shifted way off to the side (and not exactly double the previous values either).
SO the first time it's called it works fine. The second (and third, .. etc) times it gets shifted farther and farther off the page.
Example Code:
function showCentered(selector){
d = $(selector);
h = d.outerHeight();
w = d.outerWidth();
hMax = $(window).height();
wMax = $(window).width();
_top = (hMax / 2) - (h / 2);
_left = (wMax / 2) - (w / 2);
if (_left < 0) _left = 0;
if (_top < 0) _top = 0;
d.offset({
top: _top,
left: _left
});
d.show();
}
//1st time, OK
$('.demo').hide();
showCentered('.demo');
//2nd time, NOT OK
$('.demo').hide();
showCentered('.demo');
Here is a working demo of the above: Codepen.io
When running the above function for the .demo element I get the following values for h, w, hMax, wMax, _top, _left, and then offset().top, offset().left. Notice how the offset values changes the second time around.
Also of note is that this will affect any element that uses offset after the first time around.
Can anyone explain why offset is shifting after each use?

You cannot reliably get the dimensions of a hidden element.
See jQuery outerHeight for hidden element
jQuery attempts to compensate, but you can sometimes still end up with incorrect values. See jQuery: height()/width() and "display:none"
EDIT: Actually the real problem is $.offset() cannot be used to correctly set the position of a hidden element. It attempts to do calculations based on the current location of the element in relation to its offset parent and these calculations are just wrong if the element is hidden. Just move d.show(); to just before you set the offset fixes the problem.

Related

Javascript - How to set the property working?

here is my code which is not working
function gauche() {
var voiture = document.getElementsByClassName("voiture")[0];
var position = window.getComputedStyle(voiture).left;
alert(position);
position = parseInt(position, 10) - 30 + "px";
alert(position);
}
I want to move "voiture" position 30px to the left. So I want to subtract 30 from the position.
This alert well 30px, then this alert well 0px (because 30 - 30 = 0)
But unfortunately, it doesn't update on my page. My "voiture" div is always with 30 px and not width 0px. Thanks
Use voiture.offsetLeft; instead of window.getComputedStyle(voiture).left; so you don't have to parse it.
The HTMLElement.offsetLeft read-only method returns the number of
pixels that the upper left corner of the current element is offset to
the left within the HTMLElement.offsetParent node.
and to set the position simply: voiture.style.left = voiture.offsetLeft - 30 + 'px';
offsetLeft doc
element.style.left doc
You need to use DOM element's style property:
voiture.style.left = parseInt(position, 10) - 30 + "px";
Also, there's a very very wrong assumption in your code: you think that setting current left value to a local variable bounds its value to the element, while this won't happen. Whenever you want to change a DOM element (and this applies to any of its properties), you need to set its properties again instead of assuming that changing a local variable will change the element.

CSS background position move as page resizes

How do I move the background position of the image so it stays between 2 elements as the page resizes?
I managed to get it working for the first one with some Javascript but that same function doesn't work for the second one.
This is what I'm getting. Here's the link.
The bottom leaf moves too much and I need it to stay between the cat and text
This is the Javascript I've got for the first leaf.
function bgPos(){
var w = $(window).width() - $('.container').width();
w = w*2;
$('.class2').css('background-position', w+'px 0')
}
$(window).on('resize', bgPos).trigger('resize');
Any ideas?
Your bgPos function fort .class2 should look very similar to bgPos function which you use for class1, but with with a horizontal delta (I've used value 500)
var w = $(window).width() - $('.container').width();
w = w/2-500;
$('.class2').css('background-position', w+'px 0')
This delta is a distance that should be kept between these "green" leaps on resize. You could find better value to keep it sharply perfect

Why does Firefox return NaN from this parseInt of a CSS padding value?

In an application I'm working on, we have a fixed height modal with form content. The modal content is usually longer than the modal, so the user will have to scroll down inside the modal container to view and fill in the entire form.
Each form <input> also has a small tooltip that appears below the <input> when it is in focus. To ensure this tooltip is visible for users if they're tabbing through the form or click on a form field close to the bottom of the current scroll position in the modal, I've written some JavaScript/jQuery to scroll the content automatically if the tooltip would be hidden by the bottom of the modal.
This is my code:
// The amount of padding an element should always have to the bottom
var padding = 50;
// Add focus event to the form elements
$(".modal-content input, .modal-content textarea").focus(function(){
// Get element bottom position relative to modal bottom
var elementBottom = $(this).offset().top + $(this).height();
var modalPadding = parseInt($('.modal-content').css('padding'), 10);
var modalBottom = $('.modal-content').offset().top + $('.modal-content').height() + modalPadding;
var distanceFromBottom = modalBottom - elementBottom;
// Get current scroll location
var modalScroll = $('.modal-content').scrollTop();
// Scroll the modal if the element's tooltip would appear outside visible area
if (distanceFromBottom < padding){
var amountToScroll = padding + modalScroll + -distanceFromBottom;
$('.modal-content').animate({ scrollTop: amountToScroll },250);
}
});
Don't worry if things seem a bit confusing out of context; the problem here is on line 8, where I use parseInt to get an integer of the content area's padding value for use in the calculation on how much to scroll the content.
.modal-content has a padding value of 15px. As you would expect, parseInt returns 15 which I can then add to the other values in my modalBottom variable. This works perfectly in Chrome, Safari and Internet Explorer 8.
However, in Firefox, this parseInt always returns NaN (Not-a-Number) for some reason. If I replace modalPadding in the modalBottom variable with 15, like in the following code, it also works in Firefox:
var modalBottom = $('.modal-content').offset().top + $('.modal-content').height() + 15;
Obviously, the only reason for using the modalPadding variable is so that we won't have to update the JS code if we change the padding of the modal content, which is unlikely. Still, it annoys me to hell that Firefox returns a NaN no matter how I try to parse the padding value into an integer.
First I thought it had to do with the radix value of parseInt (which should be 10 for base 10) but as you can see I have it right there and it still doesn't work.
I've also tried using parseFloat and removing "px" from the value with .replace('px','') before attempting to make the value an integer with parseInt, neither of which returned anything but NaN in Firefox.
I'm running Firefox 27.0.1. Can anyone please explain to me why Firefox won't parse my padding?
Documentation says:
Shorthand CSS properties (e.g. margin, background, border) are not supported. For example, if you want to retrieve the rendered margin, use: $(elem).css('marginTop') and $(elem).css('marginRight'), and so on.
Therefore you will need to specify paddingLeft or paddingTop... etc
As can see in this live example, $.css doesn't return anything in Firefox.
If your padding is going to be 15px for all directions (left, right, top and bottom) then just get one:
var modalPadding = parseInt($('.modal-content').css('paddingLeft'), 10);
Firefox can be picky with this. Padding could refer to padding left, padding right etc. If you know that all paddings are the same, try this:
Replace
var modalPadding = parseInt($('.modal-content').css('padding'), 10);
With
var modalPadding = parseInt($('.modal-content').css('padding-left'), 10);
Check out this JSFiddle.

issue with $(document).scrollLeft() as a variable

I'm trying to use the left variable to replace '1493' in this code. It works fine when it's a number but when I changed it over to use 'left' the if statement stops working.
$(document).scroll(function () {
var width = $(document).width();
var left = $(document).scrollLeft();
var postCount = $(".post").length;
var columnLength = ( width - ((postCount*743) - 1493)) - (width-(postCount*743));
if(left >= columnLength) {
$(".num").text(left);
}
});
Does anyone have any ideas where I'm going wrong with this? Any pointers would be great.
You may need to force it to be an integer:
var left = parseInt($(document).scrollLeft());
Lets take a look at the math you have really quick.
var columnLength = ( width - ((postCount*743) - 1493)) - (width-(postCount*743));
You are basically cancelling out width, and (postCount*743). It leaves you with --1493 which is positive 1493. The following would have the same effect:
var columnLength = 1493;
So, the reason the if statement fires when you put in the static value 1493, is because columnLength ALWAYS equals 1493 which, of course satisfies this condition:
if (1493 >= columnLength)
You could as easily write:
if (1493 >= 1493)
That said, it should still, theoretically fire when left becomes greater than or equal to 1493. But left is the current horizontal scroll position in pixels. It would be a HUGELY wide page to hit a scroll position of 1493.
Edit: Here's a fiddle to give an idea of how fast the scroll position increases: http://jsfiddle.net/vdQ7B/16/
EDIT 2:
Here is an update in response to your comment.
As I understand it, you were trying to get a horizontal scrollbar that would, essentially, scroll forever.
Please see the following fiddle for a demo: http://jsfiddle.net/vdQ7B/40/
The code is below:
$(document).scroll(function () {
var width = $(document).width();
var left = $(document).scrollLeft();
var viewportwidth = window.innerWidth;
// If our scrollbar gets to the end,
// add 50 more pixels. This could be set
// to anything.
if((left + viewportwidth) === width) {
$("body").css("width", width + 50);
}
});
Per the comments in the code, we simply increase the width of the body if we determine we've reached the end. scrollLeft() will only tell us the number of pixels that are currently not visible to the left of the viewable area. So, we need to know how much viewable area we have, and how much is hidden to the left to know if we've scrolled all the way to the end.
If you have a scroll bar on an inner element, like a div, you'd need to update with width of the div, not the body.
Note: You may also need to use $(window) instead of $(document) to get scrollLeft() to work across all browsers.
Note: See here about using "innerWidth". There are some compatibility issues, and you may need to expand it a bit to handle other cases (IE6).

Handling JQuery/CSS errors in IE

I've got some code to maximize a video panel on page load / resize. I'm using JQuery 1.4.4 and everything is working great in Chrome, Firefox and Safari. Following some examples from some other posts, I adjust the video panel size based on the rendered size and styling of the other elements on the screen.
function maximizeVideo(){
var play_height = $(window).height()-42;
var play_width = $PLAY.width() - $NAV.width();
play_width -= parseInt($NAV.css("paddingLeft"), 10) + parseInt($NAV.css("paddingRight"), 10);
play_width -= parseInt($NAV.css("marginLeft"), 10) + parseInt($NAV.css("marginRight"), 10);
play_width -= parseInt($NAV.css("borderLeftWidth"), 10) + parseInt($NAV.css("borderRightWidth"), 10);
$NAV.css('height',play_height-16+"px");
$VIDEO_PANEL.resize(play_width, play_height);
}
In IE the css accessor sometimes returns NaN. Is there a better way to account for the rendered width of the other element?
If not, what's the best way to trap these errors?
Thanks!
For your situation, I think you should be looking at the outerWidth function instead of width. Using outerWidth(true), we can obtain the width of the element including its borders, padding and margin. Therefore you can replace this line:
var play_width = $PLAY.width() - $NAV.width();
with this:
var play_width = $PLAY.width() - $NAV.outerWidth(true);
And thus eliminating the next three lines of calculations altogether.
Additionally, the height and width functions are not just getters, but also setters, so this line:
$NAV.css('height',play_height-16+"px");
can be rewritten as
$NAV.height(play_height - 16);

Categories

Resources