JavaScript Sliding Sidebar Menu - javascript

I'm trying to create this sidebar menu to the right using HTML CSS transitions and standard JavaScript and I also imported some FontAwesome icons.
My code looks like this (the JavaScript code is inside the HTML document):
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sidebar Menu</title>
<script src="https://kit.fontawesome.com/b1956a1c85.js" crossorigin="anonymous"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="sidebar">
<ul>
<li><i class="fas fa-home"></i></li>
<li><i class="fas fa-user"></i></li>
<li><i class="fas fa-cogs"></i></li>
<li><i class="fas fa-wrench"></i></li>
<li><i class="fas fa-tools"></i></li>
<li><i class="fas fa-lock"></i></li>
</ul>
</div>
<i class="fas fa-bars"></i>
<script>
let btn = document.querySelector('.button'),
side = document.querySelector('.sidebar');
btn.addEventListener('click', function() {
if(btn.innerHTML === '<i class="fas fa-bars"></i>') {
btn.innerHTML = '<i class="fas fa-times"></i>';
side.style.marginLeft = '0px';
} else if (btn.innerHTML === '<i class = "fas fa-times"></i>') {
btn.innerHTML = '<i class= "fas fa-bars"></i>';
side.style.marginLeft = '-25px';
}
});
</script>
</body>
</html>
And my CSS page looks like this:
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #af8f36;
}
.sidebar {
float: left;
width: 120px;
height: 100vh;
background: #6e36af;
overflow: hidden;
margin-left: -125px;
transition: 0.5s;
}
.sidebar ul {
list-style: none;
}
.sidebar ul li a {
text-decoration: none;
color: #fff;
height: 100px;
width: 100%;
font-size: 40px;
line-height: 100px;
display: block;
text-align: center;
transition: 0.5s;
}
.sidebar ul li a:hover {
background: #5d2e94;
}
.button {
float: left;
padding: 27px 20px;
font-size: 40px;
text-decoration: none;
color: #333;
}
For some reason the sidebar won't slide to the right when I click on the hamburger button. Can someone explain to me why? Is my JavaScript code correct?

I found your problem:
In your JS code you check if the inner HTML of the Button is:
<i class="fas fa-bars"></I>
But Fontawesome adds a new Attribute to your <I> Element. So now it's inner HTML is:
<i class="fas fa-bars" aria-hidden="true"></I>
I would recommend using a variable in js or something similar to check/save wether your menu is open or not.
Your way could easy lead to more bugs.
In Addition, for better performance I would recommend animating with Transform not margin, if possible.

Related

Dropdown menu not showing after clicking the icon (HTML)

