적절한 CSS 폰트를 사용하는 것은 사용자 경험에 적지 않은 영향을 끼친다.
CSS의 Font에 깊이 이해하고 프로젝트에 적절히 적용하기 위해 자세히 알아보자.
Font는 여러가지 기준으로 분류될 수 있다.
가장 일반적이고 기본적인 폰트 포맷.
맥과 윈도우에 쓰이는 가장 오래된 폰트 포맷으로, 대부분의 브라우저에서 사용할 수 있다.
당시 비트맵 형식이었던 폰트 파일을 대체하고자 제어점이 3개인 2차 베지어 곡선 형태로 만들어졌다.
TTF의 진화 버젼.
Adobe와 MS의 합작품으로, TTF와 비슷하면서 좀 더 많은 기능을 지원한다.
제어점이 3개인 TTF보다 더 많은 4개로, 더욱 섬세한 곡선을 표현할 수 있다.
단, 작업 처리속도가 다소 느리고, 해상도가 낮은 모니터에서는 TTF보다 매끄럽게 보이지 않을 수 있다.
TTF와 OTF를 기반으로 하며 압축을 통해 효율을 개선한 폰트 포맷. 파일 내에 저작권, 메타데이터를 포함시킬 수 있어 저작권 문제를 해결하기 위해 고안되었다.
W3C에서 권장하고 있으며, 현재 가장 널리 사용되고 있는 폰트 포맷.
WOFF보다 압축률을 30% 개선된 폰트포맷.
브라우저 호환성 문제가 있다.
Vector 기반의 그래픽을 사용하는 SVG로 만들어진 글꼴 형식
system ui fonts(이하 suf)란 사용자의 디바이스에 이미 설치되어 있거나 OS에 의해 기본적으로 지원되는 fonts를 의미한다.
CSS에 suf를 사용하도록 지정하면, 별도의 폰트를 다운로드 하지 않고도 빠르게 텍스트를 렌더링할 수 있다.
하지만 디바이스 별로 지원하는 fonts들이 상이하기 때문에, 통일성을 지키기는 어렵다.
Web fonts는 말 그대로 유저 시스템에 설치되지 않아 웹을 통해 다운로드되는 폰트를 지칭한다.
여러 종류의 font를 다운받아 자유자재로 사용가능하다는 장점이 있지만, 서비스에 처음 방문하는 유저는 폰트를 다운받아야 하기 때문에 시간이 딜레이 된다는 점이 최대 단점이다.
주로 @font-face 규칙을 사용해 적용한다
font-faimly에 사용한 웹 폰트의 이름을 지정하고, src를 통해 경로와 형식을 지정한다.
그렇다면 이 중 어떤 폰트를 사용해야 할까?
사이트의 퍼포먼스가 중요하고, 별도의 UI 디자인이 존재하지 않아 임의의 폰트를 사용해도 된다면 System Ui를 사용하는 것은 좋은 선택이 될 수 있다.
Keven powell의 조언에 따르면, 두 종류의 폰트를 적절히 조합하여 사용하는 것을 권장하고 있다.
예를 들어 많은 볼륨을 차지하는 본문 텍스트와 같은 작은 크기의 텍스트들은 system ui fonts를 사용하고, 그렇지 않은 Heading이나 내비게이션 바의 텍스트 등에만 web fonts를 적용하는 것을 추천하고 있다.
물론 디자이너가 존재하고 퍼블리싱을 수반하는 대부분의 서비스에선 web font가 큰 비중을 차지할 것이다.
Font-family를 통해 선택한 엘리먼트에 대해 적용할 폰트 목록을 적용할 수 있다.
font-family: Georgia, 'Times New Roman'
font-family에 폰트 리스트를 나열시킨 것을 font stack이라 지칭한다.
앞 순서의 font가 유저의 system에 존재하지 않으면 list를 순서대로 순회하며 다음 차례의 fallback font를 적용한다.
또한, 띄워쓰기가 존재하는 텍스트는 ''를 붙여줘야 한다.
browser의 기본값은 대부분 16px이다.
PX보다 REM이 권장되는데, 그 이유는 px를 사용하면 user의 사용자의 시스템 설정(preference)를 무시하고 폰트 사이즈를 강제로 오버라이딩하기 때문이다.
폰트의 weight(굵기)를 설정하는 프로퍼티.
bold, semi-bold와 같이 text형식으로 설정할수도 있고, 400, 500과 같이 숫자 형태로 지정할 수도 있다.
font 마다 사용가능한 weight가 상이하며, 해당되는 weight가 폰트에 존재하지 않는 경우 가장 가까운 weight가 할당된다.(오름차순)
색상변경을 위한 프로퍼티.
a 태그가 href가 존재할 경우 상속이 되지 않을 때가 있다.
이는 브라우저 단에서(user agent stylesheet) 스타일을 오버라이드하기 때문이다.
이런 경우 a 태그의 font-color를 직접 변경해 주어야 한다.
line box의 높이를 설정하는 프로퍼티.
텍스트 줄 사이간 거리를 설정할 때 사용된다.
block-level 엘리먼트에서 사용될 경우, 내부 line box의 최소 높이를 조정한다.
앞서 언급하였듯이 웹 폰트는 다른 서버에 저장되어 요청을 통해 사용된다.
브라우저가 페이지를 렌더링할때, DOM과 CSSOM을 종합하여 렌더트리를 구성한 이후, 위의 T3단계에서 화면을 직접 그리게 된다.
이 때, 브라우저는 css font에 대한 요청이 완료되지 않더라도 렌더링을 일단 먼저 진행한다. 이 때 css 설정에 따라 화면을 비워둘지 그렇지 않으면 unstyle text를 그대로 렌더링할 지에 대한 차이가 있을 뿐이다.
System UI font를 사용하지 않는다면, web fonts를 직접 링크를 통해서 다운받거나 로컬단위에 저장하여야 문서에 해당 폰트를 적용할 수 있다.
앞서 언급하였듯이 주로 @font/face를 주로 사용하게 된다.
@font-face {
font-family: 'MyCustomFont';
src: url('path/to/MyCustomFont.woff2') format('woff2');
font-weight: normal;
font-style: normal;
font-display: swap;
}
body {
font-family: 'MyCustomFont', Arial, sans-serif;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Custom Font Example</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Welcome to My Website</h1>
<p>This is a paragraph using the 'MyCustomFont' font. If the custom font is not available, it will fall back to Arial, and then to the default sans-serif font of the system.</p>
</body>
</html>
웹 폰트를 적용할 때 가장 최적화가 필요한 부분은, 웹 폰트가 로드되기 전 상황에 대한 처리이다.
이에 대한 최적화 방법은 크게 FOIT(Flash Of Invisible Text)와 FOUT(Flash Of Unstyled Text)로 나뉜다.
웹 폰트가 로드되기 전 텍스트를 아예 비워두거나, 혹은 폰트가 적용되지 않은 텍스트를 그대로 보여주는 것이다.
이 중 FOUT이 주로 사용되는데, FOIT의 경우 잘못된 정보를 전달하는 문제가 발생할 수 있기 때문이다.
하지만 두 방법 모두, layout shift를 근본적으로 막을 수 없다는 데서 한계가 있다.
다음은 layout shift를 방지하기 위한 방안들이다.
셀프 호스팅은 폰트가 써드파티 URL을 통해 사용되지 않고, 서비스와 같은 서버 혹은 CDN을 통해 제공되는 것을 의미한다.
새로운 http 커넥션이 불필요해지기에 퍼포먼스, 유지보수 등 많은 측면에서 장점을 갖는다.
link태그의 preload 옵션을 통해서 css등 다른 파일 리소스보다 폰트 파일을 우선 로딩하여 layoutshift를 방지할 수 있다.
하지만 preloading이 실패할 경우나, preladoing이 성공적으로 완료되더라도 첫 텍스트 렌더링보다 늦어질 가능성도 존재한다. (font-display: block이 아닐 경우)
위와 같은 상황까지 고려하여 font-family를 통해 fallback font를 지정하여야 한다.
이 때 fallback font는 layous shift를 최소화하기 위해 최대한 목표한 웹 폰트와 비슷한 폰트를 사용하고, 필요하다면 resizing을 하는 방식으로 font-matching을 하기도 한다.
해당 프로퍼티를 사용하면 웹 폰트의 로딩 상태에 따른 동작을 설정할 수 있다.
body {
font-display: block /* -> FOIT */
font-display: swap /* -> FOUT */
}
일견 보기에도 layout shift 문제 하나를 위해서 너무 많은 작업이 필요해보인다.
그래서, 최근에는 프레임워크 레벨에서 이러한 layout shift 문제를 쉽고 종합적으로 해결하는 방식으로 font를 적용할 수 있는 방법이 도입되고 있다.
next.js의 next/font가 그것인데, 위의 방법들을 모두 종합함은 물론, 아래 사진과 같이 동적으로 text를 resizing(font-size-adjust)하여 layout shift를 최소화하기 까지한다.
따라서 상황에 따라 필요한 방법들을 사용하되, Next.js를 사용한다면 위 기능을 사용하는 것도 좋은 해결방안이 될 것이다.
Using Fonts in Next.js (Google Fonts, Local Fonts, Tailwind CSS)
웹 폰트 사용과 최적화의 최근 동향
Zero Layout Shift를 위한 Next Font Optimization의 원리
Custom fonts without compromise using Next.js and next/font