简体   繁体   中英

How can I turn my navbar into Hamburger menu for mobile using responsive design?

How could I turn this navbar I made using CSS into Hamburger menu for mobile? It needs to be responsive. I first tried using bootstrap but I'd like it to use CSS

Here's my codepen: https://codepen.io/Softee/pen/WNZpXGa

Thanks in advance for your help!

Here's the code:

 header { background: #583760; } header::after { content: ''; display: table; clear: both; }.logo { max-height: 90px; margin-left: 60px; float: left; padding: 10px; } nav { margin-right: 60px; float: right; } nav ul { margin: 0; padding: 0; list-style: none; } nav li { display: inline-block; margin-left: 40px; padding-top: 50px; } nav a { color: white; font-weight: bold; text-decoration: none; text-transform: uppercase; } nav a:hover { color: black; } #nav:not(:target) { right: -100%; transition: right 1.5s; } #nav:target { right: 0; transition: right 1s; }
 <header> <div class="container"> <img src="images/GameStar-Blanc.png" alt="logo" class="logo"> <nav> <ul> <li><a href="#">A LA UNE </a></li> <li><a href="#">L'ACTUALITE</a></li> <li><a href="#">GUIDES ET ASTUCES</a></li> <li><a href="#">PROCHAINEMENT</a></li> </ul> </nav> </header>

Responsive means you'll use media queries.

If your current CSS represents the way you want the menu to look on the desktop, then you wrap that menu-related css within a media query, which matches whatever your definition of desktop is.

something like:

/* not-menu-related generic css here ... */

/* menu-related css that should be used on both desktop/mobile here ... */

@media screen and (min-width:240px) and (max-width:480px) {
    /* all your current (desktop) menu-related css here */
}

After that, you can make a similar @media.... {... } block for mobile, and add the relevant CSS in there that makes it look whatever way you prefer there.

threw this together using @media and display:block, display:none hope it helps

 header { background: #583760; } header::after { content: ''; display: table; clear: both; }.logo { max-height: 90px; margin-left: 60px; float: left; padding: 10px; } nav { margin-right: 60px; float: right; } nav ul { margin: 0; padding: 0; list-style: none; } nav li { display: inline-block; margin-left: 40px; padding-top: 50px; } nav a { color: white; font-weight: bold; text-decoration: none; text-transform: uppercase; } nav a:hover { color: black; } #nav:not(:target) { right: -100%; transition: right 1.5s; } #nav:target { right: 0; transition: right 1s; }.hamburgerIcon { display: none; } @media only screen and (max-width: 600px) {.hamburgerIcon { display: block; }.hamburgerIcon div { width: 35px; height: 5px; background-color: black; margin: 6px 0; } nav a { display: none; } }
 <header> <div class="container"> <img src="https://via.placeholder.com/60" alt="logo" class="logo"> <nav> <ul> <li><a href="#">A LA UNE </a></li> <li><a href="#">L'ACTUALITE</a></li> <li><a href="#">GUIDES ET ASTUCES</a></li> <li><a href="#">PROCHAINEMENT</a></li> <li> <div class='hamburgerIcon'> <div></div> <div></div> <div '></div> </div> </ul> </nav> </header>

also see w3schools.com/howto/howto_js_mobile_navbar.asp for further help building the nav if you need

Here's a solution with minimal JS.

You'll want to adjust your CSS for smaller screen sizes and use a media query for your larger screen sizes styles like, @media only screen and (min-width: 768px) .

Then you'll want to add a click event to your nav to toggle an "open" class and style accordingly:

 document.getElementById('navigation').onclick = () => { document.body.classList.toggle('nav-open') }
 body { margin: 0; }.container { display:flex; justify-content: space-between; align-items: center; padding: 10px; } header { background: #583760; } header::after { content: ''; display: table; clear: both; }.hamburger { color: white; font-size: 36px; } nav { cursor: pointer; } nav a { color: white; font-weight: bold; text-decoration: none; text-transform: uppercase; } nav ul { position: fixed; top: 100px; right: 0; height: 100%; text-align: right; padding: 30px; margin: 0; list-style: none; background: #583760; display: none; }.nav-open nav ul { display: block; } @media only screen and (min-width: 768px) {.logo { max-height: 90px; margin-left: 60px; float: left; padding: 10px; }.hamburger { display: none; } nav { margin-right: 60px; float: right; } nav ul { display: block; padding: 0; position: relative; top: unset; right: unset; height: unset; } nav li { display: inline-block; margin-left: 40px; padding-top: 50px; } nav a:hover { color: black; } #nav:not(:target) { right: -100%; transition: right 1.5s; } #nav:target { right: 0; transition: right 1s; } }
 <header> <div class="container"> <img src="https://via.placeholder.com/150" alt="logo" class="logo"> <nav id="navigation"> <div class="hamburger">&equiv;</div> <ul id="navigationItems"> <li><a href="#">A LA UNE </a></li> <li><a href="#">L'ACTUALITE</a></li> <li><a href="#">GUIDES ET ASTUCES</a></li> <li><a href="#">PROCHAINEMENT</a></li> </ul> </nav> </header>

First of all, you will have to refactor the global CSS by using flex and grid which are the standard for responsive design. It is way more simple and powerful than using floats and other ancient stuff:

<header class="header">
  <img src="..." />
  <nav> ... </nav>
</header>

.header {
  display: flex;
  width: 100%;
  justify-content: space-between;
  align-items: center;
  padding: 20px 60px;
}

With justify-content: space-between you tell the container that the elements inside of it (.logo and nav) will be spaced, the first (logo) at the left and the second (nav) at the right, no need to use float. The property works only if you set display: flex . With align-items: center; you tell the flex container how you want to vertically align your items.

在此处输入图像描述

Then, you can assign a class to ul and populate it as follows:

.list {
  display: grid;
  grid-auto-flow: column;
  list-style-type: none;
  column-gap: 20px;
  padding: 0;
}

Here you're telling to <ul> element that all the <li> elements inside of it, should compose a grid of n columns as many <li> elements and that you want 20px of space between each of them. The property column-gap works only if you set display: grid . The padding should always be 0 or the browser will add some padding by default. You don't want it so you specify 0.

在此处输入图像描述

Now, you can use a powerful combo to set the width of the list items by creating a class and assigning it to your <li> elements:

.listItem {
  width: min-content;
  white-space: nowrap;
}

Here you're just telling to the list items that their width should be automatic, based on the words length. With white-space: nowrap you're telling to the list items that you never want the text to start a new line after a space. For example, "GUIDES ET ASTUCES" will always be placed on a single line. At the same time you're also setting the width for each column of the grid created before.

Now, create a button and wrap it together with the logo in a new div:

    <div class="mobileHeader">
      <img src="images/GameStar-Blanc.png" alt="logo" class="logo">
      <button class="hamburger">Menu</button>
    </div>

Basically, this will be your mobile header with the logo on the left and the button on the right. The menu will be placed below.

Create a global CSS rule and tell the button you never want to display it:

.hamburger {
  display: none;
}

Now for the mobile menu, you should change the appearance of the <nav> container and all its child element that you want to change. From now on your code should be wrapped around a media query, place the media queries at the bottom of your CSS file or at least, below the rules defined before:

@media screen and (max-width: 800px) {
  // CSS code
}

Create another CSS rule targeting all the devices with a max resolution of 800px:

@media screen and (max-width: 800px) {
    .hamburger {
      display: block;
    }
}

In short, you just said: "The menu button should always be hidden, but when a device has a width from 0 to 800px, I want to display it.

You did that because you want that the menu is hidden when you visit the website.

Now create another rule inside the media query @media screen and (max-width: 800px) and do the same you did for the header:

.mobileHeader {
  width: 100%;
  display: flex;
  justify-content: space-between;
}

Basically you want that a certain width, the header is something like:

在此处输入图像描述

Now you should have two elements inside your, a and the, let's create a rule and tell the header that you would like to display those elements one below the other:

.header {
  flex-direction: column;
  padding: 20px;
}

Basically it is just like grid-auto-flow: row for grids.

Now do the same for the list, this time you want that all the items will compose a grid with n rows and just one column:

.list {
  grid-auto-flow: row;
  list-style-type: none;
  row-gap: 40px;
  column-gap: 0;
  justify-items: center;
}

With justify-items: center you're instructing the list container to center the items. It works only with display: grid , since you set display: grid in a global rule, you don't need to write it again as long as you don't need to change it.

在此处输入图像描述

Now assign a class to your <nav> and enter another rule in the media query:

.menu {
   display: none;
}

Since your menu should be hidden when an user visits the website on mobile, it should be set on display: none by default.

Now, set a rule to target only devices with a width of 801 px and more with (min-width: 801px) :

@media screen and (min-width: 801px) {
  .menu {
    display: block !important;
  }
}

No matter what, you always want the menu to be displayed for devices which have a resolution wider than 800px.

Now, if you shrink your window the mobile menu should be vanished and here you need a bit of JS to open and close it, I am not going into the details since your question is totally related to CSS and I will only confuse you by going deeper but you will find everything in the pen I made for you.

https://codepen.io/alienopolis/pen/NWapXWZ

Finally, I would recommend you to take this free tutorial which covers everything you need to know about responsive design with CSS:

https://www.freecodecamp.org/news/css-flexbox-and-grid-tutorial/

Hope it helps!

HTML

<header class="header">
  <div class="mobileHeader">
    <img src="images/GameStar-Blanc.png" alt="logo" class="logo">
    <button onclick={openMenu()} class="hamburger">Menu</button>
  </div>
  <nav class="mobileMenu">
    <ul class="list">
      <li class="listItem"><a href="#">A LA UNE </a></li>
      <li><a href="#">L'ACTUALITE</a></li>
      <li><a href="#">GUIDES ET ASTUCES</a></li>
      <li><a href="#">PROCHAINEMENT</a></li>
    </ul>
  </nav>
</header>

CSS

body {
  width: 90%;
  height: 800px;
}

.header {
  display: flex;
  width: 100%;
  justify-content: space-between;
  background: #583760;
  align-items: center;
  padding: 20px 60px;
}


.logo {
  color: white;
}

.list {
  display: grid;
  grid-auto-flow: column;
  list-style-type: none;
  column-gap: 40px;
}

.listItem {
  width: min-content;
  white-space: nowrap;
}

nav a {
  color: white;
  font-weight: bold;
  text-decoration: none;
  text-transform: uppercase;
}

nav a:hover {
  color: black;
}

.hamburger {
  display: none;
}

@media screen and (min-width: 801px) {
  .mobileMenu {
    display: block !important;
  }
}

@media screen and (max-width: 800px) {

  .header {
    flex-direction: column;
    padding: 20px;
  }

  .mobileHeader {
    width: 100%;
    display: flex;
    justify-content: space-between;
  }

  .hamburger {
    display: block;
  }

  .mobileMenu {
    display: none;
  }

  .list {
    grid-auto-flow: row;
    list-style-type: none;
    row-gap: 40px;
    column-gap: 0;
    justify-items: center;
  }
}

JS

const hamb = document.querySelector(".hamburger");
const menu = document.querySelector(".mobileMenu");
let open;

function openMenu() {
  if (open) {
    open = false;
    menu.style.display = "none";
  } else {
    menu.style.display = "block";
    open = true;
  }
}

window.addEventListener("DOMContentLoaded", (e) => {
  hamb.addEventListener("click", openMenu())
})

To do this with just CSS is pretty high-level. Here is a solution using pure CSS. It's important for you to know how this works, so please do your due diligence. I tried to make the CSS friendly by including notes and separating out each major style in different sections.

 /* CORE STYLES */:root { --primary-color: #583760; --overlay-color: #583760; --ani-content-speed: 1s; } * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: 'Roboto', sans-serif; line-height: 1.4; } /* MENU STYLES */.togger-an { position: fixed; top: 0; right: 0; z-index: 1; display: none; }.toggler { visibility: visible;important. }.togger-an:toggler { position; absolute: top; 0: right; 0: z-index; 2: cursor; pointer: width; 50px: height; 50px: opacity; 0. }.togger-an:cta-mob { position; absolute: top; 0: right; 0: z-index; 1: width; 60px: height; 60px: padding; 1rem: display; flex: align-items; center: justify-content; center. } /* cta-mob Line */.togger-an:cta-mob > div { position; relative: flex; none: width; 100%: height; 2px: background; #fff: display; flex: align-items; center: justify-content; center: transition. all 0;4s ease. } /* cta-mob Lines - Top & Bottom */.togger-an:cta-mob > div:,before. .togger-an:cta-mob > div::after { content; '': position; absolute: z-index; 1: top; -10px: width; 100%: height; 2px: background; inherit. } /* Moves Line Down */.togger-an:cta-mob > div::after { top; 10px. } /* Toggler Animation */.togger-an:toggler.checked +:cta-mob > div { transform; rotate(135deg). } /* Turns Lines Into X */.togger-an:toggler.checked +:cta-mob > div,before. .togger-an:toggler.checked +:cta-mob > div:after { top; 0: transform; rotate(90deg). } /* Rotate On Hover When Checked */.togger-an:toggler:checked.hover +:cta-mob > div { transform; rotate(225deg). } /* Show Menu */.togger-an:toggler.checked ~:ani-content { visibility; visible. }.togger-an:toggler.checked ~:ani-content > div { transform; scale(1): transition-duration; var(--ani-content-speed). }.togger-an:toggler.checked ~:ani-content > div > div { opacity; 1: transition. opacity 0.4s ease 0;4s. }.togger-an:ani-content { position; fixed: top; 0: left; 0: width; 100%: height; 100%: visibility; hidden: overflow; hidden: display; flex: align-items; center: justify-content; center. }.togger-an:ani-content > div { background; var(--overlay-color): width; 200vw: height; 200vw: display; flex: flex; none: align-items; center: justify-content; center: transform; scale(0): transition. all 0;4s ease. }.togger-an:ani-content > div > div { text-align; center: max-width; 90vw: max-height; 100vh: opacity; 0: transition. opacity 0;4s ease. }.togger-an:ani-content > div > div > ul > li { list-style; none: color; #fff: font-size. 1;5rem: padding; 1rem. }.togger-an:ani-content > div > div > ul > li > a { color; inherit: text-decoration; none: transition. color 0;4s ease. } /* Main Navbar No Media */:navbar { width; 100%: background-color; #583760: height; 60px: display; flex: justify-content; right: align-items; center. }:navbar ul { list-style-type; none: display; flex: gap; 40px. }:navbar li a { color; white: text-decoration; none. }:navbar a:hover { color,rgba(13, 110, 139. 0:75) } /* nav media */ @media only screen and (max-width. 800px) {:togger-an { display; block. }:navbar li a { display; none; } }
 <body> <nav> <div class="navbar"> <ul> <li><a href="#">A LA UNE</a></li> <li><a href="#">L'ACTUALITE</a></li> <li><a href="#">GUIDES ET ASTUCES</a></li> <li><a href="#">PROCHAINMENT</a></li> </ul> </div> </nav> <div class="togger-an"> <input type="checkbox" class="toggler"> <div class="cta-mob"><div></div></div> <div class="ani-content"> <div> <div> <ul> <li><a href="#">A LA UNE</a></li> <li><a href="#">L'ACTUALITE</a></li> <li><a href="#">GUIDES ET ASTUCES</a></li> <li><a href="#">PROCHAINMENT</a></li> </ul> </div> </div> </div> </div> </body>

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