views:

182

answers:

1

Here's a long one. I'm trying to implement horizontal scrolling in my site. It's working fine in Safari and Chrome, but not in Firefox (I'll not get started on IE's issues just yet).

From what I can tell, Webkit is using the relative position of the scroll bar grabber div, while firefox is taking it's position relative to the document.

You can test it here to see what's happening.

Here's the CSS for the scroll bar

/* The Scrollbar */
#scrollbar
{
    position: relative;
    width: 70%;
    display: block;
    margin: 0px auto;
    border: #444444 1px solid;
    border-width: 0 0 1px 0;
    overflow: visible;
}

#grabber
{
    position: relative;
    top: 8px;
    left: 0px;
    height: 20px;
    display: block;
    background: url(assets/grabber-left.png) no-repeat;
}

#grabber-end
{
    height: inherit;
    width: 50%;
    background: url(assets/grabber-right.png) no-repeat;
    background-position: 100% 0;
    float: right;
}

And the jQuery that powers it

var grabberClicked = false;
var dragStart;
var grabberStart;
var ratio;
var scrollBound;
var totalWidth = 0;

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$(document).ready(function(){

    $("#projects").width(getTotalWidth());
    setup();
    $("#grabber").mousedown(startScroll);
    $(window).mouseup(endScroll);
    $("#viewport").scroll(positionGrabber);
    $(window).resize(setup);


});

function getTotalWidth(){

    $(".project").each(function(){

        totalWidth += $(this).width();
        totalWidth += parseInt($(this).css("marginLeft")) * 2;

    })

    return totalWidth;

}

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function setup(){
    ratio = $("#viewport").width() / $("#projects").width();

    // grabber width
    $("#grabber").width( $("#scrollbar").width() * ratio );
    scrollBound = $("#scrollbar").width() - $("#grabber").width();

    // incase the user resizes the window, position the grabber accordingly
    positionGrabber();
}

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function startScroll(event){
    $(window).bind('mousemove', scroll);
    var position = $("#scrollbar").position();
    dragStart = event.pageX - position.left;
    grabberStart = parseInt($("#grabber").css("left"));
    $("#feedback").html($("#grabber").position().left);
}

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function endScroll(event){
    $(window).unbind('mousemove', scroll);
}

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function scroll(event){ 
    var newPos = grabberStart + (event.pageX - dragStart);
    //$("#feedback").html($("#grabber").position().left +" // "+ newPos);

    // bounds
    newPos = (newPos > 0) ? newPos : 0;
    newPos = (newPos < scrollBound) ? newPos : scrollBound;

    viewportPos = ( $("#projects").width() * ( newPos / $("#scrollbar").width() ) );
    $("#viewport").scrollLeft(viewportPos);
    $("#grabber").css("left", newPos);

}

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function positionGrabber(event){
    var grabberPos = $("#scrollbar").width() * ($("#viewport").scrollLeft() / $("#projects").width());
    $("#grabber").css("left", grabberPos);
}

Any ideas? I know I should know the answer to this, but I've been staring at it so long I'm blind to it.

cheers

+1  A: 

I messed around a bit with your code, I think the problem is that position.left returns the position of the object relative to the window and it was returning the scrollbar position. So just changing the position variable from #scrollbar to #grabber worked for me.

var position = $("#grabber").position();

and because of this, you don't need to save the grabberStart position

Lastly, for some reason, and this took me a while to figure out, IE doesn't like binding to window events. So I switched them to document and BAM! IE is working perfectly.

Here is you script updated with the changes I mentioned. Nice looking site by the way!

// **********************************************
// Throll: Toms Horizontal Scroll 
// Developer: Tom Elders
// Contact: [email protected]
// **********************************************
// File: throll.1.0.js
// Description: 
// CSS and JS horizontal scriolling that doesn't
// break the browers native functionality. 
//
// Copyright 2010, Tom Elders
//
// **********************************************

var grabberClicked = false;
var dragStart;
var ratio;
var scrollBound;
var totalWidth = 0;

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

$(document).ready(function(){

    $("#projects").width(getTotalWidth());
    setup();
    $("#grabber").mousedown(startScroll);
    $(document).mouseup(endScroll);
    $("#viewport").scroll(positionGrabber);
    $(window).resize(setup);


});

function getTotalWidth(){

    $(".project").each(function(){

        totalWidth += $(this).width();
        totalWidth += parseInt($(this).css("marginLeft")) * 2;

    })

    return totalWidth;

}

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function setup(){
    ratio = $("#viewport").width() / $("#projects").width();

    // grabber width
    $("#grabber").width( $("#scrollbar").width() * ratio );
    scrollBound = $("#scrollbar").width() - $("#grabber").width();

    // incase the user resizes the window, position the grabber accordingly
    positionGrabber();
}

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function startScroll(event){
    $(document).bind('mousemove', scroll);
    var position = $("#grabber").position();
    dragStart = event.pageX - position.left;
}

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function endScroll(event){
    $(document).unbind('mousemove', scroll);
}

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function scroll(event){ 
    var newPos = event.pageX - dragStart;

    // bounds
    newPos = (newPos > 0) ? newPos : 0;
    newPos = (newPos < scrollBound) ? newPos : scrollBound;

    viewportPos = ( $("#projects").width() * ( newPos / $("#scrollbar").width() ) );
    $("#viewport").scrollLeft(viewportPos);
    $("#grabber").css("left", newPos);

}

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function positionGrabber(event){
    var grabberPos = $("#scrollbar").width() * ($("#viewport").scrollLeft() / $("#projects").width());
    $("#grabber").css("left", grabberPos);
}
fudgey