简体   繁体   中英

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()">&#9776;</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!

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

Code for simple animated menu button

HTML

<button class="menu-btn" id="menu-icon">
  <div class="btn-line"></div>
</button>

CSS

.menu-btn {
  width: 40px;
  height: 40px;
  background: none;
  border: 0;
}

.menu-btn,
.btn-line {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.btn-line,
.btn-line::before,
.btn-line::after {
  width: 35px;
  height: 5px;
  border-radius: 4px;
  background: white;
  transition: all .5s;
}

.btn-line {
  position: relative;
}

.btn-line::before,
.btn-line::after {
  position: absolute;
  content: '';
  top: -11px;
}

.btn-line::after {
  top: 11px;
}

.close > .btn-line {
  transform: rotate(225deg);
  background: red;
}

.close > .btn-line::before,
.close > .btn-line::after {
  top: 0;
  transform: rotate(90deg);
  background: red;
}

JS

const btn = document.getElementById('menu-icon');
btn.addEventListener('click', (e) => {
  e.target.classList.toggle('close');
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM