jQuery.offset() on <body> element provides incorrect "top" value - javascript

FIDDLE IS HERE (logs to console)
The situation is when the page starts out with a <H1> that has a margin-top greater than the margin found on <body>.
This causes the <body> to be pushed lower in the page yet $('body').offset().top remains set to the <body>'s margin-top. This of course causes my debug element (which highlights the position of elements) to be incorrect since the body's dummy element is now in the wrong position.
Curiously the rest of the $(elem).offset() values are correct for any descendant of <body>.
Is there a fix for this short of manually checking the margin-top of the recursively first childs of body with a while loop?
Noticing the issue on Safari 6 though I suspect I'll find it on Chrome as well.

It might work to use the offset plus the difference of the height of the html element minus the body element.
console.log("body.offset().top = "+ ($('html').offset().top + $('html').height() - $('body').height()));
Update: This solution will only work if there is not a margin-bottom on the page.
You could additionally add a clear div at the bottom of the page.
$('body').append("<div style=\"clear: all;\"> </div>");
Note that the div must have content to work.
http://jsfiddle.net/SCGdZ/7/

I found a John Resig post about how fast and awesome getBoundingClientRect is here... I wonder why it is not used for jQuery's offset()!
I shall use this method instead and hopefully it will not suffer from this same issue.
Update: Looks good! (the non integer top value is due to the somehow having style -webkit-margin-before: 0.67em;)
You can see that the body has margin=8

jQuery 1.9.0 has addressed this issue. Thanks so much, jQuery is awesome.

Find Here
a[0].style.marginTop it remains uninitialized even after declaring it in css that's why it was returning nothing.
Therefore we must take care of initializing a[0].style.marginTop

Related

Weird flicker in jQuery toggle

I have a weird problem and i cant find a solution no matter what i tried.
I have a simple menu that toggles few divs (slide up/down), like this:
<div class="navigation">
<ul class="left">
<li>lorem1</li>
<li>lorem2</li>
<li>lorem3</li>
</ul>
</div>
and a few divs that are being toggled.Pretty simple but there is a lot of code, so i wont paste it here.
Script that makes it work is:
$('.navigation a').click(function() {
var $requested = $(this.getAttribute('href'));
$('.top-drawer').not($requested).slideUp('slow');
$requested.slideToggle('slow')
});
Once the user clicks on the link, the div slides down more than it should, flickers and then it becomes the real height (the height is should be).
Here is a Fiddle. Please be sure to have the "Result" Window at at least 1000+ px wide otherwise it wont work (the error wont be shown).
See my suggestion on this JSFIDDLE
Here an explanation of the changes in there:
The Problem
With all those floating elements inside each .top-drawer jQuery has a lot of issues calculating the height of the div because the elements will move around while sliding up and down.
Suggestion
Switching to inline-block instead. But for that to work with your CSS, particularly with the padding on each .top-drawer, you need to use box-sizing: border-box; on anything that is using padding, inline-block and width with %. If curious you can read about this HERE.
New problem
If you go the route of inline-block (best practice now). You will need to use jQuery 1.8.xx or higher. I noticed in your fiddle you use 1.7.2, which has a bug with border-box that was fixed in versions after that.
Try to understand the code you are using.
This is the way I think jQuery's slideUp(), and slideDown() works; mainly the algorithm changes the height of the element, and display after the height is equal to the height of the element or at "0".
So when you will have your element's position set to relative you will see what you're calling "flickers", specially when you have multiple element at the same position. You will also see these "flickers" when you use fadeIn(), fadeOut() etc, because the display of the element is not instantly set to "none" or anything visible in these cases, but after the animation completes.
Solution:
Set the element's position to absolute. That should solve your issue;
example.

jquery position() not working correctly in safari and chrome

