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

JavaFX桌面应用替换HTML响应CSS后ProximaNova字体不生效问题排查

JavaFX WebView加载自定义CSS字体失效问题排查

问题描述

我正在开发基于JavaFX的桌面应用,其中一个界面的部分内容通过PHP接口返回的HTML加载。目标是将HTML响应中的CSS文件替换为自定义CSS文件,目前所有样式属性均已生效,但@font-face引入的ProximaNova.woff字体无法应用。


相关代码

HTML响应

<html subtitle="Please type your activation code in the text box below and click 'Next'.  ">
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>promotion activation</title>
    <link type="text/css" rel="stylesheet" href="promotion.css" />
    
    <script>
        window.addEventListener("load", function() {
                var evt = document.createEvent("Events");
          evt.initEvent("TTUpdateButton", true, false);
         document.documentElement.dispatchEvent(evt);
        }, true);
    </script>
</head>
<body>
            <button id="TTButton_continue" disabled="true"
            onclick="onButtonEvent('right')"
            style="display: none;">
        Next            </button>
                    <div id="code-body">
    <div id="code-box">
        <form name="fcode" id="code-fcode" method="post" onsubmit="return isCodeValid();">
            <input type="hidden" name="action" value="validate" />
            <div id="code-textbox">
                <span>
                    Your activation code                        </span>
                <input
                       class="field"
                       type="text"
                       name="sCode"
                       id="code"
                       value=""
                       onchange="onInputChange();"
                       onkeyup="onInputChange();"
                />
            </div>
        </form>

        
        <div id="code-text">
           As soon as you activate your code, the associated product will be available for download and/or use.<a href=# onClick="Javascript:onMoreInfoLinkClick()">Learn how you can get your activation code here.</a>                </div>
    </div>
</div>

<script type="text/javascript">
    if (document.fcode)
    {
        document.fcode.sCode.focus();
    }

    var initialCodeValue = "";
    
    function isCodeValid()
    {
        var theRawValue = document.fcode.sCode.value;
        
        // Don't enable the next button if nothing has changed
        if (theRawValue == initialCodeValue)
            return false;
        initialCodeValue = "";

        theUpperCaseValue = theRawValue.toUpperCase(); //we need first to clean the input like we do server side

        theValue = (theUpperCaseValue.replace(/\W+/g,''));
        return (theValue.search(/^[a-zA-Z0-9]{11}$|^NC[0-9]{10}$|^CC[0-9]{16}$/) == 0);
    }
    
    function writeScriptOpenTomTomHelpLink()
    {
        var evt = document.createEvent("Events");
           evt.initEvent("TTHelpLink", true, false);
           document.documentElement.dispatchEvent(evt);
    }
    function onMoreInfoLinkClick(){
        writeScriptOpenTomTomHelpLink();
    }
    
    function onInputChange()
    {
        var valid = isCodeValid();
        var theButtonElement = document.getElementById("TTButton_continue");
        if (valid)
            theButtonElement.removeAttribute("disabled");
        else
            theButtonElement.setAttribute("disabled", true);
            var evt = document.createEvent("Events");
 evt.initEvent("TTUpdateButton", true, false);
      document.documentElement.dispatchEvent(evt);
    }
    
    function onButtonEvent(buttonName)
    {
        document.fcode.submit();
    }
    
    window.addEventListener("load", onInputChange, false);
</script>

    </body>
</html>

自定义替换CSS文件(MyActivationCode.css)

@font-face {
    font-family: "proxima";
    src: url('/proximanova-regular.woff');
}

body {
    font-family: "proxima"; 
    background: #ffffff;
    color: #000000;
    font-size: 13px;
}

h1 {
    font-family: proxima;
    font-weight: bold;
    font-size: 13px;
    color: #666666;
}

.additional-offer {
    border-top: 3px #dedede solid;
}

.select-country, .select-product {
    padding: 5px 10px 15px 10px;
}

#code-text {
    margin: 5px 2px 5px 2px;
    font-family: proxima;
}

