咦,这个CSS和我想得不大一样啊😵

91 阅读2分钟

场景

上个版本中,H5有个需求,是在某个模块的底部,居中展示提示,类似这种:

screenshot-20250430-164940.png

我一想居中展示,这不是很容易吗,直接写下居中的CSS:

.tip {
    position: absolute;
    left: 50%;
    bottom: 20px;
    transform: translateX(-50%);
    max-width: 220px;
}

由于我们是有多语言的,所以加了个max-width,有些语言翻译完之后通常比较长。

中文下没问题,此时文本还没有翻译好,并且水平居中的代码left:50%;transform: translateX(-50%)公认的好用,自己也写过很多次了,没有问题,完美!

bug

测试阶段的某天,测试给我截了一张图:

screenshot-20250430-165017.png

看起来样式确实有一点点问题,感觉文本并没有很长,不应该折行。

第一反应是max-width给小了,所以产生了折行。直接把max-width改为300px,这下应该够了吧...

结果是啪啪打脸,完全没变。

从图上可以看出来,居中确实居中了,但是这个宽度好像不大对,并没有超过我们所设置的max-width,就出现了折行,难道是word-breakword-wrap(overflow-wrap)white-space之流的问题?

逮着这几个和折行有关的属性试了一通,还是不行。

我想到vant中的toast也是居中提示,就没有这种问题,然后去看了下是怎么写的:

.vant-popup--center {
    position: fixed;
    left: 0;
    right: 0;
    width: fit-content;
    margin: 0 auto;
}

没有使用translate这种,而是用的margin: 0 auto(第一个学的居中就是它了吧,对于block元素来说,这个是最简单的)。

原因

为啥使用left: 50%;transform: translateX(-50%)会有问题呢,来看看DeepSeek是咋说的:

  • 由于 left: 50% 让子元素的起始位置在父元素的中间,而 translateX(-50%) 只是让子元素向左回退自身宽度的一半,因此:

    • 子元素的右边界不能超出父元素的右边界(否则会溢出)。
    • 子元素的最大宽度不能超过父元素宽度的 50% ,否则 translateX(-50%) 会让部分内容超出父元素左侧。

看起来是在不设置具体宽度的情况下,浏览器为了防止子元素宽度超过父元素,一刀切50%。

其他方法

使用width: max-content

.tip {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    width: max-content;
    max-width: 220px;
}

使用flex

.parent {
    display: flex;
    justify-content: center;
}
.child {...}

这种就得多包一层,使用起来不咋方便。