5

I want to have to click on a hamburger menu icon and then have the list display beneath my icon. I set up my hamburger menu icon with this style

.menu-btn div {
    position: absolute;
    left: 100%;
    top: 64%;
    padding-right: 8px;
    margin-top: -0.50em;
    line-height: 1.2;
    font-size: 18px;
    font-weight: 200;
    vertical-align: middle;
    z-index: 99;
}

.menu-btn span {
    display: block;
    width: 20px;
    height: 2px;
    margin: 4px 0;
    background: #989da1;
    z-index: 99;
}

The menu of options taht should appear after you click on the hamburger menu is

 <div class="responsive-menu">
    <ul id="menu">
       <li>Vote</li>
       <li>Search</li>
       <li>About</li>
       <li>Log In</li>
    </ul>
 </div>

but I'm unclear how to set up the style of the hamburger menu so taht it appears directly under the hamburger menu when you click on it. Right now, its appearing centered at the top of the screen -- https://jsfiddle.net/wtp1k57b/1/ . How do I set up such a style?

PS - I'm looking for a solution that doesn't rely on hard-coding numeric (e.g. top: 27px) pixel values. Certainly its good to get things to work in my little Fiddle, but in my broader application I can't guarantee how big or small that hamburger menu will be.

  • set the [position](https://developer.mozilla.org/en-US/docs/Web/CSS/position) of the menu where you want it. You already set it to absolute so now set the top, and left properties – JoshKisb Feb 06 '18 at 18:45
  • @JoshKisb, "top" and "left" only seem to accept pixel values, but I'd like to be a little less rigid and somehow tell the menu to just appear under the icon. –  Feb 06 '18 at 20:38
  • the menu button / icon is absolute positioned so just do the same with menu – JoshKisb Feb 06 '18 at 22:25
  • @JoshKisb, I'm not understanding "just do the same". YOu mean put a "position:absolute;" attribute on the navigation menu liek this -- https://jsfiddle.net/wtp1k57b/4/ ? –  Feb 07 '18 at 17:06

5 Answers5

0

Use the css properties: top and right to set the position of the element under your icon.

#menu
{
  position: absolute;
  top: 48px;
  right: 2px;

  background: #ededed;
  list-style-type: none;
}
Joel García
  • 191
  • 4
  • 10
  • Is there any way to do this without hard-coding fixed pixel values (e.g. "48px")? I would like it to appear right underneath -- e.g. where the hamburger menu ends –  Feb 06 '18 at 20:37
  • You could use a relative unit (like _em_, _rem_, etc.) and determine the the values based on the parent element. – Joel García Feb 07 '18 at 00:21
0

Use this CSS for your menu - no margin, and the position defined by the top and right settings:

#menu {
  position: absolute;
  width: 300px;
  margin: 0;
  padding: 50px;  
  background: #ededed;
  list-style-type: none;
  -webkit-font-smoothing: antialiased;
  top: 50px;
  right: 0;
}

https://jsfiddle.net/meuexde6/

I left out the transition for the testing, but you should basically animate the right parameter from -100px to 0 to achieve what you seemed to have in mind.

ADDITION AFTER COMMENT:

To define the position of the menu in relation to the button, you have to apply position: relative to their common parent element, .mobile-nav. The position values of an element with position: absolute always relate to the first ancestor which has position: relative.

I changed the values in my updated fiddle accordingly to these:

#menu {
  position: absolute;
  width: 300px;
  margin: 0;
  padding: 50px;  
  background: #ededed;
  list-style-type: none;
  -webkit-font-smoothing: antialiased;
  top: 40px;
  right: -32px;
}

Updated fiddle: https://jsfiddle.net/meuexde6/1/

If you really want the menu to stick directly to the button (hard to say - it has no borders), just adjust the top and right values as needed.

Johannes
  • 64,305
  • 18
  • 73
  • 130
  • Thanks. I edited my question to make the desire more clear. I'd prefer not to hard-code values for "top" and "right" but somehow tell the drop down menu to appear whereever the hamburger menu ends. I realize 50px might work in my JSFiddle demo, but I can't guarantee that will be the size in my actual application. –  Feb 08 '18 at 21:32
  • please note the addition to my answer and updated fiddle – Johannes Feb 08 '18 at 21:39
0

So, here goes. I know you are asking for a solution to a specific problem, I solved it alright, but I couldn't help noticing that you are struggling with your code. You must simplify the way you think and your code will become leaner. The purpose of this forum is to help others become better, right? :)

HTML

It is good practice to keep the menu toggle button OUTSIDE of the menu - will solve a lot of issues - check below.

It is not semantically right to use anything else rather than a button for the toggle function, so, why not use a button here? I also removed unnecessary clutter from your code, like some divs and the id - the id could be traded with the class, your call. I also removed .mobile-nav because it is not needed at all.

<button class="menu-btn">
  <span></span>
  <span></span>
  <span></span>
</button>

<div class="responsive-menu">
  <ul id="menu">
    <li>Vote</li>
    <li>Search</li>
    <li>About</li>
    <li>Log In</li>
  </ul>
</div>

CSS

I absolutely positioned the menu-btn on the top right corner, and gave it a width equal to the #pageTitle height (which I set at 50px - a gold standard) to keep it rectangular; it should be a rule of thumb that the toggle buttons are rectangular and always the same height as the top navigation bar - in this case the before-mentioned id. The same I did for the .responsive-menu. I absolutely positioned it as shown below. The changes allowed me to remove a lot of css styling - now obsolete - like for example the absolute positioning of the ul menu inside the .responsive-menu.

.menu-btn {
  position:absolute;
  display:block;
  right:0;
  top:0;
  width:50px;
  height:50px;
  background:yellow;
  border:none;
  padding:16px;
}

.responsive-menu {
  position: absolute;
  top: 50px;
  right: 0;
  display: none;
}

Javascript

By years of practice I realized that the most efficient way to toggle a menu instead of adding and removing classes is to add a class on the body tag; this can help heaps if you want to restyle anything else on the page depending on wether your menu is opened or not.

$('.menu-btn').on('click', function() {
  $('body').toggleClass('responsive-menu-open');
});

Here is a working jsfiddle: https://jsfiddle.net/scooterlord/4atafhge/

I could have done a lot of other things in order to simplify the code even further - remove unnecessary ids and classes since most elements are considered unique and could be targeted using descendant classes, eg .responsive-menu ul, etc. After a lot of practice, you'll manage to think simpler and produce code with a smaller footprint.

Edit: Concerning the fact that you don't like the absolute pixels for alignment here is a trick.

Giving a fixed height to the parent container, equal to the toggle button's -in this case '#pageTitle' and setting its position to relative allows you to use top:100% to properly place the responsive menu exactly below the button (which is essentially the same height):

#pageTitle {
  display: flex;
  height: 50px;
  position:relative;
}

.responsive-menu {
  position: absolute;
  top: 100%;
  right: 0;
  display: none;
}

Here is an updated fiddle: https://jsfiddle.net/scooterlord/4atafhge/1/

Edit: Natalia, I gave it some thought and here is what I came up with. I created an absolutely positioned .menu-wrapper, inside of which I placed the button and the responsive menu with float:right and no positioning - aka they are positioned statically. No more pixel values! YAY!

.menu-wrapper {
  position:absolute;
  top:0;
  right:0;
}
.menu-btn {
  float:right;
  ...
}
.responsive-menu {
 float:right;
  clear:both; // to clear the .menu-btn and sit exactly below it
  ...
}

Here is a working fiddle: https://jsfiddle.net/scooterlord/4atafhge/2/

scooterlord
  • 15,124
  • 11
  • 49
  • 68
  • So I understand your solution, your hard-coding a "height" for the "#pageTitle" element and a "line-height" for the "h2" element? I guess taht gets me closer. But why do we have to hard-code a pixel number somewhere? It's not possible in CSS to tell an element to appear below another element without telling that element where the other ends? –  Feb 09 '18 at 14:26
  • @Natalia yes you can, but not in this case if you want everything to align properly. If there was no positioning involved you could just place one below the other and toggle that element. – scooterlord Feb 09 '18 at 14:33
  • @Natalia check the additional part in my answer, I think it is exactly what you are after. – scooterlord Feb 09 '18 at 21:42
0

HTML5 Semantic Elements.

details > summary {
  padding: 2px 6px;
  width:12px;
  border: none;
  list-style: none;
}

details > summary::-webkit-details-marker {
  display: none;
}

ul{
list-style: none;
margin-left:0;
padding-left:0;
}
<details>
  <summary>☰</summary>
  <ul>
  <li>a</li>
  <li>b</li>
  <li>c</li>
  </ul>
</details>
Ronnie Royston
  • 16,778
  • 6
  • 77
  • 91
  • Thanks. I like this solution b/c you're not hard-coding numbers anywhere. But I'm haivng trouble figuring out how to apply it to what I have. Is the key taking the "
      " element that I have with the menu items and applying your "::-webkit-details-marker" style to it?
    –  Feb 09 '18 at 14:30
  • you use the unordered list as normal. HTML5 `details` element simply does all the heavy lifting for you, i.e., it is simple to implement code. Don't worry about the `::-webkit-details-marker ` it's irrelevant. – Ronnie Royston Feb 09 '18 at 15:04
  • There's still something I'm missing because even after I removed all my positioning style elements and structured my stuff in terms of "details" and "summary", the list is still appearing aligned at the top and to the left of my hamburger menu -- https://jsfiddle.net/wtp1k57b/6/ . –  Feb 09 '18 at 21:04
  • `margin` and/or `padding` on the `ul` in your CSS. If that don't work try and style the actual `li` items margin/padding. – Ronnie Royston Feb 09 '18 at 22:26
  • Margin/padding just contorl how the text is spaced, no? Maybe what I'm asking needs a separate question. I'll try doing that to see what results. –  Feb 10 '18 at 19:13
  • OK. Kindly accept whatever answer suits your question best so the question does not keep popping up. – Ronnie Royston Feb 10 '18 at 19:27
  • Ok. Is it clear what I'm asking? I don't want others to be confused and I don't feel I've yet figured out my problem. –  Feb 11 '18 at 19:29
0

I would like to show a completely different approach without using display: flex.

HTML

Your approach uses too many wrappers in my opinion. You can definitely reduce the amount of divs. Moreover, you should always try to use semantic tags over general tags like div or ul. Consider looking at this article.

Hence, as @scooterlord already mentioned, you should use a button for the hamburger icon. Moreover, I recommend to use a nav instead of a list.

CSS

First of all, you should bundle the attributes for the same selector at the same place for the purpose of improved clarity. You should not have three sections where you apply the universal selector, but combine it into one. Moreover, do not set the box-sizing to a specific value, but rather set it to inherit, so you can always override this value for a specific element without having to do it for all of its children. Furthermore, I do not understand what you want to achieve with margin: 0 auto on all elements and body. It does not make any sense for me.

Since you do not want to use absolute positioning, I would strongly advise you to avoid using pixels as a measuring unit. They behave badly if some people change their default font-size because of poor eyesight or other reasons. Instead, consider to apply relative units like rem, em or %. By setting the root element's font-size to 62.5% you are still able to calculate as if you were using pixels (1rem = 10px).

As I already mentioned, I avoided to use display: flex for such a trivial thing. I do not understand why it should be used at this point. Therefore, I also had to change the positioning of the menu button. The navigation could be easily positioned using percentages for top and left.

As a side note: You should really try to only post the relevant CSS code - the first step for me was to remove all the irrelevant parts of it.

Final Solution

This is my final solution without Flexbox, without fixed sizes and without absolute positioning using px:

$('.menu-btn').click(function() {
  $('nav').toggleClass('nav-open');
});
* {
  margin: 0;
  padding: 0;
  box-sizing: inherit;
}

html {
  font-size: 62.5%;
}

body {
  font: 1.6rem/1.4 Benton Sans, -apple-system, BlinkMacSystemFont, Roboto, Helvetica Neue, Helvetica, Tahoma, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  box-sizing: border-box;
}

header {
  width: 100%;
  background-color: orange;
  text-align: center;
  padding: 1rem;
  position: relative;
}

nav {
  display: none;
  width: 30rem;
  padding: 5rem;
  background-color: #ededed;
  position: absolute;
  right: 5%;
  top: 100%;
}

.nav-open {
  display: block;
}

nav a {
  display: block;
  width: 100%;
  text-align: center;
  padding: 1.4rem 1.6rem;
  text-decoration: none;
  cursor: pointer;
  font-size: 2.2rem;
  color: #000;
}

nav a:hover {
  background-color: #111;
  color: #fff;
}

.menu-btn {
  position: absolute;
  right: 5%;
  top: 50%;
  margin-top: -1.1rem;
  display: inline-block;
  cursor: pointer;
  border: none;
  outline: none;
  background-color: transparent;
}

@media only screen and (min-width: 500px) {
  .menu-btn, nav {
    display: none !important;
  }
}

.menu-btn span {
  display: block;
  width: 2rem;
  height: 0.2rem;
  margin: 0.4rem 0;
  background: #989da1;
  z-index: 99;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<header>
  <h2>Page Title</h2>
  <button class="menu-btn">
    <span></span>
    <span></span>
    <span></span>
  </button>

  <nav>
    <a href="vote.html">Vote</a>
    <a href="search.html">Search</a>
    <a href="about.html">About</a>
    <a href="login.html">Log In</a>
  </nav>
</header>

Or see this fiddle.

Anonymous
  • 902
  • 10
  • 23