目视向下滑动固定元素,项目对齐 flex-end

Visually slide down fixed element with items aligned at flex-end

我在我的移动网络应用程序中显示一个应用程序 drawer-like component,我在其中使用底部导航图标和 more 打开其他选项。

一些options-drawer事实

  1. 幻灯片 up/down into/out 视图
  2. 具有全屏高度
  3. 垂直对齐底部的项目
  4. 显示 N options/per 行(与每行只有一个选项的附图不同)
  5. 放置在屏幕底部与主底部导航相同的 position: fixed 容器内。

我的选项抽屉的动画应该类似于在这个 iOS 动画 GIF 上看到的那样

https://jsfiddle.net/LL4dst15/

问题

我的抽屉正在使用 flexbox(正如您从示例中看到的那样),它将元素与横轴上的 flex-end 对齐,以便在最底部显示它们。但问题在于固定定位的导航容器,并且 z-index 它始终显示在内容上。

translateY 问题

如果我使用 translateY,抽屉实际上会滑动 in/out,但抽屉元素的位置不会改变,这意味着导航容器仍然具有抽屉 + 底栏的高度。这可以在我左侧的 fiddle 示例中看到,其中灰色元素始终可见。因此,这将覆盖我的实际内容,因此用户将难以与之交互。

不过,我可以使用 pointer-events: none;,但我认为这是一个相当丑陋的 hack,浏览器支持可能存在问题。所以我想避免它。

max-height 问题

如果我使用 max-height 而不是转换,那么导航容器实际上会在抽屉调整大小时调整大小。这种方法的问题是抽屉似乎没有滑动 up/down,而是 folds 作为百叶窗......原因是交叉轴对齐到 flex 端。如果我对齐到 flex start 那么它看起来就像是滑出。

我试图用自动边距解决这个问题,但似乎无法让它工作,所以我会使用 flex start 交叉轴对齐,但使用自动边距将内容推到抽屉底部。运气不好...

你有什么其他建议吗我应该怎么做CSS我的抽屉会滑动,我的容器也会调整大小?

您应该在 .extras class drawer() 之后添加以下代码。

li {
    flex: 1 0 100%;
}

JSFiddle:https://jsfiddle.net/k9apwnsq/2/

我尝试使用 css 动画和关键帧; JS Fiddle

只剩下一个问题:加载页面时代码也会运行。这可以很容易地用一些 jQuery.

来解决

我所做的简短版本:我对 transform: translateY() 进行动画处理以获得您想要的效果,然后在动画的最后 % 中我将您的最大高度设置为:0vh。就我个人而言,我更愿意使用 jQuery 来执行此操作,但您想要一个 css 解决方案,所以就这样吧。

这是代码(css 现在有点混乱,因为所有注释掉的东西,但清理它是你的工作):

html

Click any bottom bar item to toggle options drawer
<nav>
  <ul class="bottom-nav">
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
    <li>Four</li>
  </ul>
  <ul class="extras" label="Uses 'translateY' to slide drawer">
    <li>Option</li>
    <li>Option</li>
    <li>Option</li>
    <li>Option</li>
    <li>Option</li>
    <li>Option</li>
    <li>Option</li>
    <li>Option</li>
    <li>Option</li>
    <li>Option</li>
  </ul>
</nav>
<nav>
  <ul class="bottom-nav">
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
    <li>Four</li>
  </ul>
  <ul class="extras" label="Uses 'max-height' to slide drawer">
    <li>Option</li>
    <li>Option</li>
    <li>Option</li>
    <li>Option</li>
    <li>Option</li>
    <li>Option</li>
    <li>Option</li>
    <li>Option</li>
    <li>Option</li>
    <li>Option</li>
  </ul>
</nav>

css

html, body {
  background-color: #fff;
  line-height: 1.25rem;
  margin: 0;
}
nav {
  position: fixed;
  bottom: 20px;
  left: 10px;
  width: 300px;
  display: flex;
  flex-direction: column;
  background-color: #eee;
  border: 1px solid #fcc;

  ul {
    list-style: none;
    margin: 0;
    padding: 0;
    li {
      margin: 0;
      padding: 0;
    }
  }

  @mixin drawer() {
    width: 100%;
    display: flex;
    flex-flow: row wrap;
    align-content: flex-end;
    align-items: flex-start;
    cursor: default;
    background-color: #fff;
    box-shadow: 0 0 10px #999;
    overflow: hidden;
    &:before {
      content: attr(label);
      position: absolute;
      margin: 5px 0 0 10px;
      color: #999;
      font-size: 0.8125rem;
      font-style: italic;
    }
    li {
      flex-basis: 25%;
      text-align: center;
      padding: 1rem 0;
      &:hover {
        background-color: #f4f4f4;
      }
    }    
  }

  .bottom-nav {
    @include drawer();
    order: 1;
    z-index: 1;
  }

  .extras {
    @include drawer();
    order 0;
    z-index: 0;
    /* 100vh   = full height
     * 3.25rem = bottom nav bar (2×1rem padding + 1.25 line height)
     * 1.25rem = top text line height
     * 20px    = navigation fixed position bottom offset
     * 2px     = navigation container top and bottom border
     */
    height: calc(100vh - 3.25rem - 1.25rem - 20px - 2px);
    /*transform: translateY(100%);*/
    /*transition: transform 1s, opacity 0.5s;*/
    animation: closedrawer 10s forwards;
  }
  &.open {
    .extras {
      /*opacity: 1;*/
      animation: opendrawer 10s 1 forwards;
      /*transform: none;*/
      /*transition: transform 1s, opacity 0.5s 0.25s;*/
    }
  }

  + nav {
    left: 320px;

    .extras {
      /*transform: none;
      max-height: 0;
      transition: max-height 1s, opacity 0.5s 0.25s;*/
    }

    &.open {
      .extras {
        /*max-height: 100vh;
        transition: max-height 1s, opacity 1s;*/
      }
    }
  }
}
@keyframes opendrawer {
    0% {transform: translateY(100%); opacity: 1;}
    99% {background-color: blue; transform: translateY(0%); max-height: 100vh;}
    100% {background-color: blue; transform: translateY(0%);max-height: 100vh;opacity:1;}
}
@keyframes closedrawer {
  0%{transform: translateY(0%)}
   99% {background-color: red; transform: translateY(100%);max-height: 100vh; opacity: 1;}
    100% {background-color: red; transform: translateY(100%); max-height: 0vh; opacity: 0;}
}

javscript

$(function(){
    $(".bottom-nav li").click(function(evt){
    evt.preventDefault();
$(this).closest("nav").toggleClass("open");
  })
})

translateY 和延迟 max-height

的解决方案

使用动画的缺点是加载时会出现滑出动画,这应该由 javascript 单独处理,我不喜欢。使用 translateY 滑出的解决方案是在 transform 完成后也调整它的大小。之后的最大高度过渡可以没有动画,只要完成就可以了。

所以滑出而不只是做

transition: transform $duration; // plus opacity of you want

一个应该做的

transition: transform $duration, max-height 0s $duration;

这将正常完成 Y 平移,然后还将元素的高度更改为 0,这将相应地调整容器的大小,这首先是问题所在。请注意,max-height 的立即转换具有时间维度 0s 而不是简单的 0,后者会被浏览器忽略。

如果动画足够长,用户可以在进行 Y 翻译时开始单击内容,也可以将 pointer-events: none; 设置为容器,但不要忘记将其设置为 auto元素,因为这个 属性 是继承的。

这将是问题的可选解决方案。

这是实现了上限的resulting JSFiddle