html - How do I make a menu icon on a responsive navigation bar animated into an x icon?
问题描述
I am making my first web app, and am working on a top navigation bar. I am making it responsive, where the menu icon only shows up if the screen width is less than 600 px. I would like for the menu icon to turn into an X icon once the menu icon is clicked on, but I am not quite sure how to do this.
Below is my code for the navigation bar.
'''
<!DOCTYPE html>
<html>
<head>
<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;font-family:"Trebuchet MS"}
.topnav {
overflow: hidden;
background-color: #333;
}
.topnav a {
float: left;
display: block;
color: #f2f2f2;
text-align: center;
padding: 14px 16px;
text-decoration: none;
font-size: 17px;
}
.active {
background-color: #4C00AF;
color: white;
}
.topnav .icon {
display: none;
}
.dropdown {
float: left;
overflow: hidden;
}
.dropdown .dropbtn {
font-size: 17px;
border: none;
outline: none;
color: white;
padding: 14px 16px;
background-color: inherit;
font-family: inherit;
margin: 0;
}
.dropdown-content {
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
z-index: 1;
}
.dropdown-content a {
float: none;
color: black;
padding: 12px 16px;
text-decoration: none;
display: block;
text-align: left;
}
.topnav a:hover, .dropdown:hover .dropbtn {
background-color: #554647;
color: white;
}
.dropdown-content a:hover {
background-color: #ddd;
color: black;
}
.dropdown:hover .dropdown-content {
display: block;
}
@media screen and (max-width: 600px) {
.topnav a:not(:first-child), .dropdown .dropbtn {
display: none;
}
.topnav a.icon {
float: right;
display: block;
}
}
@media screen and (max-width: 600px) {
.topnav.responsive {position: relative;}
.topnav.responsive .icon {
position: absolute;
right: 0;
top: 0;
}
.topnav.responsive a {
float: none;
display: block;
text-align: left;
}
.topnav.responsive .dropdown {float: none;}
.topnav.responsive .dropdown-content {position: relative;}
.topnav.responsive .dropdown .dropbtn {
display: block;
width: 100%;
text-align: left;
}
}
</style>
<div class="topnav" id="myTopnav">
<a href="#home" class="active">Home</a>
<a href="#contact">Page2</a>
<div class="dropdown">
<button class="dropbtn">About
<i class="fa fa-caret-down"></i>
</button>
<div class="dropdown-content">
<a href="#">Hello</a>
<a href="#">Salutations</a>
<a href="#">Hi</a>
</div>
</div>
<a href="javascript:void(0);" style="font-size:15px;" class="icon"
onclick="myFunction()">☰</a>
</div>
<script>
function myFunction() {
var x = document.getElementById("myTopnav");
if (x.className === "topnav") {
x.className += " responsive";
} else {
x.className = "topnav";
}
}
</script>
</body>
</html>
'''
Thank you!
解决方案
这对我有用
理论
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">
<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%,但是当您将线条移动到位并考虑线条的高度(此处定义为 3px)时,X 最终为 20x20 正方形)。
在这个特定的实现中,我们将每条线的旋转点定义为左中。这会影响我们向上移动线条的程度,因为线条大约有 3px 高,它们每条都增加了大约 (2.1/2)=1.05px 到 X 的高度,或者大约是 X 高度的 33%。
因此 33% 是它们必须垂直向外移动的量,这样两条线在 X 的中心相遇并形成一个 20x20px 的正方形。
定制
X 总是会形成一个正方形,因此要知道将它们移动多少,您只需要知道<span>
条形的宽度和高度以及生成的汉堡图标的高度。
将这些数字代入这个等式:
或在代码中:
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)
推荐阅读
- angular - 在类构造函数中注入服务的长形式
- java - 在 Spring Cloud 应用程序中,微服务请求以 Forbidden 状态响应
- python - 运行 unittest 时出现“未找到测试”
- java - 如何解决无法加载身份验证插件“caching_sha2_password”问题
- apache-spark - Oozie Spark 动作失败
- javascript - 为什么表格超过 5 行时需要单击两次?
- php - 如何在没有凭证文件的情况下使用 AWS PHP SDK v3.0
- azure - 如何使用 ARM 模板在 Azure Monitor 中配置新警报?
- javascript - 带有工具提示的 jQuery 表单验证器
- excel - Excel VBA - 替换非英文字符