آموزش جاوا اسکریپت – جلسه ۲۸ – سایز عناصر – اسکرول صفحه

درود بر همراهان گرامی سایت راهکارینو، به جلسه بیست و هشتم از آموزش جامع جاوا اسکریپت خوش آمدید. در جلسه قبل ماژول ها را در جاوا اسکریپت آموزش دادیم. سرفصل های اصلی جلسه قبل: ماژول چیست و چه ویژگی هایی دارد + نحوه Import و export کردن ماژول و انواع روش های پیاده سازی آن + نحوه import داینامیک ماژول ها در جاوا اسکریپت (ویژگی جدید ES2020)
در این جلسه می خواهیم نحوه بدست آوردن سایز عناصر DOM + کار با اسکرول صفحه در جاوااسکریپت را بطور کامل آموزش دهیم و متدهای کاربردی مرتبط را بیان کنیم.
زبان برنامه نویسی جاوااسکریپت امکانات زیادی برای بدست آوردن مشخصات هندسی عناصر در DOM دارد. مانند طول، عرض، ارتفاع، فاصله عنصر تا بالای صفحه و…
ما اغلب هنگام جابجایی یا تغییر موقعیت عناصر در صفحات وب به مقادیر بالا نیاز داریم.
مثالی از خواص هندسی عناصر:
بعنوان مثال فرض کنید کد زیر را در HTML و CSS داریم:
<div id="example"> ...Text... </div> <style> #example { width: 300px; height: 200px; border: 25px solid #E8C48F; padding: 20px; overflow: auto; } </style>
المان بالا شامل border, padding و scroll می باشد. هیچ مارجینی برای آن تعریف نشده است. این المان شبیه تصویر زیر خواهد بود:
شما می توانید کد این مثال را در sandbox مشاهده کنید و توسعه دهید.
نکته: عرض نوار اسکرول را در نظر بگیرید. در شکل بالا، اگر عرض نوار اسکرول (scrollbar) را حساب نکنیم، فضای محتوا یا content width باید 300 پیکسل باشد اما در واقع بهتر است عرض اسکرول را نیز حساب کنیم. پس عرض محتوای ما برابر 300-16=284 خواهد شد. در مثال های این مقاله، عرض اسکرول بار را در محاسبات خود دخیل کرده ایم.
خواص هندسی عناصر (Geometry):
در تصویر زیر تمام property های هندسی را نمایش داده ایم:
مقادیر تمام این خواص به لحاظ فنی عدد هستند اما واحد این اعداد پیکسل (pixel) می باشند. بیایید این خواص را یکی یکی بررسی کنیم.
offsetParent و offsetTop/offsetLeft:
خاصیت offsetParent بیانگر نزدیکترین اجداد عنصر است که مرورگر برای محاسبه مختصات در حین رندر شدن استفاده می کند. که یکی از موارد زیر است:
- پوزیشن های CSS مانند: absolute, relative, fixed, top
- المان های <td> و <th> یا <table>
- یا تگ <body>
خواص offsetLeft/offsetTop مختصات عنصر را نسبت به offsetParent در گوشه بالا سمت چپ مشخص می کند. در مثال زیر، عنصر div یک عنصر offsetParent بنام main دارد که دارای فاصله 180 پیکسلی از بالا (offsetTop) و فاصله 180 پیکسلی از چپ (offsetLeft) می باشد. کد زیر:
<main style="position: relative" id="main"> <article> <div id="example" style="position: absolute; left: 180px; top: 180px">...</div> </article> </main> <script> alert(example.offsetParent.id); // main alert(example.offsetLeft); // 180 (note: a number, not a string "180px") alert(example.offsetTop); // 180 </script>
در برخی مواقع مقدار offsetParent برابر null خواهد بود:
- برای عناصری که پنهان هستند (display: none)
- برای تگ های <body> و <html>
- برای عناصری که position: fixed هستند.
offsetWidth/offsetHeight:
حالا می خواهیم به سراغ خواص خود عنصر برویم. این دو خاصیت جزء ساده ترین خواص عناصر در مبحث offset هستند. OffsetWidth و offsetHeight مشخص کننده عرض و ارتفاع بیرونی عنصر می باشند. به بیان دیگر، سایز کامل عنصر با لحاظ کردن border اطراف.
در این مثال، offsetWidth برابر 390 پیکسل می باشد که از مجموع دو border چپ و راست (2*25) + دو padding چپ و راست (2*20) + عرض نوار اسکرول (16) + عرض باکس محتوا (284) بدست می آید.
خاصیت offsetHeight نیز برابر 290px می باشد.
نکته: خواص هندسی عناصری که نمایش داده نمی شوند، صفر یا null هستند. خواص هندسی یا geometry properties فقط برای عناصر نمایان محاسبه می شود. اگر یک المنت (یا هر یک از اجداد آن) خاصیت display: none داشته باشند، خواص هندسی آن المنت صفر (یا null) خواهد بود.
clientTop/clientLeft:
در داخل عنصر این مثال، ما border داریم. برای اندازه گیری border می توان از خواص clientLeft و clientTopاستفاده کرد.
در مثال ما:
- خاصیت clientLeft:
25 پیکسل (بیانگر عرض border چپ)
- خاصیت clientLeft:
25 پیکسل (بیانگر عرض border بالا)
اما بخاطر داشته باشید که خواص فوق معادل border-width و border-height نمی باشند. بلکه مشخص کننده فاصله عنصر موردنظر نسبت به چپ و بالا هستند.
در وب سایت هایی که چیدمان المان ها از راست به چپ است، مانند قالب های فارسی یا عربی، نوار اسکرول در سمت چپ المان نمایش داده می شود. بنابراین عرض نوار اسکرول به خاصیت clientLeft نیز اضافه می شود. در این مثال، clientLeft دیگر 25 نخواهد بود بلکه عرض اسکرول بار یعنی 16 نیز با آن جمع شده و 41 می شود.
clientWidth/clientHeight:
این خواص مشخص کننده سایز فضای داخلی حاشیه عنصر است. clientWidth و clientHeight شامل عرض محتوا (content width) بعلاوه padding های اطراف آن است اما عرض scrollbar را شامل نمی شوند.
در تصویر بالا، ابتدا می خواهیم خاصیت clientHeight را بررسی کنیم. همانطور که مشاهده می کنید نوار اسکرول افقی نداریم. ClientHeight برابر 240 پیکسل است. 200 پیکسل برای CSS-height و 40 پیکسل (20*2) برای دو padding بالا و پایین div محتوا.
اما در مورد خاصیت clientWidth قضیه کمی فرق دارد. Content-width دیگر 300 پیکسل نیست. زیرا اسکرول افقی داریم و 16 پیکسل از فضا را اشغال کرده است. بنابراین Content-width برابر 284 (16-300) خواهد بود. در نهایت خاصیت clientWidth از مجموع مقادیر content width و دو padding چپ و راست (40=2*20) می آید. که عدد 324 خواهد بود.
نکته: اگر عنصر موردنظر padding نداشته باشد، مقدار clientWidth و clientHeight دقیقا برابر content width خواهد بود.
در شکل بالا می بینیم که برای اندازه گیری css height باید عرض scrollbar را نیز در نظر بگیریم.
نتیجه می گیریم در مواقعی که المنت موردنظر فاقد خاصیت padding است، برای بدست آوردن سایز فضای محتوا، می توان از client-width و client-height استفاده کرد.
scrollWidth/scrollHeight:
مقادیر scrollWidth/Height همانند clientWidth/Height هستند با این تفاوت که سایز ناحیه اسکرول شده را نیز شامل می شوند. به تصویر زیر توجه کنید:
در این تصویر:
- مقدار scrollHeight برابر 723 پیکسل است. در واقع شامل تمام فضای اسکرول شده عنصر (بصورت عمودی-height)
- مقدار scrollWidth برابر 324 پیکسل است. بدلیل اینکه در تصویر فوق اسکرول افقی نداریم، مقدار scrollWidth با clientWidth برابر است.
ما می توانیم از property های فوق برای توسعه سایز عنصر بصورت افقی و عمودی (تا رسیدن به عرض و ارتفاع کامل عنصر) استفاده کنیم. مانند زیر:
// expand the element to the full content height element.style.height = `${element.scrollHeight}px`;
در واقع می توان عرض/ارتفاع عنصر را تا حدی افزایش دهیم که اسکرول افقی/عمودی آن حذف شود.
scrollLeft/Top:
مقادیر scrollLeft و scrollTop در واقع طول و عرض بخش مخفی عنصر در حالت اسکرول می باشد. یعنی مشخص کننده سایز بخشی از عنصر هستند که اسکرول می شود.
در تصویر زیر مقادیر scrollHeight و scrollTop را مشاهده می کنیم:
به بیان دیگر، مقدار scrollTop بیانگر “میزان اسکرول عنصر تا بالا” می باشد.
نکته: اغلب خاصیت های هندسی عناصر که در این مقاله عنوان کردیم “فقط خواندنی-read only” هستند و غیر قابل تغییر. اما خواص scrollTop و scrollLeft را می توان تغییر داد. در اینصورت مرورگر صفحه وب سایت را به مختصات ارائه شده اسکرول می کند. این خاصیت ها کاربردهای فراوانی در طراحی و توسعه سایت دارند. مثلا می توان برای منوهای sticky (که کاربر با کلیک روی هر منو به سکشن مربوطه اسکرول می شود) استفاده کرد.
سایزهای window و اسکرول صفحه:
چگونه می توان width و height پنجره مرورگر را بدست آورد؟ چطور می توان عرض و ارتفاع کامل داکیومنت (شامل بخش اسکرول) را بدست آورد؟ چگونه می توان صفحه مرورگر را توسط جاوااسکریپت اسکرول کرد؟
برای اینگونه اطلاعات، می توانیم از المنت اصلی داکیومنت (document.documentElement) استفاده کنیم. اما متدهای دیگری نیز وجود دارند که می توانیم در نظر بگیریم:
طول و عرض window:
به منظور بدست آوردن width و height می توان از clientWidth/clientHeight استفاده کرد:
نکته: مرورگرها از خاصیت های window.innerWidth/innerHeight نیز پشتیبانی می کنند اما چرا نباید از آنها بجای clientWidth/Height استفاده کرد؟
دقت کنید که اگر عنصر موردنظر اسکرول داشته باشد، خود نوار اسکرول یک فضایی را اشغال می کند. مقادیر clientWidth/Height طول و عرض عنصر را بدون محاسبه فضای scrollbar ارائه می دهد. اما window.innerWidth/Height فضای نوار اسکرول را نیز شامل می شود.
بنابراین اگر عنصر موردنظر ما در DOM دارای اسکرول باشد، دو مقدار زیر با هم متفاوت خواهند بود:
alert( window.innerWidth ); // full window width alert( document.documentElement.clientWidth ); // window width minus the scrollbar
در اغلب اوقات ما به فضای در دسترس ویندوز نیاز داریم تا عنصری را داخل نوار اسکرول نمایش دهیم. یعنی فضای اشغال شده توسط scrollbar نباید در محاسبه فضای قابل استفاده دخیل شود. پس باید از مقادیر زیر استفاده شود:
documentElement.clientHeight/clientWidth
اهمیت DOCTYPE:
دقت کنید که برای استفاده از مقادیر هندسی عناصر، باید در بالای فایل HTML عبارت DOCTYPE تعریف شود. در غیر اینصورت ممکن است با مقادیر و خطاهای عجیب مواجه شوید. در HTML مدرن تعریف عبارت زیر الزامی است:
<!DOCTYPE HTML>
Width/Height داکیومنت:
از آنجا که المنت ریشه داکیومنت مقدار document.documentElement است و تمام محتوای صفحه را شامل می شود، برای اندازه گیری سایز کامل داکیومنت می توان از عبارت document.documentElement.scrollWidth/scrollHeight استفاده کرد.
اما در مرورگرهای Chrome/Safari/Opera اگر هیچ اسکرولی وجود نداشته باشد، سپس documentElement.scrollHeight ممکن است مقداری کمتر از documentElement.clientHeight داشته باشد. عجیب است. نه؟
روش صحیح بدست آوردن ارتفاع کامل داکیومنت، بصورت زیر است:
let scrollHeight = Math.max( document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight ); alert('Full document height, with scrolled out part: ' + scrollHeight);
یعنی باید از مقدار ماکزیمم آنها استفاده کرد. دلیل آن هم دقیقا مشخص نیست. این روش از اوایل پیدایش جاوا اسکریپت جواب میداد!
بدست آوردن موقعیت فعلی اسکرول:
برای اینکه موقعیت جاری اسکرول درعناصر DOM را بفهمیم، می توان از خاصیت های scrollLeft/scrollTop استفاده کرد.
با استفاده از همین خاصیت می توان موقعیت اسکرول داکیومنت را بدست آورد. بصورت زیر:
document.documentElement.scrollLeft/scrollTop
کد فوق در اکثر مرورگرهای مدرن بدرستی کار می کند. اما در برخی از مرورگرهای قدیمی باید از document.body بجای document.documentElement استفاده کرد.
خوشبختانه نیازی نیست تمام این مقادیر را به خاطر بسپاریم. زیرا می توان از window.pageXOffset/pageYOffset استفاده کرد:
alert('Current scroll from the top: ' + window.pageYOffset); alert('Current scroll from the left: ' + window.pageXOffset);
خاصیت های فوق غیرقابل تغیییر (read-only) هستند.
Scrolling: scrollTo, scrollBy, scrollIntoView
توجه کنید که برای اسکرول کردن صفحه توسط javascript باید DOM بطور کامل لود شده باشد. بعنوان مثال اگر اسکریپت اسکرول را در تگ head تعریف کنیم کار نخواهد کرد.
خاصیت های scrollTop/scrollLeft قابل تغییر هستند و می توان توسط آنها، موقعیت فعلی اسکرول صفحه را تغییر داد.
البته می توان برای تغییر موقعیت جاری اسکرول صفحه، بجای scrollLeft و scrollTop از متدهای ویژه window.scrollBy(x,y) و window.scrollTo(pageX,pageY) استفاده کرد.
- متد scrollBy(x,y) باعث می شود صفحه نسبت به موقعیت فعلی خود اسکرول شود. بعنوان مثال scrollBy(0,10) صفحه را به اندازه 10 پیکسل به پایین اسکرول می کند.
- متد scrollTo(pageX,pageY) باعث اسکرول صفحه به مختصات مطلق (absolute coordinates) ارائه شده می شود. بنابراین مختصات گوشه بالا سمت چپ صفحه پس از اسکرول مقادیر (pageX, pageY) را خواهند داشت. این متد شبیه scrollLeft/scrollTop عمل می کند و خروجی یکسانی دارند. برای اسکرول صفحه به نقطه ابتدایی، یعنی بالای ویندوز، کافیست scrollTo(0,0) را اجرا کنیم.
scrollIntoView:
برای تکمیل مبحث اسکرول در جاوا اسکریپت، می خواهیم متد elem.scrollIntoView(top) را بررسی کنیم.
با فراخوانی متد فوق، صفحه به موقعیتی اسکرول می شود که عنصر elem نمایان شود.
- اگر مقدار top=true باشد (بصورت پیش فرض true است) صفحه تا حدی اسکرول می شود که عنصر elem در بالای صفحه قرار گیرد. در واقع لبه بالایی عنصر با بالای پنجره مرورگر تراز خواهد شد.
- اگر مقدار top=false باشد صفحه به اندازه ای اسکرول می شود که المنت elem در پایین صفحه مرورگر قرار گیرد.
غیرفعال کردن اسکرول:
در برخی مواقع ممکن است بخواهیم صفحه وب را “غیر قابل اسکرول” یا unscrollable کنیم. بعنوان مثال وقتی می خواهیم یک پیغام بزرگ در صفحه وب به کاربر نمایش دهیم، و می خواهیم توجه کاربر به این پیغام باشد و نتواند داکیومنت را اسکرول کند.
برای غیر فعال کردن اسکرول صفحه توسط javascript فقط کافیست کد زیر را اجرا کنیم:
document.body.style.overflow = "hidden"
در اینصورت صفحه در موقعیت اسکرول فعلی قفل خواهد شد. برای برگرداندن وضعیت اسکرول به حالت قبل، کد زیر را داریم:
document.body.style.overflow = "hidden"
جمع بندی مطالب:
عناصر HTML DOM ویژگی های هندسی زیر را دارند:
- OffsetParent: نزدیکترین اجداد به عنصر یا table, th, td, body
- OffsetLeft/offsetTop: مختصات نسبی عنصر نسبت به گوشه بالا سمت چپ صفحه
- OffsetWidth/offsetHeight: مقدار width و height بیرونی عنصر شامل border های اطراف
- clientLeft/clientTop: فاصله بین گوشه بیرونی بالا سمت چپ عنصر از گوشه درونی بالا سمت چپ (content+padding). برای زبان های راست چین (مانند فارسی و عربی)، اسکرول عمودی در سمت چپ قرار دارد پس clientLeft شامل عرض نوار اسکرول نیز می شود اما در زبان های چپ چین (left-to-right) مانند انگلیسی، نوار اسکرول عمودی در سمت راست عنصر درج می شود. پس clientLeft عرض اسکرول را شامل نخواهد شد.
- clientWidth/clientHeight: برابر width و height محتوای عنصر می باشد که شامل padding می باشد اما شامل scrollbar نیست.
- scrollWidth/scrollHeight: مانند contentWidth/Height است با این تفاوت که شامل سایز محتوای مخفی شده در اسکرول نیز می شود.
- scrollLeft/scrollTop: طول و عرض بخش مخفی عنصر در حالت اسکرول می باشند.
- documentElement.clientWidth/clientHeight: برای بدست آوردن width و height بخش نمایان یا visible داکیومنت (طول و عرض فضای محتوایی)
- برای بدست آوردن width و height کامل داکیومنت کد زیر را داریم:
let scrollHeight = Math.max( document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight );
- pageYOffset/pageXOffset: برای دریافت موقعیت فعلی اسکرول
- scrollTo(pageX,pageY): برای اسکرول صفحه به یک مختصات مشخص
- scrollBy(x,y): برای اسکرول صفحه نسبت به یک عنصر مشخص
- scrollIntoView(top): برای اسکرول صفحه تا حدی که عنصر elem نمایان شود.
در جلسه بعد، سوالات تستی (چند گزینه ای) زبان برنامه نویسی جاوا اسکریپت را به همراه پاسخ های تشریحی بررسی خواهیم کرد. با ما همراه باشید…!
دیدگاهتان را بنویسید