0

I've got a working jQuery script that runs ok meaning it serves its purpose.

The question is: how to make this script more efficient?

Currently the script becomes active the moment a user places the mouse over (hover) a certain HTML5 section-tag with an ID. At this moment the script removes the existing class named 'noDisplay' from a subordinate nav-tag containing a submenu list, hence content becomes visible to the user. This submenu list may be three to four levels deep. The submenus are held in classes (subMenu1, subMenu2, subMenu3, subMenu4, etc.). The script is written to serve individually each of the given section IDs and its sublevel classes.

Basically the script interacts with the DOM by removing the class 'noDisplay' upon mouse hover and restores the same class upon mouse leave. (Tried to give a clear explanation. If not please ask.)

Here is a JSfiddle: enter link description here

I hope someone can suggest a way to do this much more efficiently. Possibly with more sections (#ID's) and subMenu-levels (a class per level).

Using the CSS properties 'display: none;' and 'display:block;' would be the simplest solution but this is not desired because a search-bot my decide to skip content flagged as invisible to the user or a screenreader. The class 'NoDisplay' in use here keeps content invisible to users and keeps its readability to screen readers (and thus to most of the search bots).

So basically the script function remains as is to remove and add the class 'noDisplay' upon hover. The goal is to obtain a script that is more efficient that could use for instance variables for each section, instead of writing code for each new section and hence extending the current script.

//section1$("#section1 .NavUL1 .subMenu1").hover(function(){
    $(".NavUL2").removeClass("noDisplay");            //display
    },function(){
    $(".NavUL2").addClass("noDisplay");            //no display
});
$("#section1").hover(function(){
    $("#section1 .NavUL1").removeClass("noDisplay");            //display
    },function(){
    $("#section1 .NavUL1").addClass("noDisplay");            //no display
});
$("#section1 .NavUL1 .subMenu1").hover(function(){
    $(".NavUL2").removeClass("noDisplay");            //display
    },function(){
    $(".NavUL2").addClass("noDisplay");            //no display
});
//#section2
$("#section2").hover(function(){
    $("#section2 .NavUL1").removeClass("noDisplay");            //display
    },function(){
    $("#section2 .NavUL1").addClass("noDisplay");            //no display
});
$("#section2 .subMenu1").hover(function(){
    $(".subMenu1 .NavUL2").removeClass("noDisplay");            //display
    },function(){
    $(".subMenu1 .NavUL2").addClass("noDisplay");            //no display
});
$("#section2 .subMenu2").hover(function(){
    $(".subMenu2 .NavUL2").removeClass("noDisplay");            //display
    },function(){
    $(".subMenu2 .NavUL2").addClass("noDisplay");            //no display
});
$("#section2 .subMenu3").hover(function(){
    $(".subMenu3 .NavUL2").removeClass("noDisplay");            //display
    },function(){
    $(".subMenu3 .NavUL2").addClass("noDisplay");            //no display
});
$("#section2 .subMenu4").hover(function(){
    $(".subMenu4 .NavUL2").removeClass("noDisplay");            //display
    },function(){
    $(".subMenu4 .NavUL2").addClass("noDisplay");            //no display
});
3
  • your use of class and id seems off. id's are unique while class is general Commented Oct 8, 2013 at 22:40
  • I know that. It's on purpose here as the sections are unique where as the classes for subMenu1(-x) and NavUL1(-x) are not unique. Commented Oct 8, 2013 at 22:43
  • I see what is going on, it's perfectly fine to use IDs/classes in that manner. Commented Oct 8, 2013 at 22:48

3 Answers 3

3

My suggestion would be to create a new class, call it whatever but for demonstrative purposes we'll call it hover-class

Then it becomes simple:

$('.hover-class').hover(
    function() { $(this).addClass('noDisplay'); },
    function() { $(this).removeClass('noDisplay'); }
);
Sign up to request clarification or add additional context in comments.

3 Comments

Did you try this in the example fiddle provided? And how would you make the complete code more efficient? The subs should not open all at once only per section.
@snahl What I showed you is simply a smarter way to employ the use of javascript using precise selectors which can then be used declaratively on your markup. In reality your best solution would be to use CSS for CSS problems.
Thank you, I know to appreciate your contribution. Adding and removing classes from the DOM is indeed a great way to influence the output on display, especially when the limits of CSS (inheritance) are reached. [In this case] using ID allows me to manipulate a specific 'visible' target in the DOM. This adds quite a bit to efficiency manipulating the DOM. Whereas class is more general and thus manipulates (in this case) 'invisible' DOM items unnecessarily.
1

