瀑布流卡片BEM命名必须绑定grid容器作用域,如.gallery__waterfall为根,子元素统一使用.gallery__card、.gallery__card__image等全路径类名,禁止全局.card或混用前缀,确保样式隔离与复用。

瀑布流卡片的BEM命名必须绑定grid容器作用域
纯CSS瀑布流用display: grid实现时,BEM类名如果只写.card或.card__title,会在多列布局中失去上下文隔离——比如你在一个页面里同时放了相册瀑布流和商品列表瀑布流,两个.card的grid-row跨度规则会互相覆盖。必须把BEM根元素绑定到grid容器上,例如.gallery__waterfall作为容器,所有卡片类都从它派生:.gallery__card、.gallery__card--featured、.gallery__card__image。
常见错误是把.card写成全局样式,结果在响应式断点切换列数时,grid-row: span 2被其他模块的同名类覆盖,卡片突然错位甚至重叠。这不是浏览器bug,是BEM作用域没收住。
- 容器类名必须唯一且语义化,避免用
.waterfall这种泛称,改用.photo-gallery__grid或.product-list__grid - 所有子元素类名前缀必须与容器严格一致,禁止混用
.card__title和.photo-gallery__title - 修饰符(如
--loading)只用于状态变更,不用于响应式列数控制——列数交给@media或@container管
响应式列数变化时,BEM不能靠媒体查询硬切类名
有人习惯在JS里监听window.resize,然后根据宽度给容器加.gallery__grid--2col、.gallery__grid--3col等类,再配一堆CSS。这会导致两个问题:一是resize事件高频触发造成重排抖动;二是类名膨胀,维护成本指数上升。真正的做法是让BEM结构保持静态,列数逻辑完全交给CSS Grid的repeat(auto-fill, minmax(...)),BEM只负责内容语义,不参与布局计算。
例如.gallery__card永远不写width或flex-basis,它的尺寸由.gallery__grid的grid-template-columns决定;高度差异通过grid-row: span或aspect-ratio控制,而不是靠.gallery__card--tall这种修饰符硬编码。
立即学习“前端免费学习笔记(深入)”;
- 列数响应式必须用CSS原生方案:
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)) - BEM修饰符只用于内容状态(
--error、--hovered)、视觉变体(--dark),绝不用于布局维度(--2col、--mobile) - 若需不同断点下卡片内部结构微调(如标题行数、图片圆角),用
@container而非@media,确保样式作用域跟随容器实际宽度而非视口
图片高度不均时,BEM需预留aspect-ratio降级兜底
瀑布流卡片最常崩的点,是图片原始尺寸差异大,而grid-row: span又依赖开发者手动标注——一旦漏标或标错,后续卡片全部错位。BEM本身不解决这个问题,但BEM结构要为aspect-ratio留出扩展空间。比如.gallery__card__image不能直接设height: 100%,而应包裹一层.gallery__card__image-wrapper,里面用aspect-ratio: 4/3 + object-fit: cover,这样即使图片加载失败或尺寸异常,卡片骨架也不会塌。
这个wrapper层不是可选项——Safari 15.4+才支持aspect-ratio,旧版需fallback到padding-top技巧。BEM结构定死,CSS实现才能分层兼容。
-
.gallery__card__image只负责图片本身,不承担尺寸控制 -
.gallery__card__image-wrapper专用于包裹和比例控制,支持aspect-ratio和padding-top双实现 - 禁止在
.gallery__card上写min-height或height,否则会破坏Grid自动行高计算
懒加载与BEM类名的动态注入必须解耦
很多瀑布流模板用JS动态插入卡片DOM,然后顺手给新节点加class="card"。问题在于:如果BEM类名是.gallery__card,而JS里写死el.classList.add('card'),就会漏掉前缀,导致样式丢失。更糟的是,有些懒加载库(如lozad.js)默认只处理data-src,不碰class,结果新卡片渲染出来是裸DOM。
正确做法是:JS只负责数据和结构,BEM类名由HTML模板或CSS-in-JS生成器统一注入。哪怕用innerHTML拼接,也要完整写出class="gallery__card gallery__card--loaded",不能靠后期补。
- 动态插入卡片时,必须完整携带BEM全名,不可省略根命名空间
- 修饰符状态(如
--loaded、--error)应由JS根据图片加载结果设置,而非CSS自动推导 - IntersectionObserver回调中,避免对
.gallery__card做getBoundingClientRect()频繁读取——它会强制同步布局,瀑布流滚动卡顿就源于此
.debug调试类,也会污染Grid的隐式轨道计算。


















