IlmHamroh
JavaScript Full-stack/5-qism. CSS asoslari va layout31/63-dars24 daqiqa
Mundarija (42)

CSS web shriftlar: @font-face, WOFF2 formati va tez yuklash

Qisqacha: Qurilmada yo'q shriftni ishlatish uchun uning WOFF2 faylini saytga qo'yasiz va @font-face bilan unga nom berasiz. Faylni o'z serveringizda saqlash (self-host) Google Fonts'dan tezroq, maxfiyroq va qat'iy CSP bilan mos. Shrift kelguncha font-display: swap matnni zaxira shriftda ko'rsatadi, preload yuklashni erta boshlaydi, size-adjust bilan moslangan zaxira esa shrift almashganda sahifani "sakratmaydi".

Bu darsda

  • «Bahor» uchun ochiq litsenziyali shrift tanlaysiz va uni assets/fonts/bahor.woff2 ga joylaysiz.
  • @font-face yozasiz: src, format(), font-weight diapazoni, local(), unicode-range.
  • Google Fonts va o'z serveringizdagi shriftni tezlik, maxfiylik va CSP bo'yicha solishtirasiz.
  • font-display qiymatlarini FOUT va FOIT bilan bog'lab tushuntirasiz, shriftni preload qilasiz.
  • Zaxira shriftni size-adjust va ascent-override bilan moslab, layout sakrashini kamaytirasiz.

Oldin bilishingiz kerak: Shrift asoslari, Shriftlar, arxivlar va hujjat fayllari, Resurs maslahatlari, HTML darajasidagi xavfsizlik.

1. Nega bu kerak?

Shrift asoslari darsida «Bahor» sarlavhasiga qurilmada bor shriftlardan stek yozdik. Windows'da u Sitka Text bo'ldi, Mac'da odatda Charter. Chiroyli, lekin har qurilmada boshqacha. Jasur aka esa choyxona peshtaxtasidagi yozuv bilan bir xil, hamma joyda bir xil ko'rinadigan sarlavha xohlaydi.

Buning yagona yo'li — shrift faylini saytning o'ziga qo'yish. Brauzer sahifa bilan birga shriftni ham yuklab oladi. Bunday shrift web shrift (web font) deyiladi.

Lekin fayl — yuklanadigan narsa. Resurs maslahatlari darsida «Bahor» sarlavhasi sekin internetda avval oddiy shriftda chiqib, keyin "sakrab" almashganini ko'rgan edik. Bugun uchta savolga javob beramiz: qaysi shrift, qanday ulanadi va qanday qilib tez, sakramasdan yuklanadi.

2. «Bahor» shrifti: Lora

2.1 Tanlov mezonlari

Shrift ham mulk (Shriftlar, arxivlar va hujjat fayllari). Saytga qo'yadigan shriftimiz uch shartga javob bersin:

  1. Ochiq litsenziya. SIL Open Font License (OFL) — tijoriy saytda ham bepul, faylni o'z serverimizga qo'yishga ruxsat bor.
  2. O'zbek lotin harflari. Matnlarimiz o' va g' ni oddiy apostrof (') bilan yozadi, demak asosiy lotin harflari yetadi. Yana « » qo'shtirnoqlar va — tire kerak.
  3. Kichik hajm va kerakli qalinliklar. Sarlavhalar uchun 400 dan 700 gacha.

2.2 Lora

Biz Lora shriftini tanladik, uni Cyreal studiyasi yaratgan. Harflarida qo'lyozma "ohangi" bor: choyxonaga mos iliq, lekin yaxshi o'qiladi. Kirill harflari ham bor. Faktlarni rasmiy manbalardan tekshirdik:

  • Litsenziya — SIL Open Font License 1.1. Google Fonts repozitoriysidagi ofl/lora/OFL.txt faylida va Fontsource katalogida shunday yozilgan.
  • Variable shrift: bitta faylda 400 dan 700 gacha hamma qalinlik. Kursiv — alohida fayl.
  • Harflar: Lora'ning lotin qismi (latin) Google Fonts ma'lumotiga ko'ra U+0000-00FF (asosiy lotin, « » ham shu yerda) va U+2000-206F (tire va boshqa tinish belgilari) oraliqlarini qamraydi. Rasmiy yozuvdagi ʻ belgisi (U+02BB) ham shu qismda bor.
  • Hajm: lotin qismining variable WOFF2 fayli — 37 788 bayt, taxminan 37 KB. Taqqoslash uchun: alohida 400 va 700 fayllari birga 42 192 bayt.

Maslahat: OFL shriftni tarqatganda litsenziya matni ham birga bo'lishini talab qiladi. Shrift yoniga litsenziya faylini ham qo'yish yaxshi odat: assets/fonts/OFL.txt.

2.3 Faylni qayerdan olamiz

Fontsource (fontsource.org) — ochiq shriftlarni o'z serveringizga qo'yish uchun tayyorlab beradigan bepul katalog. Har shrift yozuv turlari bo'yicha bo'lingan WOFF2 fayllari bilan keladi. Bizga Lora'ning lotin qismi, variable varianti kerak — Fontsource uni jsDelivr orqali beradi:

text
https://cdn.jsdelivr.net/fontsource/fonts/lora:vf@latest/latin-wght-normal.woff2

Manzilni brauzerda ochsangiz, fayl yuklab olinadi. Uni «Bahor» papkasiga shunday nom bilan qo'ying:

text
bahor/
├── index.html
├── menyu/
└── assets/
    ├── css/asosiy.css
    └── fonts/
        ├── bahor.woff2
        └── OFL.txt

Nega lora.woff2 emas, bahor.woff2? Bu nom Resurs maslahatlari darsidan tanish va shriftni emas, vazifasini aytadi. Ertaga boshqa shrift tanlansa, faqat fayl almashadi — HTML va CSS'dagi yo'llar o'zgarmaydi.

3. @font-face — shriftga nom berish

3.1 Birinchi @font-face

