Bootstrap 移动菜单图标更改为 x 关闭

Bootstrap mobile menu icon change to x close

编辑

答案使用 2020 CSS 轻松解决问题,更适用于 Bootstrap 4.

原始问题和选择的答案仍然有效且信息量很大。

原始问题

我想在移动视图中将菜单图标(在 bootstrap 基本导航栏示例中用 class 图标栏定义)更改为 X 形(类似于这里发生了什么:https://www.mint.com 但不那么花哨(我只想用 X 替换 3 条条纹)。

目前我正在使用自定义 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>

连同以下 javascript 函数(我知道这是基本的,但我是新手):

<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>

一切正常,唯一的问题是当我准确点击 X 图标时菜单没有关闭。它仅在我单击其外部(按钮中的任何其他位置)时关闭。单击 X 图标时,它所做的唯一一件事就是回到原来的 3 条纹。

有人知道我做错了什么吗?

您的 JavaScript 替换了 #ChangeToggle 元素的内部 html 以显示 X 或汉堡包图标。精确点击 X 或汉堡菜单而不是 #ChangeToggle 将删除被点击的元素,我认为它可以防止它冒泡。由于 Bootstrap 的 collapse plugin 使用文档上的事件处理程序来确定元素是否已被单击,折叠插件将永远不会收到通知。

我创建了一个小示例,其中粉红色 .outer 区域上的点击处理程序替换了绿色 .inner 区域。请注意,单击粉红色区域(您的 #ChangeToggle)将导致两个事件,而单击绿色区域(您的 X 图标)将导致一个事件。

$(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>

解决导航栏此问题的最简单方法是 hide/show X 或汉堡包图标,而不是替换。在下面的示例中,X 和汉堡包图标都在 html 中,切换 class .hidden 用于显示正确的图标。

$(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"><a href="#">Link <span class="sr-only">(current)</span></a>
        </li>
      </ul>
    </div>
  </div>
</nav>

除了在 Bootstrap 的折叠插件旁边添加 jQuery 单击处理程序,您还可以使用 the events fired by the collapse plugin 来隐藏或显示正确的图标。使用 shown.bs.collapse 事件显示 X 图标,使用 hidden.bs.collapse 事件显示汉堡包图标。

$(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"><a href="#">Link <span class="sr-only">(current)</span></a>
        </li>
      </ul>
    </div>
  </div>
</nav>

你不需要 Javascript,CSS 会完成任务

.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;
        }
    }
}

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");
});

下面的代码可以帮助您解决这个问题。

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>

此代码段用于将移动图标更改为单击按钮时关闭图标。

无需使用 javascript 到 css 也可以,请按照以下代码操作。

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(在css中使用:not比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);
}      

Bootstrap 4.1 开始,"hamburger" 切换器不再是 <span> 标签,现在是单个 SVG 图标背景图片.

因此 最简单的方法是用 CSS 将其替换掉。然后你可以使用另一个字体图标(如 FontAwesome)或一个简单的'✖'字符...

   <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


另一种选择是这个动画汉堡包:
https://codeply.com/p/L9HT5GaUtt

我试过@Zim 的解决方案,效果很好,感谢分享。 我确实做了 2 次细微调整:

  1. 我将 border-0 更改为 border-1 以在汉堡图片周围保留边框。
  2. 我在 div 上添加了背景颜色,因为 X 最终与我现有的背景颜色相似。

这对我有用

理论

CSS 提供所有必要的动画工具。基本上发生的事情是这样的:

  • 顶线和底线必须旋转形成 X
  • 中线必须消失

X 会比汉堡线更高更窄,所以:

  • 顶部和中间的线必须垂直向右移出以保持其中心

申请

/* 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>

是什么让它起作用

具体来说,由于顶线和底线旋转45度形成X,它们的中心线占宽度的70%,所以它们必须向内移动15%。这可以使用毕达哥拉斯定理计算。

碰巧,我们的汉堡菜单是 26x21 像素,比高度宽 24%,但是当您将线条移动到位并考虑线条的高度时,X 最终变成 20x20 正方形(这里定义为 3px)。

在这个特定的实现中,我们将每条线的旋转点定义为 center-left。这会影响我们将线条向上移动多少,因为这些线条大约有 3px 高,它们每条都会增加大约 (2.1/2)=1.05px 到 X 的高度,或者大约是 X 高度的 33%。

因此 33% 是他们必须垂直向外移动多少,这样两条线在 X 的中心相交并形成一个 20x20px 的正方形。

自定义

X 总是会形成一个正方形,因此要了解将它们移动多少,您只需要知道 <span> 条形的宽度和高度以及生成的汉堡包图标的高度。

将这些数字代入这个等式:

Equation

或者在代码中:

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)