0

I've been stuck on this for a few hours now and can't seem to find the issue. I'm also having issues describing the problem, since I'm not really sure where the problem really lies. I've looked all over stackoverflow and other sites to find the solution, but so far I haven't..

I'm trying to build a one-page scroller, using jQuery. My problem basically comes down to this. Whenever I view my page and manipulate the URL fragment by typing in the addressbar to an ID of another element on my page, it navigates to the element with the ID. But since I'm using a fixed nav-bar on top of my page, it displays part of the element below the fixed element.

Is there a way to catch keydown/keyup events from manipulating the addressbar so I can make sure the segment is displayed at the correct offset? Is there a way to create a default offset after changing the URL fragment? I've tried the event 'hashchange' on the window object, but this fires also when I update the location.href.hash value to whichever segment the user is viewing. I've got a default top offset on my body element to make the initial load work with the fixed element.

It seems that a lot of other onepage-websites ignore the URL fragment and don't update the url at all unless the navigation is not at the top of the website. So you won't be able to link directly to a specific part of the website, unless the navigation is on the left or on the right.

Part of my code:

$(window).load(function(){

var segment = window.location.hash;
if(segment != ""){
    if($(segment) != []){
        var originOfSegment = $(segment).offset().top - 64;
        $("body, html").animate({"scrollTop": originOfSegment + "px"}, 0);
    }
}

$("a[href*='#']").on("click", function(e){

    if(e.preventDefault){
        e.preventDefault();
    }
    else{
        e.returnValue = false;
    }

    var segment = this.hash;

    //navigateTo(segment, 500);

    window.location.hash = segment;

});

$(window).on("scroll", function(){
    var idOfSegment = $(currentSegment).attr("id");
    window.location.hash = idOfSegment;
});

});

I'm probably not the first one with this issue, but I can't seem to find the answer to this specific problem.

It's easily reproducable even without using JavaScript to initially calculate and set the offset for the element referenced to with the URL fragment.

From a users perspective:

  • User: I go to a website using an url and an url fragment.
  • Userrequest: http://example.com/index.html#contact
  • Script: The script receives the request, sees a URL fragment is used and calculates, then defines an offset. Succes!
  • User: With this link I opened the contactform and submit some information.
  • User: Next thing I want to do, is go back to the productoverview and use the addressbar to do so.
  • Userrequest: http://example.com/index.html#products
  • Script: The hashchange event gets triggered, but no keyup-event on 'enter' can be caught, which leads to an unknown source from which the event occurred. The hash can also be changed through scrolling from segment to segment. This results in an element positioned below the fixed navbar. Since the website is not refreshed, but instead loaded from cache, there's no load or ready event I can use to calculate and adjust the offset.
Jeffrey
  • 1
  • 2
  • What I've found useful in this type of situation is to add some padding above the targets so that when the page jumps to that ID via the target click, it has ample room below the navbar. – dlane May 13 '14 at 14:49
  • I understand the logic behind this, because this will always create enough space from the top of the element. But if I want to keep my whitespace in line with the rest of the site, this would mean the height of the navbar + the normal padding, which could lead to big gaps of nothing in between pages/segments that are different from the normal usage of whitespace. – Jeffrey May 13 '14 at 14:54
  • Agreed. It's a possible solution and a design decision you'll have to make. I personally like the jQuery/JS idea of calculating the `offset` then using `.scrollTop` as @Blazemonger suggests. – dlane May 13 '14 at 15:04

1 Answers1

1

You can use JavaScript's window.scrollTo() or jQuery's .scrollTop() to scroll to a specific position. The general logic is:

  1. locate the position of the desired ID using .offset().top
  2. subtract the height of your fixed header, calculated using .outerHeight()
  3. use $(body).scrollTop() to scroll instantly to the desired position, or .animate() to scroll there in a fraction of a second.
Blazemonger
  • 90,923
  • 26
  • 142
  • 180
  • [Here's an example](http://jsfiddle.net/mblase75/7FEx5/) I used on a different site not too long ago. – Blazemonger May 13 '14 at 15:04
  • Hi Blazemonger, the thing is, that this only works initially after loading the page. If you'd change the URL fragment a second time, the offset wouldn't work because the page is loaded from the cache and doesn't seem to trigger a load or ready event. How did you manage to overcome this? – Jeffrey May 13 '14 at 15:14
  • That depends on how you're changing the fragment. Without any code, I can only point you in the right direction. Read up on the [`hashchange` event](http://stackoverflow.com/questions/680785/on-window-location-hash-change) to monitor changes to the fragment, and use [`pushState`](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history) when it's available. [Modernizr](http://modernizr.com) can test whether either of those is available in the user's browser so you can work around it if it's not. – Blazemonger May 13 '14 at 15:19
  • I want it to work from a users perspective. So if I enter a URL containing a #news fragment, I might change it to #home or #contact because I understand I can use the nav-options as URL fragments. So this change is done in the addressbar by hitting enter afterwards. The hashchange event doesn't solve the problem, because this event doesn't register keys like 'enter' to monitor changes in the addressbar for me to make sure I adjust the offset. I also change the window.location.hash to make sure my users view the link of the segment they're looking at, so they can share this part of the page. – Jeffrey May 13 '14 at 15:26
  • We can't help you further without actual code and a [narrow, well-defined problem to solve](http://stackoverflow.com/help/mcve). Please work on it yourself for a while and come post a new question when you get stuck on something. – Blazemonger May 13 '14 at 15:31
  • As I said in my post, I'm not really sure where the problem lies. Either the event or the offset? I've updated my post with some more information. Hope this helps. – Jeffrey May 13 '14 at 15:55
  • You seem to be incorporating my answer into your update. Since that fundamentally changes the nature of your original question, you should really post it as a new question. – Blazemonger May 13 '14 at 16:33
  • It might seem that way, but it's not. My questions are still unanswered and the problem remains. – Jeffrey May 13 '14 at 17:45