0%

CSS 筆記 - 關於列印的那些設定

print

目前工作遇到 EDM,也有設定列印的需求,無論從網站或是 PDF,可以透過 CSS print 的設定來調整相關細節,藉此筆記一下。

列印需求

本次在專案中的某頁面需要給使用者下載搜尋結果後的 PDF,並要完整呈現 table 中 td 的資訊,不要在列印時被切斷。

使用 media print 屬性

需在 CSS 中增加 media print 屬性:

1
2
3
@media print {
...;
}

@page 頁面設定

size 的預設值為 A4portrait 為直式。

1
2
3
4
5
@media print {
@page {
size: A4 portrait;
}
}

其他 size 的相關設定

1
2
3
4
5
6
7
8
@page {
size: portrait; /* 直向(預設) */
size: landscape; /* 橫向 */
size: 10cm; /* 單值則長寬皆為10cm */
size: 4cm 6cm; /* 寬4cm 高6cm */
size: A4; /* 保留字 */
size: A4 landscape; /* 尺寸/保留字 + 方向 */
}

本次主角 - break 分頁點

相關屬性有三個,皆為分頁斷點設定,分別在是在元素本身元素前元素後插入分頁斷點。

分新舊寫法但目前瀏覽器保留舊寫法並會將舊寫法轉為新寫法。

屬性寫法

新寫法 舊寫法 說明
break-inside page-break-inside 元素本身
break-before page-break-before 元素前
break-after page-break-after 元素後

break-inside 元素本身斷點

break-inside(新) page-break-inside(舊) 說明
auto auto 預設,如果需要則會在元素內插入分頁斷點
avoid avoid 避免在元素內插入分頁斷點

break-before 元素前斷點

break-before(新) page-break-before(舊) 說明
auto auto 預設,如果需要則會在元素前插入分頁斷點
avoid avoid 避免在元素前插入分頁斷點
page always 在元素前總是插入分頁斷點
left left 在元素前插入分頁斷點直到它到達一個左手頁面
right right 在元素前插入分頁斷點直到它到達一個右手頁面

break-after 元素後斷點

break-after(新) page-break-after(舊) 說明
auto auto 預設,如果需要則會在元素後插入分頁斷點
avoid avoid 避免在元素後插入分頁斷點
page always 在元素後總是插入分頁斷點
left left 在元素後插入分頁斷點直到到達一個左手頁面
right right 在元素後插入分頁斷點直到到達一個右手頁面

關於列印的一些其他設定

列印用字體單位

相對於平常 CSS 用的 px、em,針對列印用的尺寸單位推薦使用以下單位:

em、 cm、mm、in、pt、pc、%

orphans 底部保留最小行數

必須在頁面底部保留的段落的最小行數。

1
2
3
@page {
orphans: 3;
}

widows 頂部保留最小行數

必須在頁面頂部保留的段落的最小行數。

1
2
3
@page {
widows: 2;
}

:first

列印時的第一頁。

1
2
3
@page :first {
background-color: red;
}

:left 與 :right 左手頁面與右手頁面

在印雙面文件又需要裝訂時,以橫式文件(由左至右閱讀)來說,正面就要在左側留出血,反面要在右側留出血,:left:right 就是為此而生。

用戶端會自動分別目前印到的頁數為左手頁面或右手頁面,進而去套用 :left:right 的屬性設置。

要依據文件內容書寫方向自己去判定第一頁為 :left:right

1
2
3
4
5
6
7
8
@page :left {
margin-left: 2cm;
margin-right: 4cm;
}
@page :right {
margin-left: 4cm;
margin-right: 2cm;
}

列印顏色

針對 Chrome 瀏覽器無法列印出顏色的問題解法,假設要把 table 的 th 顏色印出,可在元素中設定其屬性。

1
2
3
4
table th {
-webkit-print-color-adjust: exact !important;
color-adjust: exact !important;
}

如果要強迫列印模式都要把有顏色的地方都印出。

1
2
3
4
5
6
@media print {
* {
-webkit-print-color-adjust: exact !important;
color-adjust: exact !important;
}
}

關於 IE (還好 IE 已經死了)

  • IE 不吃 rowspan,若有使用 rowspan 的話,border 會消失不見,印不出來。
  • 可使用改背景色,或是用硬幹的也可以(像是絕對定位之類的)。

還好我們不用支援 IE。

範例程式碼:https://codepen.io/hnzxewqw/pen/MWBMpBZ

另開視窗顯示 PDF

會員里程多一個匯出 PDF 檔案功能,需求如下:

  1. 在點擊按鈕後才呼叫 API。
  2. 要在 headers 裡面放入 Authorization。
  3. 後端會回傳一個 PDF 格式檔案,前端使用 Blob 開啟。

程式碼如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
 beforeDestroy() {
this.objUrlList.forEach((url) => URL.revokeObjectURL(url));
},
/** 下載 PDF */
downloadPDF() {
this.$nuxt.$loading.start && this.$nuxt.$loading.start();
const { startDate, endDate, filter } = this.requestData;

const apiUrl = `${process.env.apiUrl}/apiUrlPath?startDate=${startDate}&endDate=${endDate}&filter=${filter}`;
// 從 cookie 取得 accessToken,避免重新整理沒有抓到 token 導致開啟檔案失敗
const cookies = this.$cookies.get('memberToken');
// 加入 Authorization 到 headers
const option = {
responseType: 'blob',
headers: {
Accept: 'application/pdf',
'Content-Type': 'application/json',
'jx-lang': this.$i18n.locale,
authorization: `${cookies.type} ${cookies.accessToken}`,
},
methods: 'GET',
};

// 使用 blob 格式取得 PDF 檔案
fetch(apiUrl, option).then(async (res) => {
if (res.status === 200) {
const blob = await res.blob(); // 加上 await 確保 blob 正確取得
const objUrl = URL.createObjectURL(blob);
window.open(objUrl, '_blank');
this.objUrlList.push(objUrl);
this.$nuxt.$loading.finish && this.$nuxt.$loading.finish();
} else {
const errText = await res.json(); // 加上 await 確保 json 正確取得
const { code, details } = errText.message;
if (!details || !details.length) return;
this.$nuxt.$emit('alert', details, code);
this.$nuxt.$loading.finish && this.$nuxt.$loading.finish();
}
});
},

參考資料