likes
comments
collection
share

一次 CSS 动画异常的分析

作者站长头像
站长
· 阅读数 53

发现问题

偶然发现一个问题,就好奇看了下,没看懂。这个需求已经上线,目前线上表现正常。所以就更加的好奇和莫名其妙。

一次 CSS 动画异常的分析

具体问题是:页面中有动画,动画大概是:

animation: moveRight 1s ease-out forwards;
@keyframes moveRight {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(100px, 0, 0);
  }
}

动画 keyframes 有多个,根据数据的不同,来进行相应的位移动画。

但是动画突然位置不对。因为是开发环境,于是我首先检查了一下数据,数据果然不对。不过和动画相关的数据似乎没问题,也就是元素的 class 是没错的。

最简试验

因为对动画也不是很精通,所以实在有点怀疑自己写的动画并不是最合理的,然后在某种情况(比如数据或者兼容)下就出现问题了。于是在项目之外又尝试写了一个简版的动画效果。

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>transition</title>
  <style>
    * {
      margin: 0;
      padding: 0;
      list-style: none;
    }
    body {
      position: relative;
      margin: 20px;
    }
    .list {
      border: 1px solid #ccc;
      height: 240px;
      clear: both;
    }
    .item {
      float: left;
      border: 1px solid red;
      box-sizing: border-box;
      margin: 0 -26px;
      width: 332px;
      height: 240px;
      line-height: 100px;
      text-align: center;
    }
    .star {
      position: absolute;
      left: 0;
      top: 240px;
      width: 100px;
      height: 100px;
      border: 1px solid red;
    }
    .star-1 {
      left: 0;
      top: 240px;
      animation: moveRight1 1s ease-out forwards;
    }
    .star-2 {
      left: 100px;
      top: 340px;
      animation: moveRight2 1s ease-out forwards;
    }
    @keyframes moveRight1 {
      from {
        transform: translate3d(0, 0, 0);
      }
      to {
        transform: translate3d(100px, 0, 0);
      }
    }
    @keyframes moveRight2 {
      from {
        transform: translate3d(100px, 0, 0);
      }
      to {
        transform: translate3d(280px, 0, 0);
      }
    }
  </style>
</head>
<body>
  <ul class="list">
    <li class="item item1">box1</li>
    <li class="item item2">box2</li>
    <li class="item item3">box3</li>
    <li class="item item4">box4</li>
    <li class="item item5">box5</li>
  </ul>
  <div class="star"></div>
</body>
</html>

结果一切正常,看起来动画没问题。

animate.css 冲突?

后来突然想起来,最近项目中同事新增了 animate.css,是不是冲突导致的?因为是突然出现的问题,所以应该是页面本身不需要修改才对;问题是有其他的地方关联导致的。很有可能是类名的冲突。

于是删除了 main.ts 引入的 animate CSS 文件,但是问题依然存在。难道是还有其他的影响,卸载依赖,依然不行。

尝试删除依赖缓存,重新 install,依然不行。

再次分析问题

问题是动画的 translate3D 偏移不对,如果我修改它能不能生效呢。

换成 translateX,无效。

修改偏移量能够生效,但是问题是为什么突然不对呢,想要改成正确的偏移量,这个修改也没有规律。

和之前对比以及依赖缓存?

但是既然之前的版本有正确的,切换到之前的版本再次查看效果,是可以的,但是这里要清除依赖缓存,重新安装依赖。

想到之前因为 package lock 文件冲突,进行了一次删除锁文件。以及对 Vite 的升级,清除依赖的缓存操作。这些操作之后,项目的依赖其实进行了一次全面的升级。

然后果然发现一个插件的版本变化:

"postcss-px-to-viewport-8-plugin": "^1.2.2",
1.2.2 -> 1.2.5

版本由 1.2.2 变成了 1.2.5

解决问题

发现版本变化,尝试恢复版本,果然就修复了问题。

也立即明白了问题所在,由于项目中使用 pxtoviewport 进行单位转换进行适配,而插件在升级后,由于某种原因,动画的单位未能进行转换。

探迹根源

但是源码的更新,到底哪里影响了?

1.2.5 的提交 github.com/lkxian888/p… 似乎只是一些格式化的修改,无关紧要

1.2.3 的更新: github.com/lkxian888/p… 看起来是关于 mediaQuery 的修改。好像也没关系。

而且看 github.com/lkxian888/p… 1.2.3 是正常的,说明只是 1.2.5 的修改导致的。

但实在未看出问题。

看原始仓库,也找到了类似的问题: github.com/evrone/post…

所以不是版本的问题,而是配置的问题。

postcss 插件原理

开始看 postcss-px-to-viewport-8-plugin 的源码实现,其实是根据 postcss-px-to-viewport 进行修改的,对于它解决的问题,我们都很熟悉。

PostCSS 用于转换 CSS 代码。它本身并不会对 CSS 做任何处理,而是通过插件来实现各种功能,比如自动添加浏览器前缀、转换单位、优化代码等。postcss-px-to-viewport 插件的作用是将 CSS 中的 px 单位转换为 vw(视口宽度单位)或其他指定单位。

PostCSS 的原理:

  • 加载配置:PostCSS 读取插件配置,并加载其中配置的插件和选项。
  • 解析 CSS:PostCSS 解析输入的 CSS 文件,生成一棵 AST。
  • 调用插件:PostCSS 按顺序调用每个插件,对 AST 进行处理。postcss-px-to-viewport 插件会遍历所有的规则和声明,找到并转换符合条件的 px 单位。
  • 生成 CSS:PostCSS 将处理后的 AST 转换回 CSS 代码。

插件的关键步骤:

  • css.walkRules:遍历 CSS 规则。
  • rule.walkDecls:遍历每个规则中的声明。
  • validateParams:检查规则的父节点参数,确定是否处理该规则。
  • createPxReplace:创建用于替换 px 单位的函数。
  • decl.value.replace:执行单位转换。

其中 validateParams 就是和 配置项 mediaQuery 相关,插件根据 medieQuery 的配置决定对 CSS 进行单位转换,其中的条件是 rule.parent.params,就是规则存在 parent 的情况。

这里配置项虽然叫 mediaQuery,但是 @keyframes 的规则也一样受影响。而且默认值为 false,也就是默认不会进行转换。

mediaQuery 是否合理?

根据以上分析,为什么更新导致问题之所以不好排查,在于参数的误导性。当然也是因为对 PostCSS 的原理不了解,不然大概也能猜到。

我们知道 atrule 还有很多类型,所以是否能增加配置参数 keyframes?这样可以对 keyframes 单独控制。代码修改添加中。

总结

开发中,对于前端依赖的处理一定要小心,可以关注以下几点:

  • 依赖锁文件的冲突处理
  • 依赖缓存的问题
  • 每一次的依赖升级要小心
  • 关注依赖的版本变化
  • 尝试回退版本
  • 查看版本的更新内容

对于问题,也不要满足于解决,要搞清楚问题的根源,直到自己满意为止,这样既能提高自己的能力,也能真正的避免类似的问题。

而问题永远不会突然出现,做好自测,一定跟最近的变化有关。

参考

转载自:https://juejin.cn/post/7376889083211857961
评论
请登录