You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何macOS 14中HTML创建NSAttributedString与initWithString:attributes:行为不同?

macOS 14下NSAttributedString HTML转换特定字体显示方框问号问题

问题背景

允许用户选择已安装字体,在三个场景中使用:

  • 场景1:通过NSFontDescriptor创建NSAttributedString用于选项列表,功能正常
  • 场景2:将设置了body字体为所选字体的小型HTML转为NSAttributedString并显示在NSTextField,升级至macOS 14后完全失效,所有字符显示为带问号的方框
  • 场景3:在WKWebView中显示同字体的长HTML文档,功能正常

问题仅出现在Calibri、Candara(微软Office字体)、SF Pro等特定字体,即使CSS中设置了serif作为后备字体也无效——系统判定字体可用,但无法正常渲染。该问题为macOS 14新增,此前版本无异常。

问题分析

macOS 14中,NSAttributedString的HTML解析模块(基于旧版WebKit组件)在处理部分字体时存在匹配问题:

  1. 部分字体的显示名称与PostScript名称不匹配,解析器无法正确定位字体文件
  2. 对于包含字重/样式变体的字体(如bold、italic),解析器无法自动关联对应变体,导致找不到可渲染的字形,且未触发后备字体逻辑

解决方案

方案1:使用字体的PostScript名称替代显示名称

获取用户所选字体的PostScript名称(而非显示名称),替换HTML中font-family的值,确保解析器能精准定位字体:

// 假设用户选择的字体显示名称为selectedFontDisplayName
NSFont *selectedFont = [NSFont fontWithName:selectedFontDisplayName size:14];
NSString *postScriptName = selectedFont.fontDescriptor.postScriptName;

// 生成带PostScript名称的HTML
NSString *htmlString = [NSString stringWithFormat:@"<!DOCTYPE html>"
                        "<html>"
                        "<head>"
                        "<style>"
                        "body { font-family: '%@', serif; font-size: 14px; }"
                        "</style>"
                        "</head>"
                        "<body>"
                        "<p>Text with <b>bold</b> or <i>italics</i> maybe.</p>"
                        "</body>"
                        "</html>", postScriptName];

方案2:显式指定字体变体的CSS规则

针对HTML中的<b>、<i>标签,显式指定对应字体变体的名称,避免解析器自动匹配失败:

NSString *htmlString = @"<!DOCTYPE html>"
                        "<html>"
                        "<head>"
                        "<style>"
                        "body { font-family: 'Candara', serif; font-size: 14px; }"
                        "b { font-family: 'Candara Bold', serif; font-weight: normal; }"
                        "i { font-family: 'Candara Italic', serif; font-style: normal; }"
                        "</style>"
                        "</head>"
                        "<body>"
                        "<p>Text with <b>bold</b> or <i>italics</i> maybe.</p>"
                        "</body>"
                        "</html>";

注:需根据实际字体的变体名称调整(可通过Font Book查看字体的完整名称)

方案3:转换后手动替换字体属性

若前两种方案无效,可在HTML转换为NSAttributedString后,遍历并替换无法渲染的字体属性:

NSData *htmlData = [htmlString dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType,
                          NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)};
NSError *error;
NSMutableAttributedString *mutableAttrStr = [[NSAttributedString alloc] initWithData:htmlData
                                                                            options:options
                                                                 documentAttributes:nil
                                                                              error:&error].mutableCopy;

// 遍历替换无效字体
[mutableAttrStr enumerateAttribute:NSFontAttributeName 
                           inRange:NSMakeRange(0, mutableAttrStr.length) 
                           options:0 
                        usingBlock:^(id  _Nullable value, NSRange range, BOOL * _Nonnull stop) {
    NSFont *currentFont = value;
    if (!currentFont) return;
    
    // 检查当前字体是否为问题字体(可根据实际情况调整判断逻辑)
    NSArray *problemFontNames = @[@"Calibri", @"Candara", @"SF Pro"];
    if ([problemFontNames containsObject:currentFont.fontDescriptor.displayName]) {
        // 替换为用户选择的正确字体(保持原字号)
        NSFont *replacementFont = [NSFont fontWithName:selectedFontDisplayName size:currentFont.pointSize];
        if (replacementFont) {
            [mutableAttrStr addAttribute:NSFontAttributeName value:replacementFont range:range];
        }
    }
}];

// 使用mutableAttrStr更新NSTextField
[self.textField setAttributedStringValue:mutableAttrStr];

内容的提问来源于stack exchange,提问作者Craig

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 21:24:53