Flash Of Invisible Text
, Flash Of Unstyled Text
로 페이지에 진입했을 때 폰트 적용이 늦게되어 깜빡이거나 갑자기 글자가 나타나는 현상을 발견했던 경험이 있을 것입니다.이는 사용자 경험에 부정적인 영향을 주게됩니다.
이 현상은 왜 일어나는 것일까요?
브라우저에 진입할 때 동작을 설명하면
1. 브라우저가 HTML 문서를 요청한다.
2. DOM 구성 & CSS,JS 및 기타 리소스 요청
3. CSSOM 구성 & 렌더트리 구축, 폰트 리소스 요청
4. Reflow, Repaint -> 폰트를 사용할 수 없는 단계면 브라우저는 글자를 렌더링하지 않을 수 있음
주목해야할 부분은 CSSOM을 생성하는 과정인데, 이 과정에서 폰트 리소스를 다운로드하기 시작합니다. 하지만 paint 단계에서 폰트 파일의 다운로드가 완료되지 않았으면 해당 자원을 사용하는 콘텐츠의 렌더링을 차단하게 됩니다.
결국 사용자의 네트워크의 속도, 폰트의 용량 등의 원인으로 폰트가 적용된 텍스트가 보이지 않는 문제가 발생하는 것입니다.
사용자의 네트워크 상태는 제어하기 힘들기 때문에 폰트의 용량과 텍스트가 보이지 않는 문제를 해결해봅시다.
폰트 리소스 요청 시점을 좀 더 앞당기도록 하는 방법입니다.
<head>
에서 폰트를 요청할 때 rel = "preload"
를 추가해주면 됩니다.
<link rel="preload" href="/font.woff2"as="font" type="font/woff2" crossorigin />
FOIT 방식은 UX 관점에서 좋지 않기 때문에 주로 FOUT 방식으로 의도적으로 작동시키는 방식으로 해결해봅시다.
CSS Font Loading Module은 웹 폰트의 로딩을 제어하기 위한 표준화된 방법을 제공하는 W3C 명세입니다.이 모듈은 JavaScript API를 통해 폰트의 로딩 과정을 프로그래밍 방식으로 제어할 수 있게 해줍니다. 웹 개발자는 이 API를 사용하여 웹 폰트의 로드 상태를 확인하고, 폰트가 준비되었을 때 CSS 클래스를 동적으로 추가하는 등의 작업을 할 수 있습니다.
새 FontFace 객체를 생성하고, 이를 document.fonts.add()
메서드를 사용하여 로드할 수 있습니다. 그리고 폰트가 로드되기를 기다리는 프로미스를 사용할 수 있습니다.
const font = new FontFace('Roboto', 'url(https://example.com/roboto.woff2)', {});
document.fonts.add(font);
font.load().then(function(loadedFontFace) {
console.log(`Font ${loadedFontFace.family} has been loaded`);
});
document.fonts.ready()
프로미스를 사용하면 페이지의 모든 초기 폰트 로드가 완료되었을 때 실행될 코드를 작성할 수 있습니다. 이는 초기 페이지 로드 시 폰트가 준비될 때까지 기다린 후 특정 스타일이나 레이아웃 조정을 수행하고자 할 때 유용합니다.
document.fonts.ready.then(function() {
console.log("All initial fonts have loaded or failed");
});
document.fonts.check()
메서드를 사용하면 특정 폰트가 사용 가능한 상태인지 확인할 수 있습니다. 이 메서드는 폰트가 로드되었고, 주어진 텍스트를 렌더링하는 데 사용될 수 있는지 여부를 불리언 값으로 반환합니다.
if (document.fonts.check("1em Roboto")) {
console.log("Roboto font is available");
} else {
console.log("Roboto font is not available yet");
}
Font Face Observer는 웹 폰트 로딩을 비동기적으로 제어할 수 있도록 돕는 JavaScript 라이브러리입니다. 이 라이브러리는 CSS Font Loading API에 기반하지 않고, Promise를 사용하여 폰트가 로드되었는지 감지합니다. 개발자는 Font Face Observer를 사용하여 웹 폰트가 사용 가능한 상태가 되었을 때 콜백을 실행할 수 있으며, 이를 통해 사용자 경험을 개선할 수 있습니다.
두 방법을 비교하면
Font Loading Module
장점 : 브라우저가 직접 지원하는 표준 API를 사용하므로, 별도의 라이브러리 없이 웹 폰트 로딩 제어 가능
단점 : 모든 브라우저에서 완벽하게 지원되지 않을 수 있으며, 구버전 브라우저에서 호환성 문제가 있을 수 있음
Font Face Observer
장점 : 폭넓은 브라우저 호환성을 제공하며, 특히 CSS Font Loading API를 지원하지 않는 구버전 브라우저에서도 사용할 수 있음
단점 : 외부 라이브러리에 의존하므로, 프로젝트에 추가적인 의존성이 생김
font-display
속성을 사용해 웹 폰트 로딩 동안의 행동을 제어할 수 있는데,다음과 같은 속성을 갖고 있습니다.
@font-face {
font-family: 'MyFont';
src: url('/path/to/font.woff2') format('woff2');
font-display: swap;
}
의도적으로 FOIN 방식을 FOUT 방식으로 변경했어도 문제가 완전히 해결되는 것은 아닙니다.
웹 폰트 적용 전후에 레이아웃이 깨져보이는 현상을 여전히 발견할 수 있는데, 이는 Font Style Matcher로 fallback 폰트와 최대한 이질감이 느껴지지 않도록 조정하는 방법이 있습니다.
아래의 코드는 font face obserber 라이브러리를 사용할 때 어떻게 적용하는지 예시입니다.
body { // 로드전 - fallback 폰트 스타일
font-family: 'Nanum Gothic',sans-serif;
font-size: 15px;
line-height: 1.65;
}
body.font-loaded { // 로드후 - 웹폰트 스타일
font-family: 'Black Han Sans','Nanum Gothic',sans-serif;
font-size: 18px;
line-height: 1;
}
웹폰트는 네트워크를 통해 다운받는 자원이기 때문에 파일의 크기가 크면 웹폰트가 적용된 글자가 화면에 표시될 때까지 시간이 지연되는 문제가 발생하는데, 이를 폰트 파일의 용량을 줄여 해결할 수 있다.
확장자에 따라 폰트의 용량이 달라지는 것을 알 수 있는데, 특히 woff2의 크기가 작은 것을 알 수 있습니다.
Name | Tag | Size |
---|---|---|
Pretendard-Black.woff2 | woff2 | 814KB |
Pretendard-Black.woff | woff | 1,153KB |
Pretendard-Black.ttf | ttf | 2,615KB |
Pretendard-Black.otf | otf | 1,601KB |
다음과 같이 용량이 작은 폰트 형식을 적용해 웹 폰트를 최적화해봅시다.
@font-face{
font-family:Pretendard;
src: url(Pretendard-Black.woff2) format('woff2'),
url(Pretendard-Black.woff) format('woff'),
url(Pretendard-Black.ttf) format('truetype');
}
WOFF2 형식과 WOFF 형식을 모두 사용할 수 없을 떄 TTF 형식을 폴백 폰트로 사용할 수 있게 TTF 형식도 추가해준 모습입니다.
서브셋 폰트는 폰트 파일에서 갞,갟,뛟,훭 같은 실생활에서 거의 사용하지 않는 글자를 폰트에서 제거하고 사용할 글자만 남겨둔 폰트입니다.
최신 폰트는 대부분 서브셋 폰트이지만 직접 만들고싶다면 サブセットフォントメーカー(이하 서브셋 폰트 메이커)나 fontTools 라이브러리를 사용해 만들 수 있다.
유니코드로 지정한 글자에만 웹 폰트를 적용하는 속성입니다.
아래와 같이 CSS의 @font-face 규칙에 unicode-range 속성을 선언해 사용합니다.
@font-face{
font-family:Pretendard;
src: url(Pretendard-Black.woff2) format('woff2');
unicode-range: U+BC14, U+CC28;
}
U+BC14는 '바' U+CC28는 '차'에 해당하는 유니코드고, 텍스트를 작성했을 때 전체에서 '바'와 '차'에만 웹 폰트가 적용됩니다.
unicode-range의 장점은 글자가 텍스트에 없으면 웹 폰트 다운로드를 요청하지 않기 때문에 불필요한 다운로드를 막을 수 있습니다.
이 글은 FOUT, FOIT 현상을 잘 해결하기 위한 글입니다.
해당 현상이 일어나는 이유는 렌더링 과정에서 폰트가 다운로드 되지 않았을 때 글자가 렌더링 되지 않기 때문이었습니다.
해결하기 위해선
4가지 방법이 있었는데,
1. 폰트 다운 시점을 이전으로 끌어올린다. <link rel='preload'>
이용
2. FOIT 현상을 전부 FOUT으로 일어나게 한다.