目视向下滑动固定元素,项目对齐 flex-end
Visually slide down fixed element with items aligned at flex-end
我在我的移动网络应用程序中显示一个应用程序 drawer-like component,我在其中使用底部导航图标和 more 打开其他选项。
一些options-drawer事实
- 幻灯片 up/down into/out 视图
- 具有全屏高度
- 垂直对齐底部的项目
- 显示 N options/per 行(与每行只有一个选项的附图不同)
- 放置在屏幕底部与主底部导航相同的
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。
我在我的移动网络应用程序中显示一个应用程序 drawer-like component,我在其中使用底部导航图标和 more 打开其他选项。
一些options-drawer事实
- 幻灯片 up/down into/out 视图
- 具有全屏高度
- 垂直对齐底部的项目
- 显示 N options/per 行(与每行只有一个选项的附图不同)
- 放置在屏幕底部与主底部导航相同的
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。