핵심 요약
Pretext는 브라우저의 비싼 DOM 측정 없이, 자바스크립트만으로 여러 줄 텍스트의 높이와 줄 배치를 계산하는 라이브러리다.
한 번 텍스트를 분석하고 나면, 이후 레이아웃 계산은 매우 빠르게 반복할 수 있어 리사이즈, 가상 스크롤, 커스텀 레이아웃에 특히 유리하다.
DOM, Canvas, SVG 같은 다양한 렌더링 방식에 연결할 수 있고, 다국어·이모지·혼합 방향 텍스트도 고려한다.
데모 사이트 :

Pretext가 해결하는 문제
웹에서 텍스트 높이를 재려면 흔히 getBoundingClientRect()나 offsetHeight 같은 DOM 측정을 떠올린다.
하지만 이런 방식은 브라우저의 레이아웃 재계산을 유발해 비용이 크다.
Pretext는 이 문제를 피한다.
텍스트를 미리 잘게 분석하고 폭을 계산해 두고, 실제 줄 수와 높이는 나중에 산술 계산으로 빠르게 구한다.
비유하면, 매번 종이를 다시 인쇄해 재보는 대신, 글자 조각의 크기를 미리 측정해 두고 조합만 바꾸는 방식이다.
핵심 사용 방식: prepare와 layout
가장 기본 흐름은 prepare()와 layout()의 분리다.
prepare()는 텍스트를 정리하고, 줄바꿈 기준을 분석하고, 폭을 재고, 이후 계산에 필요한 준비물을 만든다.
layout()은 그렇게 준비된 결과를 바탕으로 너비와 줄 높이만 바꿔 가며 최종 높이와 줄 수를 계산한다.
import { prepare, layout } from '@chenglou/pretext'
const prepared = prepare('AGI 春天到了. بدأت الرحلة 🚀', '16px Inter')
const { height, lineCount } = layout(prepared, textWidth, 20)중요한 점은 같은 텍스트와 같은 설정에 대해 prepare()를 반복하지 않는 것이다.
창 크기만 바뀌는 상황이라면 layout()만 다시 호출하는 편이 훨씬 효율적이다.
어떤 상황에서 특히 유용한가
이 도구는 "텍스트 높이를 미리 정확히 알고 싶다"는 문제에 강하다.
예를 들어 가상 스크롤에서는 각 항목 높이를 미리 알아야 스크롤 위치가 흔들리지 않는다.
또 Masonry 같은 사용자 정의 레이아웃에서는 텍스트 박스 높이를 빠르게 계산해야 전체 배치가 자연스럽다.
버튼 라벨이 다음 줄로 밀리는지 미리 검사하는 테스트에도 쓸 수 있다.
텍스트가 늦게 로드될 때 레이아웃 점프를 줄이고 스크롤 위치를 안정적으로 유지하는 데도 도움이 된다.
수동 줄 배치가 필요할 때
Pretext는 높이만 계산하는 데서 끝나지 않는다.
직접 각 줄의 내용을 받아서 Canvas나 SVG에 그릴 수도 있다.
이때는 prepareWithSegments()를 사용한다.
layoutWithLines()는 각 줄의 실제 문자열까지 돌려주고, walkLineRanges()는 문자열을 만들지 않고 줄 범위와 폭만 알려준다.
layoutNextLine()은 줄마다 허용 너비가 달라지는 경우에 유용하다.
예를 들어 이미지 옆으로 흐르는 문단처럼, 위쪽 줄은 좁고 아래쪽 줄은 넓은 구조를 만들 수 있다.
import { prepareWithSegments, layoutWithLines } from '@chenglou/pretext'
const prepared = prepareWithSegments('AGI 春天到了. بدأت الرحلة 🚀', '18px "Helvetica Neue"')
const { lines } = layoutWithLines(prepared, 320, 26)
for (let i = 0; i < lines.length; i++) {
ctx.fillText(lines[i].text, 0, i * 26)
}즉, "텍스트 높이 계산기"이면서 동시에 "줄 배치 엔진"에 가깝다.
공백과 줄바꿈 처리 방식
기본 대상은 일반적인 웹 문단이다.
즉, 보통의 공백 압축, 일반 줄바꿈 규칙, 단어 단위 줄바꿈, 필요 시 단어 내부 분할 같은 웹 기본 동작을 따른다.
만약 textarea처럼 스페이스, 탭, 줄바꿈 문자를 그대로 살리고 싶다면 whiteSpace: 'pre-wrap' 옵션을 준다.
const prepared = prepare(textareaValue, '16px Inter', { whiteSpace: 'pre-wrap' })
const { height } = layout(prepared, textareaWidth, 20)이 경우 스페이스와 t, n이 보존된다.
탭은 브라우저 기본에 가까운 tab-size: 8 기준으로 처리된다.
성능과 설계 포인트
문서에 따르면 준비 단계는 상대적으로 무겁고, 레이아웃 단계는 매우 가볍다.
즉, 비용을 앞단에 몰아 넣고 이후 반복 계산을 빠르게 만드는 구조다.
이 설계는 반응형 UI에 잘 맞는다.
한 번 측정한 텍스트를 화면 폭만 바꿔 여러 번 다시 배치해야 하는 경우가 많기 때문이다.
내부적으로는 브라우저의 폰트 엔진을 기준으로 삼아 측정 신뢰도를 높인다.
완전한 폰트 렌더러를 새로 만드는 대신, 브라우저의 실제 측정 결과를 활용하는 실용적 접근이다.
주의해야 할 제약
Pretext는 모든 CSS 텍스트 기능을 완벽히 재현하는 범용 엔진은 아니다.
현재는 흔한 문단 설정을 중심으로 맞춰져 있다.
특히 정확도를 위해 font와 lineHeight 값을 실제 CSS와 맞춰야 한다.
폰트 문자열이 다르면 계산도 어긋난다.
또 macOS에서는 system-ui가 layout() 정확도에 안전하지 않다고 안내한다.
이 경우에는 명시적인 폰트 이름을 쓰는 편이 낫다.
아주 좁은 폭에서는 overflow-wrap: break-word 성격 때문에 단어 내부도 끊길 수 있지만, 그마저도 글자 단위가 아니라 그래핌 경계 기준으로 처리된다.
보조 기능과 운영 관점
라이브러리는 캐시를 활용한다.
그래서 텍스트나 폰트 종류가 매우 다양하게 바뀌는 앱이라면 clearCache()로 메모리를 정리할 수 있다.
setLocale()로 이후 준비 작업에 사용할 로케일을 바꿀 수도 있다.
이 함수는 내부적으로 캐시를 비우지만, 이미 만들어 둔 준비 결과를 수정하지는 않는다.
즉, 새 설정은 이후 작업에만 적용된다.
프로젝트 성격과 생태계 정보
이 프로젝트는 TypeScript 중심으로 작성된 오픈소스 저장소이며, GitHub Pages 데모도 제공한다.
설치 패키지명은 @chenglou/pretext다.
뿌리는 과거의 text-layout 아이디어에서 이어졌고, canvas 측정, bidi 처리, 스트리밍 줄바꿈 같은 설계 전통을 계승해 발전한 것으로 보인다.
목표는 단순한 유틸리티를 넘어, 빠르고 정확한 텍스트 레이아웃 기반 도구를 제공하는 데 있다.
인사이트
Pretext의 핵심은 "측정"과 "배치"를 분리했다는 점이다.
한 번 준비하고 여러 번 계산하는 구조를 이해하면, 이 라이브러리를 어디에 써야 할지가 선명해진다.
실무에서는 먼저 prepare()를 캐싱하고, 리사이즈나 컨테이너 폭 변경 시 layout()만 반복하는 패턴으로 쓰는 것이 가장 효과적이다.
텍스트를 직접 그려야 하거나 줄별 제어가 필요하면 prepareWithSegments() 계열로 올라가면 된다.
출처 및 참고 : chenglou/pretext
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.