Mundarija (31)
- Bu darsda
- 1. Nega bu kerak?
- 2. next/font/local
- 2.1 Kanondagi kod
- 2.2 Ulash
- 2.3 Next nima yasadi — haqiqiy CSS
- 3. next/font/google — kanon tajribasi
- 3.1 Qanday ishlaydi
- 3.2 Internetsiz — build yiqildi
- 4. OG rasmlarga shrift va DataView tuzog'i
- 4.1 Muammo
- 4.2 Sabab — natija oynasida
- 4.3 Nega aynan .slice().buffer
- 4.4 ImageResponse ga shrift
- 5. next/script
- 5.1 Strategiyalar
- 5.2 @next/third-parties
- 5.3 portfolio da — yo'q
- 6. Tailwind bilan
- 7. Portfolio qadami: Rubik va commit
- 7.1 Fayllar (holat 32)
- 7.2 Tekshiruv va commit
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): strategiya tanlang
- 2-mashq (o'rta): fayl imzosini tekshiring
- 3-mashq (qiyin): zaxira shrift o'lchami
- 4-mashq: Portfolio qadami
- 10. Real ishda
- Xulosa
- Manbalar
next/font va next/script: o'z shriftingiz, zaxira shrift va 3-tomon skriptlar
Qisqacha:
next/fontshriftni build vaqtida loyihaning o'ziga ko'chiradi (/_next/static/media/) va brauzergapreloadishorasini beradi. U o'lchamlari moslangan zaxira shrift ham yasaydi — shrift yuklanganda matn sakramaydi (CLS 0).next/font/googleham shriftni Google'dan build vaqtida oladi, brauzer Google'ga bormaydi; lekin build uchun internet kerak.next/font/local— o'z faylingiz.next/script3-tomon skriptlarni to'g'ri vaqtda yuklaydi:afterInteractive(sukut),lazyOnload,beforeInteractive.
Bu darsda
next/font/localbilan v1 dagi Rubik shriftiniportfolioga qaytarasiz va Next yasagan haqiqiy CSS'ni o'qiysiz.- Zaxira shrift (
size-adjust) CLS'ni qanday yo'qotishini tushuntirasiz. next/font/googlevalocalfarqini kanon tajribasi bilan bilasiz: internetsiz build yiqiladi.- OG rasmlarga shrift berasiz va
DataViewxatosining sababini jonli ko'rasiz. next/scriptstrategiyalarini va@next/third-partiesni bilasiz.
Oldin bilishingiz kerak: next/image, Veb-shriftlar, SEO fayllari va OG rasmlar, Core Web Vitals, Uchinchi tomon skriptlar.
1. Nega bu kerak?
v1 saytida sarlavhalar Rubik shriftida edi (Veb-shriftlar darsida @font-face bilan ulangan). portfolio v2 hozircha tizim shriftida — Layout darsida "Rubik next/font darsida qaytadi" degan edik.
Oddiy @font-face ning uchta muammosi bor:
- Kech topilish. Brauzer shriftni CSS'ni yuklab, tahlil qilib, matnni ko'rgandagina so'raydi. Shrift kechikadi.
- Sakrash. Avval zaxira shrift (Arial) chiziladi, keyin Rubik keladi. Harflar kengligi boshqa — qatorlar siljiydi (CLS).
- Tashqi server.
fonts.googleapis.comdan ulansa — brauzer har tashrifda Google'ga so'rov yuboradi (maxfiylik), Google ishlamasa — shrift yo'q.
next/font uchalasini build vaqtida hal qiladi. Hayotiy o'xshatish: to'y uchun stullar. @font-face — mehmonlar kelgandan keyin stul qidirish. next/font — stullarni oldindan olib kelib, ularning joyiga xuddi shunday o'lchamdagi vaqtinchalik o'rindiq qo'yish: almashtirilganda hech kim joyidan siljimaydi.
2. next/font/local
2.1 Kanondagi kod
src/shriftlar/index.ts (holat 32):
import localFont from "next/font/local";
export const sarlavhaShrifti = localFont({
src: "./rubik-latin-wght.woff2",
weight: "300 900",
display: "swap",
variable: "--shrift-rubik",
adjustFontFallback: "Arial",
});| Variant | Ma'nosi |
|---|---|
src |
shrift fayli — shu papkada, Fontsource'dan (Rubik 5.3.0, lotin qismi, 35 348 B) |
weight: "300 900" |
variable font — bitta faylda 300 dan 900 gacha hamma qalinlik |
display: "swap" |
shrift kelguncha zaxira bilan ko'rsat (C-31 dagi font-display) |
variable |
CSS o'zgaruvchi nomi — CSS'da shriftni shu orqali ishlatamiz |
adjustFontFallback |
zaxira shriftni qaysi tizim shriftidan moslab yasash |
Shrift litsenziyasi — SIL OFL 1.1: OFL.txt fayli yonida turadi (litsenziya shuni talab qiladi). Variable font (o'zgaruvchan shrift) — har qalinlik uchun alohida fayl o'rniga bitta fayl: kanon 300–900 ni bitta 35 KB faylda oldi.
next/font funksiyalari modul darajasida chaqiriladi (komponent ichida emas) — Next ularni build vaqtida statik tahlil qiladi.
2.2 Ulash
Root layout'da <html> ga o'zgaruvchi klassi:
import { sarlavhaShrifti } from "@/shriftlar";
<html
lang="uz"
className={sarlavhaShrifti.variable}
suppressHydrationWarning
>globals.css dagi bitta qator o'zgardi:
- --shrift-sarlavha: var(--shrift-matn);
+ --shrift-sarlavha: var(--shrift-rubik), var(--shrift-matn);v1 tokenlari (dizayn tizimi) shu yerda yashaydi: sarlavhalar --shrift-sarlavha ni ishlatadi, endi u Rubik'ni oladi. Hech bir komponent o'zgarmadi.
2.3 Next nima yasadi — haqiqiy CSS
Build'dan keyin .next/static/chunks/ dagi CSS faylida (holat 32 nusxasi, biz ishga tushirdik; qatorlarga bo'lindi):
@font-face{font-family:sarlavhaShrifti;src:url(../media/rubik_latin_wght-s.p.2hiny1627tgmp.woff2)format("woff2");font-display:swap;font-weight:300 900}
@font-face{font-family:sarlavhaShrifti Fallback;src:local(Arial);ascent-override:91.09%;descent-override:24.36%;line-gap-override:0.0%;size-adjust:102.64%}
._3Uyl2a_className{font-family:sarlavhaShrifti,sarlavhaShrifti Fallback}
._3Uyl2a_variable{--shrift-rubik:"sarlavhaShrifti", "sarlavhaShrifti Fallback"}Qatorma-qator:
- Rubik — endi
/_next/static/media/dan. Fayl nomidagis.p— "subset, preload": oldindan yuklanadi. Oila nomi —sarlavhaShrifti: Next eksport qilingan o'zgaruvchi nomini oldi. - Zaxira shrift — oddiy Arial, lekin to'rtta tuzatish bilan:
size-adjust: 102.64%— Arial harflarini 2.64% kattalashtir;ascent-override,descent-override— qator balandligini Rubik'nikiga tenglashtir. Natija: Arial Rubik bilan bir xil joy egallaydi. className— shriftni to'g'ridan qo'llash uchun.variable— biz ishlatgan klass:--shrift-rubiko'zgaruvchisini e'lon qiladi.
Vaqt bo'yicha shunday:
sequenceDiagram
participant B as Brauzer
participant S as Server
B->>S: HTML so'rovi
S-->>B: HTML + font preload ishorasi
B->>S: rubik…woff2 (darhol)
Note over B: matn "sarlavhaShrifti Fallback" bilan
S-->>B: Rubik keldi (swap)
Note over B: harf shakli o'zgardi, joy — yo'qIkkinchi qator — butun hiylaning yuragi. Shrift kelguncha matn "Rubik o'lchamidagi Arial" bilan chiziladi; Rubik kelganda harflar shakli o'zgaradi, lekin qatorlar siljimaydi. Kanon o'lchovi: CLS 0.
Preload — HTML'ga RSC ma'lumoti ichida ishora sifatida tushdi (/loyihalar/vazifalar sahifasidan ko'chirma):
:HL[\"/_next/static/media/rubik_latin_wght-s.p.2hiny1627tgmp.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]HL — "hint link": React buni brauzerda <link rel="preload" as="font"> ga aylantiradi. Kanon Chrome o'lchovida preload ro'yxatida shrift bor edi (32-rasm-keyin.txt), h1 shrift steki: sarlavhaShrifti, "sarlavhaShrifti Fallback", system-ui, ….
Narxi: har sahifa boshiga +34.5 KB shrift (tekshiruv-32.txt), JS o'zgarmadi, CSS 2.2 → 2.4 KB.
Tekshirib ko'ring: Nega zaxira shrift uchun Arial, Georgia emas?
adjustFontFallbackni nima belgilaydi?
Javob
Zaxira asosiy shriftga shakl jihatidan yaqin bo'lishi kerak. Rubik — tirnoqsiz (sans-serif), Arial ham. Georgia tirnoqli (serif) — size-adjust bilan o'lchamni tenglashtirsa ham, harflar juda boshqacha ko'rinib, almashish sezilardi. next/font/local da adjustFontFallback: "Arial" (sukut) yoki "Times New Roman" (serif shriftlar uchun) yoki false.
3. next/font/google — kanon tajribasi
3.1 Qanday ishlaydi
import { Rubik } from "next/font/google";
const rubik = Rubik({
subsets: ["latin", "cyrillic"],
variable: "--shrift-rubik",
});Nomi "google" bo'lsa ham, brauzer Google'ga bormaydi: Next shriftni build vaqtida yuklab, o'z serveringizga qo'yadi. subsets — qaysi harflar to'plami: o'zbek lotini uchun latin yetarli (o', g' — oddiy harf + apostrof), rus tili uchun cyrillic.
Kanon buni sinab ko'rdi (natijalar/tajriba/32-next-font-google.txt). Internet bor — build 28 s, .next/static/media da 6 ta fayl:
32480 098850a6eb1f8577-s.1e7lfzpvfrh7f.woff2
15108 21445b8bd0ec5702-s.1n1ntp5se85-_.woff2
12288 6dac7af80352e41b-s.1-avrnevmoafi.woff2
9352 87c7f5b5afcd23bd-s.0kf5m0zv7sxld.woff2
35324 c9f6ebf08ddd616b-s.p.0sv86lbjkn8rn.woff2
19288 d25394c5b8ff78eb-s.0ongx-zmnmtio.woff2Google shriftni bir nechta qismga (subset) bo'lib beradi: lotin, kengaytirilgan lotin, kirill va boshqalar. s.p — faqat bittasi (lotin) preload qilinadi, qolganlari sahifada shunday harf uchrasagina yuklanadi (unicode-range).
3.2 Internetsiz — build yiqildi
Endi tarmoq yo'qligini taqlid qildik (HTTPS_PROXY ni ishlamaydigan manzilga):
Warning: Error while requesting resource
There was an issue establishing a connection while requesting https://fonts.googleapis.com/css2?family=Rubik:wght@300..900&display=swap
> Build error occurred
Error: Turbopack build failed with 1 error:Build to'xtadi. CI serverida Google'ga kirish cheklangan bo'lsa yoki Google javob bermasa — deploy ham to'xtaydi. Kanon qarori — local:
next/font/google |
next/font/local |
|
|---|---|---|
| Fayl qayerdan | build'da Google'dan | repodagi fayl |
| Build internetsiz | yiqiladi | ishlaydi |
| Brauzer Google'ga boradimi | yo'q | yo'q |
| Qulaylik | bitta qator | faylni o'zingiz olasiz (Fontsource) |
4. OG rasmlarga shrift va DataView tuzog'i
4.1 Muammo
Oldingi darsda OG rasmdagi sarlavha qalin chiqmagan edi — satori'da shrift yo'q edi. Endi Rubik bor. Lekin satori woff2 ni o'qimaydi (faqat ttf, otf, woff). Shuning uchun kanon OG uchun Rubik'ning ikkita .woff faylini qo'shdi (400 va 700) va ularni o'qiydigan yordamchi yozdi (src/shriftlar/og.ts, birinchi variant — soddalashtirilgan):
async function faylniOqi(nom: string): Promise<Uint8Array> {
"use cache";
cacheLife("max");
return new Uint8Array(
await readFile(path.join(process.cwd(), "src", "shriftlar", nom)),
);
}
// ImageResponse'ga:
// fonts: [{ name: "Rubik", data: await faylniOqi(…) }]Fayl o'qish Cache Components'da "keshlanmagan ma'lumot" — shuning uchun "use cache" (Cache Components I): build vaqtida bir marta o'qiladi. Build esa to'xtadi:
TypeError: First argument to DataView constructor must be an ArrayBufferTarjimasi: "DataView konstruktorining birinchi argumenti ArrayBuffer bo'lishi kerak".
4.2 Sabab — natija oynasida
Uint8Array — baytlar "oynasi" (view), ArrayBuffer esa baytlarning o'zi saqlanadigan xotira bo'lagi (ArrayBuffer va typed array). Satori shrift baytlarini new DataView(...) bilan o'qiydi va unga ArrayBuffer kerak. Keshdan esa Uint8Array qaytdi. Bir xil xatoni brauzerda ham olamiz:
const baytlar = new Uint8Array([0x77, 0x4f, 0x46, 0x46]); // "wOFF"
try {
new DataView(baytlar);
} catch (e) {
console.log(`${e.name}: ${e.message}`);
}
const buf = baytlar.slice().buffer;
const dv = new DataView(buf);
console.log(buf instanceof ArrayBuffer, dv.byteLength);
console.log(dv.getUint32(0).toString(16)); // 774f4646Konsolda:
TypeError: First argument to DataView constructor must be an ArrayBuffer
true 4
774f4646.slice() — massivning nusxasi, o'z alohida xotirasi bilan. .buffer — shu xotiraning ArrayBuffer i. 774f4646 — wOFF, woff fayllarining birinchi to'rt bayti (fayl "imzosi").
4.3 Nega aynan .slice().buffer
Nega shunchaki baytlar.buffer emas? Chunki Uint8Array kattaroq xotiraning bir bo'lagiga qarashi mumkin. Node'dagi Buffer (u ham Uint8Array) kichik ma'lumotlar uchun umumiy "hovuz" xotirasidan joy oladi:
const b = Buffer.from("Rubik");
console.log(b.byteLength); // 5
console.log(b.buffer.byteLength > b.byteLength); // true
console.log(new Uint8Array(b).buffer.byteLength); // 5b.buffer — 5 bayt emas, butun hovuz (Node 24 da biz o'lchaganda 65 536 bayt). Uni satori'ga bersak, shrift o'rniga begona baytlarni o'qirdi. Kanon yechimi Uint8Array.prototype.slice() — aniq o'z baytlari bilan yangi xotira:
// Keshdan Uint8Array qaytadi, satori esa ArrayBuffer kutadi
// ("First argument to DataView constructor must be an ArrayBuffer")
async function arrayBuffer(nom: string): Promise<ArrayBuffer> {
const b = await faylniOqi(nom);
return b.slice().buffer;
}Diqqat: Node
Bufferda.slice()nusxa qilmaydi (usubarraykabi o'sha xotiraga qaraydi). Kanon kodidab—Uint8Array(faylniOqiuninew Uint8Array(...)bilan nusxalab qaytaradi), shuning uchun.slice()haqiqiy nusxa.Bufferbilan ishlasangiz — avvalnew Uint8Array(buffer).
Tuzatishdan keyin build o'tdi: ○ /opengraph-image 30d 1y — rasm endi shrift keshiga bog'langan, sarlavha qalin.
4.4 ImageResponse ga shrift
return new ImageResponse(<div>…</div>, {
...size,
fonts: await ogShriftlari(),
});ogShriftlari() — ikki obyekt: { name: "Rubik", data, weight: 400 } va weight: 700. JSX'dagi fontWeight: 700 endi haqiqiy qalin faylni topadi.
5. next/script
5.1 Strategiyalar
3-tomon skriptlar (analitika, chat vidjeti, to'lov tugmasi) — Uchinchi tomon skriptlar darsidagi narx va maxfiylik muammolari Next'da ham o'sha. next/script faqat qachon yuklashni boshqaradi:
strategy |
Qachon | Misol |
|---|---|---|
beforeInteractive |
Next kodidan oldin; faqat root layout'da | bot himoyasi, cookie roziligi |
afterInteractive (sukut) |
sahifa jonlangach | analitika, teg menejeri |
lazyOnload |
brauzer bo'sh qolganda | chat vidjeti, ijtimoiy tarmoq tugmalari |
worker |
web worker'da (Partytown) | eksperimental, App Router'da ishlamaydi (hujjat) |
import Script from "next/script";
<Script
src="https://example.com/chat.js"
strategy="lazyOnload"
onLoad={() => console.log("chat tayyor")}
/>Ichki skript ham yozish mumkin — id bilan (Next uni bir marta ishga tushirish uchun kuzatadi). onLoad, onReady, onError — faqat client komponentda (funksiya brauzerda kerak).
5.2 @next/third-parties
Mashhur xizmatlar uchun tayyor komponentlar: GoogleTagManager, GoogleAnalytics, YouTubeEmbed, GoogleMapsEmbed. Ular skriptni optimal strategiya bilan ulaydi. Hujjat ochiq aytadi: kutubxona hali eksperimental.
5.3 portfolio da — yo'q
Kanonda 3-tomon skript yo'q: analitika hisobi va kaliti yo'q, va CSP script-src 'self' qoidasi tashqi skriptlarni baribir to'sadi. Shu bo'lim — hujjat bo'yicha, o'lchanmagan. Tashqi skript qo'shsangiz, ikki ishni qiling: CSP'ga domenni qo'shing va maxfiylik siyosatini yangilang (rozilik — 21-qism saboqlari).
Tekshirib ko'ring: Chat vidjeti uchun
beforeInteractivetanlandi — "tez yuklansin". Nima noto'g'ri?
Javob
Chat sahifaning asosiy vazifasi emas — foydalanuvchi uni darhol ishlatmaydi. beforeInteractive uni sahifaning o'z kodidan oldin yuklaydi va muhim JS navbatini sekinlatadi. To'g'ri tanlov — lazyOnload: sahifa tayyor, brauzer bo'sh — keyin chat. beforeInteractive — faqat sahifa ishlashi uchun oldin bo'lishi shart bo'lgan narsalar.
6. Tailwind bilan
Tailwind v4 ishlatilsa, shrift o'zgaruvchisi tema tokeniga ulanadi:
@theme inline {
--font-sarlavha: var(--shrift-rubik);
}Keyin font-sarlavha utility klassi Rubik'ni beradi. portfolio da Tailwind yo'q — nega, keyingi darsda o'lchov bilan.
7. Portfolio qadami: Rubik va commit
7.1 Fayllar (holat 32)
| Fayl | O'zgarish |
|---|---|
src/shriftlar/rubik-latin-wght.woff2 + OFL.txt |
Fontsource Rubik 5.3.0, lotin, variable |
src/shriftlar/index.ts |
localFont — sarlavhaShrifti |
src/shriftlar/og.ts + rubik-latin-400.woff, -700.woff |
OG shriftlari, "use cache", .slice().buffer |
app/layout.tsx |
<html className={sarlavhaShrifti.variable}> |
app/globals.css |
--shrift-sarlavha: var(--shrift-rubik), … |
ikki opengraph-image.tsx |
fonts: await ogShriftlari() |
loyihalar/[slug]/page.tsx, proxy.ts |
preload, matcher (next/image) |
7.2 Tekshiruv va commit
npm run lint
npm run tip
npm run build
npm run start/opengraph-image ni oching — sarlavha qalin. Sahifada DevTools → Elements → h1 → Computed → font-family. Kanon o'lchovi: JS 146.5 KB (o'zgarmadi), CSS 2.2 → 2.4 KB, shrift +34.5 KB, CLS 0, axe 0, hydration 0.
git add -A
git commitCommit (kanon): Media: Rubik next/font/local bilan, OG rasmlarda Rubik; LCP rasmiga preload; proxy matcher faqat slug'lar.
8. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
Build: Error while requesting resource … fonts.googleapis.com |
next/font/google + tarmoq yo'q |
next/font/local yoki tarmoqli build |
TypeError: First argument to DataView constructor must be an ArrayBuffer |
OG shriftiga Uint8Array berildi |
.slice().buffer |
| OG rasmda shrift ishlamaydi | woff2 berildi | ttf/otf/woff |
| Shrift qo'llanmadi | variable klassi <html> da yo'q |
className={font.variable} |
next/font komponent ichida chaqirildi — xato |
Funksiya statik tahlil qilinadi | Modul darajasida |
| Rus matni boshqa shriftda | subsets da cyrillic yo'q |
Kerakli subset |
worker strategiyasi ishlamaydi |
App Router'da hali yo'q | lazyOnload |
9. Mashqlar
Mashqlar kurs/mashqlar/23/32-next-font/ da. Jonli yechimlarni «Ishga tushir» bilan sinang.
1-mashq (oson): strategiya tanlang
- Google Analytics —
strategy="" - Sayt pastidagi chat vidjeti —
strategy="" - Sahifa ochilishidan oldin kerak bo'lgan bot himoyasi —
strategy=""
Yechim
- afterInteractive — sukut: sahifa jonlangach, iloji boricha erta; tashriflarni yo'qotmaydi.
- lazyOnload — kutishi mumkin, brauzer bo'shaganda.
- beforeInteractive — sahifa kodi uni kutishi kerak; faqat root layout'da.
2-mashq (o'rta): fayl imzosini tekshiring
Shrift fayli turini birinchi to'rt baytdan aniqlaydigan shriftTuri(baytlar) yozing: wOFF → "woff", wOF2 → "woff2", 00 01 00 00 → "ttf", OTTO → "otf", aks holda "noma'lum". DataView va getUint32 bilan o'qing. Keyin satori uchun yaroqliligini chiqaring (woff2 — yo'q).
Yechim
function shriftTuri(baytlar) {
const dv = new DataView(baytlar.slice(0, 4).buffer);
const imzo = dv.getUint32(0);
if (imzo === 0x774f4646) return "woff";
if (imzo === 0x774f4632) return "woff2";
if (imzo === 0x00010000) return "ttf";
if (imzo === 0x4f54544f) return "otf";
return "noma'lum";
}
const namunalar = [
[0x77, 0x4f, 0x46, 0x46],
[0x77, 0x4f, 0x46, 0x32],
[0x00, 0x01, 0x00, 0x00],
[0x89, 0x50, 0x4e, 0x47],
];
for (const n of namunalar) {
const tur = shriftTuri(new Uint8Array(n));
const yaroqli = ["woff", "ttf", "otf"].includes(tur);
console.log(`${tur}: satori ${yaroqli ? "o'qiydi" : "o'qimaydi"}`);
}Konsolda:
woff: satori o'qiydi
woff2: satori o'qimaydi
ttf: satori o'qiydi
noma'lum: satori o'qimaydiTo'rtinchi namuna — PNG imzosi (\x89PNG): shrift emas. baytlar.slice(0, 4).buffer — darsdagi qoida: DataView ga faqat ArrayBuffer, va aynan kerakli baytlar bilan.
3-mashq (qiyin): zaxira shrift o'lchami
Next zaxira shrift uchun size-adjust ni ikki shriftning o'rtacha harf kengligidan hisoblaydi. Soddalashtirilgan model yozing: sizeAdjust(asosiyKenglik, zaxiraKenglik) = asosiy / zaxira × 100, ikki xona aniqlik bilan, % belgisi bilan. Keyin bitta qatorning kengligini hisoblang: 40 belgi × 9 px (zaxira) — tuzatishsiz va tuzatish bilan; asosiy shriftda 40 × 9.2376 px. Qaysi biri asosiyga yaqin? Yaxlitlash — toFixed.
Yechim
function sizeAdjust(asosiy, zaxira) {
return `${((asosiy / zaxira) * 100).toFixed(2)}%`;
}
const zaxira = 9; // Arial, o'rtacha belgi kengligi (px)
const asosiy = 9.2376; // Rubik
const foiz = sizeAdjust(asosiy, zaxira);
console.log("size-adjust:", foiz);
const belgi = 40;
const tuzatishsiz = belgi * zaxira;
const tuzatilgan = belgi * zaxira * (parseFloat(foiz) / 100);
console.log("tuzatishsiz:", tuzatishsiz);
console.log("tuzatilgan:", tuzatilgan.toFixed(1));
console.log("asosiy:", (belgi * asosiy).toFixed(1));Konsolda:
size-adjust: 102.64%
tuzatishsiz: 360
tuzatilgan: 369.5
asosiy: 369.5Raqamlar ataylab tanlangan: natija — kanondagi haqiqiy size-adjust: 102.64%. Tuzatishsiz Arial qatori 9.5 px qisqa — shrift almashganda so'zlar keyingi qatorga o'tib, matn sakrardi. Next haqiqiy hisobda shrift metrikalari jadvalidan foydalanadi (capsize ma'lumotlari), bu esa g'oyaning modeli.
4-mashq: Portfolio qadami
Fontsource'dan Rubik'ning lotin variable woff2 faylini oling (va OFL.txt ni yoniga qo'ying), next/font/local bilan ulang. Build'dan keyin .next/static/chunks/*.css da Fallback qatorini toping. OG rasmlarga shrift qo'shing, /opengraph-image da sarlavha qalinligini tekshiring va holat 32 ni commit qiling.
Yechim
Kutilgan CSS — «Next nima yasadi» bo'limidagi to'rt qator (klass nomi va fayl xeshi boshqa bo'lishi mumkin). size-adjust qiymati shrift fayliga bog'liq: aynan shu Rubik faylida — 102.64%. OG uchun woff (400 va 700) alohida kerak — woff2 satori'da ishlamaydi. Agar DataView xatosi chiqsa — .slice().buffer ni unutgansiz.
10. Real ishda
- Har Next loyihasida
next/font— sukut tanlov;create-next-appshablonining o'zi Geist shriftininext/font/googlebilan ulaydi. - Korporativ CI ko'pincha tashqi tarmoqqa cheklangan — shuning uchun katta jamoalar
localshriftni afzal ko'radi. - GDPR va maxfiylik: 2022-yil 20-yanvarda Myunxen yer sudi (LG München I, ish 3 O 17493/20) qaror chiqardi. Sayt Google Fonts'ni Google serveridan ulagan edi — tashrifchining IP manzili roziliksiz Google'ga ketgan. Sud sayt egasiga tashrifchiga 100 yevro ma'naviy zarar to'lashni buyurdi. Sud muhim dalil sifatida aytdi: shriftni o'z serverdan berish mumkin edi. Shundan keyin Germaniyada bunday da'vo xatlari ko'paydi.
next/font(localham,googleham) bu muammoni hal qiladi — brauzer Google'ga bormaydi. - Intervyu savoli: "
next/fontCLS'ni qanday yo'qotadi?" —size-adjustva metrik override'lar bilan moslangan zaxira shrift.
Xulosa
next/fontshriftni build'da loyihaga ko'chiradi, preload qiladi vasize-adjustbilan moslangan zaxira shrift yasaydi — CLS 0.local— repodagi fayl, internetsiz build;google— build vaqtida Google'dan, tarmoqsiz build yiqiladi (kanon tajribasi).- Rubik variable (300–900) bitta 35 KB faylda; har sahifaga +34.5 KB, JS o'zgarmadi.
- OG (satori) — faqat ttf/otf/woff va
ArrayBuffer: keshdan kelganUint8Array→.slice().buffer, aks holdaDataViewxatosi. next/script:afterInteractivesukut,lazyOnload— kutishi mumkin bo'lganlar,beforeInteractive— faqat root layout'da.
Keyingi dars: Next.js'da stil va tema — Tailwind, CSS Modules va global CSS'ni o'lchov bilan solishtiramiz va loyiha kartasini CSS Module'ga o'tkazamiz.
Manbalar
- Next.js hujjati (16.4.0,
node_modules/next/dist/docs/): "Font Optimization",FontAPI reference (next/font/local,adjustFontFallback),ImageResponse,Scriptcomponent (strategiyalar,workerogohlantirishi), "Third Party Libraries" — nextjs.org/docs/app/api-reference/components/font (2026-10-21 da o'qildi) - Kanon natijalari:
natijalar/tajriba/32-next-font-google.txt,natijalar/32-rasm-keyin.txt,natijalar/tekshiruv-32.txt; holat 32 (src/shriftlar/) - Next yasagan
@font-faceCSS va RSC preload ishorasi, NodeBufferhovuzi — biz ishga tushirdik:portfolioholat 32 nusxasi, next 16.4.0, Node 24.21.0, 2026-10-21 - Fontsource Rubik 5.3.0 (SIL OFL 1.1) — fontsource.org/fonts/rubik
- LG München I, 2022-01-20, Az. 3 O 17493/20 (Google Fonts, 100 €): IHK Bergische Region — ihk.de/bergische/recht-und-steuern/wettbewerbsrecht/google-fonts-5646176; Dr. Datenschutz — dr-datenschutz.de/schadensersatz-urteil-google-fonts-und-die-dsgvo/ (ikkalasi 2026-10-21 da ko'rildi)
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!