如何使用 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:0right: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 保持为空,它的 width0

现在是动画。我们只需要两个 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%的主要内容,如果未能解决你的问题,请参考以下文章

前端开发常用css动画代码(自己收藏用)

css2D转换(transform)

03-css3D转换

如何在Angular 2中使用ngStyle将transform translate属性应用于元素

CSS 3D:rotateY + translateX 使元素在 Firefox 中闪烁

我如何在第一次迭代(而不是第二次)时反转 CSS3 动画