Fayl joyida. Endi brauzerga "shu fayl — «Bahor» degan shrift" deb aytamiz. asosiy.css ning boshiga:

css
@font-face {
  font-family: "Bahor";
  src: url("../fonts/bahor.woff2") format("woff2");
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

h1,
h2 {
  font-family: "Bahor", serif;
}

@font-face — CSS nima darsidagi @-qoidalardan biri. Uning ichidagi qatorlar oddiy xususiyat emas, deskriptor (descriptor) — shrift faylini tasvirlaydigan yozuvlar. Ular hech narsani bo'yamaydi, faqat brauzerga fayl haqida ma'lumot beradi:

  • font-family: "Bahor" — shriftga o'zimiz beradigan nom. Keyin h1 qoidasida aynan shu nom bilan chaqiramiz.
  • src — fayl manzili va format("woff2") — "bu WOFF2 fayl" degan maslahat.
  • font-weight: 400 700 — "bu faylda 400 dan 700 gacha hamma qalinlik bor". Variable shrift uchun oraliq yoziladi.
  • font-style: normal — bu fayl tik harflar uchun.
  • font-display: swap — shrift kelguncha nima ko'rinishini aytadi, pastda alohida bo'limda ochamiz.

Choyxona omborini tasavvur qiling. @font-face — ombor daftaridagi yozuv: "«Bahor» — ikkinchi javonda". h1 qoidasi esa Otabekning buyurtmasi: "«Bahor»dan olib kel". Otabek javon raqamini bilishi shart emas — nomni aytsa yetadi.

3.2 url() — CSS faylga nisbatan

Bu darsning eng muhim nozik joyi. src dagi nisbiy yo'l HTML sahifaga emas, CSS faylga nisbatan hisoblanadi. asosiy.css — assets/css/ papkasida. Undan bir papka yuqoriga (../) chiqsak — assets/, keyin fonts/bahor.woff2.

Shuning uchun bu yo'l bosh sahifada ham, menyu/index.html da ham bir xil ishlaydi. CSS nima darsida link yo'lini har sahifa uchun alohida yozgan edik (assets/..., ../assets/...). CSS ichida esa bitta yo'l hamma sahifaga yetadi.

3.3 Brauzer shriftni qachon yuklaydi

@font-face yozilishi bilan shrift yuklanmaydi. Brauzer faylni faqat sahifada shu shrift bilan chiziladigan matn topilganda so'raydi. Chrome'da tekshirdik: @font-face bor, lekin hech bir element "Bahor" ni ishlatmagan sahifada Network panelida shrift so'rovi umuman yo'q.

Bu foydali: o'nta @font-face yozsangiz ham, sahifa faqat kerakligini yuklaydi. Lekin bitta kamchiligi bor — shrift kech topiladi. Brauzer avval HTML'ni, keyin CSS'ni yuklab o'qiydi, sahifani tuzadi va shundan keyingina shriftni so'raydi. Buni preload bo'limida tuzatamiz.

3.4 Natijada ko'rib chiqamiz

Natija oynasida «Bahor»ning assets/fonts/ papkasi yo'q. Shuning uchun xuddi shu Lora shriftini bu yerda Google Fonts'dan olamiz — saytda esa o'z faylimiz bo'ladi:

html
<link rel="stylesheet"
  href="https://fonts.googleapis.com/css2?family=Lora:wght@400..700">
<style>
  :root {
    --rang-asosiy: #2f6b3a;
    --rang-urgu: #b4461a;
    --rang-fon: #fffaf0;
    --rang-matn: #1f2a24;
  }
  body {
    font-family: system-ui, sans-serif;
    background-color: var(--rang-fon);
    color: var(--rang-matn);
  }
  h1,
  h2 {
    font-family: Lora, serif;
    color: var(--rang-asosiy);
  }
  .narx { color: var(--rang-urgu); }
</style>
<h1>Choyxona «Bahor»</h1>
<p>Har kuni 7:00 dan 23:00 gacha ochiqmiz.</p>
<h2>Bugun qozonda: to'y oshi</h2>
<p>Narxi: <span class="narx">35 000 so'm</span></p>

Nimaga qarang: ikkala sarlavha ham Lora'da — harflar uchida yumshoq "oyoqchalar", « » qo'shtirnoqlar va ' apostrof ham shu shriftda chizilgan. Paragraflar tizim shriftida qoldi. Endi bu ko'rinish Windows'da ham, telefonda ham bir xil — farqi shunda.

3.5 Qalinlik va kursiv uchun alohida fayllar

Variable bo'lmagan (klassik) shriftda har qalinlik — alohida fayl. Ular bitta nom ostida, har biri o'z @font-face i bilan yig'iladi:

css
@font-face {
  font-family: "Bahor";
  src: url("../fonts/bahor-400.woff2") format("woff2");
  font-weight: 400;
}
@font-face {
  font-family: "Bahor";
  src: url("../fonts/bahor-700.woff2") format("woff2");
  font-weight: 700;
}
@font-face {
  font-family: "Bahor";
  src: url("../fonts/bahor-400-kursiv.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
}

Brauzer h1 uchun (qalinligi 700) ikkinchi faylni, em uchun uchinchisini oladi. Qaysi fayl yo'q bo'lsa — Shrift asoslari darsidagi soxta qalin yoki soxta kursiv chiziladi. «Bahor» kursivni sarlavhada ishlatmaydi, shuning uchun bizga bitta variable fayl yetadi.

3.6 local() — qurilmadagi nusxa

src ga bir necha manba yozish mumkin, vergul bilan. Brauzer birinchi ishlaganini oladi:

css
@font-face {
  font-family: "Bahor";
  src: local("Lora"), url("../fonts/bahor.woff2") format("woff2");
}

local("Lora") — "kompyuterda Lora o'rnatilgan bo'lsa, o'shani ol, yuklama". Bugun u kam ishlatiladi: kompyuterdagi nusxa boshqa versiya bo'lishi mumkin. Dars oxirida local() ni boshqa, foydaliroq ish uchun ishlatamiz.

Tekshirib ko'ring: asosiy.css ichida src: url("assets/fonts/bahor.woff2") yozildi. Brauzer faylni qaysi manzildan qidiradi?

Javob

assets/css/assets/fonts/bahor.woff2 dan. Yo'l CSS faylning papkasidan (assets/css/) hisoblanadi, sahifanikidan emas. Bunday fayl yo'q — Network'da 404, sarlavha zaxira shriftda qoladi. To'g'risi — ../fonts/bahor.woff2.

4. Format: faqat WOFF2

Shrift formatlarining ko'pchiligi tarixga aylandi:

Format Nima Bugun
TTF, OTF Kompyuterga o'rnatiladigan asl shrift Saytga qo'ymang — siqilmagan, katta
EOT, SVG Eski Internet Explorer va eski iPhone uchun Umuman kerak emas
WOFF Siqilgan shrift (2012-yildan) O'rniga WOFF2
WOFF2 Brotli bilan yanada kuchliroq siqilgan Yagona kerakli format

Shriftlar, arxivlar va hujjat fayllari darsidagi raqamlarni eslang: arial.ttf — 1 045 KB, WOFF2 da — 434 KB, faqat lotin harflari bilan — 47 KB. WOFF2 ni hamma zamonaviy brauzer qo'llaydi.

Eski maqolalardagi besh formatli uzun src ni (.eot, .woff2, .woff, .ttf, .svg) ko'chirmang — u Internet Explorer davrining yozuvi. format("woff2") esa foydali: formatni tushunmagan brauzer faylni yuklamaydi ham.

5. Google Fonts yoki o'z serveringiz

5.1 Google Fonts qanday ishlaydi

Google Fonts — minglab bepul shriftlar katalogi va xizmati. Saytga bitta link qo'shasiz, lekin uning ortida uch qadam bor:

flowchart LR
  H["Sahifa"] --> C["fonts.googleapis.com<br/>CSS fayl"]
  C --> F["fonts.gstatic.com<br/>WOFF2 fayllar"]
  H2["Sahifa"] --> C2["asosiy.css"]
  C2 --> F2["assets/fonts/bahor.woff2"]

Nimaga qarang: yuqori yo'l — Google Fonts, pastki yo'l — o'z serveringiz. Google yo'lida brauzer ikki begona serverga ulanadi: avval CSS uchun, keyin shrift fayllari uchun. Resurs maslahatlari darsidagi preconnect aynan shu ulanishlarni tezlashtirish uchun edi.

Google Lora uchun qaytargan CSS faylda yetti bo'lak bor, har biri o'z @font-face i bilan. Lotin bo'lagi (qisqartirilgan):

css
/* latin */
@font-face {
  font-family: 'Lora';
  font-style: normal;
  font-weight: 400 700;
  src: url(https://fonts.gstatic.com/s/lora/.../...woff2)
    format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153,
    U+02BB-02BC, ..., U+2000-206F, ...;
}

Sizga tanish qatorlar: font-family, font-weight oralig'i, src va format. Yangi qator — unicode-range, uni sal pastda ko'ramiz.

5.2 Tezlik

Ilgari "Google Fonts tezroq — shrift boshqa saytdan keshda allaqachon bor" deyilardi. Bu eskirgan. Chrome'ning rasmiy blogiga ko'ra, Chrome 86 dan beri HTTP kesh saytlar bo'yicha bo'lingan: A saytida yuklangan shrift B saytida qayta yuklanadi. Google yo'lida faqat ikki begona serverga qo'shimcha ulanish qoladi, o'z serveringizdagi fayl esa sahifa bilan bir ulanishda keladi.

5.3 Maxfiylik

Brauzer Google serveridan shrift so'raganda, Google foydalanuvchining IP manzilini oladi. Google Fonts savol-javob sahifasiga ko'ra, u cookie o'rnatmaydi va yozib qo'ymaydi, IP esa so'rovga javob berish va xavfsizlik uchun ishlatiladi.

Yevropada bu sud ishiga ham aylangan. 2022-yil 20-yanvarda Myunxen (Germaniya) sudi shriftni Google'dan ulagan sayt egasini 100 yevro tovon to'lashga majburladi: u tashrif buyuruvchining IP manzilini roziligisiz Google'ga uzatgan. Bu O'zbekiston qonuni emas, lekin sayt Yevropadan ham ochilsa, bilib qo'ying. O'z serveringizdagi shriftda foydalanuvchi ma'lumoti hech kimga ketmaydi.

5.4 Qismlarga bo'lish va unicode-range

Shriftlar, arxivlar va hujjat fayllari darsida qism ajratish (subsetting) ni ko'rgan edik: shriftdan faqat kerakli harflar qoldiriladi. unicode-range — shu g'oyaning CSS'dagi davomi. U @font-face ga "bu fayl faqat shu belgilar uchun" deb aytadi. U+0000-00FF — Unicode jadvalidagi belgi raqamlari oralig'i.

Brauzer sahifadagi matnga qaraydi va faqat kerakli bo'laklarni yuklaydi. Chrome'da tekshirdik: faqat lotincha matnli sahifada Lora'ning yetti bo'lagidan bittasi — lotin bo'lagi yuklandi. Matnga bitta kirillcha so'z qo'shganimizda, kirill bo'lagi ham yuklandi.

O'zingiz shunday qilmoqchi bo'lsangiz — masalan, lotin va kirill fayllari alohida:

css
@font-face {
  font-family: "Bahor";
  src: url("../fonts/bahor.woff2") format("woff2");
  font-weight: 400 700;
  unicode-range: U+0000-00FF, U+2000-206F;
}
@font-face {
  font-family: "Bahor";
  src: url("../fonts/bahor-kirill.woff2") format("woff2");
  font-weight: 400 700;
  unicode-range: U+0400-04FF;
}

Ikkinchi oraliq — Unicode'ning butun kirill bloki. Nozik joy: o'zbek kirill yozuvidagi "қ", "ғ" va "ҳ" Google Fonts va Fontsource'da cyrillic emas, cyrillic-ext bo'lagida (unicode-range raqamlarini solishtirib tekshirdik). Kirill fayl tayyorlasangiz, ikkala bo'lakni ham oling.

«Bahor» sayti lotinda, shuning uchun unga bitta lotin fayli yetadi va unicode-range shart emas. Fontsource fayllari allaqachon bo'lingan. Qo'lda qism ajratish vositalarini kursda keyinroq ko'rasiz.

5.5 CSP: «Bahor» uchun hal qiluvchi sabab

HTML darajasidagi xavfsizlik darsida «Bahor»ga qat'iy CSP qo'ygan edik: default-src 'self'. Unda style-src ham, font-src ham yo'q. Demak, uslublar ham, shriftlar ham faqat o'z saytimizdan keladi.

Ikki holatni Chrome'da sinab ko'rdik. Birinchisi — «Bahor» sahifasiga Google Fonts link ini qo'shdik. Konsolda shunday xato chiqdi:

text
Loading the stylesheet 'https://fonts.googleapis.com/css2?family=Lora:wght@400..700&display=swap' violates the following Content Security Policy directive: "default-src 'self'". Note that 'style-src-elem' was not explicitly set, so 'default-src' is used as a fallback. The action has been blocked.

Tarjimasi: "Uslublar faylini yuklash CSP'ning default-src 'self' qoidasini buzadi. E'tibor bering: style-src-elem alohida yozilmagan, shuning uchun default-src ishlatildi. Amal bloklandi." style-src-elem — link va style teglari uchun alohida qoida nomi.

Ikkinchisi — asosiy.css dagi @font-face ga Google shrift faylining manzilini to'g'ridan-to'g'ri yozdik:

text
Loading the font 'https://fonts.gstatic.com/s/lora/v37/0QIvMX1D_JOuMwr7Iw.woff2' violates the following Content Security Policy directive: "default-src 'self'". Note that 'font-src' was not explicitly set, so 'default-src' is used as a fallback. The action has been blocked.

Tarjimasi: "Shriftni yuklash default-src 'self' qoidasini buzadi. font-src alohida yozilmagan, shuning uchun default-src ishlatildi. Amal bloklandi."

Google Fonts ishlashi uchun CSP'ni kengaytirish kerak: style-src ga https://fonts.googleapis.com, font-src ga https://fonts.gstatic.com. Biz xavfsizlik qoidasini zaiflashtirmaymiz — shriftni o'zimizga olamiz. Resurs maslahatlari darsidagi Google Fonts misoli va CSP orasidagi ziddiyat shunday yechiladi.

Google Fonts O'z serveringiz
Ulash Bitta link Fayl + @font-face
Ulanishlar Ikki begona server Sahifaning o'zi
Foydalanuvchi IP manzili Google'ga boradi Hech kimga ketmaydi
Qat'iy CSP Kengaytirish kerak O'zgarishsiz ishlaydi

Tekshirib ko'ring: Otabek Google Fonts link ini «Bahor»ning head iga qo'shdi va "sarlavha o'zgarmadi" dedi. Qaysi panelda nimani qidirasiz?

Javob

DevTools → Console'da Content Security Policy so'zli qizil xatoni. U CSS fayl bloklanganini aytadi. Network panelida esa css2?family=... so'rovi "blocked:csp" holatida turadi. Sabab — default-src 'self'. Yechim — CSP'ni buzish emas, shriftni o'z serverga qo'yish.

6. font-display: shrift kelguncha nima ko'rinadi

6.1 FOIT va FOUT

Sekin internetda shrift fayli bir necha soniya kelishi mumkin. Shu vaqt ichida brauzer ikki yo'ldan birini tanlaydi:

  • FOIT (Flash of Invisible Text) — "ko'rinmas matn chaqnashi". Matn joyi bor, lekin harflar yo'q — shrift kelguncha kutiladi. Foydalanuvchi bo'sh sarlavhaga qaraydi.
  • FOUT (Flash of Unstyled Text) — "bezaksiz matn chaqnashi". Avval zaxira shriftda chiqadi, shrift kelgach almashadi. Matn darhol o'qiladi, lekin bir marta "sakraydi".

Resurs maslahatlari darsida Jasur aka ko'rgan "sakrash" — bu FOUT. U yomon emas: o'qiladigan matn ko'rinmas matndan yaxshi. Faqat sakrashni kichraytirish kerak — buni dars oxirida qilamiz.

6.2 Uch davr

font-display shrift yuklanish vaqtini uch davrga bo'ladi:

flowchart LR
  A["Shrift so'raldi"] --> B["Bloklash davri:<br/>matn ko'rinmaydi"]
  B --> C["Almashtirish davri:<br/>zaxira shriftda"]
  C --> D["Muvaffaqiyatsizlik:<br/>zaxira qoladi"]

Nimaga qarang: shrift qaysi davrda kelsa, taqdiri shunga bog'liq. Bloklash yoki almashtirish davrida kelsa — darhol qo'llanadi. Uchinchi davrda kelsa — shu sahifada endi ishlatilmaydi. font-display qiymatlari faqat davrlarning uzunligini o'zgartiradi. Soniyalar — CSS Fonts spetsifikatsiyasi tavsiya qilgan qiymatlar:

Qiymat Bloklash Almashtirish
block Qisqa, taxminan 3 s Cheksiz
swap Juda qisqa, ≤ 100 ms Cheksiz
fallback Juda qisqa, ≤ 100 ms Qisqa, taxminan 3 s
optional Juda qisqa, ≤ 100 ms Yo'q

Beshinchi qiymat — auto: brauzer o'zi tanlaydi, amalda odatda block ga o'xshaydi. Ya'ni font-display yozmasangiz, FOIT olasiz.

6.3 Qaysi birini tanlash

  • swap — brend sarlavhasi uchun: matn darhol ko'rinadi, shrift qachon kelsa ham almashadi. «Bahor» shu qiymatni oladi.
  • optional — "bo'lsa yaxshi" shriftlar uchun. Shrift juda tez kelmasa, sahifa zaxirada qoladi va hech narsa sakramaydi. Fayl baribir keshga tushadi, keyingi sahifada darhol ishlaydi.
  • fallback — o'rtasi: 3 soniya ichida kelsa almashtiradi, kech qolsa — yo'q.
  • block — zaxirada ma'nosiz ko'rinadigan narsalar (ikonka shriftlari) uchun. Oddiy matnga ishlatmang.

O'zingiz ko'rish uchun: DevTools → Network → throttling ro'yxatidan Slow 4G ni tanlang va sahifani yangilang (Resurs maslahatlari darsida shunday qilgan edik). swap da sarlavha avval zaxira shriftda chiqadi va keyin almashadi.

Tekshirib ko'ring: «Bahor» sarlavhasi uchun font-display: optional tanlansa, birinchi marta kirgan foydalanuvchi sekin internetda nimani ko'radi? Ikkinchi sahifaga o'tganda-chi?

Javob

Birinchi sahifada — ehtimol butunlay zaxira shriftdagi sarlavhani: shrift 100 millisoniyada kelmadi, almashtirish davri esa yo'q. Lekin sakrash ham yo'q. Brauzer faylni baribir yuklab oladi, shuning uchun ikkinchi sahifada shrift keshdan darhol chiqadi.

7. preload — shriftni erta so'rash

Yuqorida ko'rdik: brauzer shriftni kech topadi — CSS'ni o'qib, sahifani tuzgandan keyin. Resurs maslahatlari darsida buning davosini o'rgangan edik: preload. Endi uni «Bahor»ning haqiqiy fayli bilan yozamiz. Bosh sahifaning head i:

html
<link rel="preload" href="assets/fonts/bahor.woff2"
      as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="assets/css/asosiy.css">

menyu/index.html va boshqa ichki sahifalarda — ../assets/fonts/bahor.woff2. O'sha darsda yo'l /assets/... bilan yozilgan edi. CSS nima darsidan beri «Bahor» nisbiy yo'l ishlatadi — / bilan boshlangan yo'l GitHub Pages loyiha saytida buziladi.

Uchta qoidani eslang:

  • as="font" — majburiy. Usiz brauzer faylga to'g'ri navbat bermaydi.
  • crossorigin — shrift o'z serveringizda bo'lsa ham majburiy. Brauzer shriftni doim CORS rejimida so'raydi, crossorigin siz preload boshqa rejimda so'raydi va fayl ikki marta yuklanadi.
  • Manzil CSS'dagi manzil bilan aynan bir xil faylga olib borsin. HTML'dagi assets/fonts/bahor.woff2 va CSS'dagi ../fonts/bahor.woff2 yozilishi har xil, lekin ikkalasi ham bitta faylga yetadi. Shuning uchun brauzer ularni bir xil deb biladi.
flowchart LR
  subgraph Y["preload'siz"]
    direction TB
    Y1["HTML"] --> Y2["asosiy.css"]
    Y2 --> Y3["bahor.woff2"]
  end
  subgraph B["preload bilan"]
    direction TB
    B1["HTML"] --> B2["asosiy.css"]
    B1 --> B3["bahor.woff2"]
  end

Nimaga qarang: preload bilan shrift CSS bilan bir vaqtda yuklanadi — navbatda bir qadam oldinga siljiydi. Preload faqat bitta, darhol kerak shriftga qo'yiladi. Sahifada ishlatilmaydigan shriftni preload qilsangiz, Chrome "preloaded but not used" deb ogohlantiradi.

«Bahor» head idan esa Resurs maslahatlari darsidagi <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> qatorini olib tashlang. Endi Google serveriga ulanish kerak emas.

8. Zaxira shriftni moslash: size-adjust va ascent-override

8.1 Sakrash qancha?

swap bilan sarlavha avval zaxira shriftda chiqadi. Lekin Lora harflari Times New Roman'nikidan kengroq, qatori balandroq. Shrift almashganda sarlavha ko'proq qatorga o'raladi va ostidagi hamma narsani pastga itaradi.

Buni layout sakrashi (layout shift) deyishadi. Google saytlarni baholaydigan Core Web Vitals o'lchovlarida uning alohida ko'rsatkichi bor — CLS (Cumulative Layout Shift). Uni Core Web Vitals darsida o'lchaymiz.

Chrome'da o'lchadik. Eni 320 piksel qutida 2rem sarlavha va bitta paragraf:

  • Lora'da sarlavha 3 qator — 123 piksel. Paragraf — 60 piksel.
  • Oddiy Times New Roman'da sarlavha 2 qator — 74 piksel. Paragraf — 54 piksel.

Shrift kelgan zahoti paragraf 49 piksel, undan keyingi hamma narsa esa 55 piksel pastga sakraydi. Telefonda bu o'qiyotgan qatoringizni yo'qotish degani.

8.2 Zaxirani web shriftga "kiyintiramiz"

G'oya: zaxira shriftning o'lchamlarini Lora'nikiga yaqinlashtiramiz. Buning uchun local() bilan yangi shrift yasaymiz — u Times New Roman'ning o'zi, lekin o'lchamlari o'zgartirilgan:

css
@font-face {
  font-family: "Bahor zaxira";
  src: local("Times New Roman");
  size-adjust: 115.2%;
  ascent-override: 87.33%;
  descent-override: 23.78%;
  line-gap-override: 0%;
}

h1,
h2 {
  font-family: "Bahor", "Bahor zaxira", serif;
}

To'rt deskriptor:

  • size-adjust — harflarni kattalashtiradi yoki kichraytiradi. 115.2% — Times New Roman harflari o'rtacha Lora eniga yetsin.
  • ascent-override — asosiy chiziqdan yuqoridagi joy (bosh harflar va urg'ular uchun).
  • descent-override — asosiy chiziqdan pastdagi joy ("y", "g" dumlari uchun).
  • line-gap-override — qatorlar orasidagi qo'shimcha bo'shliq.

Qiymatlarni o'ylab topmadik. Ular Capsize loyihasining shrift o'lchovlari jadvalidan (@capsizecss/metrics paketi, 4.3.0) hisoblangan. Har shriftning o'lchovlari 1000 yoki 2048 "birlik"da yozilgan — hisob shunday:

text
Lora:            o'rtacha harf eni 468 / 1000,
                 yuqori 1006, pastki 274 (1000 birlikda)
Times New Roman: o'rtacha harf eni 832 / 2048

size-adjust      = (468/1000) ÷ (832/2048) = 1.152 → 115.2%
ascent-override  = 1006 ÷ (1000 × 1.152)  ≈ 0.8733 → 87.33%
descent-override = 274 ÷ (1000 × 1.152)   ≈ 0.2378 → 23.78%
line-gap-override = 0 (Lora'da qo'shimcha bo'shliq yo'q)

Chrome'da sinadik:

html
<link rel="stylesheet"
  href="https://fonts.googleapis.com/css2?family=Lora:wght@400..700">
<style>
  @font-face {
    font-family: "Bahor zaxira";
    src: local("Times New Roman");
    size-adjust: 115.2%;
    ascent-override: 87.33%;
    descent-override: 23.78%;
    line-gap-override: 0%;
  }
  div {
    width: 20rem;
    outline: 2px dashed #b4461a;
    margin-bottom: 1rem;
  }
  h1 { font-size: 2rem; margin: 0; }
  p { margin: 0; }
  div:nth-of-type(1) { font-family: Lora; }
  div:nth-of-type(2) { font-family: "Times New Roman"; }
  div:nth-of-type(3) { font-family: "Bahor zaxira"; }
</style>
<div>
  <h1>Choyxona «Bahor»: osh, lag'mon va manti</h1>
  <p>Rustam aka oshni har kuni ertalab o'tin olovida, katta
  qozonda damlaydi. Soat 7:00 dan birinchi lagan tayyor.</p>
</div>
<div>
  <h1>Choyxona «Bahor»: osh, lag'mon va manti</h1>
  <p>Rustam aka oshni har kuni ertalab o'tin olovida, katta
  qozonda damlaydi. Soat 7:00 dan birinchi lagan tayyor.</p>
</div>
<div>
  <h1>Choyxona «Bahor»: osh, lag'mon va manti</h1>
  <p>Rustam aka oshni har kuni ertalab o'tin olovida, katta
  qozonda damlaydi. Soat 7:00 dan birinchi lagan tayyor.</p>
</div>

Nimaga qarang: birinchi quti — Lora, ikkinchisi — oddiy Times New Roman, uchinchisi — moslangan zaxira. Ikkinchi quti ancha past: sarlavha kamroq qatorga sig'di. Uchinchi quti esa birinchisi bilan bir xil balandlikda — harflar boshqa, lekin egallagan joy o'sha. Chrome'da o'lchadik: sarlavha 123 piksel, paragraf 60 piksel — Lora bilan aynan bir xil. Endi shrift almashganda sahifa joyidan qimirlamaydi.

8.3 Cheklovlar

Bu usul hamma joyda ishlamaydi:

  • Times New Roman hamma qurilmada yo'q. Windows va Mac'da bor, ko'p Android telefonlarda — yo'q. U yerda local() topolmaydi va brauzer stekdagi keyingi serif ga o'tadi, u moslanmagan.
  • Baseline. size-adjust — Baseline, hamma asosiy brauzerda bor. ascent-override, descent-override va line-gap-override esa Baseline emas: Baseline ma'lumotlariga ko'ra, Chrome va Firefox'da bor, Safari'da yo'q. Safari ularni tashlab ketadi va faqat size-adjust ni qo'llaydi — sakrash kichrayadi, lekin to'liq yo'qolmaydi.

Shunday bo'lsa ham, bu progressive enhancement (Brauzer mosligi): qo'llagan brauzerda sakrash yo'qoladi, qo'llamaganida hech narsa buzilmaydi.

Maslahat: Har yangi shrift uchun qo'lda hisoblash shart emas. Next.js (React asosidagi freymvork, kursda alohida o'rganamiz) ichidagi next/font buni avtomatik qiladi — faylni yuklab, zaxirasini moslab, preload ni ham qo'yadi. Uni next/font darsida ko'rasiz. Oddiy HTML saytda esa bu darsdagi qo'l usuli.

9. Ko'p uchraydigan xatolar

9.1 CSS'dagi yo'l sahifaga nisbatan yozilgan

src: url("assets/fonts/bahor.woff2") — brauzer assets/css/assets/fonts/... ni qidiradi. Tuzatish: url("../fonts/bahor.woff2") — yo'l CSS fayldan hisoblanadi.

9.2 Fayl o'rniga HTML sahifa keldi

Ba'zi server sozlamalari noto'g'ri manzilga ham "hammasi joyida" (200) javobi bilan HTML sahifa qaytaradi. Chrome'da tekshirdik — shrift o'rniga HTML kelganda konsolda ikki ogohlantirish chiqdi:

text
Failed to decode downloaded font: http://127.0.0.1:5500/assets/fonts/bahor.woff2
OTS parsing error: invalid sfntVersion: 1008821359

Tarjimasi: "Yuklangan shriftni ochib bo'lmadi" va "OTS tahlil xatosi: noto'g'ri sfntVersion". OTS — Chrome'ning shrift fayllarini xavfsizlik uchun tekshiradigan qismi. Katta son aslida <!DO belgilari (o'n oltilikda 3C21444F), ya'ni <!DOCTYPE ning boshi: brauzer shrift kutgan, HTML olgan. Tuzatish: Network panelida shrift so'rovini oching va Response'da nima kelganini ko'ring, keyin yo'lni tuzating.

9.3 Preload ishlamadi, fayl ikki marta yuklandi

Sabab — crossorigin yo'q yoki preload manzili boshqa faylga olib boradi. Konsolda "preloaded but not used" yoki "credentials mode does not match" ogohlantirishlari chiqadi (Resurs maslahatlari). Tuzatish: crossorigin qo'shing va ikkala manzil bitta faylga yetishini Network'da tekshiring.

9.4 Nomlar mos emas

@font-face da font-family: "Bahor", qoidada esa font-family: "Bahor Regular", serif. Brauzer "Bahor Regular" degan shriftni topmaydi. Tuzatish: @font-face dagi nom — siz o'ylab topgan yorliq, qoidada aynan shu yoziladi. Stek oxiridagi zaxirani ham unutmang: "Bahor", "Bahor zaxira", serif (Shrift asoslari).

10. Mashqlar

1-mashq (oson): Menyu sahifasining head i

menyu/index.html ning head iga «Bahor» shriftini preload qiladigan qatorni yozing. Keyin javob bering: nega asosiy.css dagi @font-face yo'li bosh sahifada ham, menyuda ham bir xil, preload yo'li esa har xil?

Ishora: "url() — CSS faylga nisbatan" va preload bo'limlari.

Yechim
html
<link rel="preload" href="../assets/fonts/bahor.woff2"
      as="font" type="font/woff2" crossorigin>
<link rel="stylesheet" href="../assets/css/asosiy.css">

Preload — HTML'da, uning yo'li sahifaning papkasidan hisoblanadi: menyu/ dan bir papka yuqoriga — ../. @font-face dagi yo'l esa CSS faylning papkasidan hisoblanadi. CSS fayl bitta va joyi bitta (assets/css/) — yo'l ham bitta. Ikkala yo'l oxirida bitta faylga yetadi.

2-mashq (o'rta): Nega sarlavha o'zgarmadi?

Stajyor «Bahor»ga shrift uladi, lekin sarlavha oddiy shriftda qoldi. Uning kodi:

css
@font-face {
  font-family: "Bahor";
  src: url("assets/fonts/bahor.woff2") format("woff2");
  font-weight: 400 700;
}
h1 {
  font-family: "Bahor Lora";
}
html
<link rel="preload" href="assets/fonts/bahor.woff2" as="font">

Uch xato va bitta kamchilikni toping.

Ishora: "Ko'p uchraydigan xatolar" ro'yxatiga qarang. Kamchilik — shrift kelguncha nima ko'rinishi haqida.

Yechim
  1. url yo'li sahifaga nisbatan yozilgan — ../fonts/bahor.woff2 bo'lishi kerak.
  2. Qoidadagi nom "Bahor Lora" — @font-face da "Bahor" deyilgan.
  3. Preload'da crossorigin yo'q — to'g'ri yo'l bilan ham fayl ikki marta yuklanardi. type="font/woff2" ham qo'shilsin.
  4. Kamchilik: font-display yo'q — auto, amalda FOIT. Stekda zaxira ham yo'q.
css
@font-face {
  font-family: "Bahor";
  src: url("../fonts/bahor.woff2") format("woff2");
  font-weight: 400 700;
  font-display: swap;
}
h1 {
  font-family: "Bahor", serif;
}
html
<link rel="preload" href="assets/fonts/bahor.woff2"
      as="font" type="font/woff2" crossorigin>

3-mashq (qiyin): Uch faylli shrift va to'g'ri font-display

Dizayner «Bahor»ning aksiya sahifasi uchun boshqa shrift tanladi. U variable emas: aksiya-400.woff2, aksiya-700.woff2 va aksiya-400-kursiv.woff2. Sarlavhalar 700, matn 400, izohlar kursiv.

  1. Shriftni "Aksiya" nomi bilan ulang.
  2. Qaysi font-display ni tanlaysiz? Sarlavha va matn uchun bir xil bo'lishi shartmi?
  3. Qaysi faylni preload qilasiz va nega hammasini emas?

Ishora: "Qalinlik va kursiv uchun alohida fayllar", "Qaysi birini tanlash" va preload bo'limlari. Bitta oila uchun bir necha @font-face bo'lishi mumkin.

Yechim
css
@font-face {
  font-family: "Aksiya";
  src: url("../fonts/aksiya-400.woff2") format("woff2");
  font-weight: 400;
  font-display: optional;
}
@font-face {
  font-family: "Aksiya";
  src: url("../fonts/aksiya-700.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
}
@font-face {
  font-family: "Aksiya";
  src: url("../fonts/aksiya-400-kursiv.woff2") format("woff2");
  font-weight: 400;
  font-style: italic;
  font-display: optional;
}
  • font-display har @font-face da alohida yoziladi. Sarlavha (700) — swap: brend ko'rinishi muhim. Matn va izoh — optional: uzun matn sakramaydi.
  • Preload — faqat aksiya-700.woff2: sarlavha tepada va darhol ko'rinadi. Uchala faylni preload qilsangiz, ular asosiy CSS bilan navbat talashadi.
  • Kursiv fayl izohsiz sahifada umuman yuklanmaydi — brauzer uni faqat kursiv matn uchrasa so'raydi.

4-mashq: Portfolio qadami — sarlavhalarga o'z shriftingiz

Portfolio'ning sarlavhalari hozir tizim shriftida. Ularga o'zingiz tanlagan ochiq litsenziyali shriftni bering.

  1. Fontsource'dan (fontsource.org) OFL litsenziyali, variable, lotin harflari bor shrift tanlang. Shrift sahifasida litsenziya yozilganini tekshiring.
  2. Lotin qismining variable WOFF2 faylini sayt/assets/fonts/sarlavha.woff2 nomi bilan saqlang. Yoniga OFL.txt ni qo'ying.
  3. asosiy.css boshiga @font-face yozing (font-display: swap) va h1, h2 ga stek bering — oxirida zaxira bilan.
  4. Hamma sahifaning head iga preload qo'shing. 404.html ga alohida e'tibor bering.
  5. DevTools → Network'da sarlavha.woff2 faqat bir marta yuklanganini tekshiring.

Ishora: Fontsource, birinchi @font-face va preload bo'limlari. 404.html dagi yo'llar CSS nima darsidan beri / bilan boshlanadi.

Yechim

Namuna sifatida Rubik shriftini oldik: litsenziyasi SIL OFL 1.1 (Google Fonts repozitoriysidagi ofl/rubik/OFL.txt), variable, qalinligi 300 dan 900 gacha. Lotin qismi — 35 348 bayt. Fayl manzili:

text
https://cdn.jsdelivr.net/fontsource/fonts/rubik:vf@latest/latin-wght-normal.woff2

sayt/assets/css/asosiy.css boshiga:

css
/* Sarlavha shrifti — Rubik, SIL OFL 1.1 */
@font-face {
  font-family: "Sarlavha";
  src: url("../fonts/sarlavha.woff2") format("woff2");
  font-weight: 300 900;
  font-display: swap;
}

h1,
h2 {
  font-family: "Sarlavha", system-ui, sans-serif;
}

Preload qatorlari:

Fayl href
index.html assets/fonts/sarlavha.woff2
haqimda/, loyihalar/, aloqa/ ../assets/fonts/sarlavha.woff2
loyihalar/bahor/index.html ../../assets/fonts/sarlavha.woff2
404.html /assets/fonts/sarlavha.woff2

Har birida:

html
<link rel="preload" href="assets/fonts/sarlavha.woff2"
      as="font" type="font/woff2" crossorigin>

Bosh sahifaning yuqori qismi:

html
<link rel="stylesheet"
  href="https://fonts.googleapis.com/css2?family=Rubik:wght@300..900">
<style>
  body {
    font-family: system-ui, sans-serif;
    color: #1f2a24;
    background-color: #f7faf8;
  }
  h1,
  h2 {
    font-family: Rubik, system-ui, sans-serif;
    color: #1f6f4a;
  }
</style>
<h1>Salom, men Aziz — boshlovchi frontend dasturchiman</h1>
<p>Veb-saytlarni noldan o'rganyapman. Hozir CSS'ni
o'rganyapman.</p>
<h2>So'nggi loyihalar</h2>

Nozik joylar:

  • Natija blokida shrift Google Fonts'dan olingan: bu oynada sizning assets/ papkangiz yo'q. Portfolio faylida @font-face o'z faylingizga qaraydi.
  • Zaxira — system-ui: Rubik ham oyoqchasiz, shuning uchun sakrash kichikroq bo'ladi.
  • 404.html dagi preload / bilan, CSS'dagi ../fonts/... esa hamma sahifada ishlaydi — u CSS fayl joyidan hisoblanadi.
  • Boshqa shrift tanlagan bo'lsangiz, font-weight oralig'ini o'sha shrift sahifasidan oling.

11. Real ishda

  • Katta saytlar shriftlarini ko'pincha o'z serverida yoki CDN'ida saqlaydi. Istalgan saytda DevTools → Network → Font filtrini tanlang: .woff2 fayllar qayerdan kelayotganini ko'rasiz.
  • Freymvorklar bu qadamlarni avtomatlashtiradi: next/font shriftni o'z serveringizga qo'yadi, preload qiladi va zaxirani moslaydi. Fontsource'ning npm paketlari ham bor — npm'ni kursda keyinroq o'rganasiz.
  • Lighthouse (Lighthouse va PageSpeed) ko'rinmas matn va layout sakrashi haqida alohida ogohlantiradi — ko'pincha sababi shriftlarda.
  • Intervyuda so'raladi: "FOIT va FOUT farqi nima?", "font-display: swap va optional qachon?", "Shrift preload'ida nega crossorigin kerak?", "Shrift sabab bo'lgan CLS'ni qanday kamaytirasiz?".

Xulosa

  • Web shrift — sayt bilan birga yuklanadigan shrift fayli; @font-face unga nom beradi, src dagi yo'l CSS faylga nisbatan hisoblanadi.
  • Faqat WOFF2 kerak; variable faylda font-weight: 400 700 kabi oraliq yoziladi.
  • «Bahor» shrifti — Lora (SIL OFL 1.1), assets/fonts/bahor.woff2 da, o'z serverida: tez, maxfiy va CSP bilan mos.
  • unicode-range bilan brauzer faqat kerakli harflar faylini yuklaydi.
  • font-display: swap — matn darhol, keyin almashadi (FOUT); optional — sakrashsiz, lekin shrift chiqmasligi mumkin.
  • preload + crossorigin shriftni erta so'raydi; moslangan zaxira (size-adjust, ascent-override) almashishdagi sakrashni kamaytiradi.

Keyingi dars: Variable shriftlar va OpenType xususiyatlari — bitta fayldagi qalinlik, en va qiyalik o'qlari, narxlar ustunini tekislaydigan raqamlar va ligaturalar.

Manbalar

  • MDN: "@font-face", "src", "font-display", "unicode-range", "size-adjust", "ascent-override" — developer.mozilla.org
  • W3C: "CSS Fonts Module Level 4" (font-display davrlari, metric override deskriptorlari) — w3.org/TR/css-fonts-4
  • Google Fonts: Lora litsenziyasi — github.com/google/fonts (ofl/lora/OFL.txt); savol-javob, maxfiylik bo'limi — fonts.google.com/faq
  • Fontsource: "Lora" — fontsource.org/fonts/lora
  • Chrome for Developers: "Gaining security and privacy by partitioning the cache" — developer.chrome.com/blog/http-cache-partitioning
  • Capsize: @capsizecss/metrics — github.com/seek-oss/capsize
  • web-features (Baseline ma'lumotlari): "font-display", "size-adjust", "Font metric overrides" — github.com/web-platform-dx/web-features
Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
CSS web shriftlar: @font-face, WOFF2 formati va tez yuklash — IlmHamroh