I've seen this question posed once or twice before, but never with an answer that applies to my problem (as far as I know).
I have a tooltip that appears when a link is clicked. I set the position of the tooltip based on the position of the link similar to this:
$('#tooltip').css('left', $(this).position().left);
This works great in FF, IE, etc., but in Chrome and Safari, the tooltip is always about 60 pixels or so further to the left than I want. I really don't like writing browser specific code, so is there any reason anyone knows that this would be happening?
Thanks in advance.
UPDATE:
I was able to fix this problem by removing the margin:0 auto style from the link. Soooo...that fixed it, but I still have no idea WHY this was a problem in safari and chrome.
position() relates to the position relative to the containing DOM element, as opposed to the position on screen. The difference is probably caused by differences in the way the element hierarchy is rendered in Webkit browsers, rather than by a bug in jQuery.
You will have to check element hierarchies to find out which DOM element is causing your problem, or, if you want to position your tooltip relative to the position of an element within the window boundaries, use offset() instead.
Instead of using position() like in your example:
var link = $('#mymenu a');
var tooltip = $('#mymenu #tooltip');
link.click(function(){
tooltip.css('left', $(this).position().left);
});
you can use subtraction of the element's offset() with offset() of it's parent (not necessarily the closest parent):
var parent = $('#mymenu');
var link = $('#mymenu a');
var tooltip = $('#mymenu #tooltip');
link.click(function(){
parent.css('position', 'relative');
tooltip.css('left', $(this).offset().left - parent.offset().left);
});
It returns the same value as position() but works correctly in both FF and Chrome.
According to stackoverflow ettiquette, it's okay to answer your own question, so...
I was able to fix this problem by removing the margin:0 auto style from the link. Soooo...that fixed it, but I still have no idea WHY this was a problem in safari and chrome. But, still at least it's fixed.
Just had the same problem, and removing margin: 0 auto; wasn't an option (nor is it a solution :). This worked for my needs, since webkit reports the value we're looking for as the left margin (so long as the margin is > 0, otherwise it does report position().left!):
iPosLeft = oEl.position().left + parseInt(oEl.css('marginLeft'));

javascript getelementbyid ... how to 'get' the "html" variable

function allowscroll()
{
if (screen.width<1200){document.getElementById('html').style.cssText='overflow-x: scroll !important;';};
}
<body onLoad="allowscroll();">
hi there, the above code works for any element, e.g. subbing "html" for "wrapper", but how is it possible to edit the css applied to html? Basically, because of overflow:hidden not inheriting in ie7 - which causes a big empty righthand margin and horizontal scrollbar (only in ie7, ie 8 compatibilty), ive set the css to
html {overflow-x:hidden;}
this is the only way to fix it without losing necessary functionality, e.g. overflowed graphics visibilty.
and this is all well and good, however, lower screen resolutions need the horizontal scroll just to see all of the page itself, so I'm attempting to restore the horizontal scrollbar for those users - and restore the big right margin for anyone who happens to be, for example ie7 1024 by 768 - I can live with that (unless anyone happens to have a superdupa solution).
document.getElementById('html').style.cssText='overflow-x: scroll !important;';
So the above code works for editing the CSS of any element, but not the CSS of the html.
I've also tried:
function allowscroll()
{
if (screen.width<1200){document.getElementByName('html').style.cssText='overflow-x: scroll !important;';};
}
and
function allowscroll()
{
if (screen.width<1200){window.style.cssText='overflow-x: scroll !important;';};
}
I would really appreciate any help, - if it helps in seeing the solution, the link where this applies is: delight design, basically, its how to take out:
html {overflow-x:hidden;}
from the css when in lower screen resolutions...
many thanks
Will
There are a bunch of different ways to get the html element:
document.documentElement
document.getElementsByTagName('html')[0]
document.body.parentNode
But in all honesty, there must be a better way. I don't have time right now to track down what exactly happened here, but from what I can tell, adding position:relative to whatever needs the overflow might help.
Try document.getElementsByTagName("html")[0]
Note I just edited the answer as getElementsByTagName returns an array. You want the first element in that array.
Just use the documentElement:
document.documentElement
It has full browser suport.

When does IE7 recompute styles? Doesn't work reliably when a class is added to the body

