Rotating chevrons with JQuery - javascript

I need to make a chevron rotate 180deg when clicking on its parent element to indicate whether a section is expanded or collapsed to an existing (non-bootstrap) accordion.
Currently all sections are defaulted to display expanded (green). When the .BlackTitleExp_top_style div is clicked the header section closes and the divs bg-color turns a light green to indicate the section is collapsed.
Ideally, when the header turns grey, the chevron should also rotate 180deg so that is is pointing down indicating the section is closed.
Ideally I'd like to accomplish by clicking on BlackTitleExp_top_style parent element but I'm not married to this idea. Any suggestions would be greatly appreciated.
$(document).ready(function() {
var BTE_top = $(".BlackTitleExp_top_style");
var BTE_top_BG = "BlackTitleExp_top_style_BG";
$(BTE_top).click(function() {
var el = $(this);
el.not(el).removeClass(BTE_top_BG);
el.toggleClass(BTE_top_BG);
});
});
.BlackTitleExp_top_style {
cursor: pointer;
background-color: rgba(92, 132, 92, 0.35);
border-radius: 5px;
position: relative;
padding: 15px;
margin-bottom: 10px;
}
.BlackTitleExp_top_style_BG {
transition: all 300ms ease;
cursor: pointer;
background-color: rgba(128, 128, 128, 0.35);
}
.chevron {
position: absolute;
right: 20px;
}
.rotate {
transform: rotate(180deg);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css">
<!-- HTML -->
<div class="wrapper">
<div class="BlackTitleExp_top_style">
simulated open section
<i class="fas fa-chevron-up chevron"></i>
</div>
<div class="BlackTitleExp_top_style">
simulated open section
<i class="fas fa-chevron-up chevron"></i>
</div>
<div class="BlackTitleExp_top_style">
simulated open section
<i class="fas fa-chevron-up chevron"></i>
</div>
<div class="BlackTitleExp_top_style">
simulated open section
<i class="fas fa-chevron-up chevron"></i>
</div>
</div>

Define the states that an element(s) can exist in (ex. rotated 180o/0o, expanded/collapsed,
on/off etc) then declare the condition(s) (ex. if (fart) { smell.it }) or event(s) (ex. click, hover, etc) that can occur to invoke a behavior(s) (ex. rotate, expand, do your taxes, etc). In the demo below the adding/removing of a class (.fa-rotate-180) sets the styles on each <i>.
The class .fa-rotate-180 is a Font Awesome class that will rotate any of its icons 180o when applied. CSS animation is added as well via transform: rotate(), transition, and #keyframes
Details commented in demo
// Start with all content hidden
$('.content').hide();
// When header.title is clicked...
$('.title').on('click', function(event) {
// Reference the p.content that follows the clicked header✱
const clickedContent = $(this).next('.content');
// Reference the i.chevron that is nested within clicked header
const clickedChevron = $(this).find('.chevron');
/* Slide up all p.content with the exception of the sibling p.content that follows
the clicked header✱ */
$('.content').not(clickedContent).slideUp('fast');
// Expand/Collapse the p.content of the clicked header✱
clickedContent.slideToggle('fast');
/* Remove .fa-rotate-180 class from all i.chevron with the exception of the
i.chevron nested within clicked header */
$('.chevron').not(clickedChevron).removeClass('fa-rotate-180');
/* Add/Remove .fa-rotate-180 class to/from the i.chevron nested within the
clicked header */
clickedChevron.toggleClass('fa-rotate-180');
});
/* ✱ The expand/collapse aspect of code is not required by OP question and
is only added to provide a complete functional example. */
:root {
font: 16px/1.2 Arial;
}
.title {
font-size: 1.3rem;
cursor: pointer
}
.chevron {
/* block or inline-block for smoother animation */
display: inline-block;
/* Animation when going back to collapsed state */
transform: rotate(0deg);
transition: 0.3s;
}
.fa-rotate-180 {
/* This declares the keyframes used for animation */
animation: spin;
transition: 0.4s
}
/* An #rule used to breakdown animation into steps */
#keyframes spin {
100% {
transform: rotate(180deg);
}
}
<link href='https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css' rel='stylesheet'>
<aside class='read-more'>
<header class='title'>
<i class="fas fa-chevron-up chevron"></i> Chevron rotates 180<sup>o</sup>...
</header>
<p class='content'>...when header is clicked</p>
</aside>
<aside class='read-more'>
<header class='title'>
<i class="fas fa-chevron-up chevron"></i> Chevron rotates 180<sup>o</sup>...
</header>
<p class='content'>...when header is clicked</p>
</aside>
<aside class='read-more'>
<header class='title'>
<i class="fas fa-chevron-up chevron"></i> Chevron rotates 180<sup>o</sup>...
</header>
<p class='content'>...when header is clicked</p>
</aside>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