I made a dropdown menu in my header, and when I click the moon icon (at the top right), the dropdown list doesn't show up but the function does get called when I click the icon. I've tried to use buttons but then clicking on the icon doesn't work.
Any one help me with this? I am new to this thanks.
Html:
<li>
<div class="dropdown">
<script src="./assets/js/Dropdown.js"></script>
<i class="fa-solid fa-bolt fa-lg" class="dropbtn" onclick="Dropdown()"></i>
<div id="myDropdown" class="dropdown-content">
<a><i class="fa-solid fa-moon"></i> Dark Mode</a>
<a><i class="fa-solid fa-sun"></i> Light Mode</a>
<a><i class="fa-solid fa-display"></i> System</a>
</div>
</div>
</li>
CSS:
.dropbtn {
background-color: #24252A;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #f1f1f1;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
cursor: pointer;
}
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
.dropdown-content a:hover {
background-color: #ddd;
}
.show {
display: block;
}
Javascript:
function Dropdown() {
document.getElementById("myDropdown").classList.toggle("show");
}
window.onclick = function(event) {
if (!event.target.matches('.dropbtn')) {
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('show')) {
openDropdown.classList.remove('show');
}
}
}
}
You have two class attributes in your icon element.
When the user clicks the icon there are two click events - the first happens on the icon itself and the show class is correctly added.
The second is the general click on the window. Having two classes confuses the JS matches function which reckons the element does not match (ie would not get selected with .dropbtn) [probably not exactly 'confused' it just looks at the first class attribute so misses the dropbtn value] so it clears the show class.
If you put all the icon's classes into one attribute value then things work OK.
function Dropdown() {
document.getElementById("myDropdown").classList.toggle("show");
}
window.onclick = function(event) {
if (!event.target.matches('.dropbtn')) {
var dropdowns = document.getElementsByClassName("dropdown-content");
var i;
for (i = 0; i < dropdowns.length; i++) {
var openDropdown = dropdowns[i];
if (openDropdown.classList.contains('show')) {
openDropdown.classList.remove('show');
}
}
}
}
.dropbtn {
background-color: #24252A;
color: white;
padding: 16px;
font-size: 16px;
border: none;
cursor: pointer;
}
.dropdown {
position: relative;
display: inline-block;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #f1f1f1;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
z-index: 1;
cursor: pointer;
}
.dropdown-content a {
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
}
.dropdown-content a:hover {
background-color: #ddd;
}
.show {
display: block;
}
<li>
<div class="dropdown">
<script src="./assets/js/Dropdown.js"></script>
<i class="fa-solid fa-bolt fa-lg dropbtn" onclick="Dropdown()">click me</i>
<div id="myDropdown" class="dropdown-content">
<a><i class="fa-solid fa-moon"></i> Dark Mode</a>
<a><i class="fa-solid fa-sun"></i> Light Mode</a>
<a><i class="fa-solid fa-display"></i> System</a>
</div>
</div>
</li>
You could instead consider using event.stopPropagation in the first event handler which would stop the click event going through to the whole window.
I used to have that problem.
But, you don't have to reinvent the wheel, I recommend using a CSS framework, like Materialize or Bootstrap.
I recommend Materialize, it's easy to use and you just have to initialize each element you want to use.
I show you an example of navbar:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Example</title>
<!-- Google icons -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!-- Compiled and minified CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/css/materialize.min.css">
</head>
<body>
<nav>
<div class="nav-wrapper">
Logo
<i class="material-icons">menu</i>
<ul class="right hide-on-med-and-down">
<li>Sass</li>
<li>Components</li>
<li>Javascript</li>
<li>Mobile</li>
</ul>
</div>
</nav>
<ul class="sidenav" id="mobile-demo">
<li>Sass</li>
<li>Components</li>
<li>Javascript</li>
<li>Mobile</li>
</ul>
<!-- Compiled and minified JavaScript -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<!-- Materialize initializers -->
<script>
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.sidenav');
var instances = M.Sidenav.init(elems);
});</script>
</body>
</html>

CSS Nav Positioning Problem | HTML Burger Menu

Hello! Recently i've been building a website portfolio and have made a burger menu!
In the time so building the burger menu i've had troubles with positioning the logo and the social icons, above and below the href links.
Here is some images to understand what it looks like -
NavBar (full) :
NavBar (burger before) :
NavBar (burger after) :
NavBar (burger after EXAMPLE) :
I understand that this is happening because they are all located inside nav.
How can I modify it to have the logo above the text, and the icons below the text. I tried going around trying JS to add style to logo and icons but it seems to not work. Also changing the css in the media query (to when the burger pops up) can mess up the look "before" the burger is pressed.
html code -
<div class="logo"><img src="src/assets/TWINLOGO.png" style="width: 100px;height: 100px;"></div>
<div class="openMenu"><i class="fa fa-bars" style="color:black;"></i></div>
<ul class="mainMenu">
<!-- Center-aligned links -->
<div class="nav-center">
<div class="navLogo"><img src="src/assets/TWINLOGO.png" style="width: 100px;height: 100px;"></div>
</div>
<!-- Left-aligned links -->
<li>Contact</li>
<li>About</li>
<li>Store</li>
<div class="closeMenu"><i class="fa fa-times"></i></div>
<!-- Right-aligned links -->
<div class="nav-right">
<span class="icons">
<i class="fab fa-youtube"></i>
<i class="fab fa-instagram"></i>
<i class="fab fa-twitter"></i>
<i class="fab fa-github"></i>
</span>
</div>
</ul>
</nav>
css code -
/* Fourth Media Querie */
#media(max-width: 805px){
nav .logo{
margin: 6px;
font-size: 25px;
cursor: pointer;
display:inherit;
}
nav .mainMenu {
height: 100vh;
position: fixed;
top: -100%;
right: 0;
left: 0;
z-index: 10;
flex-direction: column;
justify-content: center;
align-items: center;
background: white;
transition: top 1s ease;
display: flex;
}
nav .mainMenu .closeMenu {
display: block;
position: absolute;
top: 20px;
right: 20px;
color:black;
}
nav .openMenu {
display: block;
}
nav .mainMenu li a {
background: none;
font-size: 2rem;
}
nav .mainMenu li a:hover {
background: none;
color: rgb(0, 110, 255);
font-size: 2.5rem;
transition: ease all .5s;
}
.icons i {
display: inline-block;
padding: 12px;
color:rgb(0, 0, 0);
}
footer .contact .holder .info{
font-size:0.8rem;
}
}
js code -
const mainMenu = document.querySelector('.mainMenu');
const closeMenu = document.querySelector('.closeMenu');
const openMenu = document.querySelector('.openMenu');
openMenu.addEventListener('click',show);
closeMenu.addEventListener('click',close);
function show(){
mainMenu.style.display = 'flex';
mainMenu.style.top = '0';
}
function close(){
mainMenu.style.top = '-100%';
}