I have an interesting problem here. I'm using a class on the element as a switch to drive a fair amount of layout behavior on my site.
If the class is applied, certain things happen, and if the class isn't applied, they don't happen. Javascript is used to apply and remove the class. The relevant CSS is roughly like this:
.rightSide { display:none; }
.showCommentsRight .rightSide { display:block; width:50%; }
.showCommentsRight .leftSide { display:block; width:50%; }
And the HTML:
<body class="showCommentsRight">
<div class="container"></div>
<div class="leftSide"></div>
<div class="rightSide"></div>
</div>
<div class="container"></div>
<div class="leftSide"></div>
<div class="rightSide"></div>
</div>
<div class="container"></div>
<div class="leftSide"></div>
<div class="rightSide"></div>
</div>
</body>
I've simplified things but this is essentially the method. The whole page changes layout (hiding the right side in three different areas) when the flag is set on the body. This works in Firefox and IE8. It does not work in IE8 in compatibility mode. What is fascinating is that if you sit there and refresh the page, the results can vary. It will pick a different section's right side to show. Sometimes it will show only the top section's right side, sometimes it will show the middle.
I have tried:
- a validator (to look for malformed html)
- double checked my css formatting, and...
- making sure my IE7 hack sheet wasn't having an effect.
- putting the flag class on a different, non-body wrapper element (still has the same odd behavior)
So my question is:
- Is there a way that this behavior can be made reliable?
- When does IE7 decide to re-do styling?
Thanks everyone.
Sounds a bit like a problem I've had with ie7, where the DOM is updated but the pixels on screen is not (sometimes hovering the mouse over it triggers redraw). I found a dirty hack that worked in my case (spesudo-javascript):
//Just after changing the css class:
if(isIe7()){
addAnEmptyDivAboveTheChangedElement();
removeTheEmptyDivFromTheDom();
}
For some reason this brutal hack of adding and removing an element (it might even work if you add and remove it anywhere) causes ie7 to repaint the document. It may cause a flicker though and it's an expensive hack since it forces a full repaint in an already slow browser, that's why i only does so if I'm sure it's ie7 (to not slow every other browser just because ie7 is stupid).
Can't promise it will work, though... When I tried to find a solution to my problem I found lots of different hacks that didn't work. Fixing ie7's inconsistencies with javascript is pretty much trial and error woodoo. :)
PS:
I see toggling display is allready suggested, it might work, or as in my case, it did not. I had to actually remove the element from the dom tree to make it work..
Try this:
.showCommentsRight .rightSide { display:block !important; width:50%; }
.showCommentsRight .leftSide { display:block !important; width:50%; }
Close to a solution here, maybe someone else can bring it the last bit of the way.
The page behaves as expected if:
- If the style is assigned to the body by hand instead of using javascript.
(not an acceptable solution, but worth noting)
- If the elements that IE7 isn't updating (the .rightSide's) are manually pants-kicked with something like $(".rightSide").hide().show();
That second solution is darn close to workable, except that I actually am looking for show hide behavior out of my flag, so I'd want a less intrusive thing to change that will make IE refresh the styles.
It seems like you're running into either an IE6/IE7 reflow/repaint issue or IE6/IE7 layout issue.
See http://www.phpied.com/rendering-repaint-reflowrelayout-restyle/ for a detailed and informative analysis of what triggers reflow, repaint, etc. Also see http://www.satzansatz.de/cssd/onhavinglayout.html to find out what causes an element in IE to "have layout".
You could trigger both "having layout" and a reflow by setting height: 1%;. This is known as the Holly hack, named after the first person to document it, Holly Bergevin.
Here is my two cents. An issue with expando object was happening, so the following worked for me with a settimout delay. My issue was the background image wasn't appearing when I inserted some HTML.
app.viewModel.modules.updateSpeech = function (element) {
if ($('html').hasClass('IE7')) {
var cssClass = $(element).attr('class') || element['class'];
if (cssClass)
setTimeout(function() { $(element).removeClass(cssClass).addClass(cssClass); }, 0);
}
};

Automatically vertically scroll div contents looping

I am trying to find a simple way to have a div with just text in it automatically scroll the text vertically. I don't want to use a framework (though I do use Prototype, so if it is easier using Prototype then that is fine, but no Scriptalicious).
I assume there has got to be a way to do this with a few lines of code, but I am not familiar enough with Javascript to know how to most effectively do that.
This might not be conventional but you can try the <marquee> tag
it works both in IE and FF, and the last time I checked, safari too.
<marquee behavior="scroll" direction="up" height="250"
scrollamount="2" scrolldelay="10"">
Your content goes here
</marquee>
should give you what you want,
and you can style them like any <div>...
and then there is the added advantage of having no javascript...
Edit in response to your comment
It gets better, try this in any browser
onmouseover="this.stop()" onmouseout="this.start()"
And this in IE
style="filter:progid:DXImageTransform.Microsoft.Alpha( Opacity=0,
FinishOpacity=100,
Style=1, StartX=0, FinishX=0, StartY=0, FinishY=10)
progid:DXImageTransform.Microsoft.Alpha( Opacity=100, FinishOpacity=0,
Style=1, StartX=0, FinishX=0, StartY=90, FinishY=100)"
As attributes of the marquee tag...
function scrollDivUp(id){
document.getElementById(id).scrollTop-=1
timerUp=setTimeout("scrollDivUp('"+id+"')",10)
}
try something like that maybe.
you could also change the .scrollTop-=1 to .scrollTop+=1 to scroll the other way.
You would also need a scrollable div which can be done by constraining the size and setting the overflow style property ie. style="width:200px; height:300px; overflow:auto"
Try changing the div's scrollTop. There is an example here.
I see that the correct answer isn't given yet. I think you have to look at cloneNode() for instance. And clone the element you want to scroll. When the first element is at the last point of scrolling then place the duplicated element after the first element. And when that duplicated element is almost at the end, place the original after the duplicate and so on!

Categories