Question

I have inherited a project, and have some questions on how to resolve a particular issue.

There is a fixed left sub-nav, seen below. As the user scrolls, there are 6-10 different "sections" that are stacked vertically. The top section has a background-image (seen below), while the remaining sections alternate between white & various colors, such as:

section 1: background-image
section 2: background-color: white
section 3: background-color: blue
section 4: background-color: white
section 5: background-color: green
... etc

The customer wants the menu items to change colors based on what background each item is over at a given time (so as you scroll, it's changing item by item). As you can see in the image, when I scroll from the header to the first content section, I'm moving to a white background, so my menu is white text on a white background (the 5th menu item is moving into the white background).

The guys that worked on this initially used jquery waypoint to trigger wholesale changes to the menu item color when a particular div scrolled to a certain location. This basically works - but only when the entire section is scrolled to the top of the menu (meaning the menu items are white-on-white until the last menu item is scrolled into the section).

Any thoughts on how to handle this?

Fixed position image

[EDIT TO ADD]

I thought I made this pretty clear above. We're already using jquery waypoints. The problem is, waypoint cannot trigger on each menu item (primarily since the menu items are not part of the ancestral tree of the content nodes, which prohibits me from passing in a context to the waypoint handler), unless I create a handler for the section div at each offset of every menu item (which are different for each page). This would result in a crazy amount of waypoint handlers being bound, which I don't think is ideal.

Here is an example of what I'm describing. As you scroll, the menu items change all at once. You can see where this is a problem when you're scrolling down from the header into the first content section. The menu items are white. So is the background of the first content section. So until the waypoint is hit, the menu is effectively hidden. What I am looking to do is change the color of each menu item as it "enters" or "exits" a particular content div. I suppose I could do this on window.scroll, but that seems pretty expensive. Was hoping there's something I'm either missing with waypoints, or a better way to do this.

Was it helpful?

Solution

Alright, so I did solve this by creating an event handler at every offset. Given that I have 6-10 menu items per page (so 6-10 sections), I don't really like a solution where I create 36-100 event handlers, so I'm hopeful somebody has a better one (although I'm starting to doubt it).

SO is telling me I need to post code, so here goes:

HTML

<div class="menu">
    <ul>
        <li>
            <a href='#header'>Header</a>
        </li>
        <li>
            <a href='#getting-started'>Getting Started</a>
        </li>
        <li>
            <a href='#zomglaserguns'>Laser Guns</a>
        </li>
        <li>
            <a href='#pewpew'>Pew Pew</a>
        </li>
    </ul>
</div>
<div id="header" data-menu-color-down='#fff' data-menu-color-up='#000'>
    Some header content
</div>
<div class="content">
    <div id="getting-started" data-menu-color-down='#000' data-menu-color-up='#fff'>
        some content
    </div>
    <div id="zomglaserguns" data-menu-color-down='#fff' data-menu-color-up='#000'>
        laser guns!
    </div>
    <div id="pewpew" data-menu-color-down='#000' data-menu-color-up='#fff'>
        pew pew!!!!
    </div>
</div>

JS:

var myObj = {
    menuOffsets: {},
    pageSections: [],
    init: function() {
        myObj.initMenuOffsets();
        myObj.initSections();
        myObj.initWaypoints();
    },
    initMenuOffsets: function() {
        $('.menu a').each(function() {
           var self = $(this),
               href = self.attr('href'),
               menuItemHeight = self.height();
            myObj.menuOffsets[href.substring(1, href.length)] = self.offset().top + self.height();
        });
        console.log(myObj.menuOffsets);
    },
    initSections: function() {
        var header = $('#header'),
            sections = $('.content > div');
        if(header.length) {
            myObj.pageSections.push('header'); 
        }
        sections.each(function() {
            var self = $(this);
            myObj.pageSections.push(self.attr('id'));   
        });
        console.log(myObj.pageSections);
    },
    initWaypoints: function() {
        var menuItemColor,
            key,
            i = 0,
            len = myObj.pageSections.length;

        for ( i; i < len; i++ ) {
            for ( key in myObj.menuOffsets ) {
                if( myObj.menuOffsets.hasOwnProperty( key ) ) {
                    (function ( key, i ) {
                        $('#' + myObj.pageSections[i]).waypoint(function(direction) {
                            var self = $(this);
                            menuItemColor = self.data('menuColor' + (direction === 'up' ? 'Up' : 'Down'));
                            $('.menu a[href="#' + key + '"]').css('color', menuItemColor);
                        }, { offset: myObj.menuOffsets[key] });
                    })(key, i);
                }
            }
        }
    }
};
myObj.init();

SEE-ESS-ESS:

.menu {
    position: fixed;
    top: 40px;
    left: 10px;
    color: white;
}
.menu li {
    list-style-type: none;
}
.menu a {
    color: inherit;
    text-decoration: none;
}
.content {

}
#header {
    background: black;
    color: white;
    height: 200px;
    padding: 0 120px;
}
#zomglaserguns {
    background: green;
    color: #777;
}
.content div {
     min-height: 300px;  
    padding: 0 120px;
}

OTHER TIPS

Well, it's not too difficult to set up some ID's on the page, and use those as anchors for when to trigger the background change.

Say you had an HTML structure like this:

<header>
  ...
</header>
<div id="getting-started" data-background-color="lightBlue">
...
</div>
<div id="afford" data-background-color="red">
...
</div>
<div id="down-payment" data-background-color="green">
...
</div>
<div id="financing" data-background-color="blue">
...
</div>

And now you include jQuery Waypoints

<script type="text/javascript">
(function($) {
  $('#getting-started').waypoint(function() {
    var $this = $(this);
    $('header').css('background-color', $this.data('background-color'));
  });
})(jQuery)  
</script>

Keep in mind this isn't a complete solution, just something to help poke you in the right direction.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top