5
\$\begingroup\$

The following code has been tested on the latest chromium, on Opera Mini, on Safari for IOS 7 and finally, on the default web browser on android 2.3.3.

As you may already know, the CSS overflow rule isnt supported on android 2.3.3 which makes sidenavs un-scrollable.

Well, guess what? I found a workaround. See the following code:

//Import element
cont=document.getElementById("content");
nav=document.getElementsByClassName("navbar");
opt=document.getElementsByClassName("option");
side=document.getElementById("sidenav");
side.style.display="none";
navtog();

function showhide(x){
	if("transform" in document.body.style)
{
    x.classList.toggle("change");
}
	//If sidenav open
	if(cont.style.left=="150px"){
		
		//Sidenav stuff
		//Store sidenav pos
		sidepos=window.scrollY;
		
		//Move sidenav to pos (to remove wierd chunky animations)
		side.style.position="fixed";
		side.style.top="-"+sidepos+"px";
		
		cont.style.left="";
		cont.style.position="";
		cont.style.top="0px";
		nav[0].style.left="0px";
		
			//Scroll back to user pos
		window.scrollTo(0,pos);
		setTimeout(function() {
			side.style.display="none";
		}, 200);
	}else{//sidenav closed
		
		//Store user POS
		pos=this.scrollY;
		cont.style.position="fixed";
		cont.style.left="150px";
		cont.style.top="-"+pos+"px";
		nav[0].style.left="150px";
		side.style.display="block";
		
		//Make sidenav scrollable again
		side.style.top="";
		side.style.position="";
		if(typeof sidepos === 'undefined'){
			sidepos=0;
		}
		window.scrollTo(0,0);
	}
}
window.onscroll = function() {navtog()};

function navtog(){
	if(cont.style.left==""){
	if(this.scrollY<1){
		nav[0].className="navbar";
		}else{
		nav[0].className="navbar shad";
	}
}
}

function bhov(el) {
  var els = Array.prototype.slice.call( document.getElementsByClassName('option'), 0 );
  opt[els.indexOf(event.currentTarget)].className="option o-a";
}

function bbay(el) {
  var els = Array.prototype.slice.call( document.getElementsByClassName('option'), 0 );
  opt[els.indexOf(event.currentTarget)].className="option o-o";
}
body{
font-family:Helvetica, sans-serif;
margin:0;
color:white;
background:#23272a;
overflow-x:hidden;
}

/*Layout*/

#sidenav{
/*Important*/
width:150px;
float:left;
background:#23272a;
}

#content{
float:left;
width:100%;
position:absolute;
left:0;
padding-top:40px;
background:#2c2f33;
-webkit-transition:left 0.2s ease-out;
-moz-transition:left 0.2s ease-out;
-ms-transition:left 0.2s ease-out;
transition:left 0.2s ease-out;
   -moz-box-shadow:0 0 20px rgba(0,0,0,0.5);
   -webkit-box-shadow:0 0 20px rgba(0,0,0,0.5);
   box-shadow:0 0 20px rgba(0,0,0,0.5);
}

/*Buttons*/
.option{
text-decoration:none;
display:block;
color:#99aab5;
line-height:14px;
font-size:12px;
padding:10px;
}
.o-a{/*ACTIVE*/
color:white;
}
.o-o{/*OFF*/
color:#99aab5;
-webkit-transition:color 0.2s ease-out;
-moz-transition:color 0.2s ease-out;
-ms-transition:color 0.2s ease-out;
transition:color 0.2s ease-out;
}

