I have a navigation with an empty div in each anchor tag that I am styling on hover.
html
<li>SPECIAL EVENTS <div></div></li>
css
a:hover div, a:active div{
color: $black;
height: 1px;
background-color: $black;
width: 100%;
margin-top: 5px;
}
I also have a active class that I am attaching on click with some js. This is currently working correctly.
var currentDiv;
function addSelected(){
if(currentDiv !== undefined){
$(currentDiv).removeClass("active");
}
currentDiv = $(this).find('div');
$(currentDiv).addClass("active");
}
$(".menu a").click(addSelected);
What I am trying to do is attached that same active class based on the user scroll. I get most of it working, but I can't seem to figure how how to attached the class to the div, and not the anchor itself. Here is the js I'm working with.
js
// Cache selectors
var lastId,
topMenu = $("#desktop-nav"),
topMenuHeight = topMenu.outerHeight()+15,
// All list items
menuItems = topMenu.find("a"),
// Anchors corresponding to menu items
scrollItems = menuItems.map(function(){
var item = $($(this).attr("href"));
if (item.length) { return item; }
});
// Bind to scroll
$(window).scroll(function(){
// Get container scroll position
var fromTop = $(this).scrollTop()+topMenuHeight;
// Get id of current scroll item
var cur = scrollItems.map(function(){
if ($(this).offset().top < fromTop){
return this;
}
});
// Get the id of the current element
cur = cur[cur.length-1];
var id = cur && cur.length ? cur[0].id : "";
if (lastId !== id) {
lastId = id;
// Set/remove active class
menuItems
//.parent().removeClass("active")
//.end().filter("[href='#"+id+"']").parent().addClass("active");
.removeClass("active");
end().filter($("[href='#"+id+"']")).find('div').addClass("active");
console.log(id);
}
});
I think the part that I am trying to change is this
"[href='#"+id+"']").parent()
but everything I try is either not working or giving me errors.
EDIT
Here is the fiddle that I am trying to modify.
fiddle link
Use children() instead of parent() or find()
Example:
if (lastId !== id) {
lastId = id;
// add/remove active class on div
menuItems
.children().removeClass("active")
.end().filter("[href='#"+id+"']").children().addClass("active");
}
Try changing it to use find() like in your click handler:
"[href='#"+id+"']").find('div')
I assume you've tried...
"[href='#"+id+"']").parent().find('div')
and/or...
"[href='#"+id+"'].div"
...if so, are you able to add a class or id to the div and target it that way?
Related
Can someone help me with my code? This code below makes my menu items red on scroll within the div where a "scrollspy" is added. But there is something missing so my first menu item (Home) does not get red when page is loaded, only when I scroll a bit below. I need to have this 1st item red on load. How can I fix this?
An example code to make first menu item active on load?
window.onload = function() {
//code?
};
This makes menu item red when added "scrollspy" class on a row in admin
var elems = $('.scrollspy');
$(window).bind('scroll', function() {
var currentActive = null;
var currentActiveDistance = -1;
var currentTop = $(window).scrollTop();
elems.each(function(index) {
var elemTop = $(this).offset().top - 102
var id = $(this).attr('id');
var navElem = $('.menu a[href="#' + id + '"]');
navElem.removeClass('active');
if (currentTop >= elemTop) {
var distance = currentTop - elemTop;
if (currentActiveDistance > distance || currentActiveDistance == -1) {
currentActive = navElem;
}
}
});
if (currentActive) {
currentActive.addClass('active');
}
});
Why not use just CSS?
.nav li a.active {
background-color: red;
}
jQuery can be used as below to make first menu item link RED i.e by applying class active.
$(document).ready(function(){
$(".menu:first a").addClass('active');
});
Please post your HTML markup if it does not work with your HTML.
Anyone could solve this? It's a code on minimalistic scrollspy. It adds active class when content is offset.top. I know this code works but could I know if there's a way to change active class to the "a" tag instead of its parent? I removed .parent() but it doesn't seem to work. I don't want the whole li to be active. Thanks in advance.
Codepen: https://jsfiddle.net/mekwall/up4nu/
HTML
<nav class="clearfix">
<ul class="clearfix" id="top-menu">
<li>Services</li>
<li>About Us</li>
<li>Testimonials</li>
<li>Contact Us</li>
</ul>
</nav>
jQuery
// Cache selectors
var lastId,
topMenu = $("#top-menu"),
topMenuHeight = topMenu.outerHeight()+15,
// All list items
menuItems = topMenu.find("a"),
// Anchors corresponding to menu items
scrollItems = menuItems.map(function(){
var item = $($(this).attr("href"));
if (item.length) { return item; }
});
// Bind click handler to menu items
// so we can get a fancy scroll animation
menuItems.click(function(e){
var href = $(this).attr("href"),
offsetTop = href === "#" ? 0 : $(href).offset().top-topMenuHeight+1;
$('html, body').stop().animate({
scrollTop: offsetTop
}, 300);
e.preventDefault();
});
// Bind to scroll
$(window).scroll(function(){
// Get container scroll position
var fromTop = $(this).scrollTop()+topMenuHeight;
// Get id of current scroll item
var cur = scrollItems.map(function(){
if ($(this).offset().top < fromTop)
return this;
});
// Get the id of the current element
cur = cur[cur.length-1];
var id = cur && cur.length ? cur[0].id : "";
if (lastId !== id) {
lastId = id;
// Set/remove active class -- This is the part.
menuItems
.parent().removeClass("active")
.end().filter("[href='#"+id+"']").parent().addClass("active");
}
});
Here an updated working jsfiddle
First I added a CSS for a.active, because it fits the [li] space so was impossible to discern what was active.
Then you must set starting as active the tag instead the [li]
Now you can change your last 2 javascript rows to
menuItems
.parent().find('a').removeClass("active")
.find('a').end().filter("[href='#"+id+"']").addClass("active");
using find('a') to get the right tag.
I'm trying to create an active menu that inserts the CSS class .active into each list item as the user scrolls and the corresponding id is passed. I tested this in JSFiddle so I know my code is solid, but it's having no affect on the site I'm developing:
http://dev.celebrate-life.com/
Here's the jQuery:
(function($) {
// Selectors
var lastId,
topMenu = $("#menu-mainmenu"),
topMenuHeight = topMenu.outerHeight()+15,
// All list items
menuItems = topMenu.find("a"),
// Anchors corresponding to menu items
scrollItems = menuItems.map(function(){
var item = $($(this).attr("href"));
if (item.length) { return item; }
});
// Bind click handler to list items
menuItems.click(function(e){
var href = $(this).attr("href"),
offsetTop = href === "#" ? 0 : $(href).offset().top-topMenuHeight+1;
$('html, body').stop().animate({
scrollTop: offsetTop
}, 300);
e.preventDefault();
});
// Bind to scroll
$(window).scroll(function(){
// Get container scroll position
var fromTop = $(this).scrollTop()+topMenuHeight;
// Get id of current scroll item
var cur = scrollItems.map(function(){
if ($(this).offset().top < fromTop)
return this;
});
// Get the id of the current element
cur = cur[cur.length-1];
var id = cur && cur.length ? cur[0].id : "";
if (lastId !== id) {
lastId = id;
// Set/remove active class
menuItems
.parent().removeClass("active")
.end().filter("[href=#"+id+"]").parent().addClass("active");
}
});
})(jQuery);
And this is my menu structure:
<ul id="menu-mainmenu" class="x-nav">
<li>
List Item
</li>
</ul>
I have CSS for when the "active" class is applied to a list item, but it's not really relevant until I resolve the issue of applying the class to an <li> in the first place.
Why won't this work?
The scrollspy effect was working fine, but suddenly it stopped working. I mean the active element of the menu is identified while scrolling the onepage site, when the href links are given as like this href="#id". But It stops working when href is given like "/home#id". I want to use it like this. Since the site uses a common navigation.
This is my code:
/ Cache selectors
var lastId,
topMenu = $("#timenav"),
topMenuHeight = topMenu.outerHeight()+15,
// All list items
menuItems = topMenu.find("a"),
// Anchors corresponding to menu items
scrollItems = menuItems.map(function(){
var item = $($(this).attr("href"));
if (item.length) { return item; }
});
// Bind click handler to menu items
// so we can get a fancy scroll animation
menuItems.click(function(e){
var href = $(this).attr("href"),
offsetTop = href === "#" ? 0 : $(href).offset().top-topMenuHeight+1;
$('html, body').stop().animate({
scrollTop: offsetTop
}, 300);
e.preventDefault();
});
// Bind to scroll
$(window).scroll(function(){
// Get container scroll position
var fromTop = $(this).scrollTop()+topMenuHeight;
// Get id of current scroll item
var cur = scrollItems.map(function(){
if ($(this).offset().top < fromTop)
return this;
});
// Get the id of the current element
cur = cur[cur.length-1];
var id = cur && cur.length ? cur[0].id : "";
if (lastId !== id) {
lastId = id;
// Set/remove active class
menuItems
.parent().removeClass("active")
.end().filter("[href=#"+id+"]").parent().addClass("active");
}
});
can someone help me with this
http://www.drkeenly.com/
Here is a Fiddle
http://jsfiddle.net/aGjTV/
Any help would be great. Thanks in advance !
var cur = scrollItems!=null?scrollItems.map(...):null;
After this line cur is either something or null.
If it's null, then you can't index it like and array, or for that matter get its length with cur.length.
You haven't specified the error, but I bet it's saying "TypeError: cur is null".
The solution depends on what you actually want your code to do, but I'd suggest wrapping the remainder of the function in
if (cur) {
...
}
I just wrote a custom scroll-spy script, if you wish.
Check the DEMO http://jsfiddle.net/yeyene/L4Gpq/
No need scrollspy plugin anymore and you only need to add in below;
1) target to your navi link.
2) Same class to your DIVs and id: same as your target of navi.
HTML
<nav>
<ul>
<li><a target="main">Home</a></li>
<li><a target="story">Our Story</a></li>
<li><a target="work">Our Work</a></li>
<li><a target="our-news">Our News</a></li>
<li><a target="contact">Contact Us</a></li>
</ul>
</nav>
<div id="main" class="content">main</div>
<div id="story" class="content">story</div>
<div id="work" class="content">work</div>
<div id="our-news" class="content">our-news</div>
<div id="contact" class="content">contact</div>
JQUERY
$('nav li a').click(function () {
var id = $(this).attr('target');
$('html, body').stop().animate({
scrollTop: $('#'+id).offset().top
}, 500);
});
$(window).scroll(function() {
var myArray = new Array();
$('div.content').each(function() {
myArray.push($(this).offset().top);
});
for( var i=0; i<= myArray.length; i++){
if($(this).scrollTop() >= myArray[i]){
$('nav a').removeClass('active');
$('nav a').eq(i).addClass('active');
}
}
});
CSS
li {
float:left;
margin-right:10px;
list-style:none;
text-decoration:none;
}
li a {
cursor:pointer;
text-decoration:none;
z-index:11;
padding:0 5px;
}
li a.active {
background:red;
color:#fff;
}
.content {
float:left;
width:90%;
padding:45% 5%;
background:#dfdfdf;
margin-bottom:10px;
}
nav {
position:fixed;
width:100%;
padding:0 0 10px 0;
top:0;
left:0;
z-index:10;
background:green;
}
var item = $($(this).attr("href")); in your code was creating problem because when you write href="#id" it is var item = $(#id); but when you write href="/home#id" it becomes var item = $(/home#id); which is incorrect.I fixed it:
scrollItems = menuItems.map(function(){
var indexItm = $(this).attr('href').indexOf('#');
var str = $(this).attr('href').substring(indexItm);
var item = $(str);
if (item.length) { return item; }
});
Another change filter("[href*=#"+id+"]") which will check for string #id within href even in href contains any text before #:
Edited line:
menuItems
.parent().removeClass("active")
.end().filter("[href*=#"+id+"]").parent().addClass("active");
Fiddle were only foo is given href="/home#foo"
Note : the above fiddle will require a text along with # for Top href also.Otherwise it will set .active to all menu items:
Top
.
.
.
<a id="top">top</a>
I am using http://jsfiddle.net/mekwall/up4nu/ for my scrolling on a one pager. How would I deactivate the current marking when a menu item is clicked? I want to keep it on scroll. But when I am on the first item and click the fourth one, I just want the fourth one to mark current, with no marking "sliding" through second and third item.
I also tried the onePageNav, but it breaks if I have a subpage that doesn't have content (section with id) on the landing page.
This should work :) I added a noScrollAction variable. I set it before the scrolling animation starts and disable it when it's ended. But the window scroll still fires after the animation is over (haven't figured out why yet). So I put an extra delay on it. And set the active class for the right anchor.
// Cache selectors
var lastId,
topMenu = $("#top-menu"),
topMenuHeight = topMenu.outerHeight()+15,
// All list items
menuItems = topMenu.find("a"),
// Anchors corresponding to menu items
scrollItems = menuItems.map(function(){
var item = $($(this).attr("href"));
if (item.length) { return item; }
}),
noScrollAction = false;
// Bind click handler to menu items
// so we can get a fancy scroll animation
menuItems.click(function(e){
var href = $(this).attr("href"),
offsetTop = href === "#" ? 0 : $(href).offset().top-topMenuHeight+1;
noScrollAction = true;
$('html, body').stop().animate({
scrollTop: offsetTop
},{
duration: 300,
complete: function() {
menuItems
.parent().removeClass("active")
.end().filter("[href=" + href +"]").parent().addClass("active");
setTimeout(function(){ noScrollAction = false; }, 10);
}
});
e.preventDefault();
});
// Bind to scroll
$(window).scroll(function(){
if(!noScrollAction){
// Get container scroll position
var fromTop = $(this).scrollTop()+topMenuHeight;
// Get id of current scroll item
var cur = scrollItems.map(function(){
if ($(this).offset().top < fromTop)
return this;
});
// Get the id of the current element
cur = cur[cur.length-1];
var id = cur && cur.length ? cur[0].id : "";
if (lastId !== id) {
lastId = id;
// Set/remove active class
menuItems
.parent().removeClass("active")
.end().filter("[href=#"+id+"]").parent().addClass("active");
}
}
});