1

I'm trying to create a full screen menu that does a bottom-to-top movement and I'm having trouble when it comes to vertically centering it.

Basically, it comes out of the screen and should end up right in the middle of it (centered).

However, since it is a fixed menu with an unknown height and I'm using animations, the options available aren't many:

  • I can't use the margin: auto technique because the auto value doesn't work with transitions;
  • I'm trying to avoid using flexbox;
  • translateY() seems to work fine but it creates a top-to-bottom movement instead of the desired bottom-to-top one (see my code)
  • anything else? (preferably that works with older browsers, but I can also manage with using translateY if there's a way to change the direction)

$('#small-nav-btn').click(function() {
  $('#overlay').addClass('open');
  $('#close-menu-cross').addClass('open');
  $('#nav').addClass('open');
})

$('#cross').click(function() {
  $('#overlay').removeClass('open');
  $('#close-menu-cross').removeClass('open');
  $('#nav').removeClass('open');
})
* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  font-family: "Now-Regular", sans-serif;
  font-size: 12px;
  font-weight: bold;
}
ul {
  list-style-type: none;
}
a {
  color: black;
}
#overlay {
  background: #fff;
  opacity: 0;
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 0;
  transition: all 1s ease 0s;
  z-index: 1555;
}
#overlay.open {
  opacity: 1;
  height: 100%;
}
#small-nav-bar {
  display: block;
  width: 80%;
  margin: 0 auto;
  text-align: center;
  color: black;
}
#small-nav-btn {
  cursor: pointer;
}
#nav {
  background: orange;
  position: fixed;
  top: -100%;  /*I need it to be bottom: -100% for the bottom-top movement*/
  left: 50%;
  transform: translate(-50%, -50%);
  transition: all 0.8s linear 0.1s;
  z-index: 1556;
}
#nav.open {
  top: 50%; /*Again, I need this to be bottom: 50%*/
}
#close-menu-cross.open {
  display: block;
  position: fixed;
  top: 15px;
  right: 20px;
  z-index: 1556;
  cursor: pointer;
}
#close-menu-cross {
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav id="nav-container">
  <div id="small-nav-bar">
    <div id="small-nav-btn">BUTTON</div>
  </div>

  <ul id="nav">
    <li><a href="contact.html"><span>HELLO</span></a>
    </li>
    <li><a href="about.html"><span>HELLO</span></a>
    </li>
  </ul>

  <div id="close-menu-cross">
    <div id="cross">X</div>
  </div>
</nav>

jsfiddle

Thanks in advance! :)

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
Acla
  • 141
  • 3
  • 12

1 Answers1

1

You were quite close. With just a few adjustments in the CSS, you have a full working demo:

$('#small-nav-btn').click(function() {
  $('#overlay').addClass('open');
  $('#close-menu-cross').addClass('open');
  $('#nav').addClass('open');
})

$('#cross').click(function() {
  $('#overlay').removeClass('open');
  $('#close-menu-cross').removeClass('open');
  $('#nav').removeClass('open');
})
#nav {
  background: orange;
  position: fixed;
  top: 100%;                           /* 1 */
  left: 50%;
  transform: translate(-50%, 0);       /* 2 */
  transition: all 0.8s linear 0.1s;
  z-index: 1556;
}
#nav.open {
  top: 50%;
  transform: translate(-50%, -50%);    /* 2 */
}

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  font-family: "Now-Regular", sans-serif;
  font-size: 12px;
  font-weight: bold;
}
ul {
  list-style-type: none;
}
a {
  color: black;
}
#overlay {
  background: #fff;
  opacity: 0;
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 0;
  transition: all 1s ease 0s;
  z-index: 1555;
}
#overlay.open {
  opacity: 1;
  height: 100%;
}
#small-nav-bar {
  display: block;
  width: 80%;
  margin: 0 auto;
  text-align: center;
  color: black;
}
#small-nav-btn {
  cursor: pointer;
}
#close-menu-cross.open {
  display: block;
  position: fixed;
  top: 15px;
  right: 20px;
  z-index: 1556;
  cursor: pointer;
}
#close-menu-cross {
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav id="nav-container">
  <div id="small-nav-bar">
    <div id="small-nav-btn">BUTTON</div></div>
  <ul id="nav">
    <li><a href="contact.html"><span>HELLO</span></a></li>
    <li><a href="about.html"><span>HELLO</span></a></li>
  </ul>
  <div id="close-menu-cross">
    <div id="cross">X</div>
  </div>
</nav>

Notes:

  1. The CSS offset properties (top, bottom, left, right), when applied to absolutely-positioned elements (which includes position: fixed), shift the element x-distance from the respective edge.

    You have top: -100% in your code. This puts the element 100% above the top edge.

    You then have it shifting to top: 50%. This puts the element halfway inside the container.

    Essentially, your animation moves the element a distance of 150%, from above the window to inside it. The movement is top to bottom.

    But you want the movement to go from bottom to top.

    So start the element all the way at the bottom and off-screen (top: 100%), and have it shift up to halfway inside the container (top: 50%).

  2. The transform: translate() rule simply fine-tunes the centering.

    If translateY(-50%) is applied to the primary state (like in your code), it will shift 50% of the nav onto the screen before the transition (demo).

    That's why I applied translateY(-50%) only to the transitioned state.

    For a complete explanation see my answer here: Element will not stay centered, especially when re-sizing screen

jsFiddle

Community
  • 1
  • 1
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • Ahh now I get it! I just realized top: 100% was not the same as bottom: 0 and that's why it works..guess we're always learning. Very well explained! :) – Acla Sep 11 '16 at 21:21
  • 1
    The layout will also work with `bottom: 0`. You just need to reverse some values: https://jsfiddle.net/zvb1La6g/5/ – Michael Benjamin Sep 11 '16 at 21:31