Jihoon's IT Development

Web Developer's Hobby Development Notes

HTML 로 1px 미만 선 인쇄하기

픽셀과 포인트

브라우저에서 선을 표현하는 단위는 대부분 px 입니다. 픽셀이죠. 이는 상대적인 값입니다. 디지털 이미지를 화면에 재현하기 위한 단위로, 이미지를 이루는 가장 작은 단위를 뜻합니다.

픽셀을 많이 표현할 수 있다. = 해상도가 높다. 로 표현할 수 있으며, 이는 더 정교하게 이미지를 표현할 수 있다는 것을 의미합니다.

즉, 픽셀은 모니터의 해상도, 크기 및 OS(windows, MAC OS) 등에 따라 바뀔 수 있는 상대적인 값임을 알 수 있습니다.

하지만 인쇄의 영역에서 사용하는 단위인 pt는 다릅니다. 포인트라고 불리는 값은 절대적인 값입니다. 1인치를 72로 나눈 값으로 1pt = 1/72 inch = 약 0.3527 입니다.

오늘은 px로 표현한 웹 문서를 가지고 인쇄물로 출력하면서 발생한 이슈에 대해 이야기해보겠습니다.

굵은 1px

1px 굵기의 선으로 구성된 통계표를 출력해 받아본 고객에게서 다음과 같은 반응이 나왔습니다.

프린트 해서 봤더니 선이 너무 굵어요. 좀 더 얇게 해주세요.

당초 계획은 통계표를 웹에서 구성한 뒤 PDF파일로 제공하고, PDF파일을 고객이 프린터로 출력해서 제본하는 것이었습니다. 하지만 고객이 받아본 통계표 PDF는 고객 기준으로는 매우 굵은 선을 가지고 있었습니다.

다시 말하지만 통계표(table)의 선 굵기(border)는 1px 이었습니다.

간단한 html로 표현해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!doctype html>
<html>
<style>
table.one {
border: solid black 1px;
border-collapse: collapse;
}
td.one {
border: solid black 1px;
}
</style>
<table class="one">
<tr>
<td class="one">가나다라</td>
<td class="one">1234</td>
</tr>
</table>
</html>

검은색 1px 굵기의 선을 가진 테이블 입니다. 아래와 같이 표현됩니다.

얼핏 보기에는 얇아보이는 선입니다. 하지만 A4용지 혹은 B4용지로 출력해서 살펴본 고객은 한글(HWP)로 제작된 표에 비해 선이 굵어보인다고 했습니다. 실제로 양쪽 출력물을 비교해봐도 HTML 기반 출력물이 더 굵었습니다. 이때까지는 단순하게 생각했습니다.

0.5px 정도 주면 해결되겠네.

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
<style>
table.one {
border: solid black 1px;
border-collapse: collapse;
}
td.one {
border: solid black 1px;
}
table.two {
border: solid black 0.5px;
border-collapse: collapse;
}
td.two {
border: solid black 0.5px;
}
</style>
<table class="one">
<tr>
<td class="one">가나다라</td>
<td class="one">1234</td>
</tr>
</table>
<hr/>
<table class="two">
<tr>
<td class="two">가나다라</td>
<td class="two">1234</td>
</tr>
</table>

two 라는 클래스의 table을 하나 더 생성한 뒤 선의 굵기를 0.5px 로 줬습니다. 단순히 1px의 절반 굵기의 선이 생성되기를 기대했습니다. 하지만 어림도 없지. 1px 이하의 굵기는 화면에서 표현할 수 없는게 당연했습니다. (표현의 최소 단위니까…)

물론 일반적인 해상도로 봤을 때는 동일해보이지만 확대를 하게되면 두 테이블은 확연히 다른 선 굵기를 가지고 있음을 알 수 있습니다.

화면은 확대가 가능하지만 출력물은 확대를 할 수 없습니다. 슬슬 출력물에 대한 부담감이 몰려왔습니다. 하지만 막연히 PDF 또는 프린트 드라이버가 알아서 해주실거야! 라는 생각도 드는 순간 입니다.

아래는 위의 html을 PDF로 출력한 결과 입니다. (잘 안보일까봐 200% 확대 출력 했습니다.)

[PDF로 확인해보자!]

하느님 맙소사. 출력된 pdf에는 0.5px 과 1px 이 모두 1px 로 표현되는 것을 확인할 수 있었습니다.

이리저리 찾아본 결과 chrome 에서 print pdf로 pdf 를 생성할 경우 1px 미만의 선은 제대로 표현이 되지 않는다는 정보가 있었습니다. 이는 현재 기준으로도 수정될 가능성이 없어보이는 이슈로 headless chrome라이브러리인 puppeteer를 이용한 pdf export 시에도 마찬가지로 발생하고 있었습니다.

해결방안 테스트1 - 투명도

