Cross Browser issue with jQuery offset()top return

2019-05-12 15:23发布

问题:

Essentially, what I'm trying to do, is apply a CSS class to an element in context to the scroll position of the document.

Specifically, allowing my sidebar navigation to scroll to 20px below the top of the view port along with the rest of the content, at which point the element becomes of fixed position, thanks to the css class added, until the document is subsequently scrolled back up above that point, when the class is removed and the element again scrolls with the rest of the page content.

I need the solution to be as light weight as possible and do not wish to use any library other than jQuery, which is is already in place. It should work with responsive layouts and be cross-browser compatible - including IOS and Andriod tablets.

Here's the JS I have so far, executed as $(document).ready() function:

// fixed element target
var $fixedElement = $("#fixIt");

// if the element exists
if ($($fixedElement).length > 0) {

    var $fixedElementTop = $fixedElement.offset().top -20;

        $(window).scroll(function(){
            // add .fixed else remove class
            if ($(this).scrollTop() > $fixedElementTop) {
                $('#fixIt').addClass('fixed');
            }else{
                $('#fixIt').removeClass('fixed');
            }

        });

} 

This works perfectly in all browsers (latest versions anyway) EXCEPT Safari - That's Safari.. no mistake.. it works in I.E. too! I have not tested on tablets as of this writing.

The issue is that Safari returns a different value for $fixedElementTop. It's out by around 450px.

From this I established that the lack of height attributes on responsive elements above the element that I want to apply the class to, is most likely the reason why this happens - but only in Safari.

I figure that jQuery provides a solution to such issues but can't for the life of me work out how. I've read 10 or more articles on this site, and more from elsewhere online and nothing seems to solve this.

Note: The function must work in a dynamic fashion - I can't simply take account of all of the elements above the the element that I want to add the class to and make calculations on that basis, for example, because these particulars will change from page to page.

This is why I have not included any HTML or CSS with the question - the correct solution should work using any compliant markup i think.

Any ideas? Thanks in advance.

EDIT

As per requested HTML / CSS (sorry about that ;)

HTML

<div id="billboard-wrap">

    <div class="container">

        <div class="sixteen columns">

            <div id="billboard-img">

                <img src="images/billboard-placeholder.png" alt="" class="scale-with-grid" />

            </div>

        </div>

    </div>

</div>

CSS

#billboard-wrap{
    padding:20px 0;
    line-height:0; 
}

#billboard-img{ 
    padding:10px; 
    background-color:#626262; 
}

img.scale-with-grid { 
    max-width: 100%;
    height: auto; 
}

NOTE: Just noticed the height:auto; on the scale-with-grid class.. hmm? Guess that could be it? If I change to 100% instead of auto, sure, it messes up image rendering in Safari at least, but the correct value is then returned for $fixedElementTop and JS function is as expected.

Hope this is sufficient.

Not the solution, but a clue, and conformation of what's been said in the comments perhaps.

UPDATE

So the plot thickens - I have a very basic 'allow cookies' routine in use on the related page... Clicking the link to 'allow cookies' simply sets a cookie and reloads the page:

document.location.href = $(this).attr('rel');

When in Safari the page loads after allowing cookies, the fixed element issue is resolved, until the page is reloaded! I mean, that's just nuts!?!?

Q. How can the two events be even remotely connected? Safari bug? Otherwise it must be Karma kicking me in the nuts for treading on a snail (by accident)!

回答1:

This issue was fixed by simply using $(window).load(); instead of $(document).ready(); to execute the script!