#code-textbox {
    font-family: "proxima";
    margin: 20px 0px 20px 0px;
    color: #878787;
}

#code-textbox span {
    font-family: proxima;
    font-size: 13px;
    font-weight: bold;
    color: #666666;
}

#code-fcode {
    display: table-row;
    text-align: center;
    height: 100%;
}

#code-error {
    color: #ff0000;
    margin: 0px 2px 5px 2px;
    font-family: proxima;
}

#traffic-error {
    color: #ff0000;
    margin: 0px 2px 5px 2px;
    font-family: proxima;
}

#message-text {
    margin: 5px 2px 5px 2px;
    font-family: proxima;
}

#message-header {
    font-family: proxima;
    margin: 20px 0px 20px 0px;
    font-weight: bold;
    font-size: 13px;
    color: #666666;
}

DeviceController.java(发起PHP接口请求)

public class DeviceController extends BaseController {

    @Override
    protected void doInitialize() {
        super.doInitialize();
       
        getActivePhpServiceCall();
       
    }

    /**
     * Gets the active php service call.
     *
     * @return the active php service call
     */
    protected void getActivePhpServiceCall() {
        new ActivationService().activationCodeService(new FutureCallback<String>() {

            @Override
            public void failed(Exception ex) {
                LOGGER.error("Failed to call Activation code service: {}", ex);
              

            }

            @Override
            public void completed(String result) {
                new ActivationCodeHelper().handleBackForActivationCodeService(result);
            }

            @Override
            public void cancelled() {
                LOGGER.debug("Activation code service call is cancelled");
            }
        });
    }
}

ActivationCodeHelper.java(替换CSS文件逻辑)

public class ActivationCodeHelper extends BaseHelper {

    /**
     * Handle back for activation code service.
     *
     * @param result the result
     */
    public void handleBackForActivationCodeService(String result) {
        Map<String, Object> map = new HashMap<>();

        
            String cssURL = "";
            try {
                cssURL = globalContext.fileUtil().getFileContents(Paths
                        .get(getClass().getClassLoader().getResource("css/MyActivationCode.css").toURI()).toString());
            } catch (URISyntaxException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(cssURL.toString());

        
            File cssFile = globalContext.fileUtil().fileWriter(".css", cssURL);
            File file = globalContext.fileUtil().fileWriter(".html",
                    result.replaceAll("promotion.css", cssFile.getName()));
            map.put("cssFile", cssFile.getName());
            map.put("UseMyActivation", file.toURI().toString());
            redirectToActivationScreen(map);

    }
    
}

字体失效原因及修复方案

核心原因

  1. 字体路径错误:CSS中url('/proximanova-regular.woff')使用了根路径(以/开头),但生成的HTML和CSS是临时文件,JavaFX WebView无法识别这个根路径对应的实际文件位置。
  2. 字体文件未同步到临时目录:代码仅生成了HTML和CSS临时文件,但没有将字体文件复制到同一目录,导致WebView找不到字体资源。
  3. 相对路径引用错误:未使用和临时文件目录匹配的相对路径指向字体文件。

修复步骤

  1. 复制字体文件到临时目录
    在ActivationCodeHelper的handleBackForActivationCodeService方法中,添加代码将字体文件复制到CSS和HTML所在的临时目录:

    // 假设字体文件放在resources/fonts目录下,根据实际路径调整
    URL fontResource = getClass().getClassLoader().getResource("fonts/proximanova-regular.woff");
    if (fontResource != null) {
        try {
            File fontFile = new File(cssFile.getParentFile(), "proximanova-regular.woff");
            Files.copy(Paths.get(fontResource.toURI()), fontFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException | URISyntaxException e) {
            e.printStackTrace();
        }
    }
    
  2. 修改CSS中的字体路径
    将@font-face中的路径改为相对路径(因为字体和CSS在同一目录):

    @font-face {
        font-family: "proxima";
        src: url('proximanova-regular.woff');
    }
    
  3. 验证文件位置一致性
    确保生成的HTML、CSS、字体三个文件都处于同一临时目录下,WebView才能正确加载字体资源。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 15:17:41