CSS常见问题概览
样式在 PC 正常、部分手机上错乱?
先核对 browserslist,不要假定 Autoprefixer 会自动为所有旧内核补充前缀。webpack、Vite 项目中,Autoprefixer(依托 PostCSS)会依据 browserslist 配置决定是否生成 -webkit-、-moz- 等前缀。
该配置属于动态规则:浏览器版本持续更新,last 2 versions 匹配范围会随之变动;原先能够自动追加的前缀会停止生成,最终在老旧 WebView 内出现样式缺失、布局错位。
在 package.json 或 .browserslistrc 中,按照项目实际需要兼容的最低环境明确配置,示例:
"browserslist": [
"> 0.5%",
"last 2 versions",
"not dead",
"iOS >= 13",
"Android >= 8"
]
注意:新版 Chrome、Firefox、Edge 以及较新 Safari,绝大多数属性不再需要浏览器前缀。
transform: scale 为什么让文字和图片变糊?
缩放倍数大于 1 时,浏览器常会将当前合成层渲染为位图再拉伸,文字与图片因此发糊。复杂 DOM 更容易被合并到同一张纹理执行缩放;简单节点有时直接基于矢量、文字路径渲染,不会出现模糊。 translateZ(0)、translate3d(0,0,0) 仅能把元素提升至独立合成层,缩放操作依旧作用在位图纹理上,无法消除模糊,甚至会加重问题。
优化方案:尽量避免使用 scale 放大元素,改用调整字号、宽高尺寸,或是使用更高分辨率图片;必须缩放时,将倍数调整为接近整数,减少亚像素渲染带来的失真。 zoom 可在 Chrome、Safari 规避部分模糊问题,但 Firefox 不支持,不能作为通用方案。
移动端 a:active 无效,点击后又变成 :visited 的颜色?
iOS 浏览器中,页面没有绑定触摸监听时,:active 状态无法触发。在 document.body 或目标链接绑定空 touchstart 事件即可激活:
document.body.addEventListener('touchstart', function () {})
:link、:visited、:hover、:active 选择器优先级一致,后声明样式会覆盖前者。必须遵循 LVHA 顺序书写,点击态才能覆盖访问态;仅设置 :active、不处理 :visited 时,点击过后的链接会恢复浏览器默认紫色访问色。
a:link { color: #06c; }
a:visited { color: #06c; }
a:hover { color: #c00; }
a:active { color: #c00; }
注意:出于隐私安全策略限制,浏览器对 :visited 可修改的样式属性做了限制,仅支持修改颜色,并非代码 Bug。
CSS 动画为什么闪、为什么卡?
动画优先修改 transform、opacity 属性,走合成层渲染;不要依靠 left、top 实现位移。修改 left、top 会持续触发页面重排、重绘,单帧运算量过高,直接造成卡顿、闪烁。位移使用 translate,缩放、旋转使用 scale、rotate。
仅对即将执行动画的元素添加 will-change: transform,动画结束后移除该属性。不要全局滥用 translate3d(0, 0, 0) 强行开启GPU加速,合成层数量过多会占用大量内存,反而加剧卡顿。
渐变里写 transparent 为什么发黑?
关键字 transparent 等价于 rgba(0, 0, 0, 0)。从彩色过渡到透明时,RGB 通道会向黑色插值,渐变中间区域发黑,该现象在 Safari 中尤为明显。 不要直接过渡到白色透明 rgba(255, 255, 255, 0),否则会向白色插值。
正确做法:使用相同色相、透明度为0的颜色完成过渡。
/* 错误:过渡中间发黑 */
background: linear-gradient(to right, #f91250, transparent);
/* 正确:同色相平滑淡出 */
background: linear-gradient(
to right,
rgb(249 18 80 / 100%),
rgb(249 18 80 / 0%)
);
设了很大的 border-radius,圆为什么还是扁的?
圆角变形根源是容器宽高不相等,并非 border-radius 数值不足。容器宽高不一致时,border-radius: 100px 只会渲染椭圆。
实现正圆:保证容器宽高相等,或设置 aspect-ratio: 1,再搭配 border-radius: 50%。
若子元素为图片、inline-block,行内基线会在容器底部产生缝隙,导致容器高度轻微变大,圆形轻微压扁。解决方案:父容器设置 font-size: 0,或者使用 display: flex 清除基线缝隙,字号在子元素单独声明。
页面高度 100% 仍被底部导航栏挡住?
移动端 height: 100%、100vh 经常不等于可视区域高度。iOS 环境下 100vh 采用大视口计算,地址栏、底部工具栏收起与展开时高度动态变化,内容容易被浏览器、App 底部栏遮挡。
推荐使用动态视口单位并适配安全区:
html,
body {
height: 100%;
height: 100dvh;
}
.page {
padding-bottom: env(safe-area-inset-bottom);
}
老旧 WebView 不支持 dvh,可通过 JS 兜底,使用实时可视高度:
document.documentElement.style.height = `${window.innerHeight}px`
overflow: hidden,为什么还有横向滚动条?
页面滚动根容器为 html,只给 body 设置 overflow: hidden 经常无法截断溢出。如果绝对定位元素的包含块是视口,超出屏幕宽度就会产生横向滚动;给 body 添加 position: relative,溢出裁剪逻辑会转移至 body。
另一高频诱因:width: 100vw。视口宽度包含滚动条占位槽,比 100% 略宽,会主动撑开横向滚动。页面满宽需求优先使用 100%,避免 100vw。
去掉点击高亮、滚动条、number 箭头要用哪些属性?
下方为 WebKit 内核常用私有前缀样式,标准属性与前缀一并书写:
/* 禁止文本选中 */
.no-select {
user-select: none;
-webkit-user-select: none;
}
/* 移除点击灰块、蓝色高亮 */
a,
button {
-webkit-tap-highlight-color: transparent;
}
/* 隐藏滚动条:Chrome、Safari + Firefox */
.hide-scrollbar {
scrollbar-width: none;
}
.hide-scrollbar::-webkit-scrollbar {
display: none;
}
/* iOS 禁止长按弹出图片菜单 */
img {
-webkit-touch-callout: none;
}
/* 清除 input、select 默认系统样式 */
input,
select {
appearance: none;
-webkit-appearance: none;
}
/* 移除 number 输入框上下箭头(Chrome) */
input[type='number']::-webkit-outer-spin-button,
input[type='number']::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* 占位文本样式 */
input::placeholder {
color: #999;
}
注意:-webkit-overflow-scrolling: touch 无需再手动添加。iOS 13 及以上滚动容器默认开启惯性滚动,额外声明该属性,部分页面反而出现滚动卡顿。
table 的列宽、圆角、边框间距为什么不生效?
- 使用
<col>设置宽度,单元格内容依旧撑开列宽:给table添加table-layout: fixed,列宽严格按照设定值生效,内容溢出配合overflow: hidden处理。 <col>、<colgroup>上稳定支持的样式仅包含width、background。border-collapse: collapse模式下,border-spacing不生效;规范仅在border-collapse: separate时支持边框间距。border-collapse: collapse与border-radius无法共存:表格圆角会被单元格直角边框覆盖。