I'd recommend just using CSS, there shouldn't be a need for JS:

nav ul{
    position: absolute;
    border: 1px solid #444444;
    box-shadow: 8px 8px 11px #222222;
    background: #888;
    padding: 0.5em 0.5em 0.5em 0em;
    list-style-type: none;
    margin-left: 15%;
    display: none;
}
.sectionBox:hover nav > ul, nav li:hover > ul {
    display: block;
}

This does away with all the IDs and classes while keeping the same effect. You html looks like this now (just a snippet):

<ul>
    <li><h2>various whatever1</h2></li>
    <li><a href="localhost">link11</a></li>
    <li><a href="localhost">link12</a></li>
    <li><a href="localhost">link13</a></li>
    <li><a href="localhost">link14</a></li>
    <li><h2>sub1</h2>
        <ul>
            <li><a href="localhost">sub1-link11</a></li>
            <li><a href="localhost">sub1-link12</a></li>
            <li><a href="localhost">sub1-link13</a></li>
            <li><a href="localhost">sub1-link14</a></li>
        </ul>
    </li>
</ul>

Here it is working: http://jsfiddle.net/VGXNz/1/

Update:

If you want to use your original noDisplay styles then this would be the CSS:

nav ul{
    position:absolute;
    border: 0;
    clip: rect(0 0 0 0);
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
}
.sectionBox:hover nav > ul, nav li:hover > ul{
    height: auto;
    width: auto;
    margin: 0 0 0 15%;
    border:1px solid #444444;
    box-shadow:8px 8px 11px #222222;
    background:#888;
    padding:0.5em 0.5em 0.5em 0em;
    list-style-type:none;
    clip: auto;
    overflow: visible;
}

Here's a fiddle: http://jsfiddle.net/KKmVU/1/

4 Comments

In my question I explain that "Using the CSS property 'display: none;' would be the simplest solution but this is not desired". Sorry, this is not an answer.
@snahl - I've updated my answer to avoid using display: none;.
Even better with no jQuery at all. So basically instead of using 'display:block;' the CSS-properties for the actually hovered ID and its classes are displayed. Cool: The simpler, the better! I will add into my code and get back to you.
OK, great this works alternatively as intended (to keep the content visible to screen readers and search-bots). Thank you! I can say this solution answers my question fully in terms of making the java script code more efficient by eliminating the code in exchange of a minor edit in CSS.
0

why would you use js in the first place? Css is perfectly capable of handling hover states, and IMO you should always go for the css solution if there is one.

I made some quick (and dirty) changes to your fiddle:http://jsfiddle.net/3epRN/1/

I removed a bunch of classes and id's from the markup, removed all js, and tweaked the css a bit. The relevant css looks like this:

.sectionBox nav {
     display: none;   
}
.sectionBox:hover nav {
    display: block;
    position: absolute;
    top: 90%;
    left: 50px;
    background-color:#646464;
    z-index: 5;
}
.sectionBox nav ul ul {
    display: none;    
}
.sectionBox nav ul li {
    position: relative;
}
.sectionBox nav ul li:hover ul {
    display: block;
    position: absolute;
    top: 0;
    left: 80%;
    background-color:#646464;
    z-index: 5;
}

Obviously this needs some finetuning, but I'm sure you get the idea...

edit
I must admit I missed the part about the display:none beeing a problem for you. I do have to say I disagree with your arguments as to why (it is used al over the net, and crawlers and screen readers are smart enough nowadays).

That beeing said, nothing prevents you to use the css styling you now use to hide content (by adding the noDisplay class) directly in your css where I used the display:none;, and countering it when you want to display content by adding the following in stead of an ordinary display:block:

    height: auto;
    width: auto;
    clip: auto;
    overflow: visible;

The result would be identical to your js solution. I updated my fiddle to demonstrate: http://jsfiddle.net/3epRN/2/

2 Comments

Same here: In my question I explain that "Using the CSS property 'display: none;' would be the simplest solution but this is not desired". Sorry, this is not an answer.
Indeed this edit version works as well by eliminating java-script and adding CSS properties.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.