ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TypeSquare 웹폰트 최적화 과정
    Problem 2024. 6. 10. 10:40

     

    안녕하세요!

    최근 프로젝트에서는 웹폰트 최적화에 대한 중요한 문제를 해결해야 했는데

    그 과정을 블로그에 공유하고자 합니다.

    프로젝트 개요

    현재 진행 중인 프로젝트는 일본어 채용 정보를 제공하는 홈페이지입니다.

    기획 팀에서는 페이지 내에 들어가는 폰트의 저작권 상 TypeSquare의 웹폰트를 사용하는게 안전하다고 판단하여

    이를 사용하기로 결정했습니다.

    문제 발견: font-face 방식의 부재

    처음 TypeSquare를 사용하면서 @font-face 방식을 사용할 수 없다는 것을 알게 되었습니다.

    이는 TypeSquare의 폰트 로딩 방식이 @font-face 대신에 자체적으로 제공하는 JavaScript API를 통해 이루어지기 때문입니다.

    그 이유를 찾아보니 TypeSquare가 폰트 전달 및 사용 추적을 직접 처리하여 라이센스 위반 가능성을 방지하기 위함인 걸 알게 되었는데요, 따라서 자체적으로 @font-face로 폰트를 호스팅 및 제어를 할 수 없어 FOUT(Flash of Unstyled Text)를

    막지 못하는 문제에 직면했습니다. 

    더보기

    FOUT : 의도한 글꼴로 전환하기 전에 시스템 글꼴을 우선적으로 적용되어 웹 페이지가 로드되는 현상

     

    FOUT 문제와 첫 렌더링 이슈

     

    위 문제로 인해 font-display 속성을 사용하지 못하기 때문에, 웹폰트가 로드되기 전까지 기본 폰트가 표시되고, 웹폰트 로드 후에야 폰트가 바뀌는 현상이 발생했습니다. 이는 사용자 경험을 저하시킬 수 있는 요소였습니다. 더불어, 공고 디테일 페이지에 들어갈 시 API에서 불러오는 텍스트들은 첫 렌더링 시 존재하지 않아서, 추가적인 폰트 변환 과정이 필요했습니다. 이로 인해 폰트 변환이 지연되어 사용자 경험에 부정적인 영향을 미쳤습니다.

    문제 해결을 위한 여러 고민과 시도

    이 문제를 해결하기 위해 여러 가지 방법을 시도했습니다:

    1. Script Tag defer: HTML 파싱이 끝난 후 스크립트 태그가 실행되나 폰트 변환 시 원활하고 정확한 로딩제어를 위해 탈락
    2. 로딩 인디케이터: 폰트 로딩 중임을 사용자에게 알리기 위해 로딩 인디케이터를 도입했습니다.

    최종 해결 방법

    - 여러 고민 끝에, 일본어 문자, 상용 한자, 숫자, 영어가 담긴 div 요소를 만들어 초기 로딩 시 삽입하고, DOM이 렌더된 후에 TypeSquare 스크립트 태그를 동적으로 생성하고 onload와 Typesquare의 기능인 onFontLoaded(모든 글꼴 적용 후 발생하는 함수) 를 통해 정확한 폰트 로딩을 제어하는 방식을 적용했습니다.

    구체적인 코드는 다음과 같습니다:

    useEffect(() => {
    	const script = document.createElement('script'); 
        script.src = 'https://typesquare.com/ts_api.js';
        script.onload = () => { 
        	if (window.Ts && typeof window.Ts.onFontLoaded === 'function') { 
            	window.Ts.onFontLoaded(() => { 
                    const elements = document.querySelectorAll('.setFontElement'); 
                    elements.forEach(element => document.body.removeChild(element)); // 폰트 로딩 완료 후의 콜백 함수 실행 
                    callback(); 
                }); 
            } else { 
                console.error('Typesquare font loading function not found.');
            } 
        }; 
        document.body.appendChild(script);
        return () => document.body.removeChild(script)
        }, [])

     마지막으로 역할이 끝난 엘리먼트는 지워줬습니다.

    결론

    이번 프로젝트에서 기존의 FOUT 문제를 해결하는 보편적인 방식에서 벗어나, 새로운 관점으로 접근하여 문제를 해결하는 법을 배우게 되었습니다. 

     

Designed by Tistory.