Try this
BTE_top.click(function() {
var el = $(this);
var icon = el.find('i');
if(!icon.hasClass('rotate')){
icon.addClass('rotate');
}
el.not(el).removeClass(BTE_top_BG);
el.toggleClass(BTE_top_BG);
});

You are very close. Just adding this little bit of CSS will get you what you want:
.chevron {
position: absolute;
right: 20px;
transition: all 300ms ease;
}
.BlackTitleExp_top_style_BG .chevron {
transform: rotate(180deg);
}
Now when the BlackTitleExp_top_style_BG is added, the chevrons transform property is updated. With a transition now defined on chevron the rest of your code works as expected.
$(document).ready(function() {
var BTE_top = $(".BlackTitleExp_top_style");
var BTE_top_BG = "BlackTitleExp_top_style_BG";
$(BTE_top).click(function() {
var el = $(this);
el.not(el).removeClass(BTE_top_BG);
el.toggleClass(BTE_top_BG);
});
});
.BlackTitleExp_top_style {
cursor: pointer;
background-color: rgba(92, 132, 92, 0.35);
border-radius: 5px;
position: relative;
padding: 15px;
margin-bottom: 10px;
}
.BlackTitleExp_top_style_BG {
transition: all 300ms ease;
cursor: pointer;
background-color: rgba(128, 128, 128, 0.35);
}
.chevron {
position: absolute;
right: 20px;
transition: all 300ms ease;
}
.BlackTitleExp_top_style_BG .chevron {
transform: rotate(180deg);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css">
<!-- HTML -->
<div class="wrapper">
<div class="BlackTitleExp_top_style">
simulated open section
<i class="fas fa-chevron-up chevron"></i>
</div>
<div class="BlackTitleExp_top_style">
simulated open section
<i class="fas fa-chevron-up chevron"></i>
</div>
<div class="BlackTitleExp_top_style">
simulated open section
<i class="fas fa-chevron-up chevron"></i>
</div>
<div class="BlackTitleExp_top_style">
simulated open section
<i class="fas fa-chevron-up chevron"></i>
</div>
</div>

Related

navigation bar drawer menu doesn't close after clicking menu item

i built a navigation bar for my website.this code is brought from another site. it's css here
* {
padding:0;
margin:0;
}
body {
font-family:Verdana, Geneva, sans-serif;
font-size:18px;
background-color:#FFF
}
header {
width:100%;
background-color:#06C;
z-index:1000;
}
.menu-bar {
color:#FFF;
font-size:26px;
cursor:pointer;
padding:10px 12px;
margin-left:10px;
margin-top:5px;
margin-bottom:5px;
}
.menu-bar:hover {
background-color:rgba(0, 0, 0, 0.1);
border-radius:50px;
}
#tag-menu {
display:none;
}
#tag-menu:checked ~ div.drawer {
animation: slide-in 0.5s ease;
animation-fill-mode: forwards;
}
.drawer {
position:fixed;
left:-280px;
background-color:#06C;
height:100%;
z-index:100;
width:200px;
animation: slide-out 0.5s ease;
animation-fill-mode: forwards;
}
.drawer ul li {
list-style:none;
}
.drawer ul li a {
padding:10px 30px;
text-decoration:none;
display:block;
color:#FFF;
border-top:1px solid #039;
}
.drawer ul li a:hover{
background-color:rgba(0, 0, 0, 0.1);
}
.drawer ul li a i {
width:50px;
height:35px;
text-align:center;
padding-top:15px;
}
#keyframes slide-in {
from {left: -280px;}
to {left: 0;}
}
#keyframes slide-out {
from {left: 0;}
to {left: -280px;}
}
it's HTML here
<header>
<input type="checkbox" id="tag-menu">
<label class="fa fa-bars menu-bar" for="tag-menu"></label>
<div class="drawer" id="drawer">
<nav class="overlay-menu">
<ul>
<li><i class="fa fa-user-secret"></i>A</li>
<li><i class="fa fa-check-circle-o"></i>B</li>
<li><i class="fa fa-user-circle"></i>C</li>
<li><i class="fa fa-info-circle "></i>D</li>
</ul>
</nav>
</div>
My problem is that the navigation bar drawer menu doesn't close after clicking on menu item. i need to close the drawer after click any item on the drawer menu. how to solve this problem. what are the scripts which i can use?. Your help is highly appreciated.Thanks
Demo is here: http://androidcss.com/demos/css/css-drawer-menu/#
I simplified the code a little bit because:
so you can have more flexibility later on when you want to add other things.
your nav menu will be closed from the start, not after 1 second like in the previous code used.
58 lines of code instead of 125
It will also give you an introduction opportunity to jQuery.
Please see the comments that explain each line of code and write a comment if you don't understand something.
Codepen to play with: https://codepen.io/larrytherabbit/pen/NWrGMWE
$("#hamburger").click(function(){
$("nav").toggleClass('open', 'close');
});
$("a").click(function(){
$("nav").toggleClass('open', 'close');
});
header, nav {
background-color:#06C;font-family:'Open Sans';
}
header {
width:100%;display:flex;align-items:center;
height:80px;color:#FFF;justify-content:flex-start;
} /* we use flex display to position the hamburger icon on the side of the AndroiCSS h2 element */
#hamburger {
cursor:pointer;
} /* add the small hand cursor pointer to indicate this element is clickable; it triggers the jQuery on click */
header * {
margin:0 15px;
}
.fa-bars, header h2 {
font-size:28px!important;
}
header h2 {
font-weight:400!important;
}
nav {
display:flex;flex-direction:column;width:0;align-items:center;
transition:width 0.2s ease;
}
nav.open {
width:250px;
}
nav.close {
width:0;
}
nav * {
color:#FFF!important;font-family:'Open Sans';font-size:20px!important;margin-right:15px;
}
nav a {
text-decoration:none!important;
border-top:0.5px solid gray;width:100%;text-align:center;display:flex;align-items:center;justify-content:center;height:55px;
}
nav a:hover {
background-color:rgba(0, 0, 0, 0.1);
} /* this changes the bg color on hover over the nav element */
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>css drawer menu demo</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css"> <!-- this loads the font aswesome library for the hamburger icon (fa-bars) and the social icons; the class 'fa' calls the font awesome library and the fa-xxx class calls the specific icon needed-->
<header>
<i id="hamburger" class="fa fa-bars"></i>
<h2>AndroidCSS</h2>
</header>
<nav>
<i class="fa fa-facebook"></i> <span>Facebook</span> <!-- nav menu no need for <ul> or <li> tags here -->
<!-- the <a> tags are link tags and the <i> tags are used to call font awesome icons again -->
<i class="fa fa-facebook"></i><span>Facebook</span>
<i class="fa fa-facebook"></i><span>Facebook</span>
<i class="fa fa-facebook"></i><span>Facebook</span>
<i class="fa fa-facebook"></i><span>Facebook</span>
</nav>

