首页Block拆分核心是识别必须独立的业务单元:header、product-card、promo-banner、footer因跨页复用或语义完整而必须为Block;轮播图等容器需按实际业务职责判断是否升格;主题变体应通过CSS自定义属性而非BEM修饰符管理。

多主题商城首页的 Block 拆分,核心不是“怎么分得细”,而是“哪些必须独立成块、哪些必须绑定上下文”。主题切换本质是视觉变体叠加,BEM 的 block--modifier 和 block__element--modifier 能覆盖大部分场景,但强行把所有主题差异都塞进修饰符,反而会让类名爆炸、逻辑混乱。
哪些区域必须拆成独立 Block,不能只是元素?
首页里看似连续的区块,只要满足「跨主题复用」或「脱离当前页仍具语义」,就必须是 Block:
-
header:页头在主题 A/B 下样式不同,但结构和功能完全一致;它也出现在商品详情页、购物车页——所以是独立 Block,不是homepage__header -
product-card:卡片组件在首页轮播区、推荐区、猜你喜欢区都出现,且各主题下只改配色/圆角/阴影——它自己就是 Block,homepage__product-list__card是典型反模式 -
promo-banner:促销横幅有“夏季大促”“开学季”等不同主题文案和背景,但它在首页、分类页、活动页都存在——必须独立,不能依附于homepage -
footer:同理,即使主题切换时 footer 字体/链接颜色变化,它仍是独立 Block
错误做法是把整个首页当一个 homepage Block,然后所有子区域都写成 homepage__xxx。这样一旦某个 banner 要挪到搜索页,就得重写 HTML 和 CSS,违背 BEM 的可复用前提。
主题变体该用 --theme-name 还是 CSS 自定义属性?
直接用 --dark、--summer 这类修饰符命名主题,短期快,长期难维护。原因有三:
- 主题不是布尔状态,而是配置集合:深色模式要改文字色、背景色、图标色、阴影强度,
.header--dark一个类名撑不起全部逻辑 - 主题可能叠加:用户既开了深色模式,又在夏季活动期,
.header--dark--summer会引发样式冲突(比如两个修饰符都设了background-color) - 无法动态切换:JS 切换主题时,得同时增删多个类名,而 CSS 自定义属性只需改一个
:root变量
更合理的做法是:header、product-card 等 Block 本身不带主题修饰符,只通过 CSS 自定义属性承接主题变量:
:root {
--header-bg: #fff;
--header-text: #333;
}
.theme-dark {
--header-bg: #1a1a1a;
--header-text: #fff;
}
.header {
background-color: var(--header-bg);
color: var(--header-text);
}
这样 Block 类名干净,主题逻辑收口在变量层,JS 控制也只需切换 theme-dark 这个顶层类。
轮播图、推荐位这类“容器型区域”怎么命名?
它们最容易被误判为 Block,但其实多数时候只是布局容器,不该承担业务语义:
-
homepage-hero-slider✅:如果这个轮播只用于首页首屏、承载品牌主推活动,且各主题下内容和交互逻辑不同(比如深色主题下自动暂停),那它值得独立成 Block -
homepage-recommend-section❌:如果它只是个带标题的卡片列表容器,“推荐”逻辑由后端 API 决定,前端只负责渲染product-card,那它就不该是 Block——直接用语义化 HTML 元素 + 布局类即可:<section class="section section--grid"></section>,里面放<div class="product-card"> <li>关键判断点:删掉这个“容器”,里面的子组件(如 <code>product-card)是否还能正常工作、语义是否完整?能,说明容器只是布局角色;不能,才考虑升格为 Block
很多团队卡在这一步,硬给每个 <div> 套 Block 名,结果导致 Block 泛滥、职责不清。BEM 不是给所有 div 贴标签,而是识别真正需要封装样式的业务单元。<p>最常被忽略的点是:Block 的边界由复用场景决定,而不是 DOM 层级。一个 <code>product-card 在首页、搜索页、订单页都用同一套样式和交互,它就该是 Block;哪怕它在首页里嵌套在五层 <div> 里,也不该变成 <code>homepage__section__list__item__card。











