柚木

[多行文本] 样式怎么没了?

背景

- “线上样式有个小问题,有时间帮忙改下”
- “诶,什么情况,订单信息的商品名称不是做了多行文本截取了吗,怎么没效果啦 ...”

是的,线上的多行文字截取没了

技术概况

多行文本... 通常情况下会采用如下方案:

.multi-ellipsis {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}

百试不爽 ...

然后,webpack bundle 配置 :

{
  test: /\.(sass|scss)$/,
  use: ExtractTextPlugin.extract({
    fallback: 'style-loader',
    use: [
      {
        loader: 'css-loader',
        options: {
          minimize: true,
        },
      },
      {
        loader: 'postcss-loader',
        options: {
          sourceMap: true,
          plugins: () => [autoprefixer],
        },
      },
      {
        loader: 'sass-loader',
      },
    ],
  }),
}

其中,postcss-loader 使用了 autoprefixer 插件。

求解过程

1. 查看线上页面元素样式,发现元素下的样式只有:

{
  display: -webkit-box;
  -webkit-line-clamp: 2;
}

2. 拉取最新代码,本地构建,查看本地环境

“诶,我这是好的啊,是不是你电脑有问题啊,要不清个缓存吧,重启也行(:”

@leohxj 登场,用一句话指明了正确的解题思路:

云构建的包依赖是会更新到最新的,你把本地 node_modules 删了重新装一下试试

3. rm -rf node_modules & npm i,然后再看本地环境

“果然如此啊,那就是哪个包升级所导致的了”

4. 首先,怀疑的肯定是 autoprefixer,只有它会做类似的事情,先移除看看 ...

{
  loader: 'postcss-loader',
  options: {
    sourceMap: true,
        plugins: () => [],
    },
}

编译,wtf ... 怎么还是没有?难道还有包也干这种事情啊 ...

5. 中间过程甚是艰辛,暂且不表,反正最后发现了 css loader 的 options 的配置里面其实是可以传 cssnano 的配置参数的

是的,去翻代码的看到了这样的玩意:

如果 css-loader 开启了 minimize, cssnano 的配置参数就可以通过 options 传进来了,比如:

{
  loader: 'css-loader',
  options: {
    minimize: true,
    zindex: true,
  },
}

就可以开启构建中使用 cssnano 做 zindex 的优化了 ...

但是,有没有发现有个货不在里面?是的,autoprefixer 啊!autoprefixer 是默认开启的啊!fuck...

于是,options 中设置 autoprefixer: false构建试试,在了!这次没消失!

敲黑板:css-loader 中使用了 cssnano,v0.26.0 之前的版本中默认开启 autoprefixer. 在 0.26.0 关掉了此配置。因此,如果你代码中有使用到 css-loader 并且无 cssnano 配置参数,建议升级,减少代码执行不确定性。

6. autoprefixer

autoprefixer issue 中,已经有相关的问题了,ai 给了回复:

一直在找构建工具的问题,忽略 CSS 本身是否有问题 ...

7. CSS

我们的 CSS 写法属于 Flexbox 的 old 2009 version, 目前我们常用的 display: flex 属于现代的版本。

问题在于,因为有一定的浏览器支持度,2009 version 的写法似乎已经被大家下意识的“标准”化了,大家都在使用这种方式处理多行文字截取的问题,但是始终都是要被抛弃的...

我们上面遇到的问题就是一种体现,也是一种警醒 ...

如果你不想去改代码,可以指定构建时的浏览器支持度:

autoprefixer({
  browsers: ['> 0.5%', 'last 2 versions']
})

多行文本的正确姿势

使用 weird webkit flexbox 去解决 ... 的问题其实很奇怪,为什么要用 flexbox 去解决这个问题,没想过 ... 而且给元素设置 padding 是会影响的:

without padding

with padding: 10px

那该用什么方法解决呢?

最稳妥的方法应该是 JS 库的介入了,比如:Clamp.js, 体积小且通用;

如果不想用 JS 库的话,我还看到了一种“歪”方法:

.text {
  position: relative;
  height: 3.6em; /* exactly three lines */
}

.text:after {
  content: "";
  text-align: right;
  position: absolute;
  bottom: 0;
  right: 0;
  width: 20%;
  height: 1.2em;
  background: linear-gradient(
    to right,
    rgba(255, 255, 255, 0),
    rgba(255, 255, 255, 1)
    80%
  );
}

定高 n 倍,结尾处放置一个渐变块 ...

当然,也可以:

.text:after {
  content: "...";
  text-align: right;
  position: absolute;
  bottom: 0;
  right: 0;
  height: 1.2em;
  background: #fff;
}

但是这种容易把字截断,不可控 ...

结语

如果你正在寻找方法,实现多行文字截取,可以考虑使用正确的姿势;

如果你已经遇到了上述同样的问题,建议:

  1. 把 css-loader 升级到 0.28 以上版本 ( autoprefixer 默认不开启 );
  2. 把 autoprefixer 升级到 8.0 以上版本,并指定 browsers,通常为: ['> 1%', 'last 2 version']

重要的备注

1. css-loader 在 0.27 后,cssnano 的参数移到了 option.minimize 中,即:

{
    minimize: {
        zindex: true
    }
}

2. autoprefixer 8.0 依赖的 browserslist@3.0.0, 在 browserslist 3.0 版本中,对默认值做了变更:

你也可以使用默认值,但是要去掉 not dead ... 顾名思义,old version supporter 无人权 ...