文字溢出省略和用户体验优化

Posted 恪愚

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文字溢出省略和用户体验优化相关的知识,希望对你有一定的参考价值。

这是我又一次探究文字溢出相关问题,也是我在用户体验道路上踏出的又一小步。

之前提到“文字溢出”瞬间就能想到 ellipsis。再接触的多了一点会同时想到 display: -webkit-box;(多行溢出)。
你一定欣喜若狂,认为掌握了“宇宙之玄妙”,拥有了“制胜之法宝”。但是如果你就此而去,你仍会时不时的发出疑问:“为什么我的溢出省略没有生效?”

先说,目前已知的所有相关问题最终都可以归结为一个点上:行内样式与块级样式
包括一个很可惜的、似乎还没有文章给出具体说明的一个问题 —— flex

flex与行内元素

你可能会疑惑,那是因为你只停留在“用”的阶段。
事实上,早在某一篇文章中笔者就发表过观点:flex会将元素变为既具有行内某些特点又具有行内块部分特性的样式结构。这一点很关键 —— 可以结合position等属性做出意想不到的效果。

笔者后面写过很多“详解”,但再看下来竟都不如这个当初随手画下的说明更清晰。按图中说明稍加思考或实践一下你也会恍然大悟。

flex与文字溢出

在我司的一个项目中有这样一个场景(代码来源于真实场景和研究,已做脱敏):
商家侧某活动已选商品展示如果只有一个商品后面的文字要限制在一定区域,溢出省略效果 ——

但笔者接手初期是这样的:

的确,多行展示确实能带给用户比单行展示更多的体验感,但上一个前辈用了这个东西: display: -webkit-box;!webkit前缀!所以在文字极多且非webkit的浏览器中是这样的:

当然这种场景几乎是很少见的,所以以至于一直保持这样;又当然可以用伪元素伪造“…”去解决,但是效果太生硬。一般不会直接去使用而是优先考虑其它方案(产品的胜利😏)。

现在问题来了,这是一个flex布局模型,基础结构如下:

<!-- 当展示只有一个时 -->
<div class="cisi__list list-single" v-if="total === 1" @click="xxx">
    <div class="cisi__img">
        <img :src="flist[0].imgHead | formatPicSelf(100)" v-img-error-item-self>
            <!-- 提示图标 -->
            <span class="pie__item-tag" v-if="flist[0].statusError">{{flist[0].statusError}}</span>
    </div>
    <div class="cisi__text-line"><span>{{flist[0].itemName}}</span></div>
</div>

其主要的css结构如下:

/** 最外面的父元素规定了大体样式和宽高,然后 **/
.cisi__list {
    margin-top: 8px;
    height: 64px;

    display: flex;
    align-items: center;
    cursor: pointer;
}
/** ... **/
.cisi__text-line {
    flex: auto;
    font-family: PingFangSC-Regular;
    font-size: 14px;
    color: #000000;
    letter-spacing: 0;
    line-height: 22px;
    & span {
    	white-space: nowrap;
    	overflow: hidden;
    	text-overflow: ellipsis;
    }
}

溢出省略竟然失效!怎么回事?

要理解省略效果为什么没出现,需要搞清楚这里的尺寸计算规则 —— 最终尺寸、最大最小尺寸。这里cisi__text-line类名的 div 属于 flex 子项,它的最终尺寸由基础尺寸、弹性增长或收缩、以及最小最大尺寸决定!
在这个例子中,出现了几个情况:

  1. width 属性和 flex-basis 属性都没有设置,因此基础尺寸就是内容尺寸,内容尺寸是最大内容宽度,也就是 div 里面内容在一行显示的宽度;
  2. flex-shrink 属性值是 1(因为默认值是1),内容超出了,因此弹性收缩是执行了的(flex-grow默认是0不会随内容拉伸,父元素设置了宽度整体的宽度无法超过某个值但 span 元素不受限超出了这时外面的 div 就像失去了对子元素的掌控一样)。

但理论上讲如果弹性收缩执行了应该是出现省略效果的。那问题只能出现这个对子元素失去掌控的 div 上了:

  1. 因为有关宽度的属性都没有设置,因此最小尺寸就是最小内容宽度。就是这里出了问题:如果 div 里面的 span 元素没有设置white-space: nowrap;,那么最小宽度就是1em,即一个中文字符的宽度(因为每个中文字符都是换行点),弹性收缩可以顺利执行。但是这里设置了white-space属性,此时的 span 元素就像一个不会换行的连续英文单词,于是 div 元素的最小尺寸就变成了 span 元素内容在一行中显示的宽度,和上面的“基本尺寸”一样!

由于最终尺寸计算时的优先级是最小尺寸 > 弹性收缩 > 基本尺寸,而最小尺寸和基本尺寸是相等的,所以弹性收缩无效,最终尺寸就是内容宽度。而单行溢出省略的效果需要内容宽度大于容器宽度,所以没有显示出来。

所以要想得到正确的效果,我们可以这么做:
给子元素设置比文字内容宽度小的一个宽度值,或是给父元素(比如这里 span 上的 div)设置一个非常非常小的最小尺寸,使得弹性模型可以正常收缩(使子元素无论如何大于父元素尺寸)

.cisi__text-line {
    /**...**/
    min-width: 0;

    /**...**/    
}

或者:

.cisi__text-line {
    /**...**/
    overflow: hidden;

    /**...**/    
}

但是需要注意:设置 overflow 会影响flex-basis或有position属性的布局!

不知道你是否注意过控制台查看器中的这个部分:

这是上面错误显示时的样子。而在我们做出改变后是这样的:

和行内元素有什么关系?

上面的最终效果是这样的:

注意:此时并没有省略号效果的出现,而且只有在overflow下才会出现“溢出隐藏”,设置min-width并没有什么作用!

这时去掉white-space 属性是这样展示的:

看到了吗?span 是行内元素,一般单独修饰文字。行内元素的标志就是“只作用于元素本身”,而块级元素通常会将元素所在区域当做一个整体!
溢出省略效果是针对一个“区域”来说的,你可以理解为“它实际上并不修改元素本身”。

所以这里需要将 span 改为 p 元素,就能正确呈现效果了!

由此引出的体验优化思考

就像案例开头说的一样,多行显示的效果一定要比单行显示的好,哪怕你有一些花里胡哨的搭配。但这里多行溢出的属性兼容性并不好。
这是一个抉择,兼容性与一定程度上的用户视觉体验相比。
你可以选择使用单行省略,或是尽可能地优化“用兼容的属性模拟未兼容属性”的美观程度。或是在源头处 —— 设置时限制活动/商品名称的长度,当然,这个也必然是牺牲了 yi 点点用户体验的。

在这个项目的列表页,笔者采用了另一种方法:

列表项是以行为维度的,通过增加行高去解决文字溢出后看不见的效果 —— 也就是强制换行。flex中应该是默认这样的~
否则,会出现什么效果呢?这就要和flex本身的“缺陷”挂🪝了…

and 顺便提一下,你觉得下面的三种实现在它们所在的场景中,哪种更合适呢?


相关链接:

  1. 小Tip:关于单行/多行文本溢出隐藏的一些看法
  2. 一种离谱到极致的页面侧边栏效果探究

以上是关于文字溢出省略和用户体验优化的主要内容,如果未能解决你的问题,请参考以下文章

用户体验思考与flex三坑:元素不均分溢出不省略和垂直不滚动

div内多行文字, 溢出部分用省略号显示

单行和多行文字溢出省略

CSS 文字溢出处添加省略号

多行文字内容溢出显示点点点(...)省略号

CSS杂记:文字溢出时显示省略号的样式效果