V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
myCupOfTea
V2EX  ›  程序员

请教一个很怪异的 css3 问题,关于 transform

  •  1
     
  •   myCupOfTea · 2020-06-14 21:55:00 +08:00 · 1744 次点击
    这是一个创建于 1651 天前的主题,其中的信息可能已经有所发展或是发生改变。

    演示如下

    https://codesandbox.io/s/material-progress-scale-qi4zd

    可以点击 refresh 演示

    背景

    最近写上传动画,用了 material-ui 的 progress,后来写上传组件文档的时候,用例里用 requestAnimationFrame 快速刷新进度条,发现进度条虽然 css 属性变了但是没有动

    仔细观察发现了,是 translate 在开了过渡(transition)的情况下高速刷新就不会变化,把过渡关了就可以(当然实际场景中不可能刷新这么快,所以我也不可能关了过渡)

    但是我脑子一抽试试用 scale 加上 transform-origin 来模拟 translate 呢,神奇的事情出现了

    高速刷新状态下,它正常的动了,艹

    问题

    为啥 scale 可以,但是 translate 不可以

    其他问题

    用 setTimeout 模拟的时候发现在 120 左右这个延迟,很容易出现进度条抖动(回弹?),就是偶尔会出现进度条一下回去一点然后又前进呢,有办法解决吗(打印过进度 value 呢,是正常的)

    13 条回复    2020-06-16 00:22:04 +08:00
    myCupOfTea
        1
    myCupOfTea  
    OP
       2020-06-15 08:42:40 +08:00
    好奇,难道没有人遇到过么
    liuhuihao
        2
    liuhuihao  
       2020-06-15 11:37:31 +08:00
    用了 JS requestAnimationFrame 控制进度条进度,为什么还要使用 transition 过渡呢?
    myCupOfTea
        3
    myCupOfTea  
    OP
       2020-06-15 12:21:54 +08:00
    @liuhuihao requestAnimationFrame 是用来 模拟高速刷新下的 upload 的
    myCupOfTea
        4
    myCupOfTea  
    OP
       2020-06-15 12:22:36 +08:00
    @liuhuihao 控制进度条还是用的 transition + (translate/scale/width)
    redbuck
        5
    redbuck  
       2020-06-15 16:20:04 +08:00
    ```html
    <style>
    .progress {
    border: 1px solid #e5e5e5;
    margin: 10px;
    overflow: hidden;
    }

    .inner {
    transition: transform 0.16s ease;
    height: 5px;
    background-color: yellowgreen;
    transform-origin: 0 50%;
    }
    </style>
    <div class="progress translate">
    <div class="inner"></div>
    </div>
    <div class="progress scale">
    <div class="inner"></div>
    </div>
    <script type="text/javascript">
    const sleep = time => new Promise(resolve => setTimeout(resolve, time));
    const frame = () => new Promise(resolve => requestAnimationFrame(resolve)) || sleep(16.7);
    const $ = s => document.querySelector(s);

    let progress = 0;
    const translate = $(".translate .inner");
    const scale = $(".scale .inner");

    function render() {
    translate.style.transform = `translateX(${progress - 100}%)`;
    scale.style.transform = `scaleX(${progress / 100})`;
    }

    async function update() {
    while (progress <= 100) {
    render();
    // await frame()
    await sleep(50);
    progress++;
    }
    }

    update();
    </script>
    ```

    帮你改个简单版的,排除多余变量.

    问题依然存在.

    但如果调整 sleep 的时间,可以发现时间越长,会稍微缓解一点.
    gaoryrt
        6
    gaoryrt  
       2020-06-15 17:49:13 +08:00
    有没有可能是这样的:
    两个 fill 上的 transition 进行的都是 transform 默认值到当前值的补帧,而不是上一个值到当前值的补帧。
    如果 dom 样式的更新时间足够大,transition duration 足够小,你应该能看到每次从头开始到当前值的动画,而非从上一个值到当前值的动画。
    myCupOfTea
        7
    myCupOfTea  
    OP
       2020-06-15 17:59:19 +08:00
    @redbuck 是的,这个问题我和 material-ui 官方讨论了下,这种场景下关闭过渡就行了
    myCupOfTea
        8
    myCupOfTea  
    OP
       2020-06-15 18:00:48 +08:00
    @gaoryrt 嗯,确实刷新时间变慢了就可以呢,
    我又另外试了一个属性 width 控制,translate 控制都不行
    但是我很好奇 scale 也是加了过渡效果的,但是 scale 是可以的
    myCupOfTea
        9
    myCupOfTea  
    OP
       2020-06-15 18:01:30 +08:00
    @redbuck 其实我就是好奇 scale 也是加了过渡效果的,但是 scale 是可以的
    本来这个场景其实基本不会出现来,没有上传会一直刷新这么快的
    myCupOfTea
        10
    myCupOfTea  
    OP
       2020-06-15 18:03:21 +08:00
    另外我测试发现 firefox 对 css var 支持不够好(该测试用例在 firefox 上闪烁的很厉害)
    我把 css var 去了写了另外一个例子,防止有人觉得是 css var 的问题
    https://codesandbox.io/s/material-progress-scale-not-css-var-zw5nt
    myCupOfTea
        11
    myCupOfTea  
    OP
       2020-06-15 18:17:12 +08:00 via Android
    @redbuck
    @gaoryrt 其实这个用例在火狐上是可以的,应该是 chromium 的问题
    gaoryrt
        12
    gaoryrt  
       2020-06-15 18:21:24 +08:00
    那应该是 scale 会有类似于视觉残留的效果?
    或者说是 react 针对 style 里面的 calc 进行了优化导致了问题?
    myCupOfTea
        13
    myCupOfTea  
    OP
       2020-06-16 00:22:04 +08:00 via Android
    @gaoryrt 跟 react 没关系,我仔细观察过了。css 上的属性已经变了,说明已经从虚拟 dom 渲染到真实 dom 呢,上面也有个老哥写了原生的 js,应该就是 chromium 的问题
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2549 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 05:37 · PVG 13:37 · LAX 21:37 · JFK 00:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.