offsetParent is different - javascript

For chrome and ff this script works perfect, when it comes to the horrible ie. there is a problem
function getY(oElement) {
var curtop = 0;
if (oElement.offsetParent) {
while (oElement.offsetParent)
{
curtop += oElement.offsetTop;
oElement = oElement.offsetParent;
}
}
else if (oElement.y) {
curtop += oElement.y;
}
return curtop;
}
I'm tried some debugging and found out that the parent of chrome and ff is <Li> which is correct, but the parent of ie is <body>
please help anyone?
Ok, i did some more digging and found that ie doesnt support offsetparent with position:relative; but I do need this css for other reason, any walkaround?

I used to use a script similar to this all the time to determine the position of the element. Since then I have moved to using jQuery which has two awesome and very cross browser compliant functions for determining position:
position() - http://api.jquery.com/position/ - gets the position of the element relative to the parent.
offset() - http://api.jquery.com/offset/ - gets the position of the element relative to the document.
I was a little reluctant to use jQuery at first because I didn't want to spend the time learning it and because I'd already written so many code snippets on my own that did things like this. When I did try jQuery I learned it within a day and I love it and now use it for all my JavaScript projects.
This might not be the answer you are looking for, but jQuery does have position finding functions.

Related

Clickable timeline on JS audioplayer - need alternative to offsetLeft

I have integrated a javascript audioplayer in a website, and it worked without problems. But ever since i limited the width of the webpage with a container div ('max-width'), the clickable timeline is not working correctly.
I narrowed down the problem, i think. This code calculates the mouseclick on the timeline:
function clickPercent(e) {
return (e.pageX - timeline.offsetLeft) / timelineWidth;
}
The problem is that pageX counts from the left browser edge, offsetLeft on the other hand counts from the parent element's edge. So when i click on the timeline, the player-dot jumps to the wrong position.
I made a JSfiddle demo: http://jsfiddle.net/2zkj25ss/35/
I suppose that i need something different than offsetLeft, something that can give me the absolute offset instead of the relative offset.
Can anyone help me with this? Please keep in mind that i'm not a programmer, and my JavaScript skills range from poor to non-existent.
If you don't need to support IE<9 (as in, windows XP and earlier which I doubt anyone needs to support), you can use Benjamin's solution instead.
Just replace timeline.offsetLeft in the function:
function clickPercent(e) {
return (e.pageX - (timeline.getBoundingClientRect().left + window.pageXOffset)) / timelineWidth;
}

Content flicker/jump on infinite scroll/loop

