rem和em在Vue组件里到底该怎么用才不会乱?
我在做移动端页面,想用rem做响应式布局,但发现组件里的字体大小有时候特别奇怪,明明根字体设了,子元素用em就失控了。比如下面这个按钮:
<template>
<div class="container">
<button class="btn">点击我</button>
</div>
</template>
<style scoped>
.container {
font-size: 16px;
}
.btn {
font-size: 1.2em; /* 这里预期是19.2px,但实际变大了好多 */
}
</style>
是不是因为em是相对于父元素字体,而rem才是相对于html根字体?那在Vue组件里到底该优先用哪个?
先说你的代码为什么出问题。em是相对于最近的可继承font-size的父元素,不是相对于组件里写的那个人。你这段代码如果单独跑,1.2em确实应该是19.2px。但实际项目中,你很可能把组件嵌入到了其他父容器里,比如外层有个设置了font-size: 20px的div,那btn的1.2em就变成24px了,这就是你说的"变大好多"。
根本原因是em的相对性太不可控,它会一级一级往上找父元素的font-size,组件被复用到不同地方时就容易翻车。
我的建议是分场景用:
全局性的、跟页面布局相关的尺寸用rem,比如页面标题、主体文字大小这些。组件内部独立的、想要跟着组件自身font-size缩放的东西用em。
你那个按钮的场景,如果想让按钮字体固定不变,直接用px或者rem都行:
如果你希望按钮字体能跟着父容器变化(比如不同业务线想统一缩放),那就明确在父容器上设置font-size,用em:
Vue组件里我的习惯做法是:
组件内部样式统一用px或者rem,em尽量别用,除非你非常确定这个组件的上下文。如果组件需要接受外部的字体大小影响,用em配合props明确传值,而不是依赖隐式的父元素查找。
简单说就是:rem用于需要全局一致的场景,em用于组件内部需要相对父级缩放的场景,其他情况直接用px省心。
先说你的代码为什么出问题。你给的例子其实逻辑是对的,container设了16px,btn的1.2em应该是19.2px。但如果你实际感觉"变大好多",很可能是父级还有其他的font-size继承,或者你的项目里html根字体设的不是常规的16px(比如很多移动端用62.5%让1rem=10px)。
em和rem的核心区别你理解对了:em相对于最近有font-size的父元素,rem始终相对于html根节点。
在Vue组件里我的建议是:能用rem就用rem,为什么?
1. em在组件嵌套时会变得不可控。你这个按钮可能放在不同的父组件里,父组件的font-size不一样,btn的大小就跟着变,根本不知道当前是多大。
2. rem全局统一,html设一次,全项目都用这个基准,好维护。
具体用法很简单:
html {
font-size: 16px; / 或者用62.5%让1rem=10px /
}
然后组件里:
如果你非要用em也行,但记住两点:要么确保父级font-size是固定值,要么在当前组件里明确重置font-size。可以在组件根元素上显式写
font-size: 16px;覆盖掉继承。移动端响应式的话,还可以结合css变量和媒体查询来动态调整html的font-size,一套代码适配各种屏幕宽度。