跳转到内容

CSS Modules 与 scoped

两个卡片使用相同结构与视觉效果。React 显式导入样式对象,Vue 则在单文件组件中直接使用普通类名。

React

样式作为模块导入,类名通过对象属性引用。

在线预览

CSS Modules

局部作用域卡片

JSX 使用 styles.card,构建后生成唯一类名。

仅影响当前组件

组件关系与数据流

ComponentBuildStyle

差异焦点CSS 以模块对象进入 JavaScript,类名引用是显式的。

实线表示依赖、数据或命令传递,虚线表示事件、回调或清理路径。

flowchart TB
  accTitle: React CSS Modules 显式导入流程
  accDescr: 独立 module CSS 文件在构建时生成唯一类名和 JavaScript 映射,ReactDemo 必须 import styles 并通过 className 显式读取映射。
  source[("ReactDemo.module.css")] --> build{{"构建时生成局部类名"}}
  build --> mapping[("styles 对象映射")]
  mapping -->|"import styles"| demo["ReactDemo.tsx"]
  demo -->|"className={styles.card}"| dom[("DOM 唯一类名")]
  class demo component
  class build process
  class source,mapping,dom resource
  classDef state fill:#ffffff,stroke:#149eca,color:#172033,stroke-width:1.2px
  classDef component fill:#e5f6fb,stroke:#149eca,color:#172033,stroke-width:2px,font-weight:600
  classDef process fill:#f4fbfd,stroke:#149eca,color:#172033,stroke-width:1.6px
  classDef resource fill:#f3f5f8,stroke:#778195,color:#172033,stroke-width:1.4px

样式文件与组件文件分离,通过 import 和 styles.* 显式绑定生成类名。

React 流程图
React 组件关系与数据流

滚轮缩放 · 按住拖动 · 双击重置 · Esc 关闭

实际运行源码

import styles from "./ReactDemo.module.css";
export function ReactDemo() {
return (
<section className={styles.card}>
<span className={styles.badge}>CSS Modules</span>
<h2>局部作用域卡片</h2>
<p>
JSX 使用 <code>styles.card</code>,构建后生成唯一类名。
</p>
<span className={styles.button}>
仅影响当前组件
</span>
</section>
);
}
Vue 3

样式写在 SFC 中,由 scoped 自动添加作用域。

在线预览

Vue scoped

局部作用域卡片

模板使用普通 class,编译器自动添加作用域属性。

仅影响当前组件

组件关系与数据流

ComponentBuildStyle

差异焦点作用域由 SFC 编译器注入,无需在脚本中导入样式映射。

实线表示依赖、数据或命令传递,虚线表示事件、回调或清理路径。

flowchart TB
  accTitle: Vue SFC scoped 编译流程
  accDescr: template 和 style scoped 位于同一个 Vue SFC,编译器同时改写模板属性与 CSS 选择器,普通 class 无需通过 JavaScript 导入。
  sfc["VueDemo.vue SFC"] --> build{{"同时编译 template + style"}}
  build --> template[("模板添加 data-v-*")]
  build --> styles[("选择器追加 data-v-*")]
  template --> dom[("匹配当前组件 DOM")]
  styles --> dom
  class sfc component
  class build process
  class template,styles,dom resource
  classDef state fill:#ffffff,stroke:#42b883,color:#172033,stroke-width:1.2px
  classDef component fill:#e7f8f0,stroke:#42b883,color:#172033,stroke-width:2px,font-weight:600
  classDef process fill:#f2fbf7,stroke:#42b883,color:#172033,stroke-width:1.6px
  classDef resource fill:#f3f5f8,stroke:#778195,color:#172033,stroke-width:1.4px

SFC 编译器同时改写模板和 scoped 选择器,组件内继续使用普通 class。

Vue 3 流程图
Vue 3 组件关系与数据流

滚轮缩放 · 按住拖动 · 双击重置 · Esc 关闭

实际运行源码

<template>
<section class="card">
<span class="badge">Vue scoped</span>
<h2>局部作用域卡片</h2>
<p>模板使用普通 class,编译器自动添加作用域属性。</p>
<span class="button">仅影响当前组件</span>
</section>
</template>
<style scoped>
.card {
display: grid;
gap: 0.75rem;
padding: 1.1rem;
border: 1px solid #83d7b1;
border-radius: 0.85rem;
color: #174331;
background: #ecfff5;
}
.card h2,
.card p {
margin: 0;
}
.badge {
width: max-content;
border-radius: 999px;
padding: 0.2rem 0.55rem;
color: #176947;
font-size: 0.7rem;
font-weight: 800;
background: #c9f5df;
}
.button {
width: max-content;
border: 0;
border-radius: 0.55rem;
padding: 0.55rem 0.75rem;
color: #fff;
font: inherit;
font-size: 0.78rem;
font-weight: 750;
background: #2f855f;
}
</style>