position: fixed 是实现图片随滚动始终可见的唯一正确方式,它脱离文档流、相对视口定位;sticky 仅条件性粘滞,无法真正跨区域悬浮;移动端需注意 Safari 兼容性及键盘/地址栏导致的错位问题。
position: fixed 实现图片跟随滚动(最常用)图片“固定”在视口某个位置、随页面滚动始终可见,本质是脱离文档流并相对于视口定位。 position: fixed 是唯一符合该需求的 CSS 定位方式, 或 
sticky 都不满足“真正跟随滚动”的效果。
常见错误是忘记设置 top/right/bottom/left,导致元素堆在默认位置(左上角),或未设 z-index 被其他内容遮挡。
fixed 元素的坐标基准是视口,不是父容器,所以不要依赖父级 transform、perspective 或 filter —— 这些会让 fixed 退化为 absolute
fixed 支持较弱,尤其在地址栏收放时可能跳动;若需兼容,可加 will-change: transform 或监听 scroll + transform: translate() 模拟(但性能和体验略差)fixed 图片使用 width: 100% 且无 max-width,否则小屏下会横向溢出@@##@@
position: sticky 不算“真正跟随滚动”sticky 是条件性定位:只在滚动到临界点时才“粘住”,一旦超出容器范围或滚动回原位,就会恢复成 static 行为。它不能像 fixed 那样始终锁定在视口某处。
典型误用场景:给图片父容器设 height: 100vh,再对图片设 position: sticky; top: 20px —— 这只是让它在该容器内“粘”,一旦容器滚出视口,图片就消失了。
sticky 必须配合明确的 top / bottom 值才生效,仅设 position: sticky 无效overflow: hidden|auto|scroll,否则粘性行为被截断fixed
纯 CSS fixed 是静态定位。如果需要“滚动到某区域才出现”或“随滚动距离缩放/偏移”,就得用 JS 监听 scroll 事件并操作 style.transform 或 style.opacity。
关键点不是“能不能做”,而是“要不要做”——多数所谓“跟随滚动”需求其实只需 fixed;加 JS 反而引入性能风险(如未节流的 scroll 导致卡顿)和兼容负担。
IntersectionObserver 替代 scroll + getBoundingClientRect() 判断进入视口transform 和 opacity,避免触发重排(top/left/width 等)img.src 或增删 class 控制显隐,容易造成 layout thrashingconst img = document.querySelector('#floating-img');
const observer = new IntersectionObserver(([entry]) => {
img.style.opacity = entry.isIntersecting ? '1' : '0.3';
}, { threshold: 0.1 });
observer.observe(document.querySelector('#trigger-section'));
iOS Safari 的 fixed 在键盘弹出、地址栏收缩时会错位,这是浏览器层限制,无法用 CSS 修复。很多开发者以为是自己代码问题,其实是系统行为。
fixed 图片放在 附近,尤其表单页;可改用 absolute + scroll 监听模拟(牺牲一点精度换稳定性)fixed 元素设 touch-action: none,否则可能干扰页面整体手势max-width: 100vw 替代 width: 100%,防止横屏时溢出fixed 元素不会触发 resize 事件,其宽高变化需靠 matchMedia 或 ResizeObserver 单独监听真正难的不是让图“固定”,而是判断它该不该固定、在哪里固定、以及固定后是否破坏了可访问性(比如遮挡主要内容、影响屏幕阅读器焦点流)。