
Hugo css.Unquoted 函数详解显式控制 css.Sass 注入变量的引号与类型【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugocss.Unquoted是 Hugocss模板函数命名空间namespace提供的一个类型标记函数它接收任意字符串并将其包装为css.UnquotedString类型告诉 Hugo 在把该值注入 Sass 样式表时必须作为不带引号的字符串输出。本指南将结合 Hugo 官方函数文档 与当前仓库的源码实现tpl/css、resources/resource_transformers/tocss讲解css.Unquoted的签名、适用前提、底层自动类型推断机制、完整实战示例以及与姊妹函数css.Quoted的区别。读完本文你将能够精准控制css.Sass函数vars选项注入值的类型避免 CSS 输出中出现多余的引号。函数签名与返回值css.Unquoted的模板签名与返回类型如下见 函数文档 front matter项目值签名css.Unquoted STRING返回类型css.UnquotedString别名无其实现位于 tpl/css/css.go#L101-L105// Unquoted returns a string that does not need to be quoted in CSS. func (ns *Namespace) Unquoted(v any) css.UnquotedString { s : cast.ToString(v) return css.UnquotedString(s) }可以看到实现非常简单先用cast.ToString将任意输入归一化为字符串再包装成css.UnquotedString类型。该类型定义在 common/types/css/csstypes.go#L19-L20// UnquotedString is a string that does not need to be quoted in CSS. type UnquotedString string它不是一个“转换”函数而是一个类型标记——真正的行为差异发生在下游的 Sass 变量注入环节。适用前提仅用于 css.Sass 的 vars 选项函数文档开头的[!NOTE]明确指出This function is only applicable to thevarsoption passed to thecss.Sassfunction.也就是说css.Unquoted只作用于css.Sass的vars选项。这一点与css.Quoted不同——Quoted 文档 说明css.Quoted同时适用于css.Sass和css.Build的vars选项css.Build走的是 ESBuild 管线见 tpl/css/css.go#L202-L227。vars选项是css.Sass的一个 map 参数详见 css.Sass 文档Hugo 会用它生成 Sass 变量并在样式表中遇到hugo:vars这一内部标识符时出现在use或import语句中将变量注入样式表{{ $vars : dict font-size 24px primary-color blue }} {{ $opts : dict transpiler dartsass vars $vars }} {{ $r : resources.Get sass/main.scss | css.Sass $opts }}use hugo:vars as v; .element { color: v.$primary-color; font-size: v.$font-size; }css.Unquoted正是用于控制这类注入变量中字符串值的输出形态。Hugo 对 vars 值的自动类型推断在介绍css.Unquoted之前需要先理解 Hugo 默认的“自动类型推断”行为。css.Sass接收的varsmap 中值大多来自dict构造的 Go 模板字符串而 Hugo 会用正则表达式识别常见的带类型 CSS 值例如24px、#FF0000。这一定义在 resources/resource_transformers/tocss/sass/helpers.go#L150-L154var ( isCSSColor regexp.MustCompile(^#[0-9a-fA-F]{3,6}$) isCSSFunc regexp.MustCompile(^([a-zA-Z-])\() isCSSUnit regexp.MustCompile(^([0-9])(\.[0-9])?([a-zA-Z-%])$) )三种正则分别对应isCSSColor十六进制颜色如#fff、#ffffffisCSSFuncCSS 函数形式如hsl(0, 0%, 100%)、calc(24px 36px)isCSSUnit带单位的数值如24px、1.5rem、10%。判断逻辑isTypedCSSValue在 helpers.go#L156-L176其行为被 helpers_test.go#L22-L43 中的TestIsUnquotedCSSValue测试用例完整覆盖{24px, true}, // 带单位数值 → 视为带类型值 {1.5rem, true}, {10%, true}, {hsl(0, 0%, 100%), true}, // CSS 函数 {calc(24px 36px), true}, {24xxx, true}, // 一个已知的误报false positive {123, true}, // 原生数字类型 {123.12, true}, {#fff, true}, // 十六进制颜色 {#ffffff, true}, {#ffffffff, false}, // 8 位色值超出 3~6 位匹配范围对于这类被判定为“带类型”的值Hugo 会原样写入生成的变量样式表不带引号对于普通字符串如sans-serif它不匹配以上任何正则在 Dart Sass 下会被包装为string.unquote(...)在 LibSass 下包装为unquote(...)见 helpers.go#L125-L136。完整示例向 font-family 注入无引号值当需要确保某个值以无引号字符串的形式注入时即可使用css.Unquoted显式标记绕过自动推断。函数文档给出了font-family的经典场景Unquoted.md#L20-L47{{ $vars : dict font-main (sans-serif | css.Unquoted) }} {{ $opts : dict vars $vars transpiler dartsass }} {{ with resources.Get sass/main.scss | css.Sass $opts }} link relstylesheet href{{ .RelPermalink }} {{ end }}样式表中通过hugo:vars标识符引用该变量use hugo:vars as h; body { font-family: h.$font-main; }最终生成的 CSS 中font-family得到的是无引号的字符串body { font-family: sans-serif; }如果把同样的值作为普通字符串传入结果将依赖正则推断与unquote()包装语义不明确使用css.Unquoted则让“此值必须无引号”这一意图在模板中一目了然结果确定且可预期。源码级原理UnquotedString 的完整流转链路从模板调用到最终 CSS 输出css.Unquoted走通的完整链路如下模板调用(sans-serif | css.Unquoted)调用Namespace.Unquoted得到css.UnquotedString类型的值tpl/css/css.go#L101-L105。注入样式表生成css.Sass最终通过CreateVarsStyleSheethelpers.go#L104-L148把varsmap 拼装成一段 Sass 变量声明。其中css.QuotedString走专门分支强制加引号%q其余值走默认分支switch v.(type) { case css.QuotedString: // Marked by the user as a string that needs to be quoted. varsSlice append(varsSlice, fmt.Sprintf(%s%s: %q;, prefix, k, v)) default: if isTypedCSSValue(v) { // E.g. 24px, 1.5rem, 10%, hsl(0, 0%, 100%), calc(24px 36px), #fff, #ffffff. varsSlice append(varsSlice, fmt.Sprintf(%s%s: %v;, prefix, k, v)) } else { // unquote will preserve quotes around URLs etc. if needed. if transpiler TranspilerDart { varsSlice append(varsSlice, fmt.Sprintf(%s%s: string.unquote(%q);, prefix, k, v)) } else { varsSlice append(varsSlice, fmt.Sprintf(%s%s: unquote(%q);, prefix, k, v)) } } }类型判定isTypedCSSValue将css.UnquotedString与 int、float 等原生数字类型并列直接返回truehelpers.go#L158-L161func isTypedCSSValue(v any) bool { switch s : v.(type) { case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, css.UnquotedString: return true ...于是该值在默认分支中命中“带类型”路径被原样写为$font-main: sans-serif;——不经过%q引号包裹也不经过string.unquote()/unquote()包装。注入与编译Dart Sass 客户端在处理hugo:vars导入时调用CreateVarsStyleSheet生成变量源交由 Sass 编译最终产出font-family: sans-serif;。这条链路可在 resources/resource_transformers/tocss/dartsass/transform.go#L238-L243 中看到importResolver.Load对hugo:vars子路径的处理。顺带一提varsmap 还支持嵌套 map每个嵌套 map 会暴露为独立的hugo:vars/name命名空间name为小写键名顶层use hugo:vars只包含标量值——这是 0.161.0 新增的能力详见 css.Sass 文档的 vars 小节。css.Unquoted处理的是其中的标量值。与 css.Quoted 的对比css.Quoted与css.Unquoted是一对方向相反的类型标记函数二者对照如下对比项css.Unquotedcss.Quoted返回类型css.UnquotedStringcss.QuotedString作用强制值以无引号字符串注入强制值以带引号字符串注入适用函数仅css.Sass的varscss.Sass与css.Build的vars典型场景font-family等无需引号的属性content属性、font-family名称等需要引号的属性源码依据tpl/css/css.go#L101-L105tpl/css/css.go#L95-L99css.Quoted的典型用例来自 Quoted 文档content属性要求值必须是带引号的字符串因此用css.Quoted显式标记6、7最终生成content: 6;。而css.Unquoted则相反用于确保输出不带引号。二者的类型定义并列存在于 common/types/css/csstypes.go并在CreateVarsStyleSheet的分支处理中分别落地css.QuotedString走%q分支css.UnquotedString走“原样输出”分支。使用注意事项仅限css.Sass的varscss.Unquoted不适用于css.Build这是与css.Quoted最明显的差异使用时请核对目标管线。transpiler 选择css.Sass的transpiler默认值为libsass但从 tpl/css/css.go#L147 的注释可见它是“已弃用的默认值未来版本将改为 dartsass”代码还在 libsass 分支中触发了v0.153.0起的弃用警告css.go#L165。推荐显式指定transpiler dartsass并确保环境中安装了 Dart Sass 编译器。与普通字符串的区别对于sans-serif这类不匹配任何类型正则的普通字符串Dart Sass 管线本身也会通过string.unquote()使其无引号输出css.Unquoted的价值在于显式声明意图、保证原样输出避免依赖正则推断也规避了边界情况如测试中24xxx这类“误报”被当作带单位值处理。标量值才有意义vars中的嵌套 map 会被拆分为独立命名空间css.Unquoted作用于其中的标量字符串值不会改变嵌套结构本身。通过css.Unquoted你可以在模板层精确掌控 Sass 变量的类型语义让 Hugo 的自动推断与真实需求保持一致从而获得干净、可预期的 CSS 输出。【免费下载链接】hugoThe world’s fastest framework for building websites.项目地址: https://gitcode.com/gh_mirrors/hu/hugo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考