CSS嵌套规则实战:用原生嵌套替代Sass,重新组织复杂卡片样式

2026-06-26 0 760

写CSS的人很少有不依赖Sass或Less的。嵌套语法是其中最大的理由——它让层级关系清晰,避免了重复书写父选择器。但预处理器的嵌套最终会编译成一大堆平铺的选择器,有时还会产生不必要的长选择器链。2023年底,所有主流浏览器都已支持CSS原生嵌套CSS Nesting),意味着你可以在没有构建工具的情况下,直接编写嵌套的CSS规则。

这不是简单的语法糖。原生嵌套有明确的解析规则,可以与:is()&嵌套标识符配合,还能在媒体查询和容器查询内部嵌套规则。本文通过一个完整的卡片列表案例,把CSS嵌套的用法、陷阱和与Sass的差异讲清楚。

一、原生嵌套的基本语法

在原生CSS中,我们可以这样写嵌套:

.product-card {
    background: white;
    border-radius: 8px;

    & .title {
        font-size: 1.25rem;
        font-weight: bold;
    }

    & img {
        width: 100%;
        display: block;
    }

    &:hover {
        box-shadow: 0 4px 12px rgba(0,0,0,0.15);
    }
}

解析后等价于:

.product-card { background: white; border-radius: 8px; }
.product-card .title { font-size: 1.25rem; font-weight: bold; }
.product-card img { width: 100%; display: block; }
.product-card:hover { box-shadow: 0 4px 12px rgba(0,0,0,0.15); }

规则很简单:一个选择器后面跟着{ },里面除了声明属性,还可以再写完整的选择器规则,这些规则必须以&开头(或者直接以元素标签、类名开头,但此时解析可能有歧义,最好始终使用&)。

注意:早期的原生嵌套草案允许直接写子选择器而不加&,但最终规范要求必须以&或元素选择器开头。推荐始终在嵌套选择器开头加上&,避免意外解析。

二、完整案例:一个带状态和响应式的卡片列表

假设我们有一个产品列表,每个卡片包含图片、标题、价格标签和收藏按钮。设计要求:卡片默认状态;悬停时放大并加深阴影;收藏按钮在悬停时变色;在暗色模式下调整背景和文字颜色;在小屏幕上卡片宽度变为100%。

2.1 HTML结构

<div class="product-list">
    <div class="product-card">
        <img src="product.jpg" alt="产品图">
        <span class="badge">新品</span>
        <h3 class="title">产品名称</h3>
        <span class="price">¥199</span>
        <button class="fav-btn">收藏</button>
    </div>
    <!-- 更多卡片 -->
</div>

2.2 用嵌套组织CSS

.product-list {
    display: grid;
    gap: 1.5rem;
    padding: 1rem;

    @media (width >= 768px) {
        grid-template-columns: repeat(2, 1fr);
    }
    @media (width >= 1024px) {
        grid-template-columns: repeat(3, 1fr);
    }
}

.product-card {
    background: var(--card-bg, #fff);
    border-radius: 12px;
    overflow: hidden;
    transition: transform 0.2s, box-shadow 0.2s;
    position: relative;

    /* 卡片内部结构 */
    & img {
        width: 100%;
        aspect-ratio: 4/3;
        object-fit: cover;
    }

    & .badge {
        position: absolute;
        top: 8px;
        left: 8px;
        background: #ff4757;
        color: #fff;
        padding: 4px 8px;
        border-radius: 4px;
        font-size: 0.75rem;
    }

    & .title {
        font-size: 1.1rem;
        margin: 0.75rem 1rem 0.25rem;
    }

    & .price {
        color: #e63946;
        font-weight: bold;
        margin: 0 1rem;
    }

    & .fav-btn {
        display: block;
        margin: 0.75rem 1rem 1rem auto;
        background: transparent;
        border: 1px solid currentColor;
        border-radius: 6px;
        padding: 4px 12px;
        cursor: pointer;
        transition: background 0.2s, color 0.2s;

        /* 收藏按钮悬停状态 */
        &:hover {
            background: #ff4757;
            color: #fff;
            border-color: #ff4757;
        }

        /* 已收藏状态(通过JS添加class) */
        .product-card.favorited & {
            background: #ff4757;
            color: #fff;
            border-color: #ff4757;
        }
    }

    /* 卡片悬停效果 */
    &:hover {
        transform: translateY(-4px);
        box-shadow: 0 8px 25px rgba(0,0,0,0.12);
    }

    /* 暗色模式适配 */
    @media (prefers-color-scheme: dark) {
        background: #2d2d2d;
        color: #e0e0e0;

        & .badge {
            background: #ff6b81;
        }

        & .price {
            color: #ff6b81;
        }
    }
}

这个样式表完整展示了嵌套的几种用法:

  • 使用&连接子元素(& img& .title等)
  • 伪类嵌套(&:hover
  • 嵌套规则内再嵌套(.fav-btn内部的&:hover
  • 引用父选择器用于状态组合(.product-card.favorited &
  • 媒体查询嵌套在规则内部(@media

三、与Sass/SCSS的关键差异

  • 字符串拼接:Sass中可以使用#{$var}在选择器中插入变量,CSS原生嵌套不支持。如果需要在嵌套中使用变量,必须通过CSS自定义属性在属性值中使用,而不能在选择器字符串中拼接。
  • 自动前缀:Sass可以输出带浏览器前缀的属性,CSS原生嵌套不具备这个能力,仍需依靠Autoprefixer。
  • 父选择器引用&在Sass中代表完整的祖先选择器串,在CSS原生嵌套中也是,但CSS原生嵌套的解析规则更严格,&不能出现在选择器中间位置(如.card &__title这种BEM写法),只能出现在开头或结尾。
  • 嵌套深度:CSS原生嵌套在浏览器中解析时,每一层嵌套都会产生一个:is()包裹的选择器,深层嵌套可能导致特异度意外升高。建议嵌套深度不超过3层。

四、嵌套时需要注意的陷阱

第一个陷阱:无&开头时,浏览器会将嵌套规则解析为后代选择器还是新的全局选择器?早期实现有差异。现在的规范明确:如果一个嵌套规则以字母开头(即不以&:[等符号开头),则它被视为一个独立的选择器规则,不再继承父选择器。为了避免混淆,强烈建议任何嵌套规则都以&开头。

第二个陷阱:特异度。嵌套生成的:is(.parent .child)特异度等同于.parent .child,所以通常不会有意外。但如果嵌套内又使用了:is():where(),需要小心计算。

第三个陷阱:性能。极深的嵌套或复杂选择器在编译时(浏览器解析CSS时)会有少许额外开销,但实际项目中几乎感知不到。合理使用嵌套能减少样式表文件体积,反而有利于加载性能。

五、浏览器支持与迁移策略

所有主流浏览器(Chrome 120+、Edge 120+、Firefox 117+、Safari 17.2+)均已支持CSS原生嵌套。覆盖率在2024年末已超过92%。

如果你的项目已经在使用Sass,可以逐步尝试将部分组件的样式迁移到原生嵌套:

  1. 先从简单的、不依赖Sass变量和混入的组件开始。
  2. 保持Sass构建流程,但将一部分样式移到单独的.css文件或<style>标签中,测试原生嵌套的兼容性。
  3. 如果项目完全不需要Sass的其他功能(变量、混入、循环),可以考虑去Sass化,仅使用PostCSS的Autoprefixer处理前缀。

对于还在使用旧浏览器的用户,嵌套会降级为无效样式,导致样式缺失。可以通过@supports或构建时回退来保证兼容性。例如:

/* 回退写法 */
.product-card & img { width: 100%; }

/* 嵌套写法(支持时才生效) */
@supports (selector(& img)) {
    .product-card {
        & img { width: 100%; }
    }
}

但在实践中,如果用户浏览器市场份额已足够高,直接使用原生嵌套即可。

六、总结

CSS原生嵌套是前端工程化向前迈出的重要一步。它没有改变CSS的本质,只是让样式表的结构更贴近开发者组织代码的思维方式。通过本文的卡片列表案例可以看到,嵌套能让同一组件的样式内聚在一个代码块里,伪类、响应式、状态变化一目了然,不再需要反复回想.parent .child .grandson:hover .icon这种长选择器的具体含义。

从Sass迁移到原生嵌套不需要一蹴而就。你可以保留Sass作为构建工具,但同时体验原生嵌套带来的便利。等生态进一步成熟,或许有一天,CSS文件里就只剩下纯CSS了。

CSS嵌套规则实战:用原生嵌套替代Sass,重新组织复杂卡片样式
收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

版权声明:
本站资源有的来自互联网收集整理,本站纯免费分享提供学习使用,如果侵犯了您的合法权益,请联系本站我们会及时删除。
本站资源仅供研究、学习交流之用,免费开源项目不代表完全可商用,若商业用途请先咨询开发企业能否商用,否则产生的一切后果将由下载用户自行承担。
原创板块未经允许不得转载,否则将追究法律责任。

淘吗网 css CSS嵌套规则实战:用原生嵌套替代Sass,重新组织复杂卡片样式 https://www.taomawang.com/web/css/2282.html

常见问题

相关文章

猜你喜欢
发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务