Chrome DevTools پشتیبانی از عناصر لایه بالایی را اضافه میکند، و این کار را برای توسعهدهندگان آسانتر میکند تا کدهای خود را که از عناصر لایه بالایی استفاده میکنند، اشکالزدایی کنند.
این مقاله توضیح میدهد که عناصر لایه بالایی چیست، چگونه DevTools به تجسم محتوای لایه بالایی برای درک و اشکالزدایی ساختار DOM که حاوی عناصر لایه بالایی است کمک میکند و چگونه پشتیبانی از لایه بالایی DevTools پیادهسازی میشود.
عناصر لایه بالایی و لایه بالایی چیست؟
وقتی یک <dialog>
به عنوان مدال باز می کنید دقیقاً چه اتفاقی می افتد؟ 🤔
در لایه بالایی قرار می گیرد. محتوای لایه بالا در بالای همه محتوای دیگر رندر می شود. به عنوان مثال، یک گفتگوی مودال باید در بالای تمام محتوای DOM دیگر ظاهر شود، بنابراین مرورگر بهجای اینکه نویسندگان را مجبور به مبارزه دستی با z-index کند، بهطور خودکار این عنصر را در «لایه بالایی» نمایش میدهد. یک عنصر لایه بالایی در بالای یک عنصر حتی با بالاترین شاخص z ظاهر می شود.
لایه بالایی را می توان به عنوان "بالاترین لایه انباشته" توصیف کرد. هر سند دارای یک نمای واحد مرتبط است و بنابراین، یک لایه بالایی نیز دارد. چندین عنصر می توانند همزمان داخل لایه بالایی باشند. وقتی این اتفاق میافتد، آنها روی هم چیده میشوند، آخرین نفر روی هم. به عبارت دیگر، تمام عناصر لایه بالایی در یک پشته آخر، اولین خروجی (LIFO) در لایه بالایی قرار می گیرند.
عنصر <dialog>
تنها عنصری نیست که مرورگر در لایه بالایی نمایش می دهد. در حال حاضر، عناصر لایه بالایی عبارتند از: پاپاورها ، دیالوگ های مدال و عناصر در حالت تمام صفحه .
اجرای گفتگوی زیر را بررسی کنید:
<main>
<button onclick="window.dialog.showModal();">Open Dialog</button>
</main>
<dialog id="dialog"></dialog>
در اینجا یک نسخه نمایشی با چند دیالوگ است که سبکهایی در پسزمینههایشان اعمال میشود (پسزمینه شرح داده شده در زیر):
پس زمینه چیست؟
خوشبختانه، راهی برای سفارشی کردن محتوای زیر عنصر لایه بالایی وجود دارد.
هر عنصر در لایه بالایی یک شبه عنصر CSS به نام پس زمینه دارد.
Backdrop کادری به اندازه ی viewport است که بلافاصله در زیر هر عنصر لایه بالایی نمایش داده می شود. شبه عنصر ::backdrop
این امکان را فراهم میکند که هر چیزی را که در زیر عنصر قرار دارد، در زمانی که بالاترین عنصر در لایه بالایی است، مبهم، سبک یا کاملاً پنهان کنید.
هنگامی که چندین عنصر را به صورت مودال در می آورید، مرورگر پس زمینه را بلافاصله در زیر جلویی ترین عنصر و در بالای سایر عناصر تمام صفحه ترسیم می کند.
در اینجا نحوه استایل کردن یک پس زمینه آمده است:
/* The browser displays the backdrop only when the dialog.showModal() function opens the dialog.*/
dialog::backdrop {
background: rgba(255,0,0,.25);
}
چگونه فقط اولین پس زمینه را نشان دهیم؟
هر عنصر لایه بالایی دارای یک پس زمینه است که به پشته لایه بالایی تعلق دارد. این پسزمینهها طوری طراحی شدهاند که روی یکدیگر همپوشانی داشته باشند، بنابراین اگر تیرگی یک پسزمینه 100٪ نباشد، پسزمینههای زیر قابل مشاهده هستند.
اگر فقط اولین پسزمینه در پشته لایه بالایی باید قابل مشاهده باشد، میتوانید با پیگیری شناسههای آیتم در پشته لایه بالایی به این هدف برسید.
اگر عنصر اضافه شده اولین عنصر در لایه بالایی نباشد، تابعی که هنگام قرار دادن عنصر در لایه بالایی فراخوانی می شود، یک کلاس hiddenBackdrop
را به ::backdrop
اعمال می کند. این کلاس زمانی حذف می شود که عنصر از لایه بالایی حذف شود.
کد موجود در این نمونه نمایشی را بررسی کنید:
طراحی پشتیبانی از لایه بالایی در DevTools
پشتیبانی DevTools از لایه بالایی به توسعه دهندگان کمک می کند تا مفهوم لایه بالایی را درک کنند و نحوه تغییر محتوای لایه بالایی را تجسم کنند. این ویژگی ها به توسعه دهندگان کمک می کند تا موارد زیر را شناسایی کنند:
- عناصر موجود در لایه بالایی در هر زمان و ترتیب آنها.
- عنصر در بالای پشته در هر نقطه.
علاوه بر این، پشتیبانی از لایه بالایی DevTools به تجسم موقعیت شبه عنصر پس زمینه در پشته لایه بالایی کمک می کند. اگرچه یک عنصر درختی نیست، اما نقش مهمی در نحوه عملکرد لایه بالایی دارد و می تواند برای توسعه دهندگان مفید باشد.
با ویژگی های پشتیبانی از لایه بالایی، می توانید:
- در هر زمان مشاهده کنید که کدام عناصر در پشته لایه بالایی قرار دارند. پشته نمایش لایه بالایی به صورت پویا با اضافه شدن یا حذف عناصر از لایه بالایی تغییر می کند.
- موقعیت عنصر را در پشته لایه بالایی ببینید.
- از عنصر لایه بالایی یا شبه عنصر پس زمینه عناصر در درخت به عنصر یا شبه عنصر پس زمینه در ظرف نمایش لایه بالایی بپرید و به عقب بروید.
بیایید ببینیم چگونه از این ویژگی ها استفاده کنیم!
ظرف لایه بالایی
برای کمک به تجسم عناصر لایه بالایی، DevTools یک ظرف لایه بالایی به درخت عناصر اضافه می کند. بعد از بستن تگ </html>
باقی می ماند.
این کانتینر به شما این امکان را می دهد که عناصر موجود در پشته لایه بالایی را در هر زمان مشاهده کنید. ظرف لایه بالایی لیستی از پیوندها به عناصر لایه بالایی و پس زمینه آنها است. پشته نمایش لایه بالایی به صورت پویا با اضافه شدن یا حذف عناصر از لایه بالایی تغییر می کند.
برای یافتن عناصر لایه بالایی در درخت عناصر یا ظرف لایه بالایی، روی پیوندهای نمایش عنصر لایه بالایی در ظرف لایه بالایی به همان عنصر در درخت عنصر و پشت آن کلیک کنید.
برای پرش از عنصر ظرف لایه بالایی به عنصر درخت لایه بالایی، روی دکمه آشکار در کنار عنصر در ظرف لایه بالایی کلیک کنید.
برای پرش از عنصر درخت لایه بالایی به پیوند در ظرف لایه بالایی، روی نشان لایه بالایی در کنار عنصر کلیک کنید.
میتوانید هر نشانی را خاموش کنید، از جمله نشان لایه بالایی . برای غیرفعال کردن نشانها، روی هر نشانی کلیک راست کنید، تنظیمات نشان را انتخاب کنید و تیکهای کنار نشانهایی را که میخواهید پنهان کنید پاک کنید.
ترتیب عناصر در پشته لایه بالایی
ظرف لایه بالایی عناصر را همانطور که در پشته ظاهر می شوند اما به ترتیب معکوس نشان می دهد. بالای عنصر پشته آخرین مورد در لیست عناصر ظرف لایه بالایی است. این بدان معنی است که آخرین عنصر در لیست کانتینر لایه بالایی عنصری است که در حال حاضر می توانید با آن در سند تعامل داشته باشید.
نشانهای کنار عناصر درختی نشان میدهند که آیا عناصر به لایه بالایی تعلق دارند یا خیر و شامل شماره موقعیت یک عنصر در پشته هستند.
در این اسکرین شات، پشته لایه بالایی از دو عنصر تشکیل شده است که عنصر دوم در بالای پشته قرار دارد. اگر عنصر دوم را حذف کنید، عنصر اول به بالا منتقل می شود.
پس زمینه در ظرف لایه بالایی
همانطور که در بالا ذکر شد، هر عنصر لایه بالایی یک شبه عنصر CSS به نام پس زمینه دارد. شما می توانید این عنصر را استایل دهید، بنابراین مفید است که آن را نیز بررسی کنید و نمایش آن را ببینید.
در درخت عناصر، یک عنصر پسزمینه قبل از تگ بسته شدن عنصری که به آن تعلق دارد، قرار میگیرد. با این حال، در ظرف لایه بالایی، یک پیوند پسزمینه درست بالای عنصر لایه بالایی که به آن تعلق دارد، فهرست شده است.
تغییرات در درخت DOM
ElementsTreeElement
، کلاسی که مسئول ایجاد و مدیریت عناصر درختی منفرد DOM در DevTools است، برای اجرای یک ظرف لایه بالایی کافی نبود.
برای نمایش کانتینر لایه بالایی به عنوان یک گره در درخت، یک کلاس جدید اضافه کردیم که گرههای عنصر درخت DevTools را ایجاد میکند. قبلاً، کلاسی که مسئول ایجاد درخت عناصر DevTools است، هر TreeElement
با یک DOMNode
مقداردهی میکرد، که کلاسی با backendNodeId
و سایر ویژگیهای مرتبط با باطن است. backendNodeId
، به نوبه خود، در backend اختصاص داده می شود.
گره کانتینری لایه بالایی، که فهرستی از پیوندها به عناصر لایه بالایی دارد، باید به عنوان یک گره عنصر درختی معمولی رفتار کند. با این حال، این گره یک گره DOM "واقعی" نیست و بخش پشتیبان نیازی به ایجاد گره ظرف لایه بالایی ندارد.
برای ایجاد یک گره frontend که نمایانگر لایه بالایی است، نوع جدیدی از گره frontend را اضافه کردیم که بدون DOMNode
ایجاد می شود. این عنصر کانتینر لایه بالایی اولین گره جلویی است که DOMNode
ندارد، به این معنی که فقط در قسمت جلویی وجود دارد و پشتیبان درباره آن «دانست». برای داشتن رفتاری مشابه با گرههای دیگر، یک کلاس TopLayerContainer
جدید ایجاد کردیم که کلاس UI.TreeOutline.TreeElement
را گسترش میدهد که مسئول رفتار گرههای frontend است.
برای دستیابی به مکان مورد نظر، کلاسی که یک عنصر را رندر می کند، TopLayerContainer
به عنوان برادر بعدی تگ <html>
متصل می کند.
نشان لایه بالایی جدید نشان می دهد که عنصر در لایه بالایی قرار دارد و به عنوان پیوندی به میانبر این عنصر در عنصر TopLayerContainer
عمل می کند.
طراحی اولیه
در ابتدا، طرح این بود که به جای ایجاد لیستی از پیوندها به عناصر، عناصر لایه بالایی را در ظرف لایه بالایی کپی کنیم. ما این راه حل را به دلیل نحوه واکشی فرزندان عناصر در DevTools پیاده سازی نکردیم. هر عنصر دارای یک اشاره گر والد است که در واکشی فرزندان استفاده می شود و وجود چند نشانگر غیرممکن است. بنابراین، ما نمیتوانیم گرهای داشته باشیم که به درستی منبسط شود و همه بچهها را در مکانهای متعدد درخت قرار دهد. به طور کلی، سیستم با در نظر گرفتن زیردرخت های تکراری ساخته نشده است.
مصالحه ای که به آن رسیدیم ایجاد پیوندهایی به گره های DOM frontend به جای کپی کردن آن گره ها بود. کلاسی که مسئول ایجاد پیوند به عناصر در DevTools است ShortcutTreeElement
است که UI.TreeOutline.TreeElement
را گسترش می دهد. ShortcutTreeElement
رفتاری مشابه سایر عناصر درختی DevTools DOM دارد، اما گره مربوطه در باطن ندارد و دکمهای دارد که به ElementsTreeElement
پیوند میدهد. هر ShortcutTreeElement
به گره لایه بالایی یک ShortcutTreeElement
فرزند دارد که به نمایش یک شبه عنصر ::backdrop
در درخت DevTools DOM پیوند می دهد.
طراحی اولیه:
پروتکل Chrome DevTools (CDP) تغییر می کند
برای اجرای پشتیبانی از لایه بالایی، تغییراتی در پروتکل ابزار توسعه کروم (CDP) لازم است. CDP به عنوان یک پروتکل ارتباطی بین DevTools و Chromium عمل می کند.
باید موارد زیر را اضافه کنیم:
- دستوری برای تماس از فرانت اند در هر زمان.
- رویدادی برای راهاندازی در قسمت جلویی از سمت باطن.
CDP: دستور DOM.getTopLayerElements
برای نمایش عناصر لایه بالایی فعلی، به یک دستور CDP آزمایشی جدید نیاز داریم که فهرستی از شناسه گرههای عناصر موجود در لایه بالایی را برمیگرداند. DevTools هر زمان که DevTools باز می شود یا زمانی که عناصر لایه بالایی تغییر می کنند، این دستور را فراخوانی می کند. دستور به شکل زیر است:
# Returns NodeIds of the current top layer elements.
# Top layer renders closest to the user within a viewport, therefore, its elements always
# appear on top of all other content.
experimental command getTopLayerElements
returns
# NodeIds of the top layer elements.
array of NodeId nodeIds
CDP: رویداد DOM.topLayerElementsUpdated
برای دریافت لیست به روز عناصر لایه بالایی، به هر تغییر عناصر لایه بالایی برای راه اندازی یک رویداد CDP آزمایشی نیاز داریم. این رویداد قسمت جلویی را از تغییر مطلع می کند که سپس دستور DOM.getTopLayerElements
را فراخوانی می کند و لیست عناصر جدید را دریافت می کند.
این رویداد به شکل زیر است:
# Called by the change of the top layer elements.
experimental event topLayerElementsUpdated
ملاحظات CDP
گزینه های متعددی در مورد نحوه اجرای پشتیبانی CDP از لایه بالایی وجود داشت. گزینه دیگری که ما در نظر گرفتیم این بود که رویدادی را ایجاد کنیم که به جای اطلاع دادن به قسمت جلویی در مورد اضافه یا حذف یک عنصر لایه بالایی، لیست عناصر لایه بالایی را بازگرداند.
از طرف دیگر، میتوانیم به جای دستور دو رویداد ایجاد کنیم: topLayerElementAdded
و topLayerElementRemoved
. در این حالت، ما یک عنصر دریافت می کنیم و باید آرایه عناصر لایه بالایی را در قسمت جلویی مدیریت کنیم.
در حال حاضر، یک رویداد frontend دستور getTopLayerElements
را فراخوانی می کند تا لیستی از عناصر به روز شده را دریافت کند. اگر بخواهیم فهرستی از عناصر یا عنصر خاصی را ارسال کنیم که هر بار که یک رویداد باعث تغییر شده است، میتوانیم از یک مرحله از فراخوانی فرمان اجتناب کنیم. با این حال، در این مورد، قسمت جلویی کنترل روی عناصر تحت فشار را از دست می دهد.
ما آن را به این روش پیادهسازی کردیم زیرا به نظر ما، بهتر است فرانتاند تصمیم بگیرد که چه زمانی گرههای لایه بالایی را درخواست کند. برای مثال، اگر لایه بالایی در رابط کاربری جمع شده باشد یا کاربر از پانل DevTools استفاده کند که درخت عناصر را ندارد، نیازی به دریافت گرههای اضافی که میتوانند عمیقتر در درخت باشند وجود ندارد.