Responsive Horizontal Scrolling Menu

26,273

Solution 1

So, finally I think I have what you are looking for:

Fiddle: http://jsfiddle.net/fzXMg/2/

CSS and HTML is in the Fiddle...

JS:

$(function(){
    var state = 0;
    var maxState = 6;
    var winWidth = $(window).width();
    $(window).resize(function(){
        winWidth = $(window).width();
        $('.box,.container_element').width(winWidth-100);
    }).trigger('resize');
    $('#lefty').click(function(){
        if (state==0) {
           state = maxState;
        } else {
           state--;
        }
        $('.container_element').animate({scrollLeft:((winWidth-100)*state)+'px'}, 800);
    });
    $('#righty').click(function(){
        if (state==maxState) {
           state = 0;
        } else {
           state++;
        }
        $('.container_element').animate({scrollLeft:((winWidth-100)*state)+'px'}, 800);
    });
});

This uses jQuery again.

Solution 2

Now that the healthunit site has changed the original question is not completely clear.

To make a nav menu that scrolls horizontally uses arrow buttons (instead of scrollbar) can be implemented with a little jQuery and easily converted to pure JavaScript.

var $bar = $('.nav');
var $container = $('#outer');
var widths = {};
var scrollOffset = 0;

var container = document.getElementById("outer");
var bar = document.getElementById("bar");

function setMetrics() {
    metrics = {
        bar: bar.scrollWidth||0,
        container: container.clientWidth||0,
        left: parseInt(bar.offsetLeft),
        getHidden() {
            return (this.bar+this.left)-this.container
        }
    }

    updateArrows();
}

function doSlide(direction){
    setMetrics();
    var pos = metrics.left;
    if (direction==="right") {
        amountToScroll = -(Math.abs(pos) + Math.min(metrics.getHidden(), metrics.container));
    }
    else {
        amountToScroll = Math.min(0, (metrics.container + pos));
    }
    $bar.css("left", amountToScroll);
    setTimeout(function(){
        setMetrics();
    },400)
}

function updateArrows() {
    if (metrics.getHidden() === 0) {
        $(".toggleRight").addClass("text-light");
    }
    else {
        $(".toggleRight").removeClass("text-light");
    }

    if (metrics.left === 0) {
        $(".toggleLeft").addClass("text-light");
    }
    else {
        $(".toggleLeft").removeClass("text-light");
    }
}

function adjust(){
    $bar.css("left", 0);
    setMetrics();
}

$(".toggleRight").click(function(){
    doSlide("right");
});

$(".toggleLeft").click(function(){
    doSlide("left");
});

$(window).on("resize",function(){
    // reset to left pos 0 on window resize
    adjust();
});

setMetrics();

Demo: https://www.codeply.com/go/HgAVBVfQFY

Solution 3

Check out that fiddle: http://jsfiddle.net/zEPQ5/15/

It's not perfect in meaning of design, but it shows off the concept.

I used jQuery with that.

$(function(){
    var state = 0;
    $('#up').click(function(){
        state += 1;
        $('ul.wrapper').animate({marginTop:(15-state*35)+'px'},400);
    });
    $('#down').click(function(){
        state -= 1;
        $('ul.wrapper').animate({marginTop:(15-state*35)+'px'},400);
    });
});
Share:
26,273
Huginn
Author by

Huginn

Smile, it'll drive them nuts. ^_^

Updated on January 31, 2020

Comments

  • Huginn
    Huginn over 4 years

    http://healthunit.com has a clean horizontal scrolling menu at the top of the screen once you view it from a mobile phone device. I'm trying to mimic that same exact functionality thanks to a site I'm redesigning with a huge level of navigation elements.

    Requirements:

    1. Left and right scroll click options
    2. Centered list item option centered in the space
    3. Only one list item visible at a time
    4. Horizontal Scrolling & Responsive
    5. Clicking the last or first option in the list will take you to either the first option or last option in the list

    My current html for this section is:

    <nav id="sub" class="clearfix">
      <ul class="wrapper">
        <a href="#"><li>Estimate</li></a>
        <a href="#"><li>About</li></a>
        <a href="#"><li>Customer Information</li></a>
        <a href="#"><li>Financing</li></a>
        <a href="#"><li>Careers</li></a>
        <a href="#"><li>Locate Us</li></a>
        <a href="#"><li>Inspiration</li></a>
      </ul>
    </nav>
    

    The CSS currently attached to it is:

    nav#sub {
      background: #004173;
      background: linear-gradient(to bottom, #004173 0%,#014f8d 100%);
      background: -moz-linear-gradient(top, #004173 0%, #014f8d 100%);
      background: -ms-linear-gradient(top, #004173 0%,#014f8d 100%);
      background: -o-linear-gradient(top, #004173 0%,#014f8d 100%);
      background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#004173), color-stop(100%,#014f8d));
      background: -webkit-linear-gradient(top, #004173 0%,#014f8d 100%);
      border-bottom: #00325a solid 3px;
      box-shadow: 0 4px 6px 0 #BFBFBF;
      filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#004173', endColorstr='#014f8d',GradientType=0 );
      webkit-box-shadow: 0 4px 6px 0 #BFBFBF;
    }
    
    #sub ul {
      text-align: center;
    }
    
    #sub ul li {
      padding: 10px 3.3%;
    }
    
    #sub a {
      color: #fff;
      font-size: 10pt;
      font-weight: 400;
      text-decoration: none;
    }
    
    #sub ul a:hover li {
      background: #007FEB;
    }
    
  • Huginn
    Huginn almost 10 years
    Definitely heading in the right direction, the main differences I think that I see between the example and yours is that yours is scrolling vertically opposed to horizontally, and that you can go past your first and last option without returning to the top or end of the list. I'll edit the requirements to include the last part. Nice work so far though, you definitely got the idea.
  • Huginn
    Huginn almost 10 years
    Exactly it! very nice Stefan. +1 Badass Token to your coding skills.
  • Harsha
    Harsha over 9 years
    Wow it's a best answer. +1
  • Francisco Corrales Morales
    Francisco Corrales Morales almost 9 years
    what if I want more than 1 item to be show at a time ? something like < item1 item2 item3 >, like split in 4, and every time the user hits <, > it moves a shift to the side.