本文目录导读:

- 核心设计原则(避坑指南)
- 推荐技术方案:
window.print() - CSS 打印样式设计(关键)
- 如果打印排版乱了?试试“CSS 列计术”
- 进阶方案:使用
jsPDF+ 前端生成图片 - 常见问题排查记录(实战经验)
- 完整的示例模板(可以直接复制使用)
在PHP中设计打印票据(小票),主要分为页面设计(HTML/CSS) 和打印控制(JavaScript) 两部分,由于打印环境(热敏打印机/激光打印机)差异很大,设计时需要特别关注兼容性。
以下是一套完整的从设计到打印的方案,涵盖核心代码和避坑指南。
核心设计原则(避坑指南)
- 宽度固定:热敏纸通常为 58mm(约 384px)或 80mm(约 576px)。必须设置纸张宽度,否则排版会乱。
- 禁止缩放:打印时关闭“缩放以适应页面”,否则会出现页边距和白边。
- 颜色限制:热敏打印机基本只能打印黑白,不要依赖彩色区分内容。
- 字体兼容:打印时浏览器默认字体优先级最高,不要使用
Arial以外的特殊字体(除非嵌入字体文件),推荐使用 宋体(SimSun) 或 微软雅黑(Microsoft YaHei)。
推荐技术方案:window.print()
这是最通用的方案,不需要安装打印插件或驱动,直接调用浏览器打印功能。
前端 HTML 结构(关键:隐藏无关内容)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">小票打印</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<!-- 页面普通显示内容(用户看到的) -->
<div class="no-print">
<button onclick="doPrint()">🖨️ 打印小票</button>
<!-- 你的订单列表、页面导航等 -->
</div>
<!-- 打印区域(只有这个区域会被打印) -->
<div id="printArea" class="print-content">
<h2>XX超市</h2>
<p>电话:010-88888888</p>
<hr>
<p>单号:202403001</p>
<p>时间:2024-03-01 10:30:00</p>
<hr>
<!-- 商品列表 -->
<table>
<thead>
<tr>
<th>商品</th>
<th>数量</th>
<th>小计</th>
</tr>
</thead>
<tbody>
<tr><td>农夫山泉</td><td>1</td><td>¥2.50</td></tr>
<tr><td>康师傅泡面</td><td>2</td><td>¥8.00</td></tr>
</tbody>
</table>
<hr>
<p>合计:<strong>¥10.50</strong></p>
<p>实收:¥100.00</p>
<p>找零:¥89.50</p>
<hr>
<p class="footer">谢谢惠顾,欢迎再次光临!</p>
</div>
<script>
function doPrint() {
// 1. 备份当前页面body内容
var bodyContent = document.body.innerHTML;
// 2. 提取打印区域内容
var printContent = document.getElementById('printArea').innerHTML;
// 3. 替换body内容为打印区域(此时页面只显示小票)
document.body.innerHTML = printContent;
// 4. 调用系统打印
window.print();
// 5. 恢复页面内容
document.body.innerHTML = bodyContent;
}
</script>
</body>
</html>
CSS 打印样式设计(关键)
这是决定票据是否美观的核心。请将以下代码写入 style.css。
/* 默认隐藏打印区域(屏幕显示时) */
#printArea {
display: none;
}
/* 针对打印机的样式 */
@media print {
/* 隐藏不需要打印的元素 */
.no-print, button {
display: none !important;
}
/* 页面核心设置 */
@page {
/* 宽度:58mm = 1mm约3.8px,但建议直接设置百分比 */
/* 关键:纸张大小设置为 58mm 宽,高度自动 */
size: 80mm auto; /* 如果是58mm纸,改成 58mm auto */
/* 关键:必须设置为0,否则打印机默认加白边 */
margin: 0;
}
body {
/* 去除浏览器默认边距 */
margin: 0;
padding: 0;
/* 宽度设为 80mm 对应像素,约 306px (80 * 3.8) */
width: 306px;
font-family: '宋体', SimSun, monospace; /* 热敏打印专用 */
font-size: 12px;
color: #000;
background: #fff;
}
/* 打印显示区域 */
#printArea {
display: block;
width: 100%;
padding: 5px; /* 给一点内边距,防止文字贴边 */
box-sizing: border-box;
word-break: break-all; /* 防止长字符串溢出 */
}
/* 标题样式 */
#printArea h2 {
text-align: center;
font-size: 16px;
margin: 0 0 5px 0;
font-weight: bold;
}
#printArea p {
margin: 2px 0;
line-height: 1.5;
}
/* 分割线 */
#printArea hr {
border: none;
border-top: 1px dashed #000; /* 虚线,省钱且美观 */
margin: 5px 0;
}
/* 商品表格样式 */
#printArea table {
width: 100%;
border-collapse: collapse;
margin: 5px 0;
}
#printArea th {
text-align: left;
font-weight: bold;
border-bottom: 1px solid #000;
padding-bottom: 3px;
}
#printArea td {
padding: 1px 0;
vertical-align: top;
}
/* 对齐需求,左对齐商品,右对齐价格 */
#printArea td:first-child {
width: 50%;
}
#printArea td:last-child {
text-align: right;
}
/* 合计样式 */
#printArea .total {
display: flex;
justify-content: space-between;
font-weight: bold;
margin-top: 5px;
}
/* 底部公告 */
#printArea .footer {
text-align: center;
margin-top: 10px;
font-size: 10px;
}
}
如果打印排版乱了?试试“CSS 列计术”
如果用户使用一台没有安装驱动的打印机,或者显示器分辨率太高导致像素计算错误,我们可以使用 <div> 配合 table,或者使用 width:100%; max-width: 300px; 来强制适应纸张。
改进方案(懒人兼容法):
直接在 @media print 中,不用固定 306px,而是固定毫米单位:
@media print {
body {
width: 80mm; /* 直接使用毫米单位,浏览器会按打印机DPI换算 */
margin: 0;
}
/* 其他不变 */
}
这种方式是最稳妥的,浏览器会按照打印机的物理尺寸进行渲染,不会因屏幕分辨率产生误差。
进阶方案:使用 jsPDF + 前端生成图片
如果客户要求不弹打印框,直接后台静默打印,或者要求把票据转成 PDF 保存,可以使用以下方案:
安装引入(CDN方式)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script> <script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
生成PDF并打印
// 假设你的票据DOM在 #printArea 内
async function printAsPdf() {
// 1. 将DOM转成图片
const canvas = await html2canvas(document.getElementById('printArea'), {
scale: 2, // 高清缩放
useCORS: true
});
const imgData = canvas.toDataURL('image/png');
// 2. 创建PDF(A5尺寸或自定义)
const doc = new jsPDF({
orientation: 'portrait',
unit: 'mm',
format: [80, 200] // 宽度80mm,高度200mm
});
// 3. 将图片放入PDF
doc.addImage(imgData, 'PNG', 0, 0, 80, 0); // 按比例缩放
// 4. 保存或打印
doc.autoPrint(); // 调用打印对话框
doc.save('小票.pdf'); // 或直接下载
}
注意:此方案生成速度较慢,且 html2canvas 对复杂 CSS 兼容性差,如果简单的小票可以,复杂的表格建议用第一种方案。
常见问题排查记录(实战经验)
-
打印出来太宽,被截断?
- 原因:设置了
width: 306px,但打印机默认有边距。 - 解决:检查
@page margin: 0;,并在 CSS 中对#printArea添加padding替代边距。
- 原因:设置了
-
打印出来有背景色(灰色)?
- 解决:在
@media print中添加:* { -webkit-print-color-adjust: exact; /* Chrome/Safari */ print-color-adjust: exact; /* 标准属性 */ }
- 解决:在
-
打印出来字体大小不一致?
- 解决:CSS 中设置
font-size: 12px !important;,并且确保没有使用rem或vw等响应式单位,直接使用px。
- 解决:CSS 中设置
-
如何去掉打印页眉页脚(网址、日期)?
- 这是浏览器行为,只能用
@page margin: 0隐藏,但无法彻底去除页眉(Chrome 打印对话框的“更多设置”中有选项),如果想彻底去除,需要转向 Electron 或 vbscript 方案。
- 这是浏览器行为,只能用
-
如何打印连续空白?
- 热敏打印纸有定位孔,如果用户选择“匹配纸张尺寸”导致空白,建议在
@page中设置size: 80mm auto;让高度自适应内容,或者建议用户打印设置中勾选“无边距”。
- 热敏打印纸有定位孔,如果用户选择“匹配纸张尺寸”导致空白,建议在
完整的示例模板(可以直接复制使用)
如果你想要一个开箱即用的模板,可以参考如下结构(包含样式):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">收银小票</title>
<style>
.print-area { display: none; }
.btn { margin: 20px; padding: 10px; }
@media print {
.btn { display: none; }
body { margin: 0; width: 80mm; font-family: '宋体', SimSun; }
.print-area { display: block; width: 100%; }
h1 { text-align: center; font-size: 16px; }
p { margin: 2px 0; }
table { width: 100%; border-collapse: collapse; }
th { text-align: left; }
td { padding: 2px 0; }
td:first-child { width: 60%; }
td:last-child { text-align: right; }
hr { border-top: 1px dashed #000; }
.total { font-weight: bold; font-size: 14px; }
}
</style>
</head>
<body>
<button class="btn" onclick="window.print()">打印小票</button>
<div class="print-area">
<h1>🌈 小卖部</h1>
<p>单号:#8888</p>
<p>时间:2024-03-01 12:00</p>
<hr>
<table>
<tr><th>商品</th><th>数量</th><th>金额</th></tr>
<tr><td>可乐</td><td>1</td><td>3.00</td></tr>
<tr><td>薯片</td><td>2</td><td>12.00</td></tr>
</table>
<hr>
<p class="total">合计:¥15.00</p>
<p style="text-align:center;">谢谢惠顾,欢迎再次光临!</p>
</div>
</body>
</html>
最后提醒:在 PHP 后端生成 HTML 时,务必对输出内容使用 htmlspecialchars() 转义(尤其是商品名称、备注),防止 XSS 注入破坏打印排版,祝开发顺利!