Make a button/class change it's own color

I'm. I just began learning HTML and CSS. My question is: How do I make the buttons above change color once they're clicked:
<div class="icon-bar">
<i class="fa fa-search" onclick="myFunction()"></i>
<i class="fa fa-envelope"></i>
<i class="fa fa-globe"></i>
</div>
I've tried adding an onclick event, but it didn't work.
This is the function:
<script>
function myFunction() {
document.getElementById("fa fa-search").style.color = "red";
}
</script>
The full code:
<!DOCTYPE html>
<html>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<style>
body {margin:0}
.icon-bar {
margin-top: 20%;
margin-left: 0.2%;
width: 90px;
background-color: rgba(85, 85, 85, 0.85);;
}
.icon-bar a {
display: block;
text-align: center;
padding: 16px;
transition: all 0.3s ease;
color: white;
font-size: 36px;
}
.icon-bar a:hover {
background-color: rgba(0, 140, 255, 0.5);
}
.active {
background-color: rgba(0, 140, 255, 1);
}
</style>
<body>
<div class="icon-bar">
<i class="fa fa-search" onclick="myFunction()"></i>
<i class="fa fa-envelope"></i>
<i class="fa fa-globe"></i>
</div>
<script>
function myFunction() {
document.getElementById("fa fa-search").style.color = "red";
}
</script>
</body>
</html>
Don't use inline JavaScript on*="" handlers, same as you hopefully don't use inline style="" attributes. JavaScript should be in one place only and that's your script tag or file.
Use Element.addEventListener()
Use .querySelectorAll() to get your desired elements
Use NodeList.prototype.forEach() to loop your elements
Use Element.classList with the API methods .add() .remove() etc.
Use higher specificity in your CSS by doing .icon-bar a.active to override the :hover styles.
const ELS_barItems = document.querySelectorAll(".icon-bar a");
function makeActive(ev) {
ev.preventDefault(); // prevent browser action on Anchors
ELS_barItems.forEach(el => el.classList.remove("active"));
ev.currentTarget.classList.add("active");
}
ELS_barItems.forEach(el => el.addEventListener("click", makeActive));
body {margin:0}
.icon-bar {
margin-top: 20%;
margin-left: 0.2%;
width: 90px;
background-color: rgba(85, 85, 85, 0.85);;
}
.icon-bar a {
display: block;
text-align: center;
padding: 16px;
transition: all 0.3s ease;
color: white;
font-size: 36px;
}
.icon-bar a:hover {
background-color: rgba(0, 140, 255, 0.5);
}
.icon-bar a.active {
background-color: rgba(0, 140, 255, 1);
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<div class="icon-bar">
<i class="fa fa-search"></i>
<i class="fa fa-envelope"></i>
<i class="fa fa-globe"></i>
</div>
You can just pass the element reference to your function:
<button onclick="turnRed(this)">click</button>
and your Javascript:
turnRed = function(e){
e.style.background = 'red'
}
As for your code, the problem is that you are calling getElementById("fa fa-search") but you're passing a class instead. You could change to getElementsByClassName but remember that every element with that class would change as well.

Collapsed sidebar as default

I'm new to web applications, so I don't know HTML, CSS and JS good enough to handle problems by myself yet. I followed some YT tutorial to create collapsible sidebar, but I don't know why it is collapsed as default and i can't make it opened. I think that the problem is that i don't know what exactly is going on in my code. Can you tell me what I'm doing wrong and help me understand how this should work?
HTML:
<div id="wrapper">
<div id="sidebar-wrapper">
<ul class="sidebar-nav">
<li>
<a href="#selectGameSubmenu" data-toggle="collapse" aria-expanded="true" class="dropdown-toggle">
<i class="fa fa-fw fa-gamepad"></i> Select something</a>
<ul class="collapse list-unstyled">
<li>
Link1
</li>
<li>
Link2
</li>
<li>
Link3
</li>
</ul>
</li>
<li>
<i class="fa fa-fw fa-home"></i> Home
</li>
<li>
<i class="fa fa-fw fa-user"></i> My profile
</li>
<li>
<i class="fa fa-fw fa-question-circle"></i> FAQ
</li>
<li>
<i class="fa fa-fw fa-phone"></i> Contact
</li>
<li>
<i class="fa fa-fw fa-sign-out-alt"></i> Logout
</li>
</ul>
</div>
<!-- Page content -->
<div id="page-content-wrapper">
<!-- some code -->
</div>
</div>
CSS:
#sidebar-wrapper{
z-index: 1;
position: fixed;
width: 0;
height: 100%;
overflow-y: hidden;
transition: 0.15s;
background-color: var(--black) ;
font-size: 1em;
}
#sidebar-wrapper .sidebar-header {
padding: 20px;
background: var(--black);
}
#page-content-wrapper{
width: 100%;
position: absolute;
padding: 15px;
transition: 0.15s;
color: black;
}
#wrapper.menuDisplayed #sidebar-wrapper{
width: 250px;
}
#wrapper.menuDisplayed #page-content-wrapper {
padding-left: 250px;
}
.sidebar-nav{
padding: 0;
list-style: none;
}
.sidebar-nav li{
text-indent: 20px;
line-height: 40px;
}
.sidebar-nav li a{
display: block;
text-decoration: none;
color: var(--gray);
}
.sidebar-nav ul li a {
font-size: 0.9em;
display: block;
color: var(--lightGray)
}
.sidebar-nav li a:hover{
color: #fff;
background: var(--gray);
}
.sidebar-nav ul li.active > a, a[aria-expanded="true"] {
color: #fff;
background: var(--deepBlue);
}
JS:
$("#menu-toggle").click(function(e){
e.preventDefault();
$("#wrapper").toggleClass("menuDisplayed");
});
Ok, I'll tell you how to achieve what you want (2 methods) and then I’ll explain how your code works.
method 1
in your first div (#wrapper), add the class menuDisplayed:
<div id="wrapper" class="menuDisplayed">
method 2
you can also change your CSS to do what you want and make the "menu displayed" the default style:
replace "menuDisplayed" with "menuHidden" throughout your code, so that it continues to make sense semantically
update styles for #sidebar-wrapper giving it a value other than 0 for width.
#sidebar-wrapper{
z-index: 1;
position: fixed;
width: 250px;
height: 100%;
overflow-y: hidden;
transition: 0.15s;
background-color: var(--black) ;
font-size: 1em;
}
now change styles for #page-content-wrapper too, so that it leaves room for your sidebar:
#page-content-wrapper{
width: 100%;
position: absolute;
padding: 15px;
padding-left: 250px; /* leaving 250px of space on the left */
transition: 0.15s;
color: black;
}
the next step is to make the closed sidebar have the right styles:
#wrapper.menuHidden #sidebar-wrapper{
width: 0; /* the element of id 'wrapper' and class 'menuHidden' must have width 0 */
}
#wrapper.menuHidden #page-content-wrapper {
padding-left: unset; /* clears the attribute that gave space to the sidebar */
}
now I'll explain how your code works (before you change the sidebar behavior):
your CSS tells the browser that the element with the sidebar-wrapper id should have null width (so it does not appear as soon as you load the page), but it also says that the element with id sidebar-wrapper should be 250px wide when inside another element that has the wrapper id and the menuDisplayed class.
the magic is in your javascript: it tells the browser to toggle the menuDisplay class of the element with id wrapper, which activates the CSS style that makes your sidebar 250px wide, and so it appears. when toggled again, the menuDisplayed class is deleted from the element with id wrapper and your sidebar returns to having width equal to 0.
the $("#menu-toggle").click adds an event listener for the 'click' event using jQuery. when this event is fired (someone clicks in the element with the menu-toggle id), the callback function is executed:
function(e){
e.preventDefault(); // prevents the default behavior of the element (if it is an anchor (<a></a>), it loses the ability to change pages, etc.)
$("#wrapper").toggleClass("menuDisplayed"); // toggles the class 'menuDisplayed' of the element with id 'wrapper'
}
You can add the class menuDisplayed to the navbar (with id #wrapper) initially, so on page load, it will be displayed.
<div id="wrapper" class="menuDisplayed">
you should add the class menuDisplayed to your #wrapper. then it can show by default.
<div id="wrapper" class="menuDisplayed">
full example can be found here :http://jsfiddle.net/9ojvnutc/

Javascript toggle working but shows unstyled menu

On my ruby on rails 5 app I have a menu button that uses javascript to toggle the menu, the toggle function is showing and hiding the menu but the menu is not styled with css anymore
onclick the menu toggles like it should but all the elements are not styled, I dont know if its related to rails or I am missing something here
//Toggle between adding and removing the "show_for_mobile" class to admin_side_bar when the user clicks on the icon
function toggleNav() {
var x = document.getElementById("admin_side_bar");
console.log(x.className)
if (x.className === "admin_side_bar") {
x.className += "show_for_mobile";
} else {
x.className = "admin_side_bar";
}
}
.admin_side_bar {
width: 70%;
height: 50vh;
background-color: #e2e6e8;
position: absolute;
left: 0;
top: 60px;
padding: 20px 10px;
display: none;
}
//show side bar on click
.show_for_mobile {
display: block;
}
.admin_side_bar>ul {
list-style-type: none;
padding: 0;
margin: 0;
}
.admin_side_bar>ul>a {
color: #3d3d3d;
font-size: 19px;
text-decoration: none;
}
.admin_side_bar>ul>a:hover {
color: #06bed3;
}
.admin_side_bar .fas {
margin-right: 20px;
color: #afaeae;
}
.admin_side_bar .fas:hover {
color: #7a7a7a;
}
.admin_side_bar>ul>a>li {
margin-bottom: 20px;
}
<!--Admin side bar-->
<div class="admin_side_bar" id="admin_side_bar">
<ul>
<a href="#">
<li><i class="fas fa-home fa-fw fa-lg"></i>Home</li>
</a>
<a href="#">
<li><i class="fas fa-tshirt fa-fw fa-lg"></i>Items</li>
</a>
<a href="#">
<li><i class="fas fa-gift fa-fw fa-lg"></i>Orders</li>
</a>
<a href="#">
<li><i class="fas fa-chart-line fa-fw fa-lg"></i>Stats</li>
</a>
<a href="#">
<li><i class="fas fa-newspaper fa-fw fa-lg"></i>Blog</li>
</a>
</ul>
</div>
When you add the .show_for_mobile class the original display:none from .admin_side_bar still takes precedence. If all you really want to do is show the nav then you can use x.style.display = "block"; to overwrite display:none from the admin_side_bar class
x.style.display="block" works because it adds inline style which is the highest CSS specificity (it overwrites all other css rules).
From CSS specificity
Inline styles added to an element (e.g., style="font-weight:bold") always overwrite any styles in external stylesheets, and thus can be thought of as having the highest specificity.
document.getElementById("toggleButton").addEventListener("click", toggleNav);
//Toggle between adding and removing the "responsive" class to topnav when the user clicks on the icon
function toggleNav() {
var x = document.getElementById("admin_side_bar");
if (x.className === "admin_side_bar") {
x.className += " show_for_mobile";
x.style.display = "block";
} else {
x.className = "admin_side_bar";
x.style.display = "none";
}
}
.admin_side_bar {
width: 70%;
height: 50vh;
background-color: #e2e6e8;
position: absolute;
left: 0;
top: 60px;
padding: 20px 10px;
display: none;
}
//show side bar on click
.show_for_mobile {
display: block !important;
}
.admin_side_bar>ul {
list-style-type: none;
padding: 0;
margin: 0;
}
.admin_side_bar>ul>a {
color: #3d3d3d;
font-size: 19px;
text-decoration: none;
}
.admin_side_bar>ul>a:hover {
color: #06bed3;
}
.admin_side_bar .fas {
margin-right: 20px;
color: #afaeae;
}
.admin_side_bar .fas:hover {
color: #7a7a7a;
}
.admin_side_bar>ul>a>li {
margin-bottom: 20px;
}
<button id="toggleButton">Toggle Nav</button>
<!--Admin side bar-->
<div class="admin_side_bar" id="admin_side_bar">
<ul>
<a href="#">
<li><i class="fas fa-home fa-fw fa-lg"></i>Home</li>
</a>
<a href="#">
<li><i class="fas fa-tshirt fa-fw fa-lg"></i>Items</li>
</a>
<a href="#">
<li><i class="fas fa-gift fa-fw fa-lg"></i>Orders</li>
</a>
<a href="#">
<li><i class="fas fa-chart-line fa-fw fa-lg"></i>Stats</li>
</a>
<a href="#">
<li><i class="fas fa-newspaper fa-fw fa-lg"></i>Blog</li>
</a>
</ul>
</div>

Categories

Resources