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
});
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'); }
);
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>link11</li>
<li>link12</li>
<li>link13</li>
<li>link14</li>
<li><h2>sub1</h2>
<ul>
<li>sub1-link11</li>
<li>sub1-link12</li>
<li>sub1-link13</li>
<li>sub1-link14</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/
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/
Related
I am working with a CMS. In order to show some list content I need a count on the list items to spread them evenly over the page. I did this function:
$(document).ready(function() {
$("button").click(function() {
var count = $("#page_menu ul li").length;
var breit = 945 / count;
$("#page_menu li").css("width", breit);
})
})
#page_menu ul {
margin: 0px;
top: 0px;
}
#page_menu li {
border: 1px solid #fff;
margin: 0 -1px 0 0;
display: flex;
justify-content: center;
text-align: center;
align-items: center;
}
#page_menu ul li {
height: 50px;
float: left;
list-style: none;
font-size: 13px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="page_menu">
<ul class="nav menu mod-list">
<li class="item-121"><a href="/index.php/about/querfloete" >Querflöte</li><li class="item-123"><a href="/index.php/about/autor" >Autor</li></ul>
</div>
<button>change</button>
This does exactly what it is supposed to do - TOO LATE!
To be precise: The page loads and builds the list. The javascript afterwards performs its counting function and releases it to the CSS. However, by then the CSS relating to the list doesn't get the information anymore. The button stays blank and without function regardless if it was placed before the javascript section or after. And it stays that way until I go a level down in the submenu with the same menu. Then it works fine.
And the other thing is, that I would like to load it by itself and not via clicking a button. How can I achieve this?
Sorry, I haven't been working this kind of stuff for the past 10 yrs. I am completely somewhat lost.
I am trying to create a div and show a timeout message in there. But it actually distorts other parts of Page. For eg see below. Session Timed out is the div with the message.
Now I don't want this to happen. PFB the JQuery code I am using to create this Div
function ShowSessionTimeOutDiv() {
var styler = document.createElement("div");
styler.setAttribute("style","font-size:15px;width:auto;height:auto;top:50%;left:40%;color:red;");
styler.innerHTML = "<b><i>Session TimedOut, Please refresh the Page</i></b>";
document.body.appendChild(styler);
var currentDiv = $('#GoToRequestControl1_UpdatePanel1').get(0);
currentDiv.parentNode.insertBefore(styler,currentDiv) ;
}
Am I missing something here? The Part in which this div is being displayed is coming from Master Page.
Have you tried the position:fixed styling on it in css, i did that on one of my websites and it didn't distort anything.
A page has a natural flow of its elements based on the default display rules specified by the W3C. When you add a div in between other elements it naturally affects the layout of the page; the positions of the other elements.
In order to drop in a new element without it affecting other elements you have to either reserve space for it, or take it out of the normal page flow.
There are a couple of ways to take an element out of the flow — you can float it, float:left or float:right, which is great, for example, to stack blocks on the left (instead of top-down) and let them wrap to new rows as available width changes. Using a flex layout gives you a lot of control also. But in this case of one thing popping up, changing the positioning of the new element is the most straightforward and can let you put the block exactly where you want it.
I have a demonstration and full explanation in a fiddle showing several examples along the way to getting what you want.
Basically, styling is needed to reposition the timeout message element that you're inserting. Styling is better done with CSS styles, compared to adding a bunch of inline styles. If I put my timeout popup message in a "messagebox" I can make a class for it.
/* Your styles, plus a couple extra to make the example stand out better */
div.messagebox {
font-size: 16px;
width: auto;
height: auto;
top: 40%;
left: 30%;
background-color: white;
border: 2px solid black;
}
Likewise, style the message itself with a class, instead of using inline styles and the deprecated presentational tags <b> and <i>.
/* I want the message in a messagebox to be bold-italic-red text. */
div.messagebox .message {
color: red;
font-style: italic;
font-weight: bold;
}
The big difference is that we will change the positioning of the element from the default static to instead use absolute positioning:
/* I don't really recommend a class called "positioned".
A class should describe the kind of thing the element *is*
not how it *looks*
*/
div.messagebox.positioned {
position: absolute;
width: 40%;
padding: 1.5em;
}
/* The container of the positioned element also has to be positioned.
We position it "relative" but don't move it from its natural position.
*/
section#hasposition {
position: relative;
}
The term "absolute" is tricky to learn ... the element being positioned is given an absolute position within its container, in a sense it's positioned relative to its container... but what position:relative means is relative to its own natural position, so it's easy to get confused at first over whether you want absolute or relative positioning.
Putting it all together, we have some basic HTML that represents major portions of a page — a real page will have far more, but those should be contained within some top-level containers. This shows only those top-level containers.
Then we have some javascript that will add the new element at the appropriate time. Here I just call the function to add it after a delay created with setTimeout(). I'm using full-on jQuery since you're using some in your example, and it makes the javascript more portable and more concise.
function ShowSessionTimeoutStyled() {
var styler = $('<div>').addClass('messagebox').addClass('positioned');
styler.html('<span class="message">The Session Timed Out</span>');
$('#hasposition .above').after(styler);
}
// wait 6 seconds then add the new div
setTimeout(ShowSessionTimeoutStyled, 6000);
div.messagebox {
font-size: 16px;
width: auto;
height: auto;
top: 20%;
left: 20%;
background-color: white;
border: 2px solid black;
}
div.messagebox .message {
color: red;
font-style: italic;
font-weight: bold;
}
div.messagebox.positioned {
position: absolute;
width: 40%;
padding: 1.5em;
}
section#hasposition {
position: relative;
}
/* also style some of the basic parts so you can see them better in the demonstration */
section.explanation {
margin: 1em 0.5em;
padding: 0.5em;
border: 1px solid gray;
}
.demonstration {
margin-left: 1em;
padding: 1em;
background-color: #e0e0e0;
}
.demonstration .above {
background-color: #fff0f0;
}
.demonstration .middle {
background-color: #f0fff0;
}
.demonstration .below {
background-color: #f0f0ff;
}
.demonstration footer {
background-color: white;
}
p {
margin-top: 0;
padding-top: 0;
}
section {
font-family: sans-serif;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section class="explanation">
<p>Here, a div is added dynamically, after the "basic part above", but the added div is <em>positioned</em>. You can see the other content isn't affected.</p>
<section class="demonstration" id="hasposition">
<div class="above">Basic part above</div>
<div class="middle">Middle part</div>
<div class="below">Part Below</div>
<footer>This is the page footer</footer>
</section>
</section>
I highly recommend the site Position Is Everything for articles and tutorials on positioning. Some of its other content is outdated — who needs to make PNGs to do drop-shadows any more? — but the way positioning works hasn't changed.
Goal
To have the page navigation positioned lower on the page when initially loaded. So that it looks like pictured below.
Background
I created a navigational element that is using Headroom.js to control its position. The point of the library is that it moves the desired navigational item out of view when a user is scrolling down so that you can see more content. Then the item shows up when you scroll back up to make it convenient to click on a link if that is what you needed to do.
Current State
I have this current demo on codepen.
That navigational item is at the top of the page but on a lower z-index. So not initially visible.
when you scroll down the element is out of view.
But when you scroll up, it is where it needs to be
Code
HTML
<nav id="page-menu" class="link-header header--fixed slide slide--reset" role="banner">
<ul>
<li>Products</li>
<li>Features</li>
<li>Testimonials</li>
<li>Cases</li>
</ul>
</nav>
CSS
#page-menu {
background-color: #BA222B;
list-style-type: none;
width: 100%;
z-index:10;
}
#page-menu ul {
list-style-type: none;
margin: 0;
position: absolute;
bottom: 5px;
right: 10px;
}
#page-menu ul li {
display: inline-block;
margin-left: 10px;
}
#page-menu ul li a {
text-decoration: none;
color: #fff;
}
.link-header {
background-color:#292f36;
height: 100px;
}
.header--fixed {
position:fixed;
z-index:10;
right:0;
left:0;
top:0px;
}
jQuery
(function() {
new Headroom(document.querySelector("#page-menu"), {
tolerance: 5,
offset : 150,
classes: {
initial: "slide",
pinned: "slide--reset",
unpinned: "slide--up"
}
}).init();
}());
Full demo on codepen.
Goal :
From what you are describing, you want the read navigation to appear as such on page load:
And move with the gray bar, but and down, as the user scrolls, until it cutoff point reaches the bottom of the gray bar. Then you want things to kick in, and have the red bar slide up and out of view, and then up and down depending on scroll. You want the transition to be smooth.
Method:
The thing to keep in mind for a smooth transition is that you have two states: A top state and a bottom state. You have to design both, you have to figure out the exact height to change over, and you have to make sure that they will be identical at that spot, so appear seamless.
Top State:
We don't need any sort of extra positioning here. We want it to be static in fact, as odd as that might sound.
Bottom State:
We want fixed positioning here. Since we want the changeover to occur right when the red bar touches the top of the window, your CSS in fixed-header is perfect already.
Changeover Height:
The header and the gray nav bar combined are 180px, so that number will be our change over.
Code:
1. Statechange
Lets work backwards and take the state change first. You will need to change from 150px to 180px in a lot of places. For example, your JS code:
Existing JS:
if ($(window).scrollTop() >= 150) {
...
(function() {
new Headroom(document.querySelector("#page-menu"), {
tolerance: 5,
offset : 150,
New JS:
if ($(window).scrollTop() >= 180) {
...
(function() {
new Headroom(document.querySelector("#page-menu"), {
tolerance: 5,
offset : 180,
And your header will need an updated height, or a removal of height entirely.
Existing CSS:
header {
height:150px;
position: relative;
z-index:30;
}
New CSS:
header {
position: relative;
z-index:30;
}
2. Top State
The big thing here messing you up is that for some reason the library you are using is applying .header--fixed and link-header on page load. I don't know how to prevent this, but we can just neutralize is by removing them from your CSS.
Remove This CSS:
.link-header {
background-color:#292f36;
height: 100px;
}
.header--fixed {
position:fixed;
z-index:10;
right:0;
left:0;
top:0px;
}
Second, we need to tweak the ul inside your red nav.
Existing CSS:
#page-menu ul {
list-style-type: none;
margin: 0;
position: absolute;
bottom: 5px;
right: 10px;
}
New CSS:
#page-menu ul {
list-style-type: none;
margin: 0 auto;
padding:0;
width:960px;
max-width:100%;
text-align:right;
}
3. Bottom State
Everything works really well here aleady, except that the fixed-header class is getting added to the gray nav as well. We need to tweak our jQuery selector bit.
Existing JS:
if ($(window).scrollTop() >= 180) {
$('nav#page-menu').addClass('fixed-header');
}
else {
$('nav#page-menu').removeClass('fixed-header');
}
NewJS:
if ($(window).scrollTop() >= 180) {
$('header nav').addClass('fixed-header');
}
else {
$('header nav').removeClass('fixed-header');
}
4. Misc Cleanup
Everything looks really good here, except that the lis inside our two navs don't line up. We need to fix some margin-right to bring them into line.
Existing CSS:
#page-menu ul li {
display: inline-block;
margin-left: 10px;
}
New CSS:
#page-menu ul li {
display: inline-block;
margin-left: 10px;
margin-right: 10px;
}
Finally, I noticed that there's a missing closing bracket in your HTML, in the gray nav. It's not hurting much, but it could:
<nav>
<ul>
<li>Dentists</li>
<li>Labs</li>
<li>Patients</li>
<ul> <--- ( Should be </ul> )
</nav>
End Result:
http://codepen.io/anon/pen/qIrhx
I have two divs that have been coded using javascript so that the "lightpole" div will expand to match the height of the "LayoutColumn2" div. It seems to be working fine everywhere except on the checkout page. This page has some dynamic form elements that expand once one section is completed. The lightpole div does not expand to match the expanded divs that container forms, even though they are within the larger LayoutColumn2 div.
Site: https://store-e262c.mybigcommerce.com/checkout.php?tk=eceb5394b7c03ae4a283b2eabff8f9f6
If that doesnt work add something to the cart>proceed to checkout>Select I'm a new Customer, Continue button. The lightpole break is visible near the footer and very apparent if you continue through the checkout process. I can delete users if someone wanted to create a test user.
<!--make lightPole expand to height of tallest column-->
<script type="text/javascript">
$(window).load(function(){
var ht=($('#LayoutColumn2').height() > $('#LayoutColumn3').height()) ?
$('#LayoutColumn2').height() : $('#LayoutColumn3').height(); $('#lightPole').height(ht); }); </script>
The html is lengthy and changes depending on the stage in the checkout process but I can still post it if someone wants it.
CSS
#lightPole {
background:url(../images/lightPole8aSlice.png);
margin: 0 0 0 19.9px;
padding: 0;
position: absolute;
width: 15px;
z-index: -100;
display: inline-block;
float: left;
}
#LayoutColumn2{
float: left;
height: auto;
margin: 0;
padding: 0;
width: 641px;
}
.Content {
background: url("../images/contentMiddleBackground.png") repeat scroll 0 0 transparent;
float: left;
font-size: 0.95em;
margin: 0;
min-height: 266.5px;
padding: 0 5px 0 28px;
width: 609px;
}
It's nested pretty deeply and there are several other script blocks in there so maybe one of those is causing the problem...?
Your issue is imho to resize the div(#lighPole) when the other div(#LayoutColumn2) changes its height. This can be archived e.g. using the jquery resize plugin.
<script type="text/javascript" src="/content/jquery.ba-resize.min.js"></script>
<script type="text/javascript">
$(function() {
$('#LayoutColumn2').resize(function() {
var ht = Math.max($('#LayoutColumn2').height(), $('#LayoutColumn3').height());
$('#lightPole').height(ht);
}).resize();
});
</script>
I want tabs along the left side of the page instead of across the top. I'm already loading jQuery for other reasons (effects), so I prefer using jQuery to another UI framework. Searches on "vertical tabs jquery" yield links to works-in-progress.
Is getting Vertical Tabs to work across browsers fraught, or is it so trivial that, once you have a solution, it doesn't seem worthwhile to post example code?
Have a look at the jQuery UI vertical Tabs Docu.
I try out it, it worked fine.
<style type="text/css">
/* Vertical Tabs
----------------------------------*/
.ui-tabs-vertical { width: 55em; }
.ui-tabs-vertical .ui-tabs-nav { padding: .2em .1em .2em .2em; float: left; width: 12em; }
.ui-tabs-vertical .ui-tabs-nav li { clear: left; width: 100%; border-bottom-width: 1px !important; border-right-width: 0 !important; margin: 0 -1px .2em 0; }
.ui-tabs-vertical .ui-tabs-nav li a { display:block; }
.ui-tabs-vertical .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 0; padding-right: .1em; border-right-width: 1px; border-right-width: 1px; }
.ui-tabs-vertical .ui-tabs-panel { padding: 1em; float: right; width: 40em;}
</style>
<script>
$(document).ready(function() {
$("#tabs").tabs().addClass('ui-tabs-vertical ui-helper-clearfix');
$("#tabs li").removeClass('ui-corner-top').addClass('ui-corner-left');
});
</script>
Try here:
http://www.sunsean.com/idTabs/
A look at the Freedom tab might have what you need.
Let me know if you find something you like. I worked on the exact same problem a few months ago and decided to implement myself. I like what I did, but it might have been nice to use a standard library.
I've created a vertical menu and tabs changing in the middle of the page. I changed two words on the code source and I set apart two different divs
menu:
<div class="arrowgreen">
<ul class="tabNavigation">
<li> Tab 1</li>
<li> Tab 2</li>
</ul>
</div>
content:
<div class="pages">
<div id="first">
CONTENT 1
</div>
<div id="secund">
CONTENT 2
</div>
</div>
the code works with the div apart
$(function () {
var tabContainers = $('div.pages > div');
$('div.arrowgreen ul.tabNavigation a').click(function () {
tabContainers.hide().filter(this.hash).show();
$('div.arrowgreen ul.tabNavigation a').removeClass('selected');
$(this).addClass('selected');
return false;
}).filter(':first').click();
});
//o_O\\ (Poker Face) i know its late
just add beloww css style
<style type="text/css">
/* Vertical Tabs ----------------------------------*/
.ui-tabs-vertical { width: 55em; }
.ui-tabs-vertical .ui-tabs-nav { padding: .2em .1em .2em .2em; float: left; width: 12em; }
.ui-tabs-vertical .ui-tabs-nav li { clear: left; width: 100%; border-bottom-width: 1px !important; border-right-width: 0 !important; margin: 0 -1px .2em 0; }
.ui-tabs-vertical .ui-tabs-nav li a { display:block; }
.ui-tabs-vertical .ui-tabs-nav li.ui-tabs-selected { padding-bottom: 0; padding-right: .1em; border-right-width: 1px; border-right-width: 1px; }
.ui-tabs-vertical .ui-tabs-panel { padding: 1em; float: right; width: 40em;}
</style>
UPDATED ! http://jqueryui.com/tabs/#vertical
I wouldn't expect vertical tabs to need different Javascript from horizontal tabs. The only thing that would be different is the CSS for presenting the tabs and content on the page. JS for tabs generally does no more than show/hide/maybe load content.
Another options is Matteo Bicocchi's jQuery mb.extruder tabs plug-in:
http://pupunzi.open-lab.com/mb-jquery-components/jquery-mb-extruder/
Have a look at Listamatic. Tabs are semantically just a list of items styled in a particular way. You don't even necessarily need javascript to make vertical tabs work as the various examples at Listamatic show.
super simple function that will allow you to create your own tab / accordion structure here: http://jsfiddle.net/nabeezy/v36DF/
bindSets = function (tabClass, tabClassActive, contentClass, contentClassHidden) {
//Dependent on jQuery
//PARAMETERS
//tabClass: 'the class name of the DOM elements that will be clicked',
//tabClassActive: 'the class name that will be applied to the active tabClass element when clicked (must write your own css)',
//contentClass: 'the class name of the DOM elements that will be modified when the corresponding tab is clicked',
//contentClassHidden: 'the class name that will be applied to all contentClass elements except the active one (must write your own css)',
//MUST call bindSets() after dom has rendered
var tabs = $('.' + tabClass);
var tabContent = $('.' + contentClass);
if(tabs.length !== tabContent.length){console.log('JS bindSets: sets contain a different number of elements')};
tabs.each(function (index) {
this.matchedElement = tabContent[index];
$(this).click(function () {
tabs.each(function () {
this.classList.remove(tabClassActive);
});
tabContent.each(function () {
this.classList.add(contentClassHidden);
});
this.classList.add(tabClassActive);
this.matchedElement.classList.remove(contentClassHidden);
});
})
tabContent.each(function () {
this.classList.add(contentClassHidden);
});
//tabs[0].click();
}
bindSets('tabs','active','content','hidden');