在 CSS 中更改特定字符可能是一个挑战。通常,我们被迫在 HTML 中逐个实现所需的更改,可能使用 span 元素。但是,在一些特定情况下,仍然可能使用以 CSS 为中心的解决方案。在本文中,我们将首先介绍一些更改字符的 CSS 优先方法,然后再考虑需要转向 JavaScript 的场景。
CSS
目前,CSS 并不擅长在不修改 HTML 的情况下定位特定字符。但是,在某些情况下,CSS 可能是最佳选择。
@font-face
@font-face
规则通常用于创建自定义字体,但其 unicode-range
属性也可以让我们定位特定字符。
例如,假设我们的网站标题中经常包含 & 符号。我们希望使用比标题字体更华丽的字体,而不是标题字体。我们可以查找 & 符号的 Unicode 值 (U
+0026
),并使用 unicode-range
定位此特定字符。
@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@300');
h1, h2, h3, h4, h5, h6 {
font-family: 'Ampersand', Montserrat, sans-serif;
}
@font-face {
font-family: 'Ampersand';
src: local('Times New Roman');
unicode-range: U+0026;
}
尝试使用以下 HTML 代码来查看其效果
<h1>Jane Austen Novels</h1>
<h2>Pride & Prejudice</h2>
<h2>Sense & Sensibility</h2>
::first-letter
::first-letter
伪元素主要用于首字母大写,并且所有主流浏览器都支持它。
p::first-letter {
font-size: 125%;
font-weight: bold;
}
当然,这仅在相对有限的场景中才有用。人们曾多次呼吁使用 ::nth-letter
伪元素(包括 CSS-Tricks 上的这篇文章),但目前这只是一个梦想!
::after
使用 ::after
伪元素和 content
属性,我们可以为最后一个字符实现类似的效果——只要该字符始终相同。例如,以下是如何在每个 h2
元素后面添加一个花哨的斜体感叹号
h2::after {
content: '\0021';
color: red;
font-style: italic;
}
font-variant-alternates
最后,还有 font-variant-alternates
属性。这 仅受 Firefox 支持,因此不建议用于生产环境,但对于非常具体的场景可能值得了解:如果字体碰巧包含备用字形,我们可以使用此属性和 character-variant()
函数为我们选择的字符选择首选字形。
JavaScript
转向 JavaScript 不需要以性能为代价,尤其是在构建时运行 HTML 修改函数时。最常见的用例可能是使用 span 元素查找并替换 HTML 中的特定字符。为简单起见,我将从客户端示例开始,之后我们将研究使用 webpack 在构建时运行此操作。
运行时查找和替换
假设,每当我们在网站的标题中包含“LOGO”文本时,我们都希望仅对第一个“O”字符添加特殊样式,方法是将其包装在一个带有 .special-o
类的 span
元素中。
const headings = document.querySelectorAll("h1, h2, h3, h4, h5, h6");
for (const heading of headings) {
heading.innerHTML = heading.innerHTML
.replace(/\bLOGO\b/g, 'L<span class="special-o">O</span>GO');
}
在上面的 JavaScript 代码中,我们对每个标题标签执行查找和替换操作。
我们的正则表达式使用元字符 \b
来确保 LOGO 始终是一个单词——而不是更大单词的一部分。例如,我们不想匹配复数“LOGOS”。目前,使用 CSS 无法做到这一点,尤其是因为我们只想定位序列中的第一个“O”。
如果我们想用图像替换“O”——甚至整个单词“LOGO”,则适用相同的原则。
构建时查找和替换
有很多构建工具可用,但由于 webpack 非常流行,因此我们将使用它作为示例——幸运的是,有一个名为 string-replace-loader 的插件可以满足我们的需求。对于 webpack 新手来说,加载器用于预处理文件。在这里,我们可以作为构建的一部分对特定文件执行查找和替换操作。
首先,我们需要安装插件
npm install --save-dev string-replace-loader
然后,在 webpack.config.js
中添加
module.exports = {
// ...
module: {
rules: [
{
test: /\.html$/i,
loader: 'string-replace-loader',
options: {
search: '/\bLOGO\b/g',
replace: 'L<span class="special-o">O</span>GO',
}
}
]
}
}
通过更改 test
属性的值,我们可以定位 JSX、TSX、PUG、Handlebars 或任何其他模板文件格式
/\.html$/i # HTML
/\.[jt]sx$/i # JSX or TSX
/\.pug$/i # PUG
/\.handlebars$/i # Handlebars
这种方法的优点是,客户端浏览器中不会运行任何不必要的 JavaScript 代码。
最后说明
最后,如果您熟悉创建和编辑字体,并且希望避免使用 CSS 或 JavaScript,则自定义字体可以解决上面列出的许多场景。对于那些想要尝试这种更注重设计的方法的人来说,有很多免费的字体编辑工具可用,例如 Font Forge 或 Birdfont。
我以前从未想过将 font-face 与 unicode-range 结合使用,我喜欢这个!
不过,在那里提供一个 CodePen 演示将是理想的!
您好 Alistair,感谢您的反馈!这是一个包含文章中示例的 CodePen 演示:https://codepen.io/BretCameron/pen/NWNpbrW。
感谢您的更新。
非常有创意
感谢这篇文章!但根据我的经验,::first-letter 在内联元素上不起作用。有时当我对页面进行一些动态更改时,它也不起作用。除非我刷新页面,否则它将不再起作用。
您好 Yiding,如果您目标是打印风格的首字母大写,请尝试将
::first-letter
与float: left
结合使用。我创建了一个简单的 CodePen 来演示此效果:https://codepen.io/BretCameron/pen/mdPKQpy。嘿 Bret!喜欢这篇文章。您能否在不使用正则表达式的情况下修改它?
谢谢!是的,
replace
函数可以接受普通字符串,string-replace-loader
的search
选项也可以接受普通字符串。