1. 先说原理为什么一行文字里可以混排两种字体很多刚接触前端的人第一次遇到这个需求脑子里想的是把文字拆成两个段落。结果实际操作后发现p标签一个比一个老实写完第二个p它自动就跑到下一行去了。这不是你的代码有问题而是对HTML元素类型的基本认知没建立起来。问题的关键其实在于行内元素inline和块级元素block的区别。p、div这类标签默认是块级元素它们的特点就是独占一行宽度占满父容器再怎么设置display都改变不了这是个块的本质。而span、a、strong这类行内元素则完全相反它们不会自己换行多个行内元素可以肩并肩排在同一行里。所以想让一行文字里呈现两种字体思路就很清晰了整行文字保持正常的段落结构把其中需要单独修饰的那几个字用span标签包裹起来然后给这个span单独设置CSS样式。span这个标签在设计上就是一个纯粹的样式挂载点它本身不带任何默认样式不换行、不加粗、不变色、不改字号完全是一张白纸你在CSS里给它写什么它就显示什么。这种方式背后其实是前端开发里一个很基础也很重要的思想HTML负责结构CSS负责表现。结构上立减20元和前后文字属于同一个句子、同一个段落只是这一小段文字在整个句子中有特殊的视觉需求于是我们用span给它一个局部身份标记再让CSS针对这个标记精准施力。值得一提的是有人会问能不能用strong、em这类标签代替span答案是可以但不推荐。strong有默认的加粗效果em有默认的斜体效果i也自带斜体这些默认样式会成为干扰因素。你可能只想换个字体结果发现文字被凭空加粗了还得再写一条font-weight: normal去抵消。所以在这个场景下最干净的工具就是span。2. 最少代码实现span加class是标准解法先看一个最基础的例子。假设我要在一段文字里让立减20元变成楷体、加粗、红色其余文字保持默认样式p新用户注册span classhighlight立减20元/span仅限今天。/p对应的CSS.highlight { font-family: 楷体, KaiTi, serif; color: #e63946; font-weight: 700; }就这么简单。拆开解释一下每个属性的作用font-family 用来指定字体。这里写了两层第一层是楷体第二层是KaiTi最后还有一个通用族serif。浏览器在渲染时会优先尝试排在前面的字体如果用户电脑上没有楷体就尝试KaiTi也就是楷体的英文名称如果依然找不到就使用系统默认的衬线字体。color 控制文字颜色这里用了十六进制色值#e63946一种偏醒目的红色。font-weight 控制字重700等同于bold加粗效果。如果需要单独放大部分文字的字号也很简单再加一个font-size属性就行.highlight { font-family: 楷体, KaiTi, serif; font-size: 18px; color: #e63946; font-weight: 700; }这段代码的效果就是同一行里前后普通文字保持默认大小被span包裹的部分变成更大一号的红色楷体加粗字。这个方案从代码量、维护成本、可读性三个角度衡量都是最均衡的。关于class命名我有一个非常实际的建议尽量用语义化的单词比如highlight、discount、em-text不要用red-font、big-size这类基于视觉效果命名的类。原因很现实页面做久了需求变来变去今天红色加粗的重点下个月可能改成了蓝色下划线。如果你的class叫red-font到时候样式改了但类名还在新接手代码的人看到red-font却对应着蓝色样式心里肯定会骂人。highlight这种词就不会有这个问题因为重点这个含义是稳定的。平时调试的时候偶尔图省事直接用内联样式p新用户注册span stylefont-family: 楷体; color: red; font-weight: bold;立减20元/span仅限今天。/p功能上确实能实现但我强烈不建议在生产环境长期这么干。原因有两个一是内联样式的优先级高于外部CSS一旦这个span需要修改样式你会发现外部CSS写什么都没效果只能去HTML文件里翻内联代码二是如果有七八处地方都需要同一个强调样式内联写法就得复制七八遍后期要统一改字体时得一个地方一个地方去改。用class的话改一处CSS所有引用这个class的元素全部同步更新。3. 不只是换字体同一行内还能控制哪些样式维度span加class这套方案本质上是局部样式覆盖它可控制的维度远不只有字体。页面里大量一行文字两种视觉效果的需求其实都是同一个套路。3.1 多个span在一行内混排一行文字里可以同时出现多处特殊样式每一处都可以拥有独立的classp普通文字 span classa重点A/span 继续普通 span classb重点B/span 结束。/p.a和.b两个类可以各自定义不同的字体、颜色、字号互不影响。这种多重点混排的形式在电商活动文案里很常见比如下单立减50元叠加优惠券再省20元两个优惠信息在视觉上各有侧重。3.2 嵌套span实现基础统一、局部强调还有一种更精细的需求整段文字是同一个字体但其中某个词还要额外变色加粗。这时候用嵌套span最合适pspan classouter外层字体效果span classinner这里是红色强调/span继续外层效果。/span/p.outer { font-family: 微软雅黑, Microsoft YaHei, sans-serif; font-size: 14px; } .inner { color: #e63946; font-weight: 700; }这里有个很重要的CSS知识点继承机制。inner没有设置font-family和font-size它会自动继承外层outer的字体和字号我们只需要在内层写需要和父级不同的属性即可。这种父级管基础子级管差异的写法比把每个span的属性都完整写一遍要干净得多。3.3 字号不同时的基线对齐问题当同一行里字号不同会遇到一个视觉细节问题比如一行里有14px的文字和20px的文字它们默认并不是垂直居中对齐的而是按文字基线对齐。直观感受就是大号字上下都突出底部和小号字对齐这在设计稿上经常会显得不整齐。解决办法是给字体较大的span加上vertical-align属性.big { font-size: 20px; vertical-align: middle; }vertical-align可以取top、middle、bottom、baseline等值也可以指定具体的像素值。我在做移动端底部导航栏的时候经常用这个方案图标和文字并排居中就是靠vertical-align来解决的对齐问题。3.4 中英文混排的字体处理技巧还有一个常见需求一行文字里中文和英文混在一起想让中文和英文用不同的字体。很多人第一反应是分别用两个span包起来其实可以利用font-family的字体匹配机制完全不需要分开处理。CSS渲染文字时是逐字符匹配字体的。英文和数字会优先使用字体栈里靠前的西文字体中文部分则会在字体栈里自动找到第一个包含中文字符的字体。比如这样写.mixed { font-family: Times New Roman, 仿宋, FangSong, serif; }实际效果就是这句文字里的英文和数字用Times New Roman渲染中文则落到仿宋上。这种中英文天然分字体的效果在正式文档排版里非常实用而且完全不用额外嵌套标签。4. 实操记录字体设置不生效的常见原因和排查思路这部分内容是我在反复使用这个方案过程中攒下来的经验很多问题看起来莫名其妙实际原因都逃不过下面这几类。4.1 写了CSS但字体就是不变大概率是选择器和优先级问题最容易出问题的两个点要么是class名字拼写不一致HTML里写的是highlightCSS里写的是highligh少了一个t样式肯定不生效要么是样式被更高优先级的选择器覆盖了比如父元素用了id选择器或者CSS里用了!important。排查方法非常简单打开浏览器开发者工具选中那段文字在Styles面板里往下翻找到font-family一栏浏览器会明确告诉你这个属性值来自哪条规则、被哪条规则覆盖。把有疑问的规则一条条勾掉来验证很快就能定位问题。4.2 span是行内元素设置width和height无效是正常现象很多新手会给span写width和height发现怎么都不生效还以为代码有错。实际上行内元素默认不参与块级盒模型的尺寸计算它的宽高由内容撑开直接给width、height赋值是无效的。如果想让它具备宽高能力需要先把display改成inline-block但在一行文字内改字体这个场景中基本用不到这个能力。4.3 字体在不同平台上表现不一致需要设置多级回退字体跨平台差异是整个方案里最让人头疼的问题。Windows上常见的宋体微软雅黑macOS上并没有macOS上的苹方Windows上也不存在。如果一个系统中不存在你指定的字体浏览器就会尝试字体栈里的下一个最后会使用系统默认的通用类型。所以写font-family时一定要至少准备三层备选西文字体、中文字体、通用类型。通用类型推荐用serif衬线字体或sans-serif无衬线字体作为兜底这样可以确保任何操作系统都能找到可用字体最多只是视觉上略有差异但不会出现方块乱码。4.4 继承导致的字体上相互覆盖CSS的继承机制让span在未设置font-family时自动使用父级字体但这也会带来一种错觉明明在父级设置了字体span里也设置了字体结果发现显示的还是父级的。检查思路是确认哪条规则的优先级更高内联样式高于class选择器class选择器高于继承值。如果你在span里写了自己的字体但没生效先检查是不是有更高优先级的选择器或内联样式存在。4.5 移动端的特殊建议别指望字体差异多用字重和颜色移动端和PC端的字体生态很不一样。iOS和Android上的中文字体种类有限你写了某个字体名系统找不到就直接回退默认字体。所以在移动端想做出同一行两种字体的视觉效果靠字体名差异的效果往往很不明显用户感知不到。更有效的做法是拉开视觉差距用font-weight 300和700形成明显的粗细对比用不同的文字颜色、加下划线、改字号来形成差异。实操下来移动端方案设计中字重差异比字体差异的感知度强得多。5. 进阶玩法伪元素、CSS变量和动态切换样式基础方案掌握之后还有几个能让代码更整洁、更灵活的进阶思路。5.1 用伪元素避免额外标签如果既不想改动HTML结构又想实现部分文字的视觉差异化可以使用伪元素。比如在某个价格后追加一段特殊样式的文字.price::after { content: 限时特惠; font-family: 楷体, KaiTi, serif; font-weight: 700; color: #e63946; }这种方式的优点是完全不动HTML特别适合后端渲染页面时不想处理内部标签的场景。但它有一个明显代价content里的文字不属于文档实际内容用户在页面上能看到但无法复制也会影响屏幕阅读器的识别效果对SEO和可访问性有轻微削弱。所以这个方案我只在特定场景用常规文案依然推荐span。5.2 用CSS变量统一管理字体栈如果项目里有多处一行内混排字体的需求字体栈重复写会显得很啰嗦。这时候可以抽成CSS变量:root { --font-main: 微软雅黑, Microsoft YaHei, sans-serif; --font-em: 楷体, KaiTi, serif; } .special { font-family: var(--font-em); } .normal { font-family: var(--font-main); }这样后续要统一替换字体只需要改变量定义那一处不用满项目里找class。页面规模稍大一些时这种写法的维护收益非常明显。5.3 用classList切换样式实现动态变化如果需要根据用户操作动态改变某个词的样式比如点击后从普通变成加粗红色最好的方式不是手动拼接style字符串而是切换classbutton idtoggle切换样式/button p这是一段span idtarget重点文字/span后面的正文。/pconst btn document.getElementById(toggle); const target document.getElementById(target); btn.addEventListener(click, function() { target.classList.toggle(active); });然后在CSS里定义.active { font-weight: 700; color: #e63946; font-family: 楷体, KaiTi, serif; }用classList.toggle的好处是不会污染元素原有的其他样式切换一次加一个class再切换一次删掉默认样式和激活样式之间互不干扰。这是我做前端交互时比较推荐的方式。5.4 网络字体加载的性能提醒如果项目使用了网络字体库要注意字体文件大小对页面加载的影响。中文字体文件通常有几MB和西文字体几个KB的体积完全不在一个量级。字体没加载出来时页面文字会先以系统字体显示加载完成后突然变成目标字体就会出现文字闪变的现象。处理这个问题需要用到font-display属性或者CSS字体加载API保证字体未加载期间以合理的方式降级展示。为了几个字的不同字体效果而引入几MB的网络字体本身就需要评估性能成本动不动就把整个字体库全量引进来是每个前端新手最容易踩的性能坑之一。这个需求我在实际项目里碰到的频率非常高做页面基本上每周都会用到。心得就一条结构上用span做局部标记样式上用语义化class管理细节上注意跨平台字体回退和继承覆盖。用顺手了之后整个流程可以做到无缝衔接从接到需求到写完代码不需要一分钟。最后分享一个小技巧如果你的项目里大量出现强调某几个字的需求可以提前准备几个预置的工具类比如.strong用于加粗变色的强调文字.price用于价格数字的特殊样式.tag用于小标签风格。写页面的时候直接套类名不用再重复编写CSS定义。很多看起来高大上的前端细节基础解决方案其实都简单得很真正拉开差距的是思路熟练度和代码组织的习惯。
阅读完成 · 觉得有帮助?