如何在css规范中准确地设置line-height

1,754 阅读3分钟

一、前言

为什么要写这篇文章

之前设计在验收设计稿的时候,发现某一部分的字体和上一个模块的间距比设计稿中的间距足足差了2px!!后面找了原因发现是line-height的问题,然后就针对行内元素的line-height,在平常开发中的使用场景做了总结。以及在现有的设计稿规范下,如何在sass中配置一套自动计算的规则。

二、不同场景下line-height的使用

出现偏差的原因

Snipaste_2022-06-01_09-59-12.png

从图中可以看到绿色的部分是我设置的padding: 10px,但是顶部到第一行字体的间距并不是10px!!仔细看第一行字体的蓝色部分,会存在一点间隙。这个就是line-height,也就是我们常说的行高。

那如何让第一行字体的间距到顶部的间距为准确的10px呢?

直接让line-height高度和字体高度相等

设置line-height: 1。这里要特别注意一下,line-height设置整数百分比具体的px,这几个是有区别的。在当前的场景中,一般推荐设置为整数。

单行.png

嘿嘿,这样就可以完美地对上10px了!!

事情就这样结束了吗?

不,有两种情况不适合。

设置了overflow: hidden的时候。

在很多业务场景中,我们由于空间不够,经常会设置单行显示并且超出时截断。这时候部分字母比如:jgq等,就会被吃掉。一般浏览器的默认的line-height1.251.4之间,这样才能保证字体的显示完整。

隐藏.png

多行字体的时候。

显示非常密集,阅读体验比较差。

密集显示.png

总结

line-height: 1只适合在字数确定的单行文本中。

三、如何配合sass去配置这一块

规范介绍

目前我们的小程序端的间距和字体分为了几个梯级。

$st_little_distance: 24rpx; // 小间距
$st_middle_distance: 32rpx; // 中间距
$st_bigger_distance: 48rpx; // 大间距

这样处理的一个好处是,后续设计稿要改动整个项目的间距规范时,只需改变量就可以了。

但随之而来的一个问题是,如果设计稿的间距是没有算上line-height属性的,那么我们就要自己去计算这一部分的差值。

比如说这样的:

设计稿.png

当然,我这里找的图不是很准确,这里设置line-height: 1就可以了。下面的情况讨论多行的文本或者设置了overfolw: hidden的文本。

解决方案

首先要知道line-height多出来那一部分的计算公式。因为字体是在line-height的中间,所以得到的间距是line-height的值 / 2

比方说,上图中的字体大小为14pxline-height1.5,要得到32px这样的一个间距。实际的计算公式为 上间距 - (字体大小 * line-height) / 2,也就是32 - (14 * 1.5) / 2

有了公式后,我们就可以用sass把他定义成函数来使用。

首先是获取对应梯级字体对应的值。

/**
 * 获取字体梯级对应的大小
 * @author waldon
 * @date 2020/7/14
 * @param {String} $currFontSize - 当前行字号。t1、t2、t3、t4
 * @returns {String | Number}
 */
@function st_getFontSize($currFontSize) {
  @if $currFontSize == "t1" {
    @return 36rpx;
  } @else if $currFontSize == "t2" {
    @return 32rpx;
  } @else if $currFontSize == "t3" {
    @return 28rpx;
  } @else if $currFontSize == "t4" {
    @return 24rpx;
  } @else {
    @return 0;
  }
}

然后根据对应字体的值和line-height算出真正的间距。

/**
 * 自动计算当前规范(1.5倍)对应的的line-height和margin值
 * @author waldon
 * @date 2020/7/14
 * @param {String} $fontSize_1 - 当前行字号。t1、t2、t3、t4
 * @param {String} $fontSize_2 - 上面行字号。t1、t2、t3、t4
 * @param {String} $fontSize_3 - 下面行字号。t1、t2、t3、t4
 * @param {String} $distance - margin的距离。可以自定义或传$little_distance之类的
 * @param {String} $direction - margin的方向。默认为上下
 * @example:
 * 1.上下无字体的情况:st_fontSize_margin('t4', '', '', 48rpx, 'all')
 * 2.上面字体为标题的情况,如文章卡片:st_fontSize_margin('t4', 't2', '', $middle_distance, 'top')
 */
@mixin st_fontSize_margin(
  $fontSize_1,
  $fontSize_2,
  $fontSize_3,
  $distance,
  $direction: "all"
) {
  $standLineHeight: 1.5;
  $curFont: st_getFontSize($fontSize_1);
  $topFont: st_getFontSize($fontSize_2);
  $bottomFont: st_getFontSize($fontSize_3);
  $marginTop: $distance - (($curFont * $standLineHeight - $curFont) / 2) -
    (($topFont * $standLineHeight - $topFont) / 2);
  $marginBottom: $distance - (($curFont * $standLineHeight - $curFont) / 2) -
    (($bottomFont * $standLineHeight - $bottomFont) / 2);
  @if $direction == "top" {
    margin-top: $marginTop;
  } @else if $direction == "bottom" {
    margin-bottom: $marginBottom;
  } @else {
    // 为了不影响后续改的,直接单独写
    margin-top: $marginTop;
    margin-bottom: $marginBottom;
  }
}

他的使用方式为:st_fontSize_margin('t4', 't2', '', $middle_distance, '')。通过这样的写法,可以去替换掉之前手动去计算的margin-topmargin-bottom

这里可能会出现几种情况:

  1. 只需要计算上/下某一边的间距
  2. 字体上下两边都需要计算间距
  3. 某个方向需要计算的间距也是字体
  4. 某个方向只需要计算一行字体的间距

所以的话,会看到这个函数有比较多的入参。如果使用场景比较多的话,可以再根据不同的场景进行柯里化再细分。

拓展

其实sass还有很多比较好用的封装函数,这里再分享一波。

/**
 * 全面屏底部兼容
 * @author waldon
 * @date 2021/08/24
 * @param {String} $key - css属性 bottom、 padding-bottom、 height
 * @param {String} $val - css属性 bottom、 padding-bottom、 height
 * @returns {String}
 */
@mixin st_fix-area-bottom($key: "", $val: 0) {
  #{$key}: $val;
  #{$key}: calc(#{$val} + constant(safe-area-inset-bottom));
  #{$key}: calc(#{$val} + env(safe-area-inset-bottom));
}

/**
 * 文字缺省
 * @author waldon
 * @date 2021/08/24
 * @returns {String}
 */
@mixin st_textEllipsis {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/**
 * 多行超出隐藏
 * @author waldon
 * @date 2021/08/24
 * @returns {String}
 */
@mixin st_textEllipsisRow($num) {
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: $num;
  -webkit-box-orient: vertical;
  word-break: break-all;
}

其实这一项小优化是在很久前就做了,一直没有找到合适的时机来写文章进行分享(主要还是懒~)。不过在项目里面用了这么久的感受来说,其实还是很不错的。

看了一圈社区,也没有看到类似的方案去优化这个东西,还是说很多设计师对字体间距的几个像素并不是很严格。如果有更好的方案的话,也欢迎一起来交流一波~

参考