打印特定HTML元素时Chrome/Edge不显示logo,Firefox正常求助
问题:Chrome和Edge打印特定元素时Logo不显示
我需要实现一个点击后调用window.print()打印包含Logo的特定HTML元素的功能。目前Firefox中点击链接时Logo正常显示,但Chrome和Microsoft Edge里Logo不显示;直接打印整个document body时,三个浏览器都能正常显示Logo。求解决Chrome和Edge中该元素打印时Logo不显示问题的方向。
TestPage.jsp
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%> <%@ taglib uri="/WEB-INF/anti_csrf.tld" prefix="anti_csrf" %> <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1"> <title><spring:message code="Common.Info1.ApplicationName" text="Common.Info1.ApplicationName"/></title> <link rel="stylesheet" href="<c:url value="/resources/css/main.css"/>"/> <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.0-rc.2/themes/smoothness/jquery-ui.css" title="no title" charset="utf-8"> <link rel="stylesheet" href="<c:url value="/resources/css/spinner.css"/>"/> </head> <body> <div>Some Text</div> <div>Some Text</div> <div>Some Text</div> <div><select class="form-control" id="yy" name="yy" onChange="actionRefresh()"> <c:forEach var="i" begin="1" end="21" step="1"> <option value="i" selected>${i+1}</option> </c:forEach> </select> </div> <div class="row form-element-margin"> <div class="col-sm-11"> </div> <div class="col-sm-1"> <a href="#" onclick="printDiv('generateData')"><i class="fa fa-print fa-2x" aria-hidden="true"></i></a> </div> <div style="font-family: Arial, Helvetica, sans-serif;font-size: 10pt;" id="genericData"> <div style="font-family: Arial, Helvetica, sans-serif;font-size: 10pt;" class="row form-element-margin"> <div class="col-sm-12 col-xs-12 txt_right"> <c:if test="${not empty requestScope.logo}"> <label class="header"><img height="35" src="<c:url value="/resources/assets/${requestScope.logo}" />"/></label> </c:if> </div> <div class="col-xs-12 col-sm-4"> </div> <div class="col-sm-4 text-center"> <label class="header" ><b><c:out value="${requestScope.ReportTitle1}" /></b></label></br> <label class="header"><b><c:out value="${requestScope.ReportTitle2}" /></b></label> </div> </div> </div> <div>Some more text</div> <script src="<c:url value="/resources/js/Testmenu.js" />"></script> </body> </html>
Testmenu.js
function printDiv(divName) { var printContents = document.getElementById(divName).innerHTML; var originalContents = document.body.innerHTML; document.body.innerHTML = printContents; window.print(); document.body.innerHTML = originalContents; }
解决方向
问题根源在于你直接替换document.body.innerHTML的方式:Chrome和Edge的打印渲染引擎在这种快速DOM替换场景下,不会等待图片资源重新加载完成就触发打印,导致Logo无法显示。可以从以下几个方向修复:
1. 使用隐藏iframe打印
创建隐藏iframe,把要打印的内容复制到iframe中,等待iframe加载完成后再打印,确保资源全部加载:
function printDiv(divName) { var printContents = document.getElementById(divName).innerHTML; var iframe = document.createElement('iframe'); iframe.style.display = 'none'; document.body.appendChild(iframe); var doc = iframe.contentDocument || iframe.contentWindow.document; doc.open(); // 复制原页面样式,保证打印效果一致 var styleHtml = ''; document.querySelectorAll('link[rel="stylesheet"], style').forEach(style => { styleHtml += style.outerHTML; }); doc.write(` <html> <head>${styleHtml}</head> <body>${printContents}</body> </html> `); doc.close(); iframe.onload = function() { iframe.contentWindow.print(); document.body.removeChild(iframe); }; }
2. 用CSS控制打印可见性
不修改DOM结构,通过打印媒体查询只显示目标元素,其他元素隐藏:
首先添加CSS:
@media print { body * { visibility: hidden; } #genericData, #genericData * { visibility: visible; } #genericData { position: absolute; left: 0; top: 0; } }
然后修改打印函数:
function printDiv() { window.print(); }
这种方式浏览器会正常加载已存在的所有资源,包括Logo。
3. 强制等待图片加载完成
如果坚持使用原有的替换body方式,可在替换后等待所有图片加载完成再打印:
function printDiv(divName) { var printContents = document.getElementById(divName).innerHTML; var originalContents = document.body.innerHTML; document.body.innerHTML = printContents; var imgs = document.querySelectorAll('img'); var loadedCount = 0; function checkAllLoaded() { loadedCount++; if (loadedCount === imgs.length) { window.print(); document.body.innerHTML = originalContents; } } if (imgs.length === 0) { window.print(); document.body.innerHTML = originalContents; return; } imgs.forEach(img => { if (img.complete) { checkAllLoaded(); } else { img.onload = checkAllLoaded; img.onerror = checkAllLoaded; // 处理加载失败情况 } }); }
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

