When you navigate through form elements or anchors using the tab key (and shift + tab) the browser automatically scrolls to that focused element. If the element is not viewable because it is a part of an overflown content where overflow is set to be hidden, it moves (or scrolls) the content's container to reveal the focused element. I want to either stop or find a way to negate this behavior
Here's something I put together to showcase the issue. I reproduced it in Chrome.
https://jsfiddle.net/charlieko/wLy7vurj/2/
var container = $("#container")
var cur = 0;
function go(increment) {
var next = cur + increment;
if (next < 0) next = 4;
else if (next > 4) next = 0;
cur = next
var newX = cur * 500;
container.css({
transform: 'translate(-' + newX + 'px, 0)'
})
}
$("#left").click(function(e) {
go(-1);
});
$("#right").click(function(e) {
go(1);
});
body {
overflow: hidden;
}
#container {
width: 2600px;
overflow: none;
transition: transform 0.4s;
transform: translate(0, 0);
overflow: hidden;
margin: 0;
}
li {
width: 500px;
text-align: center;
list-style-type: none;
float: left;
margin: 0;
padding: 0;
}
a {
color: black;
font-size: 2.0rem;
}
#ui {
position: fixed;
top: 200px;
}
#ui span {
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
<ul>
<li>Link 1 | ABCD EFG</li>
<li>Link 2 | HIJK LMNO</li>
<li>Link 3 | PQRSTU VW</li>
<li>Link 4 | XYZA BC</li>
<li>Link 5 | DEFG HI</li>
</ul>
</div>
<div id="ui">
<div>
<span id="left">Left</span>
|
<span id="right">Right</span>
</div>
<p>
Use left and right to move. Issue: Use tab key (and shift+tab) to navigate to any of the links. The container of the links shift to show the focused link. Notice the content is decentered when it happens.
</p>
</div>
The issue is that now there are two ways to slide the contents: via interacting with the left|right buttons and via tabbing through the links. When the user chooses to navigate using the tabs it messes up the sliding logic. The content is de-centered, and the index I saved in a variable no longer represents what's visible on the screen. I can handle the accessibility issue programmatically using an onFocus event, so this automatic behavior isn't helping anything.
Is there a way to stop this behavior? I already tried preventDefault() method on onFocus events on the anchor elements.
I was able to figure out a solution. What the browser does is that it scrolls the direct parent of the overflowing content to the position so that the focused element is right in the center. Simply modifying scrollLeft property of the parent element did the trick. So in the onFocus event of the link:
function onFocus (e) {
document.getElementById('content-parent').scrollLeft = 0;
// Code for repositioning the content itself using transform with transition animation
}
Overflow:hidden is usually good for content which is intended to scroll and move, so preventing that will be difficult. If you want the Tab control to stay only on things which are visible (including any buttons or links that update your slider), then you'll need a different method of hiding your content in addition to (or instead of) overflow.
Try display:none on your list items until they are within the open/visible part of div#container. That removes them from the DOM (and therefore from keyboard focus) until you're ready. If you create a class called 'hidden' with just display:none in it, then the only script you'll need is to add/remove the class from the list item when the Left/Right controls are used. I'd edit your code sample to demonstrate but I'm on a tiny screen right now.
The problem then is that your keyboard users can't reach the Left/Right controls. If you change those to button or link elements, then they'll have keyboard support by default in every browser. And then all your users are relying on your Left/Right controls no matter whether they're using a mouse or the keyboard, which gives you more control over how it looks at each stage.
You could just set tabindex to -1 for the links to avoid focusing.
You could set tabindex="-1" for elements that are off the screen. This is suggested by MDN.
https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex
Related
Using the Google Chrome browser, I need to drag-and-drop an item from a menu, in a way so that the menu will automatically close/hide/collapse/disappear/(or something similar) as soon as the dragstart event fires. This has to be done in a way such that the DOM space is freed up, so approaches using "visibility" and "opacity" for instance while possible are not good for this situation.
Instead, it is necessary to do something like display:none or pushing the menu off of the web page (without scrollbar). However, I've gotten stuck trying to accomplish this and could use some help (or if an alternative approach comes to mind that accomplishes the same, please let me know. I also tried a z-index approach without success.):
Approach 1 - Trying to hide dragged item's parent element via absolute positioning
https://jsfiddle.net/gratiafide/4m5r186v/
function dragstart_handler(ev) {
ev.dataTransfer.setData("text/plain", ev.target.id);
ev.currentTarget.parentElement.style.cssText = "position:absolute; right:-5000px;";
}
Approach 2 - Trying to hide dragged item's parent via setting display:none
https://jsfiddle.net/gratiafide/Luj7d089/
function drag(event) {
event.dataTransfer.setData("Text", event.target.id);
document.getElementById('parent').style.display = 'none';
}
You will see in both approaches, the dragged item gets dropped in both instances as soon as the CSS rule gets applied to the dragged item's parent element. I just want to be able to keep dragging the element even though I've hidden or moved the parent element out of sight. Thanks in advance for your help!
You seem to want your parents to disappear by dragging your child's element as it is.
The child element is influenced by the CSS style attribute of the parent element. If parents are erased through css properties such as "display", "visibility", and "opacity", the child element is not visible unconditionally.
Hiding using the "absolute" property(but not z-index -1) is also a way, but unwanted scrollbars may occur depending on the "overflow" attribute of the parent element, and the child element position must be added in reverse and recalculated.
As a result of my test, a dragend event occurred in Chrome when the parent element of the element to be dragged was redrawn. But in Firefox, both of your examples work.
Anyway, to explain based on how it works in Chrome, it is to separate the relationship between Child and Parent and use it as a sibling. Modify your HTML as follows.
<div id='relative_div'>
<div id="parent"></div>
<p id="source" ondragstart="dragstart_handler(event);" draggable="true">Drag me to the Drop Zone below</p>
</div>
Next update your CSS as follows. #parent should serve as a background for filling in #relative_div.
#relative_div {
position: relative;
overflow: hidden;
width: 200px;
height: 100px;
padding: 2em;
}
#parent {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
background-color: lightgrey;
}
#source {
position: relative;
cursor: grab;
color: blue;
border: 1px solid black;
}
Now, regardless of whether you use #parent's "position" to push it away, or hide it using "display", "opaicty", or "visibility", #source drag does not stop.
ok, I think my comment was wrong and that you want to remove the space on the page occupied by the origin element (rather than freeing up memory).
To achieve this, add document.body.removeChild(document.getElementById('parent')); to your drop handler. I've made a js fiddle to demonstrate (with the id=spacer div removed and an extra paragraph below it to show the element is removed):
https://jsfiddle.net/dj825rbo/
(revision following comment clarifying that the origin element should disappear as the drag begins)
This is horrible, but works (horrible because you can't see the text while it is being dragged). It relies on a hidden element into which the origin's content is stored while the drag is proceeding. Replacing the 'drop' event listener with a 'mouseup' listeners, allows the content of the temp (hidden element to be transferred to the target where the mouse click was released)
https://jsfiddle.net/dj825rbo/1/
I have a div element with overflow-y: scroll which wasn't scrolling when I used the keyboard up and down arrows. I finally found a fix which was simply to add to my div tabindex="0". I am okay with this fix, but I was very surprised that if I select text in my div to make it the selected node (proved by using window.getSelection()), arrow keys still didn't work. Apparently the target of my keydown event goes to a parent which has a tabindex.
// DIRECTIONS:
// 1) Run the Fiddle
// 2) Using the mouse select some text in the green box
// 3) Use up and down arrows to scroll
// --- Scrolling was scoped to the parent so the green box doesn't scroll
// --- Add this to the scrollBox div to fix: tabindex="0"
window.addEventListener('keydown', listener);
function listener(evt) {
console.log(`${evt.code}: ${evt.target.tagName}, ${evt.target.className}`);
//console.log(window.getSelection());
}
.foreground {
height: 100%;
width: 100%;
}
.scroll-box {
background-color: green;
overflow: scroll;
max-height: 200px;
}
<div tabindex="0" class="foreground">
<div class="scroll-box" id="scrollBox">
Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test<br>Test
</div>
</div>
Why am I seeing this behavior? Why would tabindex take precedent over the focused/selected element when it comes to using keys for scrolling? Is the recommendation then that all of my divs which overflows with scroll or auto also include tabindex?
Thanks
Update: I forgot to mention that I do not control the parent div and cannot remove the parent div's tab index.
Update 2: Even more strange behavior regarding this... elements without tabIndex do not return undefined from tabIndex, instead they always return -1. Therefore if I do document.documentElement.tabIndex = document.documentElement.tabIndex, the value before and after will be -1 when read. Only, afterward the entire document is applying the tabIndex behavior such that scrollable divs cannot be used with keyboard navigation unless they have tabIndex="0".
Is there no way to detect whether or not an element has an implied tabIndex behavior set? What if I wanted to create a function that detected whether or not the container of selected text would scroll, I would have no way of detecting for sure because of the tabIndex read behavior?
In the code below for a simple menu, if the sub-menu is expanded/showing, then I need the sub-menu to collapse on several conditions:
When the main menu or sub-menu LI is clicked
When the viewport is larger than the defined minimum width
When a click happens anywhere else on the screen
Number 2 works and number 1 works as long as I don't declare the addEventListener for the mainMenuID element. For some reason, when I add that event listener for any mainMenuID element, it takes precedence over anything else thus clicking on a main menu item other than Portfolio or its sub-menu items, expands and collapses the menu, but clicking on the submenuID or the ulID does nothing. As soon as I remove the eventlistener for mainMenuID, clicking on submenuID or ulID expand/collapse the sub-menu.
The second question is, how do I add a click event listener to the rest of the page so that if the sub-menu is showing, the click collapses the sub-menu.
Thank you!
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
</head>
<style media="screen">
body{
background-color: black;
}
nav ul {
position: relative;
text-align: left;
}
nav ul li {
display: block; /* WHAT???? REMOVING THIS ACTUALLY MAKES TEXT-DECORATIONS REAPPEAR.... WHY???*/
}
nav a {
text-decoration: none;
}
/* Hide dropdowns by default */
nav ul ul {
position: relative;
display: none;
left: 0;
}
/* Display Dropdowns on Click */
nav ul li.showSubmenu > ul {
display: block;
position: relative;
width: 30%;
}
.menu a {
text-decoration-style: none;
text-decoration: none;
background-color: black;
color: white;
}
.menu a:hover{
background-color: white;
color: black;
}
</style>
<body>
<nav id="mainMenuID" class="menu">
<ul>
<li class="menuItem">Home</li>
<li class="menuItem">About</li>
<li id="submenuItem" class="submenu_class"><span id="submenuID">Portfolio ▼</span>
<ul id="ulID">
<li>Landscape</li>
<li>Architecture</li>
<li>Animal</li>
<li>Other</li>
</ul>
</li>
<li class="menuItem">Information</li>
<li class="menuItem">Contact</li>
</ul>
</nav>
<script>
function openSubmenu() {
if (document.getElementsByClassName('showSubmenu').length == 0){
document.getElementById("submenuItem").classList.toggle("showSubmenu");
document.getElementById("submenuID").textContent = "Portfolio ▲";
} else {
document.getElementById("submenuItem").classList.toggle("showSubmenu");
document.getElementById("submenuID").textContent = "Portfolio ▼";
}
}
function resetSubmenu() {
var submenuElements = document.getElementsByClassName('submenu_class showSubmenu');
for (var i = 0; i < submenuElements.length; i++) {
submenuElements[i].setAttribute('class', 'submenu_class');
document.getElementById("submenuID").textContent = "Portfolio ►";
}
}
function screenWidthFunction(x) {
if (x.matches) {//if it's a narrow screen
document.getElementById("submenuID").textContent = "Portfolio ▼";
document.getElementById("ulID").addEventListener("click", openSubmenu, true);
document.getElementById("submenuID").addEventListener("click", openSubmenu, true);
document.getElementById("mainMenuID").addEventListener("click", openSubmenu, true);
} else {
resetSubmenu();
document.getElementById("submenuID").textContent = "Portfolio ►";
document.getElementById("ulID").removeEventListener("click", openSubmenu);
document.getElementById("submenuID").removeEventListener("click", openSubmenu);
document.getElementById("mainMenuID").removeEventListener("click", openSubmenu);
}
}
var x = window.matchMedia("(max-width: 480px)");
screenWidthFunction(x);
x.addListener(screenWidthFunction);
</script>
<>
Hi Robidu, I had this menu working using just CSS, but I was led to use JS for some of its functionality, which stopped most of the CSS from working.
So at glacier speeds, I’ve been trying to learn JS on the fly. Believe it or not, learning from videos, W3Schools, etc…. I’ve been writing, re-working, and kludging this menu into existence for the better part of 5 or 6 weeks. Totally ridiculous.
It seems you understand and are readily familiar with JS. It would take me many more weeks of trying to figure out how to implement all of your advice, and along the way, I would very likely destroy what already works. Is there any way I could kindly ask you to please save me that pain by providing me with either the code snippets for where they need to go, or just more specific advice.
I’ve excerpted below the parts of your text about which I have questions (because of the character limits on comments, I have to split them across multiple comments):
“…you should use CSS to hide the submenu since I think that this
is to be the default.”
q. Yes, it is the default. I thought I was already doing this in “nav
ul li.showSubmenu > ul {…}” in my CSS.
“…implement an initialization stage that fires on DOMContentReady
to set up a support infrastructure.”
q. This, I would never know how to figure out myself.
“…need a flag that indicates whether or not the menu is open so
that the handler can react accordingly…spare yourself the problem
with "toggle"…have the menu's state at hand…”
q. I thought the “toggling” of the class “showSubmenu” was serving as that kind of ‘flag’. How and where would I use the variable in place of the toggle?
“…spare yourself…repeatedly attaching and removing event
listeners.”, and later on “If the menu is hidden, it doesn't get any
events at all.”
q. Are you saying to assign the listeners to variables anywhere in the JS code? Would I not still need to refer to those variables in the same places where I use the listeners now and in the same manner?
“…attach an event listener that checks for mouse events to the
the item that opens the submenu here.”
q. You mean other than the listener I have on id=“submenuID”? What would be different about what you are advising?
“…attach a resize event handler to the window that performs this
check...”
q. I cropped the screen width code from W3’s examples. How/where would using innerWidth/innerHeight be different?
“…set the bubbling stage to true to intercept the event”.
q. I haven’t been able to find any explanation about bubbling works if you apply one kind to the items in a menu system, and another kind to other elements on a page, etc. I understand the basics, but couldn’t figure out why it wasn’t working on this simple menu when all three listeners were used.
“Collapsing the menu when a menu item is clicked…attach an event
handler to each individual menu item (the best spot would be the links inside the menu”.
q. Would I have to assign an ID to each LI?
Overall question: I used a NAV element with ULs and LIs because
I was told it’s the most accessible for screen readers. Is there a
better way to do what I’m trying to do with this menu or am I sort
of on the right track?
I sincerely apologize for all the follow-up questions/clarifications, but I’m sincerely spinning my wheels on this, going in circles, in rough seas, wearing a blindfold…. and any other analogy you can throw into the mix.
I would truly appreciate any specific coding you can provide to demonstrate the specifics of your advice. (or even point me to examples so that I can try and figure them out).
A bit of retooling should do the trick here.
First of all, you should use CSS to hide the submenu since I think that this is to be the default. Furthermore you should implement an initialization stage that fires on DOMContentReady to set up a support infrastructure. This way you spare yourself the hassle with repeatedly attaching and removing event listeners. You would want to attach an event listener that checks for mouse events to the item that opens the submenu here. You would also need a flag that indicates whether or not the menu is open so that the handler can react accordingly (this way you spare yourself the problem with "toggle" and the likes, plus you immediately have the menu's state at hand if you need to do any additional checks). A simple variable should do the trick here.
The plus side: If the menu is hidden, it doesn't get any events at all.
If you are interested in the window size, I'd recommend that you switch to window.innerWidth / window.innerHeight instead, because that is a numeric value that you get and which can easily be compared to the minimum size that you require. Just attach a resize event handler to the window that performs this check, and you are set. If the window size cuts below your minimum, just force the menu to collapse.
As far as collapsing the menu if the user clicks anywhere within the document, attaching an event listener looking for mouse clicks / key presses to the document object does the trick here (set the bubbling stage to true to intercept the event before anything else can happen).
Collapsing the menu when a menu item is clicked can best be achieved by attaching an event handler to each individual menu item (the best spot would be the links inside the menu - set the bubbling stage to false) that merely closes the menu.
EDIT:
I have done some tinkering now by taking your HTML and CSS, and this is what I have come up with (please note that I have also transformed the file to XHTML - but that's up to you whether or not you want to do that):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en">
<head>
<title>Submenu Test Case</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style type="text/css">
body {
background-color: black;
color: white;
}
aside {
width: 15em;
float: left;
}
nav ul {
position: relative;
text-align: left;
list-style: none; /* Kills any list decoration */
}
nav ul ul {
position: relative;
left: 0;
}
nav a {
text-decoration: none;
}
/* This ARIA attribute can greatly improve accessibility and can also be used
to actually hide elements just by tying "display: none;" to it... */
[aria-hidden="true"] {
display: none;
}
.menu a {
color: white;
}
.menu a:hover, .menu span:hover {
background-color: white;
color: black;
}
/* Style definitions that override settings for mobile devices go here! */
#media screen and (min-width: 480px)
{
/* Reposition the submenu if it's on a sufficiently wide window... */
nav ul li > ul {
position: absolute;
margin-top: -1.2em;
left: 7em;
}
}
</style>
<script type="application/javascript">
/* <![CDATA[ */
var submenu_open = false; // Has the submenu been opened?
var need_mobile = false; // Are we on a narrow window?
// Takes care of hiding and showing the submenu
function ToggleMenu(p_event)
{
// Do not activate e. g. on a right click...
if(p_event.button != 0)
return;
if(submenu_open)
{
// If the submenu has previously been open, close it (and adjust the
// controlling menu item if necessary)
document.getElementById('sub1').setAttribute('aria-hidden', 'true');
if(window.innerWidth < 480)
document.getElementById('sub-item1').childNodes[0].childNodes[0].data = 'Portfolio ▼';
}
else
{
// If the submenu has previously been closed, open it (and adjust the
// controlling menu item if necessary)
document.getElementById('sub1').setAttribute('aria-hidden', 'false');
if(window.innerWidth < 480)
document.getElementById('sub-item1').childNodes[0].childNodes[0].data = 'Portfolio ▲';
}
// This prevents the document's root node (i. e. the document object) from
// seeing the event when clicking on the superordinate item for the submenu...
p_event.stopPropagation();
submenu_open = !submenu_open;
}
// Triggered upon clicking anywhere inside of the document...
function CloseMenu(p_event)
{
if(!submenu_open)
return;
document.getElementById('sub1').setAttribute('aria-hidden', 'true');
if(window.innerWidth < 480)
document.getElementById('sub-item1').childNodes[0].childNodes[0].data = 'Portfolio ▼';
submenu_open = false;
}
function CheckWindowSize(p_event)
{
if(window.innerWidth < 480)
{
if(need_mobile)
return;
// On a mobile device, insert the submenu into the main one...
if(submenu_open)
document.getElementById('sub-item1').childNodes[0].childNodes[0].data = 'Portfolio ▲';
else
document.getElementById('sub-item1').childNodes[0].childNodes[0].data = 'Portfolio ▼';
}
else
{
if(!need_mobile)
return;
// If the window is wide enough, we can display the submenu next to the main
// one...
document.getElementById('sub-item1').childNodes[0].childNodes[0].data = 'Portfolio ►';
}
need_mobile = !need_mobile;
}
// Initialization sequence (adds a few event handlers)
document.addEventListener('DOMContentLoaded', function (p_event) {
document.getElementById('sub-item1').addEventListener('click', ToggleMenu, false);
window.addEventListener('resize', CheckWindowSize, false);
document.addEventListener('click', CloseMenu, false);
// If we are on a mobile device, adjust the text of the menu item.
if(window.innerWidth < 480)
{
need_mobile = true;
document.getElementById('sub-item1').childNodes[0].childNodes[0].data = 'Portfolio ▼';
}
}, false);
/* ]]> */
</script>
</head>
<body>
<header><h1>Submenu Test Case</h1></header>
<aside>
<nav class="menu">
<ul>
<li class="menuItem">Home</li>
<li class="menuItem">About</li>
<!-- Assume normal operation here (window width >= 480 pixels) so the
text is set accordingly...
Please note that I have removed some extraneous elements and
attributes. -->
<li class="submenu" id="sub-item1"><span>Portfolio ►</span>
<ul id="sub1" aria-hidden="true">
<li>Landscape</li>
<li>Architecture</li>
<li>Animal</li>
<li>Other</li>
</ul>
</li>
<li class="menuItem">Information</li>
<li class="menuItem">Contact</li>
</ul>
</nav>
</aside>
<main />
</body>
</html>
Please see the annotations in the (X)HTML for details on what's going on there.
By working on this I have discovered that I could greatly simplify the method that I have mentioned yet again so it just boils down to three events:
Resize: Switches the menu layout when the window width undercuts a certain threshold
Mouse click on menu item: Opens or closes the submenu
Mouse click anywhere else: Closes the menu
As for your questions...
ad 1.: I have done a bit of retooling of the CSS that you have provided. I have tossed some definitions out and have tied hiding any elements to the aria-hidden attribute (if that is set to true, the element is not displayed). Said attrtibute also helps a lot in improving accessibility. In this example, if you cannot see it on the screen, a screenreader won't display it, either.
ad 2.: It's rather simple to set up. Just include document.addEventListener('DOMContentLoaded', function (p_event) { }, false);
in the main execution path and add anything that needs to be set up into the function. This is crucial especially for so-called unobtrusive JavaScript (that is, JavaScript that itself attaches hooks to the document where needed instead of hard-coding them into the (X)HTML).
ad 3.: You can get that done with a simple variable (a boolean that indicates whether the menu is open). You can then quickly check on the menu's state without having to query the DOM.
ad 4.: That is extremely tedious and costly at best so handlers are only attached once. The rest should be up to the control logic whether any events are silently ignored (by just returning if certain conditions aren't met).
ad 5.: It takes a handler of the sort that you have implemented, but I have simplified it a bit to avoid calling the DOM where unnecessary (it resorts to the aforementioned flag), plus it also takes into account the window's width for adjusting the text.
ad 6.: innerWidth / innerHeight are numeric values that can easily be returned by the DOM. I don't know about your method, but by my reckon it seems to be a bit expensive, plus when you store the value in a variable, you can perform multiple checks on it (e. g. if you need to check for different widths/heights), which just requires simple comparisons. Your approach would require you to reset the matching condition.
ad 7.: I need to correct myself here, because by chewing on your problem I found that everything (i. e. the third parameter to addEventListener) should be set to false. Otherwise the order of execution is messed up, or some links don't see the event in the first place.
ad 8.: Turned out to be unnecessary as well. I had derived my initial answer from a context menu that I have implemented in JavaScript, but because of its nature I had to resort to these handlers to close it. Here things are a little different so things can be simplified just by omitting these handlers.
ad 9.: You actually have picked the best way here. When implementing a navigation, I'm also using this approach.
I hope I could turn some of your question marks into exclamation marks. However, if you still have questions, by all means, please ask. There's nothing worse than questions left unanswered.
For a one-page layout website I would need the current section's heading to display in a fixed position on the left side of the screen in order to show the user where he currently is.
The heading will probably have an icon on its left side. I would like the floating heading to be only visible when the user is scrolling on the page, thus disappear when he halts, while the icon stays visible all the time. Is that possible?
This is possible, and most easily done in JQuery. In CSS using
position: fixed;
Will allow you to position a element, then it'll stick where it is on the screen, regardless of the user scrolling up and down the page. Using this JQuery code:
$(window).scroll(function(){
}
Will detect when the user scrolls then will run whatever is inside of the function. If you put this inside of the function:
$("#scrollerbar").css({"display": "block"});
clearTimeout($.data(this, 'scrollTimeout'));
$.data(this, 'scrollTimeout', setTimeout(function() {
$("#scrollerbar").css({"display": "none"});
}, 250));
With this HTML:
<div id="scrollerbar">You're scrolling</div>
And the following CSS:
#scrollerbar{
display: none;
position: fixed;
top: 50px;
left: 0;
}
This will create and position the div scrollerbar 50px down the page and set it to be invisible. Then whenever the user scrolls, it will set the scrollerbar to display: block (which makes it visible). Then stops the timeout "scrollTimeout" (if it's running). Then create the timeout "scrollTimeout" what will wait 250 milliseconds then set scrollerbar to invisible again.
Here's a JSFiddle: http://jsfiddle.net/Xanco/5q6oq8tm/
Please contact me if you have some questions.
EDIT
In order to answer the first part of your question, I've updated the JSFiddle: http://jsfiddle.net/Xanco/5q6oq8tm/2/
The scrollerbar contains a set of list items, each will be bound to a div:
<li id="1read">Reading 1</li>
<li id="2read">Reading 2</li>
<li id="3read">Reading 3</li>
<li id="4read">Reading 4</li>
There's also a new class name:
.active{
font-weight: bold;
}
I've created a function that will remove all "active" class names from the list items in the scrollerbar:
function removeActive(){
$("#1read").removeClass("active");
$("#2read").removeClass("active");
$("#3read").removeClass("active");
$("#4read").removeClass("active");
}
And now whenever the user scrolls, JavaScript will check what the user is currently reading and add the "active" class to the appropriate list items in the scrollerbar:
if ($("#1").is(":hover")) {
removeActive();
$("#1read").addClass("active");
}
if ($("#2").is(":hover")) {
removeActive();
$("#2read").addClass("active");
}
if ($("#3").is(":hover")) {
removeActive();
$("#3read").addClass("active");
}
if ($("#4").is(":hover")) {
removeActive();
$("#4read").addClass("active");
}
EDIT 2
Now, the JavaScript will take the innerText of a child of the hovered div with the ID "articleheader" instead of using a non-standard attribute, as demonstrated by this line of code:
$("#displayaArticleName").text($(this).children("#articleheader")[0].innerText);
Here is the JSfiddle: http://jsfiddle.net/5q6oq8tm/6/
Please note that there are no set of attributes that can only be used, you may use custom attributes, as demonstrated here: http://jsfiddle.net/5q6oq8tm/4/
I have an interesting problem.
Background: I have a simple header. A logo and two links are floated on the left side, while two drop down menu links are floated on the right, all contained in a header div that i 100% width. If I shrink the screen horizontally enough the two drop down menu links dropped below the left-floated elements (of course). After doing some research I decided to use overflow: hidden on the parent header div so that the two drop-down menus would disappear instead of dropping to the next line. This solution works great in my situation. However, I found that the drop-down menu layer was cut off below the header because of the overflow:hidden solution. Just for reference, my drop down menu was created using simple javascript that toggles between css classes to get the drop down effect. I simply added a line to the function onclick events in the javascript that when a menu link is clicked on, overflow changes from overflow:hidden to overflow: none (and of course toggles back to hidden when the menu is unclicked), which works great because there is supposed to never be overflow if the menu buttons are visible (they disappear and are hidden when there is overflow,).
Problem: If a user opens a menu (aka clicks on a drop down menu link) and THEN shrinks the horizontal scrollbar without first closing the menu, the header has an overflow that is still set to none because the user hasn't toggled the header back to hidden because the menu is still open. Thus, my original problem of the two menu links dropping beneath the floated left divs again. Working with what I'm already doing, I'm trying to come up with some kind of onchange() event in the header that will detect when there is overflow, even though overflow is set to hidden. Any thoughts?
Relevant CSS Code:
.level1raise { //header class
background: #F8F8F8;
margin: 0px;
border-bottom: 1px solid #BCD2EE;
height: 55px;
overflow: hidden;
}
.level1drop { //alternate header class
background: #F8F8F8;
margin: 0px;
border-bottom: 1px solid #BCD2EE;
height: 55px;
overflow: none;
}
Sample of Javascript that toggles menu:
function supportdrop() {
if (document.getElementById("support").className == "hidesupportmenu") {
document.getElementById("support").className = "showsupportmenu";
document.getElementById("supportdrop").className = "supportmenuheadclicked";
document.getElementById("supportarrow").className = "uparrowimage";
document.getElementById("help").className = "hidehelpmenu";
document.getElementById("helpdrop").className = "helpmenuhead";
document.getElementById("helparrow").className = "downarrowimage"; //^THESE DEAL WITH MENU
document.getElementById("level1").className = "level1drop"; //THIS IS THE HEADER TOGGLE
} else if (document.getElementById("support").className == "showsupportmenu") {
document.getElementById("support").className = "hidesupportmenu";
document.getElementById("supportdrop").className = "supportmenuhead";
document.getElementById("supportarrow").className = "downarrowimage"; //^MENU
document.getElementById("level1").className = "level1raise"; //HEADER TOGGLE
}
}
If you need me to post more code I will, but I think what I've included kind of shows what I'm doing, let me know otherwise. I'd post an attempted solution, but I'm not really sure what solution to attempt. I'm trying to avoid JQuery. Thanks!
I came up with a solution for any others who are attempting a similar path. Because (1) I use 100% width of the page and the page is dynamic I can disable the horizontal scrollbar and (2) the width of the elements inside the header don't change so I can add up the minimum-required width before the drop down menu links drop to the next line, I can use the following solution:
HTML:
<body onresize="checkwidth()">
Javascript:
function checkwidth() {
var currentwidth = window.innerWidth || document.documentElement.clientWidth ||
document.body.clientWidth;
if (currentwidth < 770) {
document.getElementById("level1").className = "level1raise";
document.getElementById("help").className = "hidehelpmenu";
document.getElementById("helpdrop").className = "helpmenuhead";
document.getElementById("helparrow").className = "downarrowimage";
document.getElementById("support").className = "hidesupportmenu";
document.getElementById("supportdrop").className = "supportmenuhead";
document.getElementById("supportarrow").className = "downarrowimage";
} else {
document.getElementById("level1").className = "level1drop";
}
}
Works beautifully and is cross-browser. A little crude, but oh well.