perf(fonts): self-host Inter via next/font instead of remote stylesheets - #755
Open
dgaponov wants to merge 1 commit into
Open
perf(fonts): self-host Inter via next/font instead of remote stylesheets#755dgaponov wants to merge 1 commit into
dgaponov wants to merge 1 commit into
Conversation
Inter was pulled in by CSS `@import url(https://fonts.googleapis.com/...)` statements. A CSS @import is only discovered after the importing stylesheet has been downloaded and parsed, so the critical path was serialized: document -> app CSS -> fonts.googleapis.com -> fonts.gstatic.com, with a DNS lookup and TLS handshake for each third-party origin. Under mobile throttling this measured as roughly 0.9-1.2s of render-blocking time. There were three sources, not one: - src/vendors.scss (Inter wght@200) - @gravity-ui/uikit/styles/fonts.css, imported directly by _app - the same uikit file again, imported transitively by @gravity-ui/blog-constructor/styles/styles.css Inter is now downloaded at build time and served from our own origin with a preload hint. The two extra origins and both extra round trips are gone; the font files are now requested before the stylesheets rather than after them. next/font also generates a size-adjusted fallback face, which reduces layout shift while the font loads. Notes on the implementation: - The font must be declared in _app, not _document. Declaring it in _document produced the class names but emitted no CSS and downloaded no font files, which would have silently dropped Inter site-wide. - The uikit stylesheet is aliased to an empty file so the transitive import cannot reintroduce the remote request. - The .g-root override uses a doubled selector. uikit's own .g-root rule has equal specificity and wins on source order, which left sandbox pages resolving a literal "Inter" that no longer exists as a family name. Verified in a production build and a real browser: zero requests to googleapis/gstatic on landing, blog, component and sandbox pages; Inter 200, 400 and 600 loaded from our origin and applied to headings; sandbox pages still render Inter; ru pages still render Cyrillic. All page types return 200. Build, lint and typecheck pass. E2E not run - Playwright browsers are not installed locally. This addresses the font half of the render-blocking finding only. The 522 kB (68 kB gzip) global CSS chunk is untouched and still render-blocking. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
dgaponov
marked this pull request as ready for review
September 11, 2026 08:35
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Inter подключался через CSS
@import url(https://fonts.googleapis.com/...). Такой импорт обнаруживается только после парсинга импортирующего стиля, поэтому цепочка была последовательной: документ → CSS → googleapis → gstatic, с DNS и TLS на каждый сторонний домен (~0.9–1.2 с блокировки на мобильном).Источников было три, а не один:
vendors.scss, прямой импортuikit/styles/fonts.cssв_appи он же транзитивно черезblog-constructor. Последний заглушён алиасом, иначе возвращается через зависимость.Стало: 0 сторонних доменов, шрифты грузятся до стилей по preload. Бонусом next/font даёт size-adjusted fallback, уменьшающий сдвиг макета.
Две детали: шрифт нужно объявлять в
_app, а не_document(иначе CSS не эмитится и Inter молча пропадает), и override.g-rootиспользует удвоенный селектор — правило uikit имеет ту же специфичность и выигрывает по порядку.Это только половина находки про render-blocking. Глобальный CSS-чанк на 522 КБ не тронут.
🤖 Generated with Claude Code