Share sheet

One little button. A little more room to share.

Demo recipients and delivery. Copy link is real.

Behind the motion

让动画连续的三个细节

这次最明显的改善,来自让旧状态的最后一帧,接上新状态的第一帧。下面是这个实验从“有动画”到“顺滑”的三个修正。

Copy:让两层内容交接

直接把 Copy 替换成 Copied,再给新文字加淡入,旧状态会突然消失。这里保留两层内容:Copy 向上离开,✓ Copied 从下方进入,两者在同一个裁切窗口里交接。

按钮固定为 92px 宽,文字轨道固定为 18px 高;变化只发生在内部的 transform 和 opacity 上。文字长短改变时,按钮和旁边的链接都不必重新让位。

查看 Copy 的核心 CSS

简化示意:状态切换时保留旧层,为新旧两层分别加上进入、退出类;退出动画完成后再移除旧层。

.copy-window {
  display: grid;
  height: 18px;
  overflow: hidden;
}
.copy-face { grid-area: 1 / 1; }

.copy-enter {
  animation: enter 340ms
    cubic-bezier(.2, .85, .25, 1.12) both;
}
.copy-leave {
  animation: leave 340ms
    cubic-bezier(.22, 1, .36, 1) both;
}

@keyframes enter {
  from { transform: translateY(110%); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}
@keyframes leave {
  from { transform: translateY(0);     opacity: 1; }
  to   { transform: translateY(-110%); opacity: 0; }
}

实际实现还会从被打断时的可见位置继续退出,并在重复点击时保留当前 Copied 状态。

头像:落点先稳定,飞行层再交接

上一版让收件人标签也从 scale(.85) 放大到 scale(1)。飞行开始时,原本 22px 的目标头像被测成了约 18.7px。飞行层缩到这个尺寸后,突然切回真正的 22px 头像,就出现了肉眼可见的一抖。

修正后,标签只淡入,尺寸始终稳定。头像沿路径连续缩小到准确的落点尺寸,飞行层用 fill: 'forwards' 保持末帧,然后在同一次更新里显示真实头像、移除飞行层。交接前后的位置和尺寸一致,眼睛就不会察觉到“换了一个元素”。

这里的头像飞行使用原生 Web Animations API;Copy 的文字切换使用 CSS keyframes。两者都没有新增动画库。

缓动:最后一点弹性,留给位置

Copy 的进入曲线 cubic-bezier(.2, .85, .25, 1.12) 带一点轻微越过终点的回弹,退出则平稳减速。头像的尺寸变化保持单向,不叠加忽大忽小的弹簧。每一层负责自己的动作,就少了一层互相拉扯。

这次用慢放和放大截图检查了动画中间帧,再回到正常速度验证手感;也保留了减少动态效果的直接切换。只比较起点和终点,很容易漏掉发生在交接那一刻的跳变。