CSS打印设置页眉页脚

之前写过一篇文章CSS实现自动分页打印同时每页保留重复的自定义内容,可以实现window.print()打印时多张页面保留相同的内容(如header、footer),但其并不是真正意义上的页眉页脚,footer内容在最后一张页面未撑满时不能置于页面底部。为了实现打印使用CSS自定义页眉页脚,解决之前遗留的问题,本文对之前的办法做了改进,提出了一种解决方案。

效果图

基本原理

  1. 在要打印的内容中,页眉页脚元素使用position: fixed,并设定各自的高度。
  2. 正文内容使用table元素,table的开头(thead)和结尾(tfoot)各使用一个设定高度(大于等于页眉页脚高度)的空DOM元素,防止页眉页脚与正文内容重叠。

此时即可实现自定义页眉页脚,调用window.print()时多张页面具有相同的页眉页脚,且页眉页脚可自定义内容,包括插入logo等图片。

示例代码

只打印指定dom内容,要打印的内容在#printDom中,页面在非打印模式不会显示其内容,只有在点击打印按钮调用window.print()时才会显示打印内容。

下方两个示例代码一样,根据个人阅读方式喜好查看。

示例代码-github:github

示例代码:

html 复制代码
<html>
  <head>
    <title>print demo</title>
    <meta name="description" content="CSS打印,支持自定义页眉页脚" />
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
    <meta
      name="viewport"
      id="WebViewport"
      content="initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
    />
    <style>
      @media print {
        @page {
          size: A4 portrait;
          /* 调整页边距 */
          margin: 1cm 1cm 1cm;
        }

        #printDom {
          display: block !important;
        }
      }

      #printDom {
        /* 打印区域在非打印时不显示 */
        display: none;
        position: relative;
        font-size: 16px;
        font-family: SimSun, Songti SC;
      }

      #printDom .page-header {
        /* 页眉高度 */
        height: 2cm;
        display: flex;
        align-items: center;
        position: fixed;
        top: 0mm;
        width: 100%;
        border-bottom: 1px solid #ddd;
        z-index: 2000;
      }

      #printDom .page-header-space {
        /* 控制内容区距离顶部的距离,防止与页眉重叠 */
        height: 2cm;
      }

      #printDom .page-footer {
        /* 页脚高度 */
        height: 1cm;
        position: fixed;
        bottom: 0;
        width: 100%;
        border-top: 1px solid grey;
        z-index: 2000;
      }

      #printDom .page-footer-space {
        /* 控制内容区距离底部的距离,防止与页脚重叠 */
        height: 1.5cm;
      }

      #printDom > table {
        width: 100%;
      }
      
      #printDom .content table {
        width: 100%;
        font-size: 30px;
      }

      #printDom .content .header {
        text-align: center;
      }
    </style>
  </head>
  <body>
    <button onclick="handlePrint()">打 印</button>
    <div id="printDom">
      <!-- 页眉 -->
      <div class="page-header">Logo</div>
      <table>
        <!-- 占位,给页眉留出位置 -->
        <thead>
          <tr>
            <td><div class="page-header-space"></div></td>
          </tr>
        </thead>
        <!-- start: 正文 -->
        <tbody>
          <tr>
            <td>
              <div class="content">
                <!-- 正文的标题 -->
                <h1 class="header">H1</h1>
                <div>
                  <!-- 正文内容,可随意写,demo是表格 -->
                  <table>
                    <thead>
                      <tr>
                        <td>Index</td>
                        <td>Name</td>
                      </tr>
                    </thead>
                    <tbody id="tableBody">
                    </tbody>
                    <tfoot></tfoot>
                  </table>
                </div>
              </div>
            </td>
          </tr>
        </tbody>
        <!-- end: 正文 -->
        <!-- 占位,给页脚留出位置 -->
        <tfoot>
          <tr>
            <td><div class="page-footer-space"></div></td>
          </tr>
        </tfoot>
      </table>
      <!-- 页脚 -->
      <div class="page-footer">Footer</div>
    </div>

    <script>
      /**
       * 打印指定元素
       * @param {string} element 需要打印的元素选择器
       */
      function printElement(element) {
        var printContents = document.querySelector(element).cloneNode(true);
        
        var popupWin = window.open('', '_blank');
        popupWin.document.open();
        
        const styles = document.head.innerHTML;
        popupWin.document.write(`<html><head><title>Print Title</title>${styles}</head><body οnlοad="window.print(); window.close();">`);
        popupWin.document.body.appendChild(printContents);
        popupWin.document.write('</body></html>');
        
        popupWin.document.close();
      }

      function handlePrint() {
        printElement('#printDom');
      }

      const tempTableData = document.querySelector('#tableBody');
      const tempFragument = document.createDocumentFragment();

      // mock data
      for (let i = 0; i < 30; i++) {
        const _tr = document.createElement('tr');
        const _td1 = document.createElement('td');
        _td1.appendChild(document.createTextNode(`No${i + 1}`));
        const _td2 = document.createElement('td');
        _td2.appendChild(document.createTextNode(new Date().getTime()));
        _tr.appendChild(_td1);
        _tr.appendChild(_td2);
        tempFragument.appendChild(_tr);
      }

      tempTableData.appendChild(tempFragument);
    </script>
  </body>
</html>
相关推荐
jay神3 分钟前
基于 YOLOv8 的轴承缺陷检测(Web 版)
前端·人工智能·yolo
jay神11 分钟前
基于 YOLOv8 的森林火灾检测系统(Web 版)
前端·yolo
code2cat16 分钟前
HTML基础篇之第一张网页:从index.html到浏览器里的任务清单
前端·html
miss1 小时前
AI 改完不敢上线?OpenSpec 规约驱动开发实战
前端·代码规范·前端工程化
AiMan2 小时前
腾讯ima还是不可以导出左侧所有对话,只能单条导出,方法不对吗
前端
去伪存真2 小时前
并发量一高就装死?Agent 全链路“防猝死”手册
前端·agent
Moment2 小时前
AI 编程时代,聊聊我的 Mac mini 双屏桌面
前端·后端
AiMan2 小时前
先确认能不能一次把Microsofat Copilot所有内容打包一个文件导出
前端
总要学点什么2 小时前
第97篇:三维数据加载-城市建筑白模自定义着色器——让一条光带沿高度扫上去,快慢却由帧率说了算
前端·gis·webgl·cesium·着色器·空间分析·白模
上海懒图科技2 小时前
工厂厂区电子地图定位导航:厂区人车精准定位,安全合规双保障
前端·arcgis·vue