/*Navbar*/
.navbar{
position:fixed;
top:0;
left:0;
width:100%;
height:40px;
/*style*/
-webkit-transition:left 0.2s ease-out,background 0.2s;
-moz-transition:left 0.2s ease-out,background 0.2s;
-ms-transition:left 0.2s ease-out,background 0.2s;
transition:left 0.2s ease-out,background 0.2s;
}
.shad{background:#99aab5;}

/*Logo*/
.navbar img{
display:block;
margin:0 auto;
padding:5px;
height:30px;
}

/*Ham menu*/
.ham{
width:40px;
height:28px;
position:absolute;
top:5px;
left:5px;
/*style*/
border:1px solid white;
border-radius:3px;
cursor:pointer;
}

.bar1, .bar2, .bar3 {
  width: 30px;
  height: 4px;
  background: white;
  margin: 4px 5px;
  transition: 0.4s;
  border-radius:3px;
}

.change .bar1 {/*Gauche Haut*/
  transform: rotate(45deg) translate(8px, -3px);
  width:16px;
}

.change .bar2 {opacity: 0;}

.change .bar3 {
  transform: rotate(-45deg) translate(8px, 3px);
  width:16px;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>

<div id="page">

<div id="sidenav">
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #1</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #2</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #3</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #4</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #5</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #6</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #7</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #8</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #9</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #10</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #11</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #12</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #13</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #14</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #15</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #16</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #17</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #18</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #19</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #20</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #21</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #22</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #23</a>
<a href="javascript:void(0);" class="option" onmouseover="bhov(this)" onmouseout="bbay(this)">Option #24</a>
</div>


<div id="content">
	
	<div class="navbar">
		
		<div class="ham" onclick="showhide(this);">
			<div class="bar1"></div>
			<div class="bar2"></div>
			<div class="bar3"></div>
		</div>
		
<img src="https://proxy.duckduckgo.com/ip3/codereview.stackexchange.com.ico">
</div>
this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br><a href="javascript:showhide();">showhide();</a>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>this is some content<br>
</div>


</div>
<script src="script.js"></script>
</body>
</html>

How it works:

The page content (were the dummy content is+navbar) is set at width="100%"

when clicking on the hamburger menu, heres what happens

1) We store the user scroll position before changing anything

2) We set the page content to position="fixed"

3) We add the following property to the content: top="(page scroll position)";

4) We make the sidenav go display="block" (if its not set as none when closed, sometimes, old browsers will click on the sidenav buttons even if closed)

5) The page content goes left:150px (Lets not forget that CSS makes it transition between the two stages which makes it look real good)

6) We also make the navbar go left:150px cause on old browsers, it doesnt moves (or glitches/stretches if youre on iOS 7 safari)

7) The sidenav is now scrollable and the page content isnt. Yay!

8) (optional) cool ass hover effect for items in the sidenav.

When closing the sidenav

Pretty much the reverse thing but we add those steps:

1) The animation between open and closed lasts 0.2 seconds. Keep that in mind.

2) We store the user's scroll position

We add the following properties to the sidenav:

3) Position="fixed"

4) top="(scroll pos)"

Wait 0.2 seconds

5) display="none"


SO thats pretty much how it works... I may have brushed over some details tho, bare with me please, haha.

Any suggestions? Ideas? Toughts? Do you think this could be used as production code?

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

This code appears to function correctly but I wouldn't use it in production unless it is cleaned up. See the suggestions below.

The first five variables are declared as globals:

cont=document.getElementById("content");
nav=document.getElementsByClassName("navbar");
opt=document.getElementsByClassName("option");
side=document.getElementById("sidenav");
side.style.display="none";

It would be wise to declare them with the var keyword, and wrap everything in an IIFE to avoid polluting the global namespace. For a small page this likely wouldn't be an issue but as a page grows into a single-page application or larger it could cause issues - for example if a variable name is used in different sections of code.

Also pos should be declared at the top using var to avoid it being used as a global variable.


The onmouseover and onmousout could be removed from all the anchors with class option by changing the CSS rulesets to use the :hover pseudo-class selector though maybe some of those mobile browsers would have compatitibilty issues, depending on the version.

Instead of using CSS selectors .o-o and .o-a, use .option and .option:hover, respectively. The styles under the .o-o ruleset can be moved up into the styles for .option (except for the color, since it is duplicate).


The onscroll function can be simplified from

window.onscroll = function() {navtog()};

To simply a reference to the function name:

window.onscroll = navtog;

For the element with class navbar why not use an id attribute instead of class name? There only appears to be one of those elements and the JS code appears to be selecting the first element with that class so it could be selected by id instead.

<div class="navbar">

can be changed to

<div id="navbar">

Then

nav=document.getElementsByClassName("navbar");

Can be changed to

 nav=document.getElementById("navbar");

And CSS selectors must be changed as well.

Those functions bhov and bbay are quite inefficient - mostly because they get all elements with class name option each time either function is called and then look for the element in opt. Why not just use event.currentTarget and modify the className directly? If that doesn't work, then why re-query the DOM instead of using opt to copy elements into els?


Indentation is not always consistent - many lines in the JavaScript are indented with a tab, while some of the lines in the bhov and bbay functions are indented with two spaces. And many of the CSS lines inside rulesets are not indented, whereas others are indented with two spaces.

\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.