从使用autoprefixer遇到的一个小问题说起

最近一直在写应用里的webview项目,使用webpack打包前端代码时遇到了一个小问题,具体来讲是autoprefixer的问题,记录一下。

遇到的问题是一个样式在页面写好,结果qa打包出的结果里一直没有这个样式,具体情况是这样的:

要实现的和遇到的问题

简单讲就是溢出文本显示省略号,如果是单行文本可以直接使用text-overflow:ellipsis

1
2
3
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;

但是这个属性并不支持多行文本溢出显示省略号,而针对移动端绝大部分是WebKit内核的浏览器,页面实现也比较简单,可以直接使用WebKit的CSS扩展属性(WebKit是私有属性)-webkit-line-clamp ;注意:这是一个 不规范的属性(unsupported WebKit property),它没有出现在 CSS 规范草案中。

-webkit-line-clamp用来限制在一个块元素显示的文本的行数。 为了实现该效果,它需要组合其他的WebKit属性。常见结合属性:

  1. display: -webkit-box; 必须结合的属性 ,将对象作为弹性伸缩盒子模型显示 。
  2. -webkit-box-orient 必须结合的属性 ,设置或检索伸缩盒对象的子元素的排列方式 。
  3. text-overflow: ellipsis;,可以用来多行文本的情况下,用省略号“…”隐藏超出范围的文本 。

所以可以这样写:

1
2
3
4
5
overflow : hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;

但是发现webpack编译以后,-webkit-box-orient: vertical检查元素样式并没有这个属性,其他的几个属性都有,现在只有把这个属性放入内联样式才行。

关于autoprefixer

查了查发现这个样式会被干掉,干掉他的是正是autoprefixer,而干掉的理由也是李菊福的,以下是autoprefixer作者Andrey Sitnik(同时创作了PostCSS)给出的解释:

27F3AD95-3C53-4045-97C9-05B732BC45D5

按照这位大神接下来的说法,最好的解决方法是:

2FA6FCEC-BA24-4B84-A732-50CCE5B10FA2

然鹅我并不想因为一个属性增加太多复杂性,所以找了一种简单的方法hack了这个问题:

1
2
3
4
5
6
/* autoprefixer: off */
/* stylelint-disable */
-webkit-box-orient: vertical;
display: -webkit-box;
/* autoprefixer: on */
/* stylelint-enable */

是的,我直接用注释把autoprefixer关了,然后stylelint又报错,我又不得不把他也关了,大神不太推荐这种做法,不过我感觉还OK,而且挺多人这么搞的🤣。

0A16AE75-137F-4B0C-A0DA-88A496484EDE

疑惑之处

最后在此位置关闭autoprefixer发现确实有效,但是还有个让我困惑的地方,那就是为什么我本地的dev环境没有问题,到了qa就有问题了呢?也就是经过build的代码是有问题的,这显然应该跟qa环境的webpack配置有关,经过对比我把目标锁定在了optimize-css-assets-webpack-plugin这个插件。

查阅 optimize-css-assets-webpack-plugin 文档:

7FF418BC-23E0-4EA1-85D2-98EFCDAE48FC

意思是说,啥都没做,只是把 cssProcessorOptions 的配置传给处理器 cssProcessor ,默认为cssnano来优化css,而cssnano内部自然又调用了autoprefixer

再查阅 cssnano 文档,可以看到,默认情况下,autoprefixer 是不开启的,但是在项目中莫名其妙默认开启了。仔细检查了下,项目中使用的 cssnano 是 3.10.0 版本。也就是说,v3 系列默认都是开启的,文档看的是 v4 的。可以参考这个 issue。如果在参数里面加上 safe/isSafe 字段,也可以解决此问题。

但是,等等。我明明已经加了safe了好吗?所以说不应该啊,难道我误会了这个插件?然后继续看还有哪些包引用了autoprefixer,结果如下:

FD571AC2-EAB0-40DF-9293-F5260F986DA5

看来就是css-loader无疑了,看了下.postcssrc.js确实引用了autoprefixer作为插件,遂删除重新构建,属性正常了,没有被删除,果然是这个浓眉大眼的家伙叛变了革命。但是为什么本地环境没有问题,到了qa就有问题了呢,我试了下把autoprefixerremove属性配置为false,果然没有再删除我的属性了。

D5C61F5C-5C5C-4B1A-9B00-30780D5176A8

我又分别看了下本地和qa环境autoprefixer的版本,发现一致,并且自动添加前缀,兼容浏览器的功能是生效的,但在qa环境build和在本地使用webpack-dev-middleware或build产生的结果就是不同的,我想还是可能跟某个依赖版本有关系吧,于是我生成了shrinkwrap.json,在qa上又了一版,果然跟本地表现一致了,所以还是跟某个依赖的版本有关,具体哪个不细究了,侧面证明了版本锁的重要性,npm 5大法好,问题暂时告一段落。

关于loader和plugin

autoprefixer的作用,官方解释:Parse CSS and add vendor prefixes to CSS rules using values from the Can I Use website,也就是说它是一个自动检测兼容性给各个浏览器加个内核前缀的插件。autoprefixer算是PostCSS的插件,但不是webpack的。

恰逢组里webpack分享,简单学习了一些webpack中lodaer和plugin的知识,对于lodaer和plugin的区别,简单版本:

  • Loader:模块转换器,用于把模块原内容按照需求转换成新内容(例如使用babel-loader将前端js代码从ES6转到ES5)。
  • Plugin:扩展插件,在 Webpack 构建流程中的特定时机会广播出对应的事件,插件可以监听这些事件的发生,在特定时机做对应的事情。

更详细的下次再写。

参考链接

多行文本溢出显示省略号(…)全攻略

https://github.com/postcss/autoprefixer/issues/776

使用 webpack 编译 less 后 z-index 值改变处理