Selenium如何获取Rendered Fonts板块中的实际渲染字体名称
Selenium检测实际渲染字体实现方案
Selenium原生的element.getCssValue("font-family")只能读取CSS中声明的字体栈配置,无法拿到浏览器排版后实际生效的渲染字体,要获取DevTools Elements面板Computed标签下Rendered Fonts板块的内容,直接调用Chrome DevTools Protocol(CDP)对应接口即可,返回数据和DevTools展示的内容完全一致。
核心原理
Rendered Fonts板块的所有数据来自CDP暴露的CSS.getPlatformFontsForNode接口,传入目标DOM节点的ID,就能直接返回该节点文本渲染时实际调用的所有系统字体列表,字体加载失败触发fallback的情况会被完整记录。
注意:不存在Rendered Fonts板块完全无条目的场景,只要元素可见、参与页面排版,该区域一定会展示最终生效的渲染字体。你需要校验的是列表中是否存在非预期的替代字体(比如Times New Roman),而非判断列表是否为空。
Java代码实现(Selenium 4+ 原生支持,无需额外依赖)
import org.openqa.selenium.WebElement; import org.openqa.selenium.chrome.ChromeDriver; import java.util.HashMap; import java.util.List; import java.util.Map; public class FontCheckUtil { /** * 检测元素实际渲染字体,存在非预期 fallback 时抛出错误 * @param driver ChromeDriver实例(Edge等Chromium内核浏览器通用) * @param target 待检测的页面元素 * @param expectedFont 预期生效的字体名称 */ public void assertNoFontFallback(ChromeDriver driver, WebElement target, String expectedFont) { // 1. 获取目标元素在CDP中的nodeId Map<String, Object> evalParams = new HashMap<>(); evalParams.put("expression", "arguments[0]"); evalParams.put("objectGroup", "font-check"); evalParams.put("includeCommandLineAPI", Boolean.TRUE); Map<String, Object> evalArgs = new HashMap<>(); evalArgs.put("0", target); evalParams.put("arguments", List.of(evalArgs)); Map<String, Object> evalResult = driver.executeCdpCommand("Runtime.evaluate", evalParams); String objectId = (String) ((Map<String, Object>) evalResult.get("result")).get("objectId"); Map<String, Object> nodeReqParams = new HashMap<>(); nodeReqParams.put("objectId", objectId); Map<String, Object> nodeResult = driver.executeCdpCommand("DOM.requestNode", nodeReqParams); Number nodeId = (Number) nodeResult.get("nodeId"); // 2. 拉取实际渲染字体列表 Map<String, Object> fontQueryParams = new HashMap<>(); fontQueryParams.put("nodeId", nodeId); Map<String, Object> fontResult = driver.executeCdpCommand("CSS.getPlatformFontsForNode", fontQueryParams); List<Map<String, Object>> renderedFonts = (List<Map<String, Object>>) fontResult.get("fonts"); // 3. 校验逻辑 for (Map<String, Object> font : renderedFonts) { String actualFamily = (String) font.get("familyName"); if (!expectedFont.equals(actualFamily)) { throw new AssertionError(String.format( "检测到字体替代渲染:预期字体%s未正常加载,实际生效字体为%s", expectedFont, actualFamily )); } } } }
使用注意事项
- 必须等页面字体加载流程完成(含浏览器字体加载超时触发fallback的时间)后再调用检测方法,否则会拿到加载中间态的错误结果
- 不要对
display:none、visibility:hidden等脱离排版流的隐藏元素做检测,这类元素不会触发字体排版计算,返回结果无效 - 如果使用Firefox浏览器,需要替换为对应版本的Marionette协议接口,逻辑一致仅接口命名有差异
内容的提问来源于stack exchange,提问作者S P
相关产品推荐
相关产品推荐

