Mundarija (34)
- Bu darsda
- 1. Nega bu kerak?
- 2. Uch oila: offset, client, scroll
- 2.1 Bitta karta, uch xil o'lcham
- 2.2 scroll* — ko'rinmay turgan kontent
- 3. Aylantirish: scrollTop va uning chegaralari
- 3.1 scrollTop — o'qish va yozish
- 3.2 Foizda: "qancha o'qildi?"
- 4. getBoundingClientRect — ekrandagi joy
- 4.1 To'rtburchak
- 4.2 Viewport'ga nisbatan — aylantirsa o'zgaradi
- 4.3 Layout va ko'rinish: transform farqi
- 5. Amaliy holat: tugma ostiga ishora
- 6. Oyna va sahifa darajasida
- 6.1 Oyna o'lchamlari
- 6.2 Sahifani aylantirish
- 7. scrollIntoView — elementni ko'rinishga olib kelish
- 7.1 Nega "nearest"?
- 7.2 Forma xatosiga aylantirish
- 8. O'lcham o'qish — bepul emas
- 9. Ko'p uchraydigan xatolar
- 9.1 style.width dan o'lcham kutish
- 9.2 Yashirin elementni o'lchash
- 9.3 Silliq aylantirishdan keyin darhol o'qish
- 9.4 Rasm yuklanmasdan o'lchash
- 9.5 margin ni o'lchamda qidirish
- 10. Mashqlar
- 1-mashq (oson): O'lchamlarni oldindan ayting
- 2-mashq (o'rta): Kontent sig'dimi?
- 3-mashq (qiyin): Ishora ekrandan chiqmasin
- 4-mashq: Portfolio qadami — "Yuqoriga" faqat kerak bo'lganda
- 11. Real ishda
- Xulosa
- Manbalar
Element o'lchamlari va scroll: getBoundingClientRect, offsetWidth, scrollTop va scrollIntoView
Qisqacha: Element qancha joy egallashini uch oila xususiyat aytadi:
offsetWidth— chegarasi bilan,clientWidth— chegarasiz ichki qismi,scrollWidth— ko'rinmay turgan kontent bilan birga. Ekranning qayerida turganinigetBoundingClientRect()beradi. Aylantirish uchunscrollTopga qiymat yozasiz yokiscrollTo,scrollBy,scrollIntoViewmetodlarini chaqirasiz —behavior: "smooth"bilan silliq.
Bu darsda
offset*,client*vascroll*xususiyatlari nimani o'lchashini va qaysi biri qachon kerakligini bilasiz.getBoundingClientRect()bilan elementning ekrandagi joyini topib, uning yoniga boshqa element qo'ya olasiz.- Ro'yxatni JavaScript bilan aylantira olasiz va "oxiriga yetdimi?" savoliga javob bera olasiz.
- Oyna o'lchamlarini (
innerWidth,clientWidth,scrollY) farqlay olasiz. - O'lcham o'qish nega qimmat ekanini va qaysi tuzoqlar borligini tushuntira olasiz.
Oldin bilishingiz kerak: Ko'p elementni samarali chizish, Box model, position va containing block, Skroll xulqi va scroll-snap.
1. Nega bu kerak?
Hozirgacha DOM'dan ma'no o'qidik: matn, atribut, class. Lekin ba'zi vazifalarda boshqa savol turadi: element qancha joy egallaydi va qayerda turibdi?
«Bahor» saytidagi vaziyatlar:
- "Bron qilish" tugmasi ustiga ishora (tooltip) chiqishi kerak — aynan tugmaning ostida, tugma qayerda bo'lmasin.
- Bron formasida xato bo'lsa, sahifa o'sha maydonga o'zi aylanib borishi kerak.
- Menyu ro'yxati uzun. "Boshiga qaytish" tugmasi va "ro'yxat oxiriga yetdingiz" yozuvi kerak.
- Sahifa qisqa bo'lsa, "Yuqoriga" havolasining keragi yo'q.
CSS'da o'lchamni berasiz: width: 200px. JavaScript'da esa brauzer hisoblab bo'lgan haqiqiy o'lchamni o'qiysiz. Box model darsidagi qutilarni eslang — bugun o'sha qutilarni raqam bilan ko'ramiz.
2. Uch oila: offset, client, scroll
2.1 Bitta karta, uch xil o'lcham
Kartaga aniq o'lchamlar beramiz va JavaScript'dan so'raymiz:
<style>
#karta {
width: 200px;
height: 100px;
padding: 10px;
border: 2px solid #1f6f4a;
margin: 20px;
}
</style>
<div id="karta">Osh — 35 000 so'm</div>
<script>
const karta = document.getElementById("karta");
console.log(karta.offsetWidth, karta.offsetHeight);
console.log(karta.clientWidth, karta.clientHeight);
console.log(karta.scrollWidth, karta.scrollHeight);
</script>Konsolda:
224 124
220 120
220 120Hisoblab chiqamiz (eni bo'yicha):
offsetWidth= kontent 200 + padding 10 × 2 + chegara 2 × 2 = 224. Ko'zga ko'rinadigan butun quti.clientWidth= kontent 200 + padding 20 = 220. Chegaraning ichi.scrollWidth— ichidagi kontent to'liq sig'ib turibdi, shuning uchunclientWidthbilan teng: 220.margin(20px) hech birida yo'q. Tashqi bo'shliq — elementning o'lchami emas, qo'shnilar bilan masofa.
Hamma qiymatlar — piksel, px siz oddiy son.
Diagrammada uch oila ichma-ich qutilar sifatida — tashqisidan ichkarisiga:
flowchart TB
subgraph O["offsetWidth = 224: chegara bilan"]
subgraph C["clientWidth = 220: padding bilan"]
K["kontent: 200"]
end
end
M["margin — hech biriga kirmaydi"]Hayotdan o'xshatish: choynak qutisi. offset — qutining tashqi o'lchami, karton devori bilan. client — ichki bo'shliq, devorsiz. scroll — qutiga solingan hamma narsa, hatto qopqoqdan chiqib turgan qismi bilan. Qutilar orasidagi masofa esa (margin) — qutining o'lchami emas.
2.2 scroll* — ko'rinmay turgan kontent
scroll* oilasining ma'nosi kontent sig'may qolganda ochiladi. Menyuda 6 ta taom, har biri 40px, lekin ro'yxat balandligi — 120px. Ortiqchasi aylantirish (scroll) ortida:
<style>
#menyu {
height: 120px;
overflow: auto;
margin: 0;
padding: 0;
list-style: none;
border: 1px solid #c9d6cf;
}
#menyu li { height: 40px; }
</style>
<ul id="menyu">
<li>Osh</li>
<li>Manti</li>
<li>Lag'mon</li>
<li>Ko'k choy</li>
<li>Somsa</li>
<li>Shashlik</li>
</ul>
<script>
const menyu = document.getElementById("menyu");
console.log(menyu.offsetHeight, menyu.clientHeight);
console.log(menyu.scrollHeight);
</script>Konsolda:
122 120
240offsetHeight— 122: 120 + yuqori va pastki chegara.clientHeight— 120: ko'rinadigan "deraza".scrollHeight— 240: 6 × 40, ya'ni kontentning to'liq balandligi, ko'rinmaydigan qismi bilan.
Demak, scrollHeight > clientHeight — "kontent sig'madi, aylantirish bor" degani. Somsa va shashlik shu misol uchun qo'shilgan, «Bahor» menyusiga kirmaydi.
Tekshirib ko'ring: Kartaga
box-sizing: border-boxqo'shilsa (Box model),offsetWidthvaclientWidthnechaga teng bo'ladi?
Javob
offsetWidth — 200, clientWidth — 196. border-box da width: 200px chegara bilan birga hisoblanadi: tashqi quti 200 bo'ladi. Ichkarisi — 200 dan ikki chegarani (4px) ayirganda 196. Kontentning o'zi esa 176 ga torayadi: 196 dan padding (20px) chiqadi. "Tahrirlab ko'rish" bilan tekshiring.
3. Aylantirish: scrollTop va uning chegaralari
3.1 scrollTop — o'qish va yozish
scrollTop — kontent qancha piksel yuqoriga surilganini bildiradi. Uni o'qish ham, unga yozish ham mumkin. Yozsangiz — element o'sha joyga aylanadi:
<style>
#menyu {
height: 120px;
overflow: auto;
margin: 0;
padding: 0;
list-style: none;
border: 1px solid #c9d6cf;
}
#menyu li { height: 40px; }
</style>
<ul id="menyu">
<li>Osh</li>
<li>Manti</li>
<li>Lag'mon</li>
<li>Ko'k choy</li>
<li>Somsa</li>
<li>Shashlik</li>
</ul>
<script>
const menyu = document.getElementById("menyu");
console.log(menyu.scrollTop);
menyu.scrollTop = 80;
console.log(menyu.scrollTop);
menyu.scrollTop = 1000;
const eng = menyu.scrollHeight - menyu.clientHeight;
console.log(menyu.scrollTop, eng);
const oxirida =
Math.ceil(menyu.scrollTop + menyu.clientHeight) >=
menyu.scrollHeight;
console.log(`Oxiriga yetdi: ${oxirida}`);
</script>Konsolda:
0
80
120 120
Oxiriga yetdi: true- Boshida 0 — hech narsa surilmagan.
- 80 yozdik — ro'yxat ikki taomga suriladi.
- 1000 yozdik, lekin 120 bo'ldi. Brauzer qiymatni chegaraga "qisib" qo'ydi: kontentdan ortiq surib bo'lmaydi. Eng katta qiymat —
scrollHeight - clientHeight. - "Oxiriga yetdimi?" formulasi: surilgan + ko'rinadigan ≥ to'liq balandlik.
Natija tabiga qarang: ro'yxat oxirgi uchta taomni ko'rsatib turibdi.
Formuladagi Math.ceil nega kerak? Telefonlarda scrollTop kasr bo'lishi mumkin (masalan 119.5) — ekran piksellari zichligi tufayli. Math.ceil yuqoriga yaxlitlab, "deyarli oxirida"ni ham "oxirida" deb hisoblaydi (Math obyekti).
3.2 Foizda: "qancha o'qildi?"
Uzun maqolalarda tepada "o'qish chizig'i" bo'ladi — qancha o'qilganini ko'rsatadi. Uning hisobi bitta formula:
<style>
#matn { height: 120px; overflow: auto; margin: 0; }
#matn p { height: 60px; margin: 0; }
</style>
<div id="matn">
<p>Osh — o'zbek dasturxonining toji.</p>
<p>Guruch, go'sht, sabzi va piyoz.</p>
<p>Qozonda, olov ustida pishiriladi.</p>
<p>«Bahor»da har kuni tayyorlanadi.</p>
</div>
<script>
const matn = document.getElementById("matn");
matn.scrollTop = 60;
const jami = matn.scrollHeight - matn.clientHeight;
const foiz = Math.round((matn.scrollTop / jami) * 100);
console.log(`O'qildi: ${foiz}%`);
</script>Konsolda:
O'qildi: 50%To'liq balandlik 240, deraza 120 — surish mumkin bo'lgan masofa 120. 60 surilgan — demak yarmi. Haqiqiy o'qish chizig'ida bu hisob har aylantirishda qayta bajariladi. Buning uchun scroll hodisasi kerak — uni Fokus, scroll va resize hodisalari darsida qo'shamiz.
Tekshirib ko'ring: Kontent derazaga to'liq sig'sa (
scrollHeight === clientHeight), formuladagijaminechaga teng va natija nima bo'ladi?
Javob
jami — 0, va 0 / 0 — NaN (Number turi). Konsolda O'qildi: NaN% chiqadi. Aylantirish yo'q bo'lsa, hisobni umuman qilmaslik kerak: avval if (jami === 0) bilan tekshiring va, masalan, 100% deb oling.
4. getBoundingClientRect — ekrandagi joy
4.1 To'rtburchak
offset* va client* o'lchamni beradi, lekin "ekranning qayerida?" degan savolga to'liq javob bermaydi. Buning uchun getBoundingClientRect() bor. U elementni o'rab turgan to'rtburchakni qaytaradi — ko'rinadigan oyna (viewport) chap-yuqori burchagiga nisbatan:
<style>
body { margin: 0; }
#tugma {
display: block;
width: 120px;
height: 40px;
margin: 30px 0 0 50px;
}
</style>
<button id="tugma" type="button">Bron qilish</button>
<script>
const tugma = document.getElementById("tugma");
const joy = tugma.getBoundingClientRect();
console.log(joy.top, joy.left);
console.log(joy.width, joy.height);
console.log(joy.bottom, joy.right);
console.log(joy.x === joy.left, joy.y === joy.top);
</script>Konsolda:
30 50
120 40
70 170
true trueNatijadagi obyekt — DOMRect. Uning xususiyatlari:
| Xususiyat | Ma'nosi | Bu yerda |
|---|---|---|
top, left |
Yuqori va chap chetgacha masofa | 30, 50 |
bottom, right |
Pastki va o'ng chetgacha (yuqori/chapdan) | 70, 170 |
width, height |
O'lcham — offset* ga o'xshash |
120, 40 |
x, y |
left va top ning sinonimi |
50, 30 |
E'tibor bering: bottom — pastdan emas, tepadan pastki chetgacha masofa: 30 + 40 = 70. CSS'dagi bottom bilan adashtirmang.
Konsolga console.log(joy) ni to'g'ridan-to'g'ri yozsangiz, haqiqiy Chrome'da DOMRect {x: 50, y: 30, width: 120, …} chiqadi. Jonli oyna konsoli bu obyektni ochib ko'rsatmaydi — shuning uchun xususiyatlarni alohida chiqardik.
4.2 Viewport'ga nisbatan — aylantirsa o'zgaradi
getBoundingClientRect doim hozirgi ko'rinishga nisbatan. Sahifa yoki ota element aylansa, qiymat ham o'zgaradi. offsetTop esa o'zgarmaydi:
<style>
body { margin: 0; }
#menyu {
position: relative;
height: 120px;
overflow: auto;
margin: 0;
padding: 0;
list-style: none;
}
#menyu li { height: 40px; }
</style>
<ul id="menyu">
<li>Osh</li>
<li>Manti</li>
<li>Lag'mon</li>
<li>Ko'k choy</li>
<li>Somsa</li>
</ul>
<script>
const menyu = document.getElementById("menyu");
const choy = menyu.children[3];
console.log(choy.offsetTop, choy.offsetParent === menyu);
console.log(choy.getBoundingClientRect().top);
menyu.scrollTop = 80;
console.log(choy.offsetTop);
console.log(choy.getBoundingClientRect().top);
</script>Konsolda:
120 true
120
120
40offsetTop— 120: ko'k choy ro'yxat boshidan 3 × 40 piksel pastda. U joylashuv (layout) bo'yicha hisoblanadi va aylantirishga bog'liq emas.offsetParent—offsetTopqaysi elementga nisbatan hisoblanganini aytadi. Bu eng yaqinpositionberilgan ota. Biz#menyugaposition: relativeberdik (positionva containing block). Bunday ota bo'lmasa —body.getBoundingClientRect().top— avval 120, 80 piksel surilgach 40. Ko'k choy ko'rinishda yuqoriga ko'tarildi.
Qoida: "hozir ekranning qayerida?" — getBoundingClientRect. "Hujjat ichida qayerda, aylantirishdan qat'i nazar?" — offsetTop yoki getBoundingClientRect().top + window.scrollY (sahifa darajasida, pastda ko'ramiz).
4.3 Layout va ko'rinish: transform farqi
2D transformlar darsida transform layout'ga ta'sir qilmasligini ko'rgandik: element joyida "turadi", faqat ko'rinishi o'zgaradi. O'lchamlar ham shuni tasdiqlaydi:
<style>
.karta {
width: 200px;
height: 40px;
border: 2px solid #1f6f4a;
}
#kichik { transform: scale(0.5); }
#kasr { width: 100.5px; }
</style>
<div class="karta" id="kichik">Manti</div>
<div class="karta" id="kasr">Lag'mon</div>
<script>
const kichik = document.getElementById("kichik");
console.log(kichik.offsetWidth);
console.log(kichik.getBoundingClientRect().width);
const kasr = document.getElementById("kasr");
console.log(kasr.offsetWidth);
console.log(kasr.getBoundingClientRect().width);
</script>Konsolda:
204
102
105
104.5scale(0.5)dan keyinoffsetWidth— hali ham 204 (layout o'lchami).getBoundingClientRect— 102: ekranda ko'rinadigan o'lcham.- Kasr kenglikda
offsetWidthbutun songa yaxlitlanadi (105),getBoundingClientRectesa aniq qiymatni beradi 104.5-bob.
Xulosa: ekrandagi haqiqiy joy kerak bo'lsa (tooltip, sudrab olib borish) — getBoundingClientRect. Layout hisoblari uchun — offset*.
5. Amaliy holat: tugma ostiga ishora
Bilganlarimizni birlashtiramiz. "Bron qilish" tugmasi bosilganda uning ostida ishora chiqsin: "Bron 10:00 dan 22:00 gacha". Ishora position: fixed — u viewport'ga nisbatan joylashadi, xuddi getBoundingClientRect qiymatlari kabi. Ikkalasi bir xil "koordinatalar tizimi"da — shuning uchun qiymatni to'g'ridan-to'g'ri berish mumkin.
Bosishga javob uchun yana DOM bo'ylab harakatlanish darsidagi qolipdan foydalanamiz: addEventListener("click", ...) (addEventListener asoslari da to'liq):
<style>
body { margin: 0; }
#tugma {
display: block;
width: 120px;
height: 40px;
margin: 30px 0 80px 50px;
}
#ishora {
position: fixed;
margin: 0;
padding: 4px 8px;
background: #1f2a24;
color: #fff;
}
</style>
<button id="tugma" type="button">Bron qilish</button>
<p id="ishora" hidden>Bron 10:00 dan 22:00 gacha</p>
<script>
const tugma = document.getElementById("tugma");
const ishora = document.getElementById("ishora");
function ishoraniKorsat() {
const joy = tugma.getBoundingClientRect();
ishora.style.top = `${joy.bottom + 8}px`;
ishora.style.left = `${joy.left}px`;
ishora.hidden = false;
console.log(`Ishora: top ${joy.bottom + 8}, left ${joy.left}`);
}
tugma.addEventListener("click", ishoraniKorsat);
</script>Tugmani bosing: uning ostida, 8 piksel pastda, qora ishora paydo bo'ladi, konsolda — Ishora: top 78, left 50. "Tahrirlab ko'rish" bilan tugmaning margin ini o'zgartiring — ishora tugmaga "ergashadi", chunki joy har bosishda qaytadan o'lchanadi.
Ikki muhim eslatma:
- O'lchashni bosish paytida qiling, oldindan emas. Sahifa aylanadi, oyna o'lchami o'zgaradi — oldindan saqlangan raqam eskiradi.
- Bugun CSS buni JavaScript'siz ham qila oladi. Anchor positioning darsida ishorani tugmaga CSS bilan "bog'lagan" edingiz. Brauzer qo'llasa — CSS yo'li yaxshiroq: aylantirishda ham, o'lcham o'zgarganda ham o'zi yangilanadi. JavaScript hisobi — eski brauzerlar uchun zaxira va murakkab holatlar uchun.
6. Oyna va sahifa darajasida
6.1 Oyna o'lchamlari
Element o'rniga butun oyna kerak bo'lsa:
| Xususiyat | Nima |
|---|---|
window.innerWidth, innerHeight |
Oyna o'lchami, aylantirish chizig'i (scrollbar) bilan |
document.documentElement.clientWidth |
Oyna eni, scrollbar'siz — kontent uchun haqiqiy joy |
window.scrollY, scrollX |
Sahifa qancha aylantirilgan |
document.documentElement.scrollHeight |
Butun sahifaning balandligi |
Bu qiymatlar har kimda har xil — ekranga, brauzerga, sahifa qayergacha aylantirilganiga bog'liq. Jonli oyna esa sahifa ichidagi kichik oyna, uning o'lchami haqiqiy ekranniki emas. Shuning uchun ularni haqiqiy sahifada sinang: F12 → Console va birma-bir yozing:
window.innerWidth; // masalan 1280
window.scrollY; // hozir qancha aylantirilgan
const sahifa = document.documentElement;
sahifa.clientWidth; // masalan 1265 — scrollbar ayirildi
sahifa.scrollHeight; // butun sahifa balandligi
// Elementning sahifa boshidan masofasi (aylantirishdan qat'i nazar):
const joy = $0.getBoundingClientRect();
joy.top + window.scrollY;innerWidth va clientWidth farqi — scrollbar'ning eni. Windows'da u odatda 15–17 piksel, telefonda va macOS'da ko'pincha 0 (scrollbar kontent ustida suzadi). Media query'lar (Media queries) innerWidth ga mos keladi — scrollbar bilan.
Oxirgi ikki qatorga qarang. getBoundingClientRect().top — viewport'ga nisbatan; unga scrollY qo'shsak, sahifa boshidan masofa chiqadi. Bu raqam aylantirsangiz ham o'zgarmaydi.
6.2 Sahifani aylantirish
Butun sahifa uchun window ning metodlari:
// boshiga, silliq
window.scrollTo({ top: 0, behavior: "smooth" });
// yana 300px pastga
window.scrollBy({ top: 300, behavior: "smooth" });
// eski shakl, darhol
window.scrollTo(0, 500);scrollTo— aniq joyga ("500-pikselga bor").scrollBy— joriy joydan qancha ("yana 300 piksel").behavior: "smooth"— silliq,"instant"— darhol,"auto"— CSS'dagiscroll-behaviorqiymatiga qarab.
Xuddi shu metodlar istalgan aylanadigan elementda ham bor: menyu.scrollTo({ top: 0 }). Baseline ma'lumotlariga ko'ra, behavior parametri hamma asosiy brauzerlarda 2020-yildan beri ishlaydi (keng tarqalgan — 2023-yildan).
Maslahat:
behaviorni yozmasangiz, u"auto"bo'ladi va CSS'ga bo'ysunadi. Skroll xulqi darsidascroll-behavior: smoothniprefers-reduced-motion: no-preferencesharti ichiga yozgan edingiz (prefers-reduced-motion). Shunda harakatni kamaytirishni so'ragan foydalanuvchiga JavaScript ham silliq emas, darhol aylantiradi. JavaScript'da"smooth"ni qattiq yozib qo'yish bu sozlamani buzadi.
7. scrollIntoView — elementni ko'rinishga olib kelish
Ko'pincha "nechta pikselga?" emas, "shu element ko'rinsin" degan vazifa turadi. Buning uchun element.scrollIntoView() bor. U kerakli ota elementlarni o'zi aylantiradi:
<style>
#menyu {
height: 120px;
overflow: auto;
margin: 0 0 8px;
padding: 0;
list-style: none;
border: 1px solid #c9d6cf;
}
#menyu li { height: 40px; }
@media (prefers-reduced-motion: no-preference) {
#menyu { scroll-behavior: smooth; }
}
</style>
<ul id="menyu">
<li>Osh</li>
<li>Manti</li>
<li>Lag'mon</li>
<li>Ko'k choy</li>
<li>Somsa</li>
<li id="shashlik">Shashlik</li>
</ul>
<button type="button" id="korsat">Shashlikni ko'rsat</button>
<button type="button" id="boshiga">Boshiga</button>
<script>
const menyu = document.getElementById("menyu");
const shashlik = document.getElementById("shashlik");
function shashlikniKorsat() {
shashlik.scrollIntoView({ block: "nearest" });
}
function boshigaQayt() {
menyu.scrollTo({ top: 0 });
}
const korsat = document.getElementById("korsat");
korsat.addEventListener("click", shashlikniKorsat);
const boshiga = document.getElementById("boshiga");
boshiga.addEventListener("click", boshigaQayt);
</script>"Shashlikni ko'rsat" ni bosing — ro'yxat silliq aylanib, shashlik pastki chetda to'xtaydi. "Boshiga" — osh'ga qaytadi. Silliqlik JavaScript'dan emas, CSS'dan keldi: tizimda harakat kamaytirilgan bo'lsa, aylanish darhol bo'ladi.
scrollIntoView ning block parametri element derazaning qayerida to'xtashini aytadi:
block |
Element qayerda to'xtaydi |
|---|---|
"start" (sukut bo'yicha) |
Yuqori chetda |
"center" |
O'rtada |
"end" |
Pastki chetda |
"nearest" |
Eng kam aylantirish bilan; allaqachon ko'rinsa — umuman aylanmaydi |
Gorizontal yo'nalish uchun xuddi shunday inline parametri bor.
7.1 Nega "nearest"?
scrollIntoView faqat eng yaqin otani emas, hamma aylanadigan ota-bobolarni aylantiradi — butun sahifani ham. Sukut bo'yicha ("start") u elementni ekran tepasiga olib chiqishga harakat qiladi va sahifa kutilmaganda "sakraydi".
Biz buni o'zimiz sinab ko'rdik: jonli oyna ichida "start" bilan chaqirilgan scrollIntoView dars sahifasining o'zini ham aylantirib yubordi. "nearest" esa element allaqachon ko'rinib turgan bo'lsa, ortiqcha harakat qilmaydi.
Yangi imkoniyat ham bor: container: "nearest" parametri faqat eng yaqin aylanadigan otani aylantiradi, sahifaga tegmaydi. Baseline ma'lumotlariga ko'ra, 2026-yil oktabr holatida u faqat Chrome va Edge 140+ da bor — hali Baseline emas. Tushunmagan brauzer uni shunchaki e'tiborsiz qoldiradi.
7.2 Forma xatosiga aylantirish
scrollIntoView ning eng ko'p uchraydigan ishi — bron formasida birinchi xato maydonini ko'rsatish. U ko'pincha fokus bilan birga yoziladi:
const xatoMaydon = document.querySelector("[aria-invalid='true']");
xatoMaydon?.scrollIntoView({ block: "center" });
xatoMaydon?.focus();Forma tekshiruvini Constraint Validation API darsida to'liq yozamiz. Bir nozik joy: focus() ning o'zi ham elementni ko'rinishga olib keladi, lekin qayerda to'xtashini siz boshqarmaysiz. block: "center" maydonni ekran o'rtasiga qo'yadi — yopishqoq header ostida qolib ketmaydi.
Tekshirib ko'ring: Sahifada yopishqoq header bor.
scrollIntoView({ block: "start" })dan keyin sarlavha header ostida qolib ketdi. JavaScript'ni o'zgartirmasdan qanday tuzatasiz?
Javob
CSS bilan: scroll-margin-top (elementga) yoki scroll-padding-top (aylanadigan otaga — sahifa uchun html). Skroll xulqi darsida portfolio'da aynan scroll-padding-block-start ni qo'ygan edingiz. scrollIntoView bu qiymatlarni hurmat qiladi va elementni chetdan shuncha pastda to'xtatadi.
8. O'lcham o'qish — bepul emas
Ko'p elementni samarali chizish darsida offsetHeight ni sikl ichida o'qish sahifani 12 baravar sekinlashtirganini o'lchagan edik. Bu darsdagi hamma xususiyat o'sha guruhdan: offset*, client*, scroll*, getBoundingClientRect(), scrollIntoView(). DOM o'zgargandan keyin ularni o'qisangiz, brauzer shu zahoti layout qiladi.
Qoidalar o'sha:
- Bir xil qiymatni sikl ichida qayta-qayta o'qimang — bir marta o'qib, o'zgaruvchiga saqlang.
- Bir nechta elementni o'lchash kerak bo'lsa — avval hammasini o'lchang, keyin hammasini o'zgartiring.
- O'lchamni doimiy kuzatish kerak bo'lsa (element kattalashdimi?) — har safar so'rash o'rniga, brauzerning maxsus "kuzatuvchisi"dan foydalaniladi:
ResizeObservervaIntersectionObserver. Ularni keyinroq o'rganamiz.
Qaysi o'lchamni tanlash — diagrammada. Yuqoridan o'qing:
flowchart TD
S{"Nima kerak?"}
S -->|"ekrandagi joy"| R["getBoundingClientRect"]
S -->|"o'lcham"| O{"Chegara kerakmi?"}
O -->|ha| OW["offsetWidth / offsetHeight"]
O -->|"yo'q, ichi"| CW["clientWidth / clientHeight"]
S -->|"kontent sig'dimi?"| SH["scrollHeight va clientHeight"]
S -->|"qancha aylangan?"| ST["scrollTop / scrollY"]9. Ko'p uchraydigan xatolar
9.1 style.width dan o'lcham kutish
<style>
#karta { width: 200px; padding: 10px; }
</style>
<div id="karta">Osh</div>
<script>
const karta = document.getElementById("karta");
console.log(`"${karta.style.width}"`);
console.log(karta.offsetWidth);
</script>Konsolda:
""
220style.width — bo'sh satr. classList va stillar darsidan eslang: element.style faqat style="..." atributida yozilgan qiymatni ko'radi, CSS faylidagini emas. Haqiqiy o'lcham — offsetWidth yoki getBoundingClientRect(). Hisoblangan CSS qiymati kerak bo'lsa — getComputedStyle(karta).width ("200px", satr).
9.2 Yashirin elementni o'lchash
display: none yoki hidden element joy egallamaydi — uning hamma o'lchami 0, offsetParent esa null. Masalan, ishorani ko'rsatishdan oldin uning balandligini o'lchab, joyini hisoblamoqchi bo'lsangiz — 0 olasiz. Tuzatish: avval ko'rsating (hidden = false), keyin o'lchang. Ikkalasi bitta skript ichida bo'lsa, foydalanuvchi oraliq holatni ko'rmaydi — brauzer skript tugagach chizadi (Ko'p elementni samarali chizish).
9.3 Silliq aylantirishdan keyin darhol o'qish
<style>
#menyu { height: 80px; overflow: auto; margin: 0; }
#menyu li { height: 40px; }
</style>
<ul id="menyu">
<li>Osh</li>
<li>Manti</li>
<li>Lag'mon</li>
<li>Ko'k choy</li>
</ul>
<script>
const menyu = document.getElementById("menyu");
menyu.scrollTo({ top: 80, behavior: "smooth" });
console.log(menyu.scrollTop);
</script>Konsolda:
080 kutgan edik. Silliq aylanish bir zumda emas, bir necha yuz millisekund davom etadi — scrollTo esa harakatni boshlab, darhol qaytadi. Keyingi qatorda element hali joyidan qo'zg'almagan. Tuzatish: natija darhol kerak bo'lsa — behavior siz (yoki "instant"). Aylanish tugashini kutish kerak bo'lsa — scrollend hodisasi bor (Baseline: 2025-yil dekabrdan, yangi), hodisalarni esa Fokus, scroll va resize hodisalari darsida o'rganamiz.
9.4 Rasm yuklanmasdan o'lchash
width va height atributisiz <img> yuklanmaguncha 0 balandlikka ega. defer skript rasmni kutmaydi (Brauzer muhiti), shuning uchun u o'lchagan sahifa balandligi rasm kelgach o'zgaradi. Tuzatish: rasmlarga doim width va height yozing (Rasm qo'yish: img asoslari darsidagi qoida). Butun sahifa o'lchami kerak bo'lsa — load hodisasidan keyin o'lchang.
9.5 margin ni o'lchamda qidirish
offsetWidth ham, getBoundingClientRect().width ham margin ni o'z ichiga olmaydi. Qo'shni bilan masofa kerak bo'lsa — getComputedStyle(element).marginTop yoki ikki elementning getBoundingClientRect qiymatlarini ayiring.
10. Mashqlar
1-mashq (oson): O'lchamlarni oldindan ayting
Kodni ishga tushirmasdan, konsolda nima chiqishini hisoblang. Keyin Natija tabida tekshiring.
<style>
#bron {
width: 300px;
height: 50px;
padding: 15px 20px;
border: 5px solid #1f6f4a;
margin: 10px;
}
</style>
<div id="bron">Stol band qilish</div>
<script>
const bron = document.getElementById("bron");
console.log(bron.offsetWidth, bron.offsetHeight);
console.log(bron.clientWidth, bron.clientHeight);
</script>Yechim
Konsolda:
350 90
340 80offsetWidth= 300 + 20 × 2 + 5 × 2 = 350;offsetHeight= 50 + 15 × 2 + 5 × 2 = 90.clientWidth= 300 + 40 = 340;clientHeight= 50 + 30 = 80.margin: 10pxhech qayerda yo'q.
2-mashq (o'rta): Kontent sig'dimi?
sigdimi(element) funksiyasini yozing: element ichidagi kontent to'liq ko'rinsa true, aylantirish kerak bo'lsa false qaytarsin. Ikki izoh blokida tekshiring: Qisqa: true, Uzun: false.
Ishora: scrollHeight va clientHeight ni solishtiring («scroll* — ko'rinmay turgan kontent» bo'limi).
<style>
.izoh { height: 60px; overflow: auto; margin: 0 0 8px; }
.izoh p { height: 40px; margin: 0; }
</style>
<div class="izoh" id="qisqa"><p>Juda mazali!</p></div>
<div class="izoh" id="uzun">
<p>Osh zo'r edi.</p>
<p>Choy issiq keldi.</p>
<p>Yana kelamiz.</p>
</div>
<script>
// shu yerga yozing
</script>Yechim
<style>
.izoh { height: 60px; overflow: auto; margin: 0 0 8px; }
.izoh p { height: 40px; margin: 0; }
</style>
<div class="izoh" id="qisqa"><p>Juda mazali!</p></div>
<div class="izoh" id="uzun">
<p>Osh zo'r edi.</p>
<p>Choy issiq keldi.</p>
<p>Yana kelamiz.</p>
</div>
<script>
function sigdimi(element) {
return element.scrollHeight <= element.clientHeight;
}
const qisqa = document.getElementById("qisqa");
const uzun = document.getElementById("uzun");
console.log(`Qisqa: ${sigdimi(qisqa)}`);
console.log(`Uzun: ${sigdimi(uzun)}`);
</script>Konsolda:
Qisqa: true
Uzun: falseUzun izohda kontent 3 × 40 = 120, deraza esa 60. Bu funksiya real saytlarda "Batafsil o'qish" tugmasini faqat kerak bo'lganda ko'rsatish uchun ishlatiladi: matn sig'sa, tugma keraksiz.
3-mashq (qiyin): Ishora ekrandan chiqmasin
«Amaliy holat: tugma ostiga ishora» bo'limidagi kodni o'zgartiring: agar ishora tugma ostiga sig'masa (pastda joy yetmasa), u tugmaning ustida chiqsin. Sinash uchun tugma oynaning pastki chetiga yaqin turibdi.
Ishora: oyna balandligi — document.documentElement.clientHeight. Ishoraning balandligi — ishora.offsetHeight, lekin uni faqat ko'rsatilgandan keyin o'lchash mumkin («Yashirin elementni o'lchash» xatosi). Ustida chiqish uchun top = tugmaning top i − ishora balandligi − 8.
<style>
body { margin: 0; min-height: 200px; }
#tugma {
position: fixed;
bottom: 10px;
left: 50px;
width: 120px;
height: 40px;
}
#ishora {
position: fixed;
margin: 0;
padding: 4px 8px;
background: #1f2a24;
color: #fff;
}
</style>
<p>Sahifa pastida — bron tugmasi.</p>
<button id="tugma" type="button">Bron qilish</button>
<p id="ishora" hidden>Bron 10:00 dan 22:00 gacha</p>
<script>
const tugma = document.getElementById("tugma");
const ishora = document.getElementById("ishora");
// shu yerga ishoraniKorsat funksiyasini yozing
// va uni tugma bosilganda chaqiring
</script>Yechim
<style>
body { margin: 0; min-height: 200px; }
#tugma {
position: fixed;
bottom: 10px;
left: 50px;
width: 120px;
height: 40px;
}
#ishora {
position: fixed;
margin: 0;
padding: 4px 8px;
background: #1f2a24;
color: #fff;
}
</style>
<p>Sahifa pastida — bron tugmasi.</p>
<button id="tugma" type="button">Bron qilish</button>
<p id="ishora" hidden>Bron 10:00 dan 22:00 gacha</p>
<script>
const tugma = document.getElementById("tugma");
const ishora = document.getElementById("ishora");
function ishoraniKorsat() {
ishora.hidden = false;
const joy = tugma.getBoundingClientRect();
const balandlik = ishora.offsetHeight;
const oyna = document.documentElement.clientHeight;
let tepa = joy.bottom + 8;
if (tepa + balandlik > oyna) {
tepa = joy.top - balandlik - 8;
}
ishora.style.top = `${tepa}px`;
ishora.style.left = `${joy.left}px`;
console.log(tepa < joy.top ? "Ishora ustida" : "Ishora ostida");
}
tugma.addEventListener("click", ishoraniKorsat);
</script>Tugmani bosing: ishora tugmaning ustida chiqadi, konsolda Ishora ustida. "Tahrirlab ko'rish" bilan #tugma dagi bottom: 10px ni top: 10px ga almashtiring — endi pastda joy yetarli va Ishora ostida chiqadi.
Tartibga e'tibor bering: avval hidden = false, keyin o'lchash. Hammasi bitta funksiyada — foydalanuvchi ishoraning "noto'g'ri joydagi" oraliq holatini ko'rmaydi. Real kutubxonalar (masalan, Floating UI) aynan shu hisobni chap-o'ng chetlar uchun ham qiladi.
4-mashq: Portfolio qadami — "Yuqoriga" faqat kerak bo'lganda
Portfolio bosh sahifasi footer'ida "Yuqoriga" havolasi bor (Skroll xulqi darsidan): <p><a href="#asosiy">Yuqoriga</a></p>. Katta ekranda sahifa butunlay sig'ib qolsa, bu havola ma'nosiz — aylantiradigan joyning o'zi yo'q.
asosiy.js ga yuqoriganiTekshir funksiyasini qo'shing:
- Footer'dagi
a[href="#asosiy"]ni toping. Yo'q bo'lsa (boshqa sahifalar) — tugasin. - Sahifaning to'liq balandligi oyna balandligidan katta emasmi — tekshiring.
- Sahifa sig'sa, havolaning otasi (
p) ni yashiring (hidden), sig'masa — ko'rsating. - Funksiyani
loadhodisasida chaqiring: rasmlar va shriftlar yuklangach sahifa balandligi aniq bo'ladi (Brauzer muhiti darsidagi qolip).
Yechim
asosiy.js ga:
function yuqoriganiTekshir() {
const havola = document.querySelector(
'footer a[href="#asosiy"]',
);
if (havola === null) {
return;
}
const sahifa = document.documentElement;
const sigadi = sahifa.scrollHeight <= sahifa.clientHeight;
havola.parentElement.hidden = sigadi;
}
window.addEventListener("load", yuqoriganiTekshir);Tekshirish: DevTools'da qurilma rejimini yoqing (Ctrl + Shift + M) va balandligi katta ekranni tanlang yoki oynani DevTools bilan pastga cho'zing. Sahifani yangilang — sahifa sig'sa, "Yuqoriga" yo'qoladi. Telefon o'lchamida (360 × 740) esa qaytadi. Elements panelida p ga hidden atributi qo'shilganini ko'rasiz.
Uch nozik joy:
- Nega
parentElement? Yolg'iz havolani yashirsak, bo'shpqoladi va o'zmargini bilan joy egallaydi. Butun qatorni yashiramiz (DOM bo'ylab harakatlanish). - Nega
clientHeight,innerHeightemas? Ikkalasi ham ishlaydi.clientHeightgorizontal scrollbar'ni chiqarib tashlaydi — "kontent uchun haqiqiy joy" bilan solishtirish aniqroq. - Oyna o'lchami o'zgarsa-chi? Hozircha tekshiruv faqat yuklanganda bo'ladi. Oynani kattalashtirsangiz, sahifani yangilaguncha natija eski qoladi. Oyna o'zgarishiga javob berishni Fokus, scroll va resize hodisalari darsida qo'shasiz.
Commit: JS: qisqa sahifada Yuqoriga havolasini yashir.
11. Real ishda
- Tooltip, dropdown, kontekst menyu — hammasi tugma yoki matn atrofida chiqadi va
getBoundingClientRectbilan joylashadi. Floating UI kabi kutubxonalar shu hisobni ekran chetlari, aylantirish va o'lcham o'zgarishini hisobga olib qiladi. Yangi loyihalarda esa CSS Anchor positioning ga o'tish boshlangan. - Cheksiz lenta (Instagram, Telegram kanal): "oxiriga yaqinlashdikmi?" —
scrollTop + clientHeightvascrollHeightsolishtiruvi. Zamonaviy kodda bu ishIntersectionObserverga topshiriladi. - Chat oynasi — yangi xabar kelganda pastga aylantirish (
scrollTop = scrollHeight), lekin foydalanuvchi o'zi tepaga chiqqan bo'lsa — aylantirmaslik. Bu "oxiriga yetdimi?" formulasi bilan aniqlanadi. - Formalar — xato maydonga
scrollIntoView+focus(Constraint Validation API). - Intervyuda: "
offsetWidth,clientWidthvascrollWidthfarqi?", "getBoundingClientRectnimaga nisbatan?", "Nega o'lcham o'qish qimmat?" — o'rta darajadagi tez-tez beriladigan savollar.
Xulosa
offset*— chegara bilan,client*— chegarasiz ichki qism,scroll*— ko'rinmaydigan kontent bilan;marginhech qaysida yo'q.getBoundingClientRect()— viewport'ga nisbatan joy va ko'rinadigan o'lcham; aylantirsa o'zgaradi,transformni hisobga oladi.scrollTopni o'qish va yozish mumkin; eng katta qiymat —scrollHeight - clientHeight.scrollTo,scrollBy,scrollIntoView— aylantirish;behaviorni CSS'ga qoldirsangiz, harakat sozlamasi hurmat qilinadi;scrollIntoViewdablock: "nearest"sahifani bekorga "sakratmaydi".- Oyna:
innerWidth(scrollbar bilan),documentElement.clientWidth(scrollbar'siz),scrollY. - Har o'lcham o'qish — majburiy layout: o'qishlarni guruhlang.
Keyingi dars: Holatdan UI chizish: state → render — ma'lumotni bitta joyda saqlab, butun ro'yxatni undan qayta chizish: freymvorklar g'oyasining ildizi.
Manbalar
- MDN: "Element: getBoundingClientRect()", "Determining the dimensions of elements", "HTMLElement: offsetParent" — developer.mozilla.org
- MDN: "Element: scrollIntoView()", "Element: scrollTo()", "Window: innerWidth" — developer.mozilla.org
- CSSOM View Module — drafts.csswg.org/cssom-view
- web-features (Baseline):
scroll-elements,scroll-into-view,scroll-into-view-container,scrollend— github.com/web-platform-dx/web-features
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!