javascriptjqueryjquery-eventshashchange

hashchange event possible bug


I think I've found a really unusual bug in Javascript but I'm not sure.

So I have three child divs absolutely positioned inside a parent div (that is position relative).

The three child divs are 1200px wide and are side by side inside the parent.

So the first div is left:0px the second is left:1200px and the third is left:2400px.

Now my goal is to click and the divs shift. (The parent div is acting as a 1200px viewport)

$("#blogNav").click(function() 
{
    $("#blog").css( "left", "0px");
    $("#software").css( "left", "1200px");
    $("#about").css( "left",  "2400px");
});


$("#softwareNav").click(function() 
{
    $("#blog").css( "left", "-1200px");
    $("#software").css( "left", "0px");
    $("#about").css( "left",  "1200px");

});

$("#aboutNav").click(function() 
{
    $("#blog").css( "left", "-2400px");
    $("#software").css( "left", "-1200px");
    $("#about").css( "left",  "0px");

});

THIS WORKS PERFECTLY.

Now here's the issue.

When I do the exact same thing with a hashchange event:

window.onhashchange = function()
{
    if(window.location.hash=="#blog")
    {
            $("#blog").css( "left", "0px");
            $("#software").css( "left", "1200px");
            $("#about").css( "left",  "2400px");

    }
    if(window.location.hash=="#software")
    {
            $("#blog").css( "left", "-1200px");
            $("#software").css( "left", "0px");
            $("#about").css( "left",  "1200px");

    }
    if(window.location.hash=="#about")
    {
            $("#blog").css( "left", "-2400px");
            $("#software").css( "left", "-1200px");
            $("#about").css( "left",  "0px");
}
};

THE POSITIONING IS ALL MESSED UP.

The 0px location of the parent div is shifted so that the 0px is no longer the left border of the parent div. Its at some negative margin.

The only thing that has change is the hashevent.

I hope I'm explaining this well enough.

I'll try to upload some examples to my site soon.

It's really strange how the exact same logic works with a click event but not with a hashchange event.


Solution

  • You have two ways of achieving this.

    HTML markup (for testing, as you didn't provide any)

    <p>
        <a href="#blog">Blog</a>
        <a href="#software">Software</a>
        <a href="#about">About</a>
    </p>
    <div id="container">
        <div id="blog">Blog</div>
        <div id="software">Software</div>
        <div id="about">About</div>
    </div>
    

    - First (my choice) is to forget about using Javascript and do everything with simple CSS:

    CSS

    a {
        display: inline-block;
        margin: 0 5px;
    }
    div {
        width: 300px;
        /* 1200px would be too much to test on jsFiddle */
        height: 200px;
        color: white;
    }
    #container {
        overflow: hidden;
    }
    #container > div {
        display: inline-block;
    }
    #blog {
        background-color: red;
    }
    #software {
        background-color: blue;
    }
    #about {
        background-color: green;
    }
    

    Demo: http://jsfiddle.net/JWzaw/1/

    - Second is to use jQuery (Javascript) as you proposed:

    CSS

    a {
        display: inline-block;
        margin: 0 5px;
    }
    div {
        width: 300px;
        /* 1200px would be too much to test on jsFiddle */
        height: 200px;
        color: white;
    }
    #container {
        position: relative;
        overflow: hidden;
    }
    #container > div {
        position: absolute;
        top: 0px;
    }
    #blog {
        left: 0px;
        background-color: red;
    }
    #software {
        left: 300px;
        background-color: blue;
    }
    #about {
        left: 600px;
        background-color: green;
    }
    

    jQuery (Javascript)

    $(function () {
        $("a").on("click", function (e) {
            e.preventDefault();
    
            var left = 300;
    
            $("#container > div").not($(this)).each(function (ind, el) {
                $(this).css("left", left + "px"); 
                left += 300;
            });
    
            $($(this).prop("hash")).css("left", "0px");
        });
    });
    

    Demo: http://jsfiddle.net/JWzaw/2/