如何使用 transform:translateX 在父元素上水平移动子元素 100%
Posted
技术标签:
【中文标题】如何使用 transform:translateX 在父元素上水平移动子元素 100%【英文标题】:How to use transform:translateX to move a child element horizontally 100% across the parent 【发布时间】:2014-02-28 17:12:15 【问题描述】:全部,
我希望能够使用 translateX
为子元素设置 100% 跨父元素的动画(即从左边缘到右边缘)。
挑战在于translateX
中的百分比指的是元素本身,而不是父元素。
例如,如果我的 html 看起来像这样:
<div id="parent">
<div id="child">
</div>
我的 CSS 是这样的(省略了供应商前缀):
#parent
position: relative;
width: 300px;
height: 100px;
background-color: black;
#child
position: absolute;
width: 20px;
height: 100px;
background-color:red;
transform: translateX(100%);
这不起作用 - 孩子只移动 20 像素(自身的 100%),而不是一直移动到父母身上。 (你可以在jsfiddle看到这个):
我可以这样做:
#child
position: absolute;
width: 20px;
height: 100px;
background-color:red;
-webkit-transform: translateX(300px) translateX(-100%);
transform: translateX(300px) translateX(-100%);
这行得通(见here again on jsfiddle),因为它首先将孩子移动300px(父母的全宽),减去20px(孩子的宽度)。但是,这取决于具有固定的已知像素尺寸的父级。
但是,在我的响应式设计中 - 我不知道父级的宽度,它会改变。
我知道我可以使用left:0
和right:0
,但是left/right的动画性能比translateX差很多(Thanks Paul Irish!)。
有没有办法做到这一点?
提前致谢。
【问题讨论】:
我能想到的唯一方法是在孩子周围有一个包装器,宽度 = 100%,并为它而不是孩子设置动画 @vals 动画width
可能会遇到与动画left
相同的性能缺陷,不是吗?
@MurraySmith 正确,margin/width/left 不是 GPU 加速的,会影响性能。进行转换。
【参考方案1】:
我最初并没有发布我的想法,因为它涉及创建一个额外的 HTML 层,并且预计会有更好的解决方案。
既然那还没有发生,我解释一下我的评论。我的意思是:
#parent
position: relative;
width: 300px;
height: 100px;
background-color: black;
#wrapper
position: absolute;
width: 100%;
height: 100px;
border: solid 1px green;
transition: all 1s;
#wrapper:hover
-webkit-transform: translateX(100%);
transform: translateX(100%);
#child
position: absolute;
width: 20px;
height: 100px;
background-color:red;
#wrapper:hover #child
-webkit-transform: translateX(-100%);
transform: translateX(-100%);
由于包装器是父级的 100% 宽度,因此 100% 翻译它可以按预期工作。
fiddle
请注意,正如您所说,包装器正在 100% 翻译。但是,似乎您真正想要的是将元素移动 100% - 宽度。要实现这一点,您还必须将子项也向相反方向平移 100%(现在这适用于子项宽度)。
更正:孩子应该共享包装器的过渡属性:
#parent
position: relative;
width: 300px;
height: 100px;
background-color: black;
#wrapper
position: absolute;
width: 100%;
height: 100px;
border: solid 1px green;
transition: all 5s;
#wrapper:hover
transform: translateX(100%);
#child
position: absolute;
width: 50px;
height: 100px;
background-color:red;
transition: inherit;
#wrapper:hover #child
transform: translateX(-100%);
<div id="parent">
<div id="wrapper">
<div id="child"></div>
</div>
</div>
【讨论】:
Vals - 这是一个真的聪明的解决方案。我在孩子身上添加了一个过渡,所以当包装器向右 100% 时,孩子已经向左移动了 100%。 (见这里:jsfiddle.net/Nprs7/1)。它完美地工作。谢谢! 很好的解决方案!但是为了避免在过渡开始时尴尬地移出父级,您可能希望为子级过渡添加延迟,以便始终在父级内。 @gigaDIE 好点,我在原始答案中没有注意到这个问题。解决了让子继承transition属性(见sn-p) 很好,但仍然有一个错误,动画在#child
悬停时挂起。您需要在#parent
上指定:hover
以避免所有问题:jsfiddle.net/Nprs7/65
我喜欢这个提示【参考方案2】:
使用 Flexbox 有一个非常酷的解决方案。关键是利用 flex-grow 属性。
假设你有一些看起来像这样的 HTML:
<div class="flex-container">
<div class="flex-spacer"></div>
<div class="slider"></div>
</div>
首先,为 .flex-container 赋予基本的 display: flex 属性,并将其 flex-direction 设置为 row。将子元素的定位设置为 relative,因此它们将在 .flex-container 中彼此相邻。
默认情况下,flex-grow属性设置为0,这正是我们一开始想要的。这意味着 .flex-spacer 和 .slider 将只有它们的正常尺寸开始。我们只是将 .flex-spacer 保持为空,它的 width 为 0。
现在是动画。我们只需要两个 CSS 规则就可以让它工作:在 .flex-spacer 中添加一个 transition 并将 flex-grow 设置为 .flex 上的 1 -在某些事件中的间隔。第二条规则将 .flex-container 内所有未使用的 width 赋予 .flex-spacer 的 width,而第一条规则动画化了宽度的变化。 .slider 元素被推到 .flex-container 的边缘。
CSS 看起来像这样 - 我在 .flex-spacer 中添加了一个背景以使其存在更加明显,并将 flex-grow 设置为 1用户将鼠标悬停在 .flex-container 上:
body *
box-sizing: border-box;
.flex-container
cursor: pointer;
display: flex;
flex-flow: row nowrap;
width: 100%;
border: 2px solid #444;
border-radius: 3px;
.flex-spacer,
.slider
flex-grow: 0;
position: relative;
.slider
padding: 25px;
background-color: #0DD;
.flex-spacer
background-color: #DDD;
transition: all .4s ease-out;
.flex-container:hover .flex-spacer
flex-grow: 1;
<div class="flex-container">
<div class="flex-spacer"></div>
<div class="slider"></div>
</div>
Flexbox 也使这变得非常可配置。例如,假设我们希望 .slider 改为从右向左移动。我们所要做的就是将 .flex-container 中的 flex-direction 属性切换为 row-reverse,我们就完成了!
请随意在pen 中使用它。
请记住,如果我们想要为不同类型的事件制作动画,事情可能会变得有点棘手。例如,当用户在输入元素中键入内容时,我尝试为标签设置动画时遇到了这个问题。需要更多的 HTML 和 CSS 才能使其工作(我也使用了一些 JS),但概念是相同的。
这是另一个pen,这次是在带有输入的表单的上下文中。
【讨论】:
这样做的问题是它会触发油漆闪烁,所以它不是很流畅/高效。 遗憾的是,这在 IE11 上不起作用,因为 IE11 显然不能为 flex-grow 设置动画。 滑块宽度可变时的良好解决方案,例如自定义文本。以上是关于如何使用 transform:translateX 在父元素上水平移动子元素 100%的主要内容,如果未能解决你的问题,请参考以下文章
如何在Angular 2中使用ngStyle将transform translate属性应用于元素