【问题标题】:SVG Text bounding box is different from browser to browser when using @font-face?使用@font-face 时,SVG 文本边界框因浏览器而异?
【发布时间】:2022-01-27 19:41:16
【问题描述】:

我正在尝试通过使用 getBBox() 方法获取边界框来根据文本的宽度和高度放置一个 SVG 文本元素。

如果文本使用网络安全字体,这在不同的浏览器中运行良好,但如果文本使用@font-face 和自定义网络字体设置样式,则在 Firefox (Mac) 中返回的文本宽度不正确和 Safari (iOS)。 它在 Safari (Mac) 和 Chrome (Mac) 中都能完美运行。

如果灰色框与文本的宽度相同,则它可以在该浏览器中使用。

有人知道如何在所有浏览器中获得正确的文本边界框宽度吗?

【问题讨论】:

    标签: text svg cross-browser font-face bounding-box


    【解决方案1】:

    浏览器在完成加载/应用@font-face之前正在计算边界框,假设你不需要IE,你可以将你的BBox计算函数包装在document.fonts.ready promise中...

    document.fonts.ready.then(() => const bbox = textEl.getBBox());
    

    这是一个展示问题和解决方法的工作示例:

    const xmlns = "http://www.w3.org/2000/svg";
    const correct = document.getElementById("correct");
    const incorrect = document.getElementById("incorrect");
    
    visualizeBBox(incorrect);
    document.fonts.ready.then(()=> visualizeBBox(correct));
    
    
    function visualizeBBox(el){
      const bbox = el.getBBox();
      const rect = document.createElementNS(xmlns, "rect");
      for (prop in bbox) rect.setAttribute(prop, bbox[prop]);
      document.querySelector("svg").appendChild(rect);
    }
    svg text {
      font-family: 'Diplomata SC', serif;
    }
    
    svg rect {
       stroke: red;
       fill: none;
    }
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Diplomata+SC&display=swap" rel="stylesheet">
    
    <svg xmlns="https://www.w3.org/2000/svg" width="600" height="400">
      <text x="0" y="40" font-size="24" id="correct">Correct dimensions</text>
      <text y="100" font-size="24" id="incorrect">Incorrect dimensions</text>
    <svg>

    【讨论】:

    • 感谢您的建议!实际上我今天早些时候有完全相同的想法,所以我已经将该测试添加到示例中并且它有效!
    • @MadsBuchStage 用更强大的解决方案更新了这个答案
    【解决方案2】:

    今天我遇到了类似的问题。 Duopixel 是正确的,getBBox() 可能会返回可能出乎意料的矩量度,因为尚未加载外部字体,而是使用了一些标准字体。

    WebKit 中的问题(在 Chrome 24.0.1312.52 和 26.0.1389.0 canary 中测试)是浏览器延迟外部字体加载,直到它首次在页面上的任何位置有效使用。因此,即使您等待 onreadystatechange 变为“完成”,您也不能保证在调用 getBBox() 时准备好字体指标 - 您可能仍然是第一个渲染带有外部字体样式的文本,将其插入文档并立即调用的人getBBox() 就可以了(我的情况)。

    我的解决方法不是直接调用 mySVGInitCode():

    $("body").append(
      $("<div/>")
        .attr("class", "force-external-font-loading")
        .attr("style", "font-family: \"xkcd\";visibility:hidden;position:absolute")
        .text("x")
      );
    setTimeout(function(){ mySVGInitCode() }, 100); // 100ms is just arbitrary waiting time which should be sufficient for fetching the external font on a fast network, anyone has a better solution?
    

    如您所见,我动态插入绝对定位的样式文本以强制加载外部字体(可见性:隐藏在这里很重要,而不是显示:无)。然后,我等待一段时间,然后执行我的 SVG 代码,该代码可能会呈现某些内容,然后立即询问指标。

    【讨论】:

      猜你喜欢
      • 2012-03-20
      • 2018-12-24
      • 2012-10-15
      • 2017-08-25
      • 2015-04-25
      • 2016-10-13
      • 1970-01-01
      • 2012-06-12
      • 2013-01-25
      相关资源
      最近更新 更多