红点必须用::after伪元素实现,核心是content: ""+position: absolute+父容器position: relative,配合top: 0; right: 0; transform: translate(50%, -50%)精确定位,并用data-unread属性控制显隐,移动端需@media降级尺寸。

红点必须用 ::after 伪元素,别用 <span></span> 或字符 ●
直接塞一个 <span class="red-dot"></span> 到 DOM 里,看似简单,实则埋雷:它会参与文档流、影响行高、响应式缩放失真;用字符 ● 更糟——字号一变,圆就变形,抗锯齿糊成一团。真正可靠的是 ::after + content: "" + 绝对定位。父容器必须设 position: relative,否则 ::after 会相对 body 定位,红点飞出屏幕。
关键参数要配齐:
-
width和height固定写死(如8px),不用em或rem -
border-radius: 50%确保是正圆,不是椭圆 -
background-color: #f00,别依赖透明度或渐变,兼容性差 - 定位靠
top: 0; right: 0; transform: translate(50%, -50%),不是凭感觉调right: -5px
data-unread 属性比 class 更适合控制显隐
用 class="unread" 切换红点状态,代码写起来顺手,但语义弱、易冲突——比如组件库自带 unread 类,样式就被覆盖了。改用 data-unread="1" 更干净:[data-unread]::after 控制显示,[data-unread="0"]::after 或直接不设该属性来隐藏。
这样做的好处:
- JS 更新时只需
el.dataset.unread = "5",无需操作 classList - 未读数为 0 时删掉属性就行,比 toggleClass 更确定
- 可直接在 HTML 模板里写
<div data-unread="{{count}}">,服务端渲染友好 <h3>移动端红点尺寸必须单独降级</h3> <p>桌面端看着刚好的 <code>8px红点,在手机上会显得突兀、遮挡图标细节。别指望媒体查询只调颜色——尺寸也得动。加一条@media (max-width: 768px)把红点缩到6px,同时微调transform的偏移量(比如translate(55%, -55%)),避免小屏下右上角贴边错位。容易漏的点:
-
font-size变化会影响 inline 元素基线,导致transform锚点漂移 - SVG 图标作为父容器时,需确保其
display是inline-block,否则position: relative失效 - 不要给红点加
box-shadow,低端 Android 渲染卡顿明显
红点位置总偏移?先查这四个值是否联动
红点看起来“差一点点”没对准右上角,90% 是这四个 CSS 值没协同好:
top、right、transform、父容器的line-height或padding。尤其当父容器是<button></button>或<i></i>这类 inline 元素时,基线(baseline)会偷偷拖拽定位参考点。稳解法:
- 父容器统一设
display: inline-block或block - 红点伪元素固定用
top: 0; right: 0; transform: translate(50%, -50%) - 禁用
vertical-align,它和transform冲突 - 调试时临时加
outline: 1px solid blue看父容器真实边界
visibility: hidden配合opacity: 0而非display: none,否则键盘用户 tab 到这里会跳过。 -