검색 결과 1px 미만의 선을 표현하기 위한 많은 개발자들의 노력과 답변들이 존재했습니다. 다만, 인쇄를 해야겠다라는 개발자는 많지 않았습니다.

우선 화면에서 표현이 된다는 CSS 트릭 부터 테스트해봤습니다. 바로 투명도를 이용한 방식 입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!doctype html>
<html>
<style>
.container {
border-style: solid;
border-width: 1px;
margin-bottom: 10px;
}
.border-100 {border-color: rgba(0,0,255,1);}
.border-75 {border-color: rgba(0,0,255,0.75);}
.border-50 {border-color: rgba(0,0,255,0.5);}
.border-25 {border-color: rgba(0,0,255,0.25);}
</style>
<div class="container border-100">1px</div>
<div class="container border-75">0.75px</div>
<div class="container border-50">0.5px</div>
<div class="container border-25">0.25px</div>
</html>

1px 미만의 선은 표현하기 어렵기 때문에 선의 투명도를 조절하여 얇게 보이도록 하는 트릭 입니다. 화면에서의 결과는 아래와 같습니다.

모니터 너머로 보이는 선은 정말 얇아보입니다. 0.25px 정도는 억지스러워보이지만 0.5px 정도까지는 눈감고 넘어가줄만 합니다.

이제 인쇄만 이쁘게 되면 됩니다.

[PDF로 확인해보자!]

PDF로 출력된 선은 뚜꺼워 보였으며, 얇아지지도 않았습니다. 투명해져가는 선은 단순히 프린터의 잉크가 떨어진 것 처럼 보일 뿐이었습니다.

화면과 출력물은 다르다 라는 교훈만 얻게 되었습니다.

해결방안 테스트2 - background-image 속성

CSS에는 border-image 속성이 존재합니다. 이는 image 파일을 border 에 줄 수 있는 것으로, HTML BOX를 디자인하기 좋아지는 속성 입니다.

구현은 간단하지 않은 관계로(현재 기억이 자세히 나지 않….) 히스토리만 적어보겠습니다.

  • 디자이너에게 0.5px 선 이미지를 요청해 받았습니다. (포토샵은 대단합니다.)
  • border-image 속성으로 표현합니다.
  • 필요에 따라 회전 시키며 사용합니다.

결과적으로는 PDF 상에 0.5px 를 표현하는데 성공했습니다. 이미지는 벡터로 랜더링 되는 선이 아니라 이미지 그 자체이기 때문에 문제가 없어 보였습니다.

다만 문제가 있었습니다.

구현 방식이 너무 복잡해, 수시로 편집 및 병합이 될 수 있는 통계표 테이블에 적용해주기는 어려웠던 것입니다. 때문에 절반의 성공으로 다음을 기약할 수 밖에 없었습니다.

해결방안 테스트 3

마지막 방법은 @media print를 이용해 print시 적용되는 css를 별도로 제작하는 것 입니다.
이 방법에는 약간의 트릭이 있습니다.

  • PDF print시 1px 미만이 표현되지 않는 문제 회피 필요.
  • @media print CSS에서 1px 미만의 숫자가 존재하지 않도록 기존의 CSS 수치에 일정 수치를 곱해준다.
    • 예> 0.5px 이 가장 얇은 선일 경우 = 모든 수치를 2배
    • 1px => 2px, 0.5px => 1px
  • 마지막으로 body 부분에 0.5배 축소 설정을 추가

아래는 예 입니다.

@media screen

1
2
3
4
5
6
7
8
9
10
11
@media screen {
.container {
border-style: solid;
border-width: 1px;
margin-bottom: 10px;
font-size: 14px;
}
.border-100 {border-width:1px}
.border-75 {border-width:0.75px}
.border-50 {border-width:0.5px}
.border-25 {border-width:0.25px}

@media print

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@media print {
body {
transform: scale(.25);
}
.container {
border-style: solid;
border-width: 4px;
margin-bottom: 40px;
font-size: 56px;
}
.border-100 {border-width:4px}
.border-75 {border-width:3.05px}
.border-50 {border-width:2.5px}
.border-25 {border-width:1px}
}

문제없이 pdf 에서 원하는 굵기가 출력되는 것을 확인할 수 있었습니다.

결론

프로젝트에서는 세가지 방법 중 가장 만족도가 높았던 3안을 선택하여 제작했습니다. WEB의 화면을 PDF로 출력한다는 일반적이지 않은 작업이었지만 원하는 결과에 가까운 출력물을 얻을 수 있어 다행이었습니다.

모든 CSS의 굵기를 계산해서 만들어야 한다는 점이 어렵게 느껴질 수 있겠지만, SASS 등과 같이 CSS를 일괄 빌드할 수 있는 툴을 사용한다면 print CSS를 빠르게 생성할 수 있으니 충분히 쓸만해 보입니다.