I am looking for help / a point in the right direction / or a solution for a flicker/jump, when scrolling on a looping/infinite website, which can be seen in this fiddle.
What seems to be causing the jump is:
"$(window).scrollTop(half_way - child_height);", and what could also be a Chrome windows scrollTop bug, but it is happening in all browsers at the moment.
If I remove "- child_height" there is no longer a flicker but the page no longer scrolls correctly, which can be seen in this fiddle.
Also, on the very first scroll the right hand column jumps up by three boxes - also because of 'half_way', which I can fix by giving it a "bottom: -600px;"
The full code:
http://jsfiddle.net/djsbaker/j3d8r/1/
var num_children = $('#up-left').children().length;
var child_height = $('#up-left').height() / num_children;
var half_way = num_children * child_height / 2;
$(window).scrollTop(half_way);
function crisscross() {
$('#up-left').css('bottom', '-' + window.scrollY + 'px');
$('#down-right').css('bottom', '-' + window.scrollY + 'px');
var firstLeft = $('#up-left').children().first();
var lastLeft = $('#up-left').children().last();
var lastRight = $('#down-right').children().last();
var firstRight = $('#down-right').children().first();
if (window.scrollY > half_way ) {
$(window).scrollTop(half_way - child_height);
lastRight.appendTo('#up-left');
firstLeft.prependTo('#down-right');
} else if (window.scrollY < half_way - child_height) {
$(window).scrollTop(half_way);
lastLeft.appendTo('#down-right');
firstRight.prependTo('#up-left');
}
}
$(window).scroll(crisscross);
Okay - here is a 'working' version - and by works I mean it less flickery than before. I thought it was flicker free, and it was when I was on battery power, but plugged into the mains and the CPU is fast enough to get flicker.
As I mentioned, to get rid of the flicker you need to clone the objects, manipulate them and then replace them into the DOM, rather than just manipulating the DOM directly.
I did this by getting the contents of <div id="content"> manipulating them and then replacing them into that <div>.
Also, it's a good idea to only find things in the DOM once, and from then on use a reference to that object rather than searching repeatedly. e.g.
var leftSide = $(clone).find('.up-left');
....
lastRight.appendTo(leftSide);
....
$(leftSide).css('bottom', '-' + window.scrollY + 'px');
rather than:
lastRight.appendTo('#up-left');
$('#up-left').css('bottom', '-' + window.scrollY + 'px');
Searching the DOM is relatively slow, and so storing references can improve performance/reduce flicker.
Storing the object also makes the code easier to understand (imho) as you can easily see that you're referencing the same thing, rather than possibly different things.
I still get flickering in chrome on windows with Danack solution. For this site I would control all the scrolling (you already scroll manually one of the sides), and give elements absolute positions.
Or if you insist on using the browser scrolling, may be use animations: animate the height of the last elements till 0px then use appendTo, and then animato from 0px to the normal height...
This might be a long shot, but I had the same flickering when working with infinitescroll,
and ended up using imagesLoaded.I ended up appending the additional images (now loaded) with a fade in, and that prevented them from flickering because of the fact they were loaded.
So maybe by using the imagesloaded - or a callback on the images, you can solve the flickering. It does decrease the speed though. I can image that if you want to scroll through everything as fast as possible, this might not be the solution. Good luck!
A solution would be to not use the native scrolling functionality but to simulate scrolling. This would be done by setting the overflow of your content to "hidden" in addition with capturing the "mousewheel" event on it and triggering some action when it is called. I started to try this out here (using MooTools instead of jQuery since I'm more fimilar with it). It's currently just "working" on the left side by altering the margin-top of the first element.
My next steps would be:
Check if the negative margin-top of the first element is bigger than the height of it and move it to the right side if so.
Same logic for the last box on the right side with a negative margin-bottom.
This has some downsides, though. Simulating scrolling doesn't feel as natural as the native scrolling functionality and clicking the mousewheel doesn't work. These might be solveable but it would require some more coding to get it to work smoothly. Anyway, in the end you would have a solution without any flickering and with no sticky scrollbar at the side (An idea for a replacement could be a small area on the side that triggers the scrolling on mouseover).

How do I keep a bar on the bottom of a page in IE 6,7,8 or how do I force IE to redraw the interface?

I need to glue a bar to the bottom of the client view in the web browser. Traditionally I would use position:fixed; except that I need to support my IE 6 clients. I've got a very extensive hack to glue the bar to the bottom of the page and over the content, however when the user scrolls down or right, the bar stays fixed on the page.
To correct this issue I use a javascript event that gets fired using setInterval and when running the function in IE (8)'s debug tools the event fires and changes the position top and position left attributes but the page doesn't redraw the element. The code works but the element is not moving, see below.
Just so you know, the fix has to work in IE quirks mode... it can't work if the other IE versions are trying to use a standard. Believe me, I've tried.
P.S. This is really aggravating because I'm double checking IE9 support as well... get this the element does not move with the scroll bars in IE 6, 7, and 8 but moves in IE 9 and it still displays "IE Quirks Mode." And Microsoft said that this release wouldn't effect anything,...
HTML Structure
<body>
<div id="j_zoom_area" style="zoom:100%;">
The Application area the the zoom is changed (by the bar) for accessibility...
</div>
<div id="j_protectorite">
<div class="j_bar">
<div class="j_plate">Zoom Controls, Help, Search, other misc controls</div>
<div class="j_plate">Copyright info, privacy policy, etc...</div>
</div>
</div>
<script type="text/javascript" language="javascript">
j_doBar();
</script>
</body>
The CSS for the bar is https://kscserver.com/ERP-API/Style/includes.css.
The particular javascript for the bar correction.
//This controls the scrolling of the bar
function j_FixBarSlowly(){
var nTop = 0;
var nLeft = 0;
nTop = (document.body.scrollTop + document.body.clientHeight) - 67;
nLeft = document.body.scrollLeft;
//document.title = document.body.scrollTop + '+' + document.body.clientHeight + '-67' + '=' + nTop + 'px';
document.getElementById("j_protectorite").style.Top = nTop + 'px';
document.getElementById("j_protectorite").style.Left = nLeft + 'px';
document.getElementById("j_protectorite").style.Bottom = '';
document.getElementById("j_protectorite").style.Position = 'absolute';
//Ie6,7,8 hack to force redraw
}
function j_doBar() {
//j_FixBarSlowly();
//if (setInterval != undefined) {
// setTimeout("j_doBar();",5);
//} else {
setInterval("j_FixBarSlowly();",5);
//}
}
I'd suggest using an IE fix hack, such as Dean Edwards' IE7.js.
This script runs when your page loads in IE and fixes some common problems in older versions of IE. The documentation lists the things it deals with, and includes position:fixed;.
Hope that helps.
(Of course, the best solution - for your sanity - is just to give up trying to make IE6 look identical to newer browsers, and just live with a non-sticky footer in IE6. As long as it doesn't affect usability, I don't see a problem with IE6 users having a slightly less perfect page layout. But I know some people don't have the luxury of doing that; if your users are demanding it, they're the ones you have to listen to, not me!)
After further testing the best solution was to use an I Frame for the page content and have a div at the bottom of the page content. Of course a few javascript tweaks for proper sizing and you have a perfect solution.
Just for a visual reference.

Getting element position in IE versus other browsers

We all know IE6 is difficult. But there seems to be disparate behavior in positioning in later versions of IE as well, when compared with Firefox or other browsers. I have a simple pair of javascript functions which finds the position of an element, and then displays another element in relation to the first element. The idea is to get the second element, which is somewhat larger, to appear in front of the first element when the mouse hovers over it. It works fine, except on all versions of Internet Explorer, the position of the second element appears different than in Firefox.
The code to get the position of an element is:
function getPosition(e)
{
var left = 0;
var top = 0;
while (e.offsetParent) {
left += e.offsetLeft;
top += e.offsetTop;
e = e.offsetParent;
}
left += e.offsetLeft;
top += e.offsetTop;
return {x:left, y:top};
}
And the actual rollover display code is:
var pos = getPosition(elem1);
elem2.style.top = pos.y - 8;
elem2.style.left = pos.x - 6;
In Firefox, elem2 appears directly over elem1, as I want it to. But in IE7 or IE8 it appears way off. What is the reason this occurs, and is there a way to fix it?
elem2.style.top = pos.y - 8;
CSS requires a unit. +'px'.
(There could conceivably be differences between IE and other browsers depending on how exactly elem2 is positioned.)
As Pointy commented the best thing is to go and look up the jQuery (or YUI that is probably more readable) code. There are normalization needed mainly by the IE quirksmode (but it's not the only issue). For instance (but I'm not sure) I think you need to add to the left/top total amount borders' size of each positioned absolute/relative elements you encounter in the while loop, but in IE6 you need to add borders only if position is absolute at least in quirksmode.
Your code might work without adding more normalization only if you use the DOCTYPE (either Transitional or Strict) as very 1st line of your HTML pages and you reset body/html border/margins and padding. In other words use this line at the beginning of your pages:
<!DOCTYPE...
and in your CSS:
html, body {margin: 0; padding: 0; border-width: 0;}
These anyway might not suffice.

jQuery .css("margin-top", value) not updating in IE 8 (Standards mode)

I'm building an auto-follow div that is bound to the $(window).scroll() event. Here is my JavaScript.
var alert_top = 0;
var alert_margin_top = 0;
$(function() {
alert_top = $("#ActionBox").offset().top;
alert_margin_top = parseInt($("#ActionBox").css("margin-top"));
$(window).scroll(function () {
var scroll_top = $(window).scrollTop();
if(scroll_top > alert_top) {
$("#ActionBox").css("margin-top", ((scroll_top-alert_top)+(alert_margin_top*2))+"px");
console.log("Setting margin-top to "+$("#ActionBox").css("margin-top"));
} else {
$("#ActionBox").css("margin-top", alert_margin_top+"px");
};
});
});
This code assumes that there is this CSS rule in place
#ActionBox {
margin-top: 15px;
}
And it takes an element with the id "ActionBox" (in this case a div). The div is positioned in a left aligned menu that runs down the side, so it's starting offset is approximately 200 px). The goal is to start adding to the margin-top value once the user has scrolled past the point where the div might start to disappear off the top of the browser viewport (yes I know setting it to position: fixed would do the same thing, but then it would obscure the content below the ActionBox but still in the menu).
Now the console.log shows that the event is firing every time it should and it's setting the correct value. But in some pages of my web app the div isn't redrawn. This is especially odd because in other pages (in IE) the code works as expected (and it works every time in FF, Opera and WebKit). All pages evaluate (0 errors and 0 warnings according to the W3C validator and the FireFox HTMLTidy Validator), and no JS errors are thrown (according to the IE Developer Toolbar and Firebug). One other part to this mystery, if I unselect the #ActionBox margin-top rule in the HTML Style explorer in the IE Developer Tools then the div jumps immediately back in the newly adjusted place that it should have if the scroll event had triggered a redraw. Also if I force IE8 into Quirks Mode or compatibility mode then the even triggers an update.
One More thing, it works as expected in IE7 and IE 6 (thanks to the wonderful IETester for that)
I'm having a problem with your script in Firefox. When I scroll down, the script continues to add a margin to the page and I never reach the bottom of the page. This occurs because the ActionBox is still part of the page elements. I posted a demo here.
One solution would be to add a position: fixed to the CSS definition, but I see this won't work for you
Another solution would be to position the ActionBox absolutely (to the document body) and adjust the top.
Updated the code to fit with the solution found for others to benefit.
UPDATED:
CSS
#ActionBox {
position: relative;
float: right;
}
Script
var alert_top = 0;
var alert_margin_top = 0;
$(function() {
alert_top = $("#ActionBox").offset().top;
alert_margin_top = parseInt($("#ActionBox").css("margin-top"),10);
$(window).scroll(function () {
var scroll_top = $(window).scrollTop();
if (scroll_top > alert_top) {
$("#ActionBox").css("margin-top", ((scroll_top-alert_top)+(alert_margin_top*2)) + "px");
console.log("Setting margin-top to " + $("#ActionBox").css("margin-top"));
} else {
$("#ActionBox").css("margin-top", alert_margin_top+"px");
};
});
});
Also it is important to add a base (10 in this case) to your parseInt(), e.g.
parseInt($("#ActionBox").css("top"),10);
Try marginTop in place of margin-top, eg:
$("#ActionBox").css("marginTop", foo);
I found the answer!
I want to acknowledge the hard work of everyone in trying to find a better way to solve this problem, unfortunately because of a series of larger constraints I am unable to select them as the "answer" (I am voting them up because you deserve points for contributing).
The specific problem I was facing was a JavaScript onScoll event that was firing but a subsequent CSS update that wasn't causing IE8 (in standards mode) to redraw. Even stranger was the fact that in some pages it was redrawing while in others (with no obvious similarity) it wasn't. The solution in the end was to add the following CSS
#ActionBox {
position: relative;
float: right;
}
Here is an updated pastbin showing this (I added some more style to show how I am implementing this code). The IE "edit code" then "view output" bug fudgey talked about still occurs (but it seems to be a event binding issue unique to pastbin (and similar services)
I don't know why adding "float: right" allows IE8 to complete a redraw on an event that was already firing, but for some reason it does.
The correct format for IE8 is:
$("#ActionBox").css({ 'margin-top': '10px' });
with this work.
try this method
$("your id or class name").css({ 'margin-top': '18px' });

Categories

Resources