CSS and javascript only works after couple of seconds after loading of page

My website loads and only after few seconds I get for example functionality.
For example I have
<a href="news.php" class="home-page--news-box-button-wrapper">
<div class="home-page--news-box-button-text-wrapper">
<span class="home-page--news-box-button-text">Sve vijesti</span>
</div>
<div class="home-page--news-box-button-arrow-wrapper">
<span>here goes arrow</span>
</div>
</a>
And css has a simple transition
.home-page--news-box-button-wrapper {
background-color: $red;
transition: background-color 100ms;
&:hover{
background-color: $brown;
.home-page--news-box-button-arrow-wrapper {
text-align: center;
height: 43px;
transform: translateX(5px);
}
}
And hover only triggers after few seconds.
Did anyone had this problem before

jquery animate makes other elemtents dance

so I have this problem with jQuery .animate() function where I animate one element and it displaces all other elements associated with it.
This is the menu I am working with:
<div class="row">
<div class="col-md-3"></div>
<div class="col-md-9 navbar">
<ul>
<li id="home_button" class="menu_button">
<i class="fa fa-home"></i>
<p>Home</p>
</li>
<li id="projects_button" class="menu_button">
<i class="fa fa-pencil"></i>
<p>Projects</p>
</li>
<li id="about_button" class="menu_button">
<i class="fa fa-balance-scale"></i>
<p>About</p>
</li>
<li id="contact_button" class="menu_button">
<i class="fa fa-user"></i>
<p>Contact</p>
</li>
</ul>
</div>
</div>
To see what I mean, I transferred my code into jsfiddle
Any help is appreciated!
This is normal HTML behaviour. Browsers "flow" the layouts, so if you make one element bigger, it reflows the rest of the document and displaces elements where it needs to.
If you want an element to move from one position to another, you have to take it out of the normal layout. You can do this by setting the position CSS attribute of the element to something other than relative. For example position: absolute makes the element positioned relative to the whole document, position: fixed makes the element positioned relative to the window's border, etc.
Additionally, you can use CSS transforms which also don't affect layout. These allow you to do a combination of translation, rotation and scaling to an element without displacing it's nearby siblings. This is ideal for, say, a slight size increase on mouse over or to transition items in from off screen.
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions
Either way, I strongly recommend using CSS animations and transitions, rather than jQuery animate. You can then use jQuery to apply classes to enable and disable animations.
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations
https://developer.mozilla.org/en/docs/Web/CSS/#keyframes
$('.animation-test').on('click', function() {
$(this).toggleClass('animation-test--enabled');
});
* {
font-family: arial, helvetica, san-serif;
}
.transition-test {
padding: 20px;
background: cornflowerblue;
transition: transform 200ms ease-in-out;
}
.transition-test:hover {
transform: scale(1.1);
}
.animation-test {
padding: 20px;
background: salmon;
}
.animation-test--enabled {
animation: identifier 1s infinite;
}
#keyframes identifier {
0% { transform: translateX(0); }
33% { transform: translateX(20px); }
66% { transform: translateX(-20px); }
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="transition-test">Hover over me to see a transition on a transform scale (no Javascript required)</div>
<br/>
<div class="animation-test">Click me to toggle an animation (Javscript applies and removes the class)</div>
In addition to this breaking your layout, you'd also have to consider a way to stop and reverse the animation midway or else it'll keep going and potentially repeat if the user comes back to it. Try moving your mouse back and forth across all the buttons really fast on your fiddle to see what I mean. It's entertaining, but not the effect you want I think.
Fortunately not everything needs to be solved with javascript. CSS transitions are easy to understand and do all the hard work for you. Combine it with psuedo selectors and you'll get the effect your looking for.
CSS Transitions:
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Transitions/Using_CSS_transitions
Psuedo Classes:
https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes
.menu_button{
transition: .250s width;
}
.menu_button:hover{
width : 100px;
}
.menu_button{
transition: .250s width;
}
.menu_button:hover{
width : 100px;
}
/** Note so important **/
ul {
list-style: none;
}
.container-fluid {
margin: 0;
padding: 0;
}
.photo-placeholder {
height: 350px;
background-color: green;
}
/* Navbar menu */
.menu_button {
width: 35px;
height: 35px;
display: inline-block;
margin-top: 15px;
margin-right: 10px;
border-radius: 20px;
}
#home_button {
background-color: red;
}
#home_button i {
margin-left: 0.6em;
margin-top: 0.5em;
}
#projects_button {
background-color: blue;
}
#projects_button i {
margin-top: 0.5em;
margin-left: 0.6em;
}
#about_button {
background-color: yellow;
}
#about_button i {
margin-top: 0.55em;
margin-left: 0.55em;
}
#contact_button {
background-color: green;
}
#contact_button i {
margin-top: 0.5em;
margin-left: 0.75em;
}
stretch {
width: 80px;
}
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-3"></div>
<div class="col-md-9 navbar">
<ul>
<li id="home_button" class="menu_button">
<i class="fa fa-home"></i>
<p>Home</p>
</li>
<li id="projects_button" class="menu_button">
<i class="fa fa-pencil"></i>
<p>Projects</p>
</li>
<li id="about_button" class="menu_button">
<i class="fa fa-balance-scale"></i>
<p>About</p>
</li>
<li id="contact_button" class="menu_button">
<i class="fa fa-user"></i>
<p>Contact</p>
</li>
</ul>
</div>
</div>
</div>
</body>

making a menu that pops out of screen right

I am writing a bootstrap site, and want to make a sort of pop out menu from the right of the screen. This menu needs to be hidden' and when a button "Menu" is clicked it pops out of screen right, and covers whatever is on screen right. it does not push the content out of the way. Kind of like the windows 8 menu when you slide your finger from screen right.
I've thought of making a dropdown menu, since it behaves almost like I want, except for it's position. But I need to change the dropdown behaviour, So that instead of the dropdown menu popping out attached to the dropdown button, it pops out of screen right, but I can't find out how to do this.
<head>
...
<link href ="CSS/Bootstrap.min.css" rel ="stylesheet"/>
</head>
<div class="col-xs-3">
<!--some side content-->
</div>
<div class="col-xs-9">
<!--some side content-->
</div>
<div class="col-xs-12">
<nav class="navbar navbar-inverse navbar-fixed-bottom">
<div class="container-fluid">
<li class="dropup">
<a class="dropdown-toggle" data-toggle="dropdown">Menu
<ul> class="dropdown-menu">
<li>
</li>
<li>
</li>
</ul>
</a>
</li>
</div>
</nav>
</div>
<script src="JS/jquery-1.11.3.min.js"></script>
<script src="JS/bootstrap.min.js"></script>
I have three folders in my project:
Css with bootstrap css files(bootstrap-theme, bootstrap-theme min, bootstrap, bootstrap min)
Fonts
JS with bootstrap.js and bootstrap.min.js
Please show me how to do this.
If you know of a different way of making the menu I want in bootstrap I'd love to hear it as well.
Here is a simple example to get you going:
jsFiddle Demo
Note that an id was added to the a tag that opens the menu, to make it easy for jQuery to capture the click event on that element.
In the jQuery, we are using a variable mnuOut to keep track of whether the menu is IN or OUT (visible or hidden).
Also, we use the .animate() method to animate the slide out from the right. This works by changing the css attribute right:
FROM right:-80px (slid 80px beyond the right side of the screen)
TO right:0 where the right-most edge of the myMenu DIV is flush against the right side of the screen.
HTML:
<div id="myMenu">
<div id="item1" class="submenu">Item 1</div>
<div id="item2" class="submenu">Item 2</div>
<div id="item3" class="submenu">Item 3</div>
</div>
<a id="menuTrigger" class="dropdown-toggle" data-toggle="dropdown">Menu
CSS:
#myMenu{position:fixed;top:20px;right:-80px;width:80px;height:300px;background:palegreen;}
.submenu{width:100%;height:20px;padding:20px 5px;border:1px solid green;}
#menuTrigger:hover{cursor:pointer;}
jQuery:
mnuOut=false;
$('#menuTrigger').click(function(){
if (mnuOut){
//Menu is visible, so HIDE menu
$('#myMenu').animate({
right: '-80px'
},800);
mnuOut = false;
}else{
//Menu is hidden, so SHOW menu
$('#myMenu').animate({
right: 0
},800);
mnuOut = true;
}
})
If you want your menu to cover the content make sure you add
position: absolute;
Or
position: fixed;
Then after that give it
right: 500px;
But instead of 500px use the width of your menu
And to make it popout just override the
right: 0;
Making it 0 will make it stick to the right back to its original position
What you want requires a little more than just a couple of lines of css but I think this will give you a good start. Just style according to your theme:
HTML
<div id="oneout">
<span class="onetitle">
menu
</span>
<div id="oneout_inner">
<center>
menu info here
<br>
</center>
</div>
</div>
CSS
#oneout {
z-index: 1000;
position: fixed;
top: 64px;
right: 1px;
width: 18px;
padding: 40px 0;
text-align: center;
-webkit-transition-duration: 0.3s;
-moz-transition-duration: 0.3s;
-o-transition-duration: 0.3s;
transition-duration: 0.3s;
}
#oneout_inner {
top: 60px;
right: -250px;
position: fixed;
width: 230px;
padding: 10px;
background: #FFFFFF;
height: auto;
-webkit-transition-duration: 0.3s;
-moz-transition-duration: 0.3s;
-o-transition-duration: 0.3s;
transition-duration: 0.3s;
text-align: left;
border:1px solid #333;
}
#oneout:hover {
z-index: 1000;
right: 250px;
}
#oneout:hover #oneout_inner {
z-index: 1000;
right: 0px;
}
.onetitle {
display: block;
writing-mode: lr-tb;
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
-o-transform: rotate(-90deg);
transform: rotate(-90deg);
position: absolute;
right: -11px;
top: 3px;
font-family: Lucida Sans;
font-size: 16px;
font-weight: normal;
text-transform: uppercase;
letter-spacing: -1px;
}
Here is a working DEMO

Bootstrap mobile menu icon change to x close

EDIT
#zim answer uses 2020 CSS to easily solve the issue and better applies to Bootstrap 4.
The original question and selected answer are still valid and very informative.
ORIGINAL QUESTION
I would like, when in mobile view, for the menu icon (defined with class icon-bar in the bootstrap basic navbar example) to change to an X shape (Something similar to what happens here: https://www.mint.com but less fancy (I just want to replace the 3 stripes with an X).
At the moment I am using a custom id: #ChangeToggle
<button id="ChangeToggle" type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
Along with the following javascript function (I know it's basic but I'm new to this):
<script>
$('#ChangeToggle').click(function () {
if($('#ChangeToggle span').hasClass('ToggleButton')) {
$('#ChangeToggle').html('<span class="sr-only">Toggle navigation</span><span class="icon-bar"></span><span class="icon-bar"></span><span class="icon-bar"></span>');
}
else {
$('#ChangeToggle').html('<span class="ToggleButton glyphicon glyphicon-remove"></span>');
}
});
</script>
Everything works, the only issue is that when I click exactly on the X icon the menu does not close. It only closes when I click outside of it (anywhere else in the button). The only thing it does while clicking on the X icon is going back to the original 3 stripes.
Anyone knows what I am doing wrong?
Your JavaScript replaces the inner html of the #ChangeToggle element to show either the X or the hamburger icon. Precisely clicking on the X or the hamburger menu instead of the #ChangeToggle will remove the element being clicked on which I think prevents it from bubbling up. As Bootstrap's collapse plugin uses an event handler on the document to determine if an element has been clicked, the collapse plugin will never get notified.
I've created a small example where a click handler on the pink .outer area replaces the green .inner area. Note that clicking on the pink area (your #ChangeToggle) will lead to two events, where clicking on the green area (your X icon) will lead to a single event.
$(function() {
$('.outer')
.click(function() {
$('.outer').html('<div class="inner"></div>');
fired('.js-outer');
});
$(document).on('click', '.outer', function() {
fired('.js-document');
});
});
function fired(el) {
$(el).addClass('event--fire');
window.setTimeout(function() {
$(el).removeClass('event--fire')
}, 100);
}
body {
font-family: Helvetica Neue, Helvetica, Arial;
}
.outer,
.inner {
display: inline-block;
padding: 20px;
}
.outer {
border: 1px solid #c66;
background-color: #f99;
}
.inner {
border: 1px solid #6c6;
background-color: #9f9;
}
.event {
margin: 10px 0;
}
.event::before {
display: inline-block;
content: '';
border: 1px solid #ccc;
padding: 10px;
vertical-align: middle;
margin-right: 10px;
}
.event--fire:before {
background-color: #ff9;
}
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<div class="outer">
<div class="inner">
</div>
</div>
<div class="event js-outer">Event fires on .outer</div>
<div class="event js-document">Event fires on document</div>
The easiest way to solve this issue for your navigation bar is to hide/show the X or hamburger icon instead of replacing. In the example below both the X and the hamburger icon are in the html, and toggling the class .hidden is used to show the correct icon.
$(function() {
$('#ChangeToggle').click(function() {
$('#navbar-hamburger').toggleClass('hidden');
$('#navbar-close').toggleClass('hidden');
});
});
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet" />
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button id="ChangeToggle" type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<div id="navbar-hamburger">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</div>
<div id="navbar-close" class="hidden">
<span class="glyphicon glyphicon-remove"></span>
</div>
</button>
<a class="navbar-brand" href="#">Brand</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active">Link <span class="sr-only">(current)</span>
</li>
</ul>
</div>
</div>
</nav>
Instead of adding a jQuery click handler next to Bootstrap's collapse plugin, you could also use the events fired by the collapse plugin to hide or show the correct icon. Use the shown.bs.collapse event to show the X icon, and the hidden.bs.collapse event to show the hamburger icon.
$(function() {
$('#bs-example-navbar-collapse-1')
.on('shown.bs.collapse', function() {
$('#navbar-hamburger').addClass('hidden');
$('#navbar-close').removeClass('hidden');
})
.on('hidden.bs.collapse', function() {
$('#navbar-hamburger').removeClass('hidden');
$('#navbar-close').addClass('hidden');
});
});
#navbar-close {
color: #888;
width: 22px;
height: 14px;
}
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet" />
<script src="//code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<nav class="navbar navbar-default">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button id="ChangeToggle" type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
<div id="navbar-hamburger">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</div>
<div id="navbar-close" class="hidden">
<span class="glyphicon glyphicon-remove"></span>
</div>
</button>
<a class="navbar-brand" href="#">Brand</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active">Link <span class="sr-only">(current)</span>
</li>
</ul>
</div>
</div>
</nav>
This worked for me
Theory
CSS provides all the necessary animation tools. Basically what's happening is this:
The top and bottom lines must rotate to form the X
The middle line must disappear
The X will be taller an more narrow than the hamburger lines, so:
The top and middle lines must move out vertically and to the right to maintain its center
Application
/* Define the shape and color of the hamburger lines */
.navbar-toggler span {
display: block;
background-color: #4f4f4f;
height: 3px;
width: 25px;
margin-top: 5px;
margin-bottom: 5px;
position: relative;
left: 0;
opacity: 1;
transition: all 0.35s ease-out;
transform-origin: center left;
}
/* top line needs a little padding */
.navbar-toggler span:nth-child(1) {
margin-top: 0.3em;
}
/**
* Animate collapse into X.
*/
/* top line rotates 45 degrees clockwise and moves up and in a bit to close the center of the X in the center of the button */
.navbar-toggler:not(.collapsed) span:nth-child(1) {
transform: translate(15%, -33%) rotate(45deg);
}
/* center line goes transparent */
.navbar-toggler:not(.collapsed) span:nth-child(2) {
opacity: 0;
}
/* bottom line rotates 45 degrees counter clockwise, in, and down a bit to close the center of the X in the center of the button */
.navbar-toggler:not(.collapsed) span:nth-child(3) {
transform: translate(15%, 33%) rotate(-45deg) ;
}
/**
* Animate collapse open into hamburger menu
*/
/* top line moves back to initial position and rotates back to 0 degrees */
.navbar-toggler span:nth-child(1) {
transform: translate(0%, 0%) rotate(0deg) ;
}
/* middle line goes back to regular color and opacity */
.navbar-toggler span:nth-child(2) {
opacity: 1;
}
/* bottom line goes back to initial position and rotates back to 0 degrees */
.navbar-toggler span:nth-child(3) {
transform: translate(0%, 0%) rotate(0deg) ;
}
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet"/>
<!-- Bootstrap Navigation -->
<nav class="navbar bg-light">
<a class="navbar-toggler collapsed border-0" type="button" data-toggle="collapse" data-target="#collapsingNavbar">
<!-- these spans become the three lines -->
<span> </span>
<span> </span>
<span> </span>
</a>
<a class="navbar-brand" href="./">
Brand
</a>
<div class="collapse navbar-collapse" id="collapsingNavbar">
<ul class="nav navbar-nav">
<li class="nav-item">
<a class="nav-link" href="#">About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Contact</a>
</li>
</ul>
</div>
</nav>
<main class="container">
<h1>Content Here</h1>
<p>Shrink the viewport if to expose the hamburger menu.</p>
</main>
What makes it work
Specifically, since the top and bottom lines rotate by 45 degrees to form the X, their center lines take up 70% of the width, so they must move in by 15%. This can be calculated using pythagorean theorem.
As it happens, our hamburger menu is 26x21 px, or 24% wider than it is tall, but the X ends up being 20x20 square when you move the lines into place and you take into account the height of the lines (here defined as 3px).
In this particular implementation, we are defining the point of rotation of each line as being the center-left. This affects how much we move the lines up, since the lines are about 3px tall, they each add about (2.1/2)=1.05px to the height of the X, or about 33% of the height of the X.
Therefore 33% is how much they must move out vertically out so the two lines meet at the center of the X and form a 20x20px square.
Customizing
The X will always make a square, so to find out how much to move them by, you just need to know the width and height of your <span> bars and the height of the resulting hamburger icon.
Plug those numbers into this equation:
Or in code:
const line_width = 26; // px
const line_height = 3; // px
const hamburger_height = 21; // px
const x_width = x_height = 0.8 * line_width;
const line_move_y_percent = 100 * (line_width - x_width) / (2 * line_height)
const line_move_right_percent = 100 * (x_height - hamburger_height) / (2 * line_height)
You don't need Javascript, CSS will do the Job
.navbar-toggle {
.icon-bar {
transition: 300ms ease-in-out;
background-color: #fff;
position: relative;
width: 24px;
height: 3px;
}
.icon-bar:last-child {
-webkit-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
-o-transform: rotate(-45deg);
transform: rotate(-45deg);
top: -7px;
}
.icon-bar:nth-child(2) {
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
top: 0px;
}
.icon-bar:nth-child(3) {
opacity: 0;
}
&.collapsed {
.icon-bar {
-webkit-transform: rotate(0deg);
-ms-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
top: 0;
opacity: 1;
}
}
}
As of Bootstrap 4.1, the "hamburger" toggler is no longer <span> tags, and is now a single SVG icon background image.
Therefore it's simplest to swap it out with a little CSS. Then you can use another font icon (like FontAwesome) or a simple '✖' character...
<button class="navbar-toggler collapsed border-0" type="button" data-toggle="collapse" data-target="#collapsingNavbar">
<span class="navbar-toggler-icon"></span>
<div class="close-icon py-1">✖</div>
</button>
/* hide close when burger shown */
.navbar-toggler.collapsed .close-icon {
display: none;
}
.navbar-toggler:not(.collapsed) .navbar-toggler-icon {
display: inline;
}
Demo
Another option is this animated hamburger:
https://codeply.com/p/L9HT5GaUtt
Smart decision helped me in codepen
HTML
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
CSS
.navbar-toggle .icon-bar:nth-of-type(2) {
top: 1px;
}
.navbar-toggle .icon-bar {
position: relative;
transition: all 500ms ease-in-out;
}
.navbar-toggle.active .icon-bar:nth-of-type(1) {
top: 6px;
transform: rotate(45deg);
}
.navbar-toggle.active .icon-bar:nth-of-type(2) {
background-color: transparent;
}
.navbar-toggle.active .icon-bar:nth-of-type(3) {
top: -6px;
transform: rotate(-45deg);
}
JS
$(".navbar-toggle").on("click", function () {
$(this).toggleClass("active");
});
No need to use javascript through css also you can do please follow below code.
HTML
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
CSS (in css use :not which will perform faster animation rather than javascript)
.navbar-toggle .icon-bar {
position: relative;
transition: all 200ms ease-in-out;
}
.navbar-toggle:not(.collapsed) .icon-bar:nth-of-type(1) {
top: 6px;
transform: rotate(45deg);
}
.navbar-toggle:not(.collapsed) .icon-bar:nth-of-type(2) {
background-color: transparent;
}
.navbar-toggle:not(.collapsed) .icon-bar:nth-of-type(3) {
top: -6px;
transform: rotate(-45deg);
}
The below code helps you to solve this issue.
Html:
<div class="content">
<h1>Mobile Navigation menu using css and jquery</h1>
<div class="icons">
<button class="icon">
<span></span>
<span></span>
<span></span>
</button>
</div>
</div>
css:
.btn {
background-color: #ffd200;
color: #00174f;
display: inline-block;
text-decoration: none;
padding: 13px 30px;
margin: 30px 0 0 0;
border-radius: 3px;
font-weight: bold;
}
.btn:hover {
background-color: #fff;
}
.btn--transition {
-webkit-transition: -webkit-transform 0.2s;
-webkit-transition: all 200ms ease-in-out;
transition: all 200ms ease-in-out;
}
:focus {
outline: none;
}
.icons {
margin: 50px 0;
}
.icon {
margin: 0 30px 0 0;
}
.icon {
background-color: #ff3000;
border: 0;
height: 79px;
width: 79px;
border-radius: 50%;
cursor: pointer;
position: relative;
}
.icon span {
display: block;
height: 5px;
width: 33px;
background-color: #ffffff;
border-radius: 2px;
position: absolute;
left: 23px;
-webkit-transition: -webkit-transform 0.3s;
-webkit-transition: all 300ms ease-in-out;
transition: all 300ms ease-in-out;
}
.icon span:first-child {
top: 28px;
}
.icon span:nth-child(2) {
top: 37px;
}
.icon span:last-child {
top: 46px;
}
.icon--active span:first-child {
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
position: absolute;
top: 37px;
}
.icon--active span:last-child {
-webkit-transform: rotate(-45deg);
-ms-transform: rotate(-45deg);
transform: rotate(-45deg);
position: absolute;
top: 37px;
}
.icon--active span:nth-child(2) {
opacity: 0;
}
.icon--button {
border-radius: 10px;
}
.icon-transition {
-webkit-transition: -webkit-transform 0.3s;
-webkit-transition: all 300ms ease-in-out;
transition: all 300ms ease-in-out;
}
javascript
<script>
var animation = 'rubberBand';
$('.icon').on('click', function () {
$(this).toggleClass('icon--active');
});
$('.icon').on('click', function () {
$(this).addClass('animated ' + animation).one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function () {
$(this).removeClass('animated ' + animation);
});
});
</script>
This snippets is used to change the mobile icon to close icon on click the button.
I tried #Zim's solution and it worked perfectly, thanks for sharing.
I did make 2 slight adjustments:
I changed border-0 to border-1 to keep a border around the hamburger image.
I added a background color on the div since the X ended up being a similar color to my existing background.
Bootstrap v5.2:
HTML:
<button class="navbar-toggler" id="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
<span class="close py-1"><i class="bi bi-x-lg"></i></span>
</button>
CSS:
.navbar button[aria-expanded="true"] > span.close {
display: inline;
}
.navbar button[aria-expanded="true"] > span.navbar-toggler-icon {
display: none;
}
.navbar button[aria-expanded="false"] > span.close {
display: none;
}
In my example I'm using Bootstrap Icons to display the close icon. So make also sure to download or at least include the icon fonts stylesheet.

Categories