11

Preface

I'm trying to create a responsive website with a navigation menu that satisfies the following two requirements:

  1. Navigation is fully visible in a normal browser window, laid out horizontally.
  2. Navigation becomes a toggleable vertical menu for mobile devices and small screens, which animates between its "opened" and "closed" state.

I want performance to be good on mobile devices — especially on iOS — which means that the animation should use a GPU-accelerated translate3d transform CSS transition.

My Problem

Setting this up was a piece of cake, and for the most part it works great. I used z-index: 1 and transform: translate3d(0,-100%,0) to hide the menu behind a header with z-index: 2 in its default closed state, and then transform: translate3d(0,0,0) to animate the menu to its opened state.

But I'm just having one problem: When I resize my Chrome browser window and the mobile media query kicks in, the menu animates from an opened to closed state.

Resize your browser window to less than 600px wide to see the problem in action:

I think I know why this is happening: when the mobile media query kicks in, the browser sees that .nav is not currently active, so it animates it to the default closed state. I've tried experimenting with using display:none and display:block for the different media query states, but that seems to completely break the animation.

How can I prevent the nav menu's "closing" animation from firing as the browser window is resized?

4

3 回答 3

12

干得好,很干净。我可以偷吗?:-)

无论如何,这是您的演示解决方案。

我只是将过渡转移到另一个班级:

.nav {
    /* stuff */
    z-index: 1;
    transform: translate3d(0,-100%,0);
    -webkit-transform: translate3d(0,-100%,0);
}
.nav.active {
    transform: translate3d(0,0,0);
    -webkit-transform: translate3d(0,0,0);
}
.nav.activated {
    transition: transform 400ms linear;
    -webkit-transition: -webkit-transform 400ms linear;
}

您可以在第一次“切换”时将其添加到元素中:

function toggle(){
    $(".nav").addClass("activated").toggleClass("active");
}

PS如果您不希望在用户打开菜单然后再次调整窗口大小后发生转换,您可以使用 Modernizr 的mq方法

$(window).on('resize',function(){
    if(Modernizr.mq('(min-width:600px)')) $(".nav").removeClass("activated");
});
于 2013-05-20T17:08:49.353 回答
3

提到 Giona 提到的副作用:

PS 如果您不希望即使在用户打开菜单然后再次调整窗口大小后也发生转换(...)

有一种更简洁的方法可以解决此问题,而无需在每次调整大小事件时触发。您可以在转换结束后删除负责转换的类(此处为完整演示):

$(function()
  {
    $(".nav").on("transitionend", function() {
        $(this).removeClass("activated");
    });
  }
)();
于 2015-01-20T22:32:03.973 回答
1

通过结合GionaJanusz Kacalak的答案(以及 Justin Bull 的评论),我们可以进一步优化代码,以便导航栏永远不会从打开状态变为关闭状态(不仅仅是第一次,这是 Giona 的代码所做的) .

function toggle() {
  var navbar = $(".nav");
  if (navbar.hasClass("active")) {
    // Closing the nav bar.
    navbar.removeClass("active");
    // Listening for a transition.
    // Use `.one` here because we only want this to be called once.
    navbar.one(whichTransitionEvent(), function() {
      // Remove animation property after the nav bar is closed.
      navbar.removeClass("activated");
    });
  } else {
    // Opening the nav bar.
    navbar.addClass("activated").addClass("active");
  }
}

// Ref: https://davidwalsh.name/css-animation-callback
function whichTransitionEvent() {
  var t;
  var el = document.createElement('fakeelement');
  var transitions = {
    'transition': 'transitionend',
    'OTransition': 'oTransitionEnd',
    'MozTransition': 'transitionend',
    'WebkitTransition': 'webkitTransitionEnd'
  };

  for (t in transitions) {
    if (el.style[t] !== undefined) {
      return transitions[t];
    }
  }
}
body { margin: 0; }
.toggle { display: none; }
.nav { list-style-type: none; margin: 0; padding: 0; }
.nav li { float: left; margin: 0; padding: 20px; background: #fdd; }
.nav li:nth-child(2n) { background: #dfd; }

@media only screen and (max-width: 599px)
{
    .toggle {
        display: block;
        position: relative;
        z-index: 2;
        padding: 20px;
        background: #eee;
    }
    .nav li {
        display: block;
        float: none;
    }
    .nav {
        display: block;
        position: relative;
        z-index: 1;
        transform: translate3d(0,-100%,0);
		-webkit-transform: translate3d(0,-100%,0);
    }
    .nav.active {
        transform: translate3d(0,0,0);
		-webkit-transform: translate3d(0,0,0);
    }
    .nav.activated {
        transition: transform 400ms linear;
		-webkit-transition: -webkit-transform 400ms linear;
    }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<a href="#" class="toggle" onclick="javascript:toggle();return false;">Toggle menu</a>
<ul class="nav">
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
    <li>Four</li>
    <li>Five</li>
</ul>

于 2018-12-31T01:38:26.710 回答