kebab-case、snake_case、camelCase、PascalCase 和 CONSTANT_CASE 解决的是同一个问题:怎样在没有空格的情况下写出多个单词。但每种写法都有自己的「地盘」:网址和 CSS 用连字符,Python 用下划线,JavaScript 用驼峰。用错了地方,轻则代码评审里满是改名意见,重则出现 bug 或失效链接。本指南把各种命名风格并排对比,解释网址为什么用连字符,依据 MDN 和 PEP 8 列出各语言、各文件格式习惯用哪种风格,并讲清最容易出错的缩写词与数字。文中所有转换结果都由我们的 Kebab Case 转换器 实际跑出,两段示例代码也在测试里与转换器逐条比对过。
提示
简短回答
- 网址用 kebab-case。 Google 建议网址中用连字符而不是下划线分隔单词;全部小写还能避免重复网址。
- CSS 和 HTML 用 kebab-case。
background-color这样的属性和aria-label这样的特性名都用连字符。 - Python 和 Rust 的函数、变量用 snake_case; Python 的类用 PascalCase(PEP 8 称为 CapWords)。
- JavaScript 和 Java 的变量、函数用 camelCase, 类用 PascalCase。
- 常量和环境变量用 CONSTANT_CASE。
- 身处哪个生态就遵循哪个生态的约定, 在边界处做转换,比如 JSON 接口与代码之间。
命名风格一览
以短语「Summer Clothing Sale」(夏季服装促销)为例:
| 风格 | 结果 | 典型用途 |
|---|---|---|
| kebab-case | summer-clothing-sale | 网址、CSS 类名、文件名、命令行参数 |
| snake_case | summer_clothing_sale | Python 和 Rust 的函数与变量、数据库字段 |
| camelCase | summerClothingSale | JavaScript 和 Java 的变量与函数、许多 JSON 接口 |
| PascalCase | SummerClothingSale | 类和类型、React 组件 |
| CONSTANT_CASE | SUMMER_CLOTHING_SALE | 常量、环境变量 |
| dot.case | summer.clothing.sale | 配置键、翻译键、部分生态的包名 |
MDN 对 kebab case 的描述是:用连字符连接单词,通常全部小写;并指出在许多语言里连字符表示减号,所以 kebab case 不能用作变量名。在 JavaScript 里,summer-clothing-sale 的意思是 summer 减 clothing 再减 sale。snake case 从不包含大写字母;像 Number.MAX_SAFE_INTEGER 这样全部大写的写法,MDN 称之为「screaming snake case」。camel case 从第二个单词起首字母大写;如果第一个字母也大写,就叫大驼峰(upper camel case)或 Pascal case。
网址为什么用连字符
Google 的网址结构指南写得很明确:网址中用连字符而不是下划线分隔单词,这样有助于用户和搜索引擎识别网址中的概念。不推荐下划线是出于历史原因:下划线常用来表示应当连在一起的概念,比如各种编程语言里的函数名 format_date;而连字符清楚地表示单词边界。指南列出了同一网址的三种写法:
| 写法 | 示例 | Google 的态度 |
|---|---|---|
| 连字符 | https://example.com/summer-clothing/filter?color-profile=dark-grey | 推荐 |
| 下划线 | https://example.com/summer_clothing/filter?color_profile=dark_grey | 不推荐 |
| 单词连写 | https://example.com/greendress | 不推荐 |
还有两个理由支持网址用 kebab-case:
- 网址区分大小写。 Google 把
/APPLE和/apple视为不同网址,所以驼峰式路径很容易产生/SummerSale与/summersale这样的重复页面。全小写的 kebab-case 没有这个问题。 - 下划线在链接里会「消失」。 很多应用会给链接加下划线,
_被遮住后,summer_sale看起来就像 summer sale。
这也是我们的 URL Slug 生成器 只输出小写、连字符分隔的 slug 的原因。好 slug 的其他要点见 URL Slug SEO 指南。
各种风格在代码里的位置
Python(PEP 8)。 函数名和变量名小写,必要时用下划线分隔单词以提高可读性;类名通常用 CapWords;常量全部大写并用下划线分隔,例如 MAX_OVERFLOW;模块名简短、全小写,可以用下划线,但包名不鼓励用下划线。mixedCase(即 camelCase)只允许在已经是主流风格的地方使用,以保持向后兼容。
JavaScript 和 Java。 MDN 说 camelCase 是 JavaScript、Java 等许多语言里最流行的约定,内置名称就是例子:encodeURIComponent、ArrayBuffer、HTMLElement。类和 React 组件用 PascalCase。
Rust。 MDN 把 snake case 列为 Python、Rust 等语言里最流行的约定。
CSS 和 HTML。 background-color、font-family 等 CSS 属性是 kebab-case,aria-label 和 data-* 等 HTML 特性也是。在 JavaScript 里,element.dataset 会把 data-user-id 变成 userId,element.style 用的是 backgroundColor,同一个名字在边界处从 kebab-case 变成了 camelCase。
文件和命令行。 summer-sale.md 这样的 kebab-case 文件名在任何操作系统上都安全,在静态网站上也会直接变成干净的网址。命令行参数按惯例用连字符,例如 --dry-run。
数据。 JSON 接口各不相同:面向 JavaScript 的接口多用 camelCase,以 Python 或数据库为后端的接口多用 snake_case。每个接口选定一种,并在一个地方统一转换,最好放在序列化层或接口客户端里,这样业务代码只会看到一种风格。
缩写词与数字
缩写词是各种风格分歧最大的地方。MDN 指出 camel case 对缩写词的处理并不统一:有人保持缩写词全大写(encodeURIComponent),有人只大写首字母(XmlHttpRequest),而真实存在的 XMLHttpRequest 两种都用了。PEP 8 对 Python 类名表了态:「HTTPServerError 比 HttpServerError 好」。
转换器必须先把这类名字拆成单词,才能重新拼接。我们的转换器把一串连续大写字母当作一个单词,把「大写字母 + 小写字母」当作新单词的开头:
| 输入 | kebab-case | snake_case | camelCase | PascalCase |
|---|---|---|---|---|
| XMLHttpRequest | xml-http-request | xml_http_request | xmlHttpRequest | XmlHttpRequest |
| getUserID | get-user-id | get_user_id | getUserId | GetUserId |
| HTTPServerError | http-server-error | http_server_error | httpServerError | HttpServerError |
| parseHTML5Doc | parse-html5-doc | parse_html5_doc | parseHtml5Doc | ParseHtml5Doc |
| user_profile_v2 | user-profile-v2 | user_profile_v2 | userProfileV2 | UserProfileV2 |
注意 PascalCase 一列:转换器会把缩写词规范成 HttpServerError。如果你的 Python 类名遵循 PEP 8,就手动改回 HTTPServerError。数字会跟在前一个单词后面,所以 v2 和 html5 都作为一个单词保留。
这也是 slug 生成器和大小写转换器是两种工具的原因。slug 生成器把输入当作标题,XMLHttpRequest 只会变成一个单词 xmlhttprequest;大小写转换器把输入当作标识符,会找出其中的单词边界,得到 xml-http-request。页面标题用 slug 生成器,代码里的名字用 Kebab Case 转换器。
在代码里转换命名风格
下面两个函数对 ASCII 名字的拆分方式与我们的转换器相同,输出 kebab-case;我们在测试中用本指南的每个例子与转换器做了比对:
function toKebab(name) {
return name
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
.replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')
.split(/[^A-Za-z0-9]+/)
.filter(Boolean)
.map((w) => w.toLowerCase())
.join('-');
}
toKebab('XMLHttpRequest'); // 'xml-http-request'import re
def to_kebab(name):
name = re.sub(r"([a-z0-9])([A-Z])", r"\1-\2", name)
name = re.sub(r"([A-Z])([A-Z][a-z])", r"\1-\2", name)
return "-".join(w.lower() for w in re.split(r"[^A-Za-z0-9]+", name) if w)
to_kebab("getUserID") # 'get-user-id'两个正则各管一种边界:第一步在「小写字母或数字 + 大写字母」之间插入连字符,处理 getUser 这样的驼峰;第二步在「一串大写字母」与「大写字母 + 小写字母」之间插入连字符,把 XMLHttp 拆成 XML 和 Http。之后再按非字母数字字符切分、转小写、用连字符拼接。两步的顺序要与转换器保持一致,结果才能逐字相同。
想要 snake_case,把 - 换成 _ 拼接即可。名字含非 ASCII 字符、或者用于生产代码时,请使用经过测试的库或直接用转换器,不要依赖自己手写的正则。要把页面标题变成网址 slug,请用我们 代码片段指南 里的 slugify 代码,它还能处理重音字母和 &。
注意
常见错误
- 网址里用下划线或驼峰。 用小写 kebab-case,Google 推荐连字符。
- 变量名用 kebab-case。 在大多数语言里
user-id是一个减法。 - 同一接口混用风格。
userId和created_at放在一起,每个调用方都得猜。 - 忘了在边界处转换。
data-user-id在 JavaScript 里是dataset.userId。 - 缩写词完全交给转换器。 按你的风格指南核对
HTTPServerError与HttpServerError。 - 为了「统一风格」改网址却不做跳转。 把
/Summer_Sale改成/summer-sale需要 301 跳转。
可复制的命名风格检查清单
[ ] 网址和 slug:小写 kebab-case
[ ] CSS 类名、文件名、命令行参数:kebab-case
[ ] Python 和 Rust 的函数/变量:snake_case
[ ] JavaScript 和 Java 的变量/函数:camelCase
[ ] 类、类型和组件:PascalCase
[ ] 常量和环境变量:CONSTANT_CASE
[ ] 每个接口只用一种风格,并在一处统一转换
[ ] 缩写词已按风格指南核对
[ ] 改过的网址已配好 301 跳转用工具转换命名
把名字粘贴到 Kebab Case 转换器,每行一个,即可同时看到 kebab-case、snake_case、camelCase、PascalCase、CONSTANT_CASE 等多种写法。页面标题请用 URL Slug 生成器;修正旧的下划线或大写网址时,用 301 重定向生成器 生成跳转规则。
参考资料
- MDN Web Docs:Kebab case
- MDN Web Docs:Snake case
- MDN Web Docs:Camel case
- Python:PEP 8,Python 代码风格指南,「Naming Conventions」一节
- Google 搜索中心:Google 搜索的网址结构最佳做法
FAQ
常见问题
网址用 kebab-case 还是 snake_case 更好?
kebab-case。Google 建议网址中用连字符而不是下划线分隔单词,因为连字符清楚地标出单词边界,而下划线常用来把概念连在一起(比如函数名)。另外网址区分大小写,记得保持全部小写。
为什么变量名不能用 kebab-case?
在大多数编程语言里连字符就是减号,user-id 的意思是 user 减 id。变量名请根据语言用 snake_case 或 camelCase,kebab-case 留给网址、CSS 和文件名。
Python 用哪种命名风格?
PEP 8 规定函数、变量和模块用 snake_case,类用 CapWords(即 PascalCase),常量用 CONSTANT_CASE。camelCase 只允许在它已经是主流风格的地方使用。
camelCase 里的缩写词该怎么写?
没有统一做法。JavaScript 自带的名字就混用了两种风格(XMLHttpRequest、encodeURIComponent),PEP 8 则推荐 Python 类名写成 HTTPServerError。许多风格指南把缩写词当普通单词处理,写成 xmlHttpRequest。为你的代码库定一条规则并全部遵守即可。
