المقدمة
لو سألت نفسك إزاي المتصفح بيقدر يعرض صفحة ويب كاملة قدامك بعد ما تضغط على لينك؟ الموضوع دا بيعدي بكذا خطوة مهمة، وكل خطوة ليها شغل مختلف وبتأثر بشكل مباشر على سرعة تحميل الصفحة وتجربة المستخدم.
في الجزء اللي فات، اتكلمنا عن بناء شجرة الـ DOM وشجرة الـ CSSOM من الـ HTML والـ CSS اللي جايين من السيرفر. المهم هنا إن الشجرتين دول هما objects مستقلين، واحدة بتوصف المحتوى (DOM)، والتانية بتوصف قواعد التصميم (CSSOM). السؤال بقى: إزاي ندمج الاتنين مع بعض عشان المتصفح يرسم العناصر على الشاشة؟ 🤔
رحلة المتصفح من الـ DOM والـ CSSOM لحد الـ Render Tree
1- إنشاء الـ Render Tree
يبدأ المتصفح من شجرة DOM ويقوم بمسحها من أعلى لأسفل لكل عنصر مرئي وركز علي مرئي في الـ DOM، المتصفح بيدور عن القواعد المطابقة له في الـ CSSOM و بينشئ node في الـ Render Tree تجمع بين معلومات المحتوى من الـ DOM وقواعد التنسيق من الـ CSSOM
استبعاد العناصر غير المرئية:
العناصر التي لها خاصية display: none
مش بتتضاف للـ Render Tree.
العناصر مثل <script>
و <head>
برضو مش بتظهر في الـ Render Tree لأنها مبتأثرش على العرض المرئي.
بعض العناصر مثل أرقام القوائم أو بعض الـ pseudo-elements (مثل ::before و::after) ممكن تتضاف إلى الـ Render Tree رغم عدم وجودها في الـ DOM
2- حساب الأبعاد وتحديد المواضع (Layout)
لكل عنصر في الـ Render Tree، المتصفح بيحسب أبعاده وموقعه وفقًا للـ Box Model (margin, border, padding, content) موضع كل عنصر بالنسبة للعناصر الأخرى بيتم تحديده باستخدام ( Flow Layout) مثل:
- الـ Normal Flow
- الـ Float
- الـ Absolute Positioning
3- التعامل مع الطبقات (Layers)
بعض العناصر ممكن تشكل طبقات منفصلة (Layers)، مثل:
- العناصر ذات الخاصية position: fixed
- العناصر التي تستخدم will-change أو transform
- الــ Layers دي بيتم رسمها بشكل منفصل لتحسين الأداء أثناء الرسم (Painting)
4- الرسم (Painting)
بعد إنشاء الـ Render Tree، يقوم المتصفح برسم البكسلات على الشاشة بناءً على الأبعاد والمواضع المحسوبة. يتم رسم كل عنصر حسب خصائصه النهائية (الألوان، الخلفيات، الحواف... إلخ)
5- الـ Layout وإعادة التدفق (Reflow)
هذه العملية تسمى بـ "Layout" أو "Reflow"، وهي عملية مكلفة حسابيًا. لذلك، المتصفحات الحديثة تستخدم تقنيات مثل التحسين الذكي وتقسيم العمل إلى مراحل لتحسين الأداء من المهم أيضًا أن نذكر أن هذه العملية قد تتكرر إذا حدثت تغييرات في الـ DOM أو الـ CSSOM (مثلاً بسبب JavaScript)، مما قد يؤدي إلى إعادة حساب الـ Layout وإعادة الرسم.
كل خطوة ليها تكلفة معينة، والهدف إننا نقلل التكلفة دي بقدر الإمكان عشان الصفحة تشتغل بأسرع وقت! ⚡
Building Render Tree
كل مرحلة لها شغل معين، تعالوا نفهمهم مع بعض:
أول حاجة المتصفح بيعملها إنه بيجمع الـ DOM مع الـ CSSOM عشان يكون الـ (Render Tree). الشجرة دي بتحتوي على كل المحتوى اللي ظاهر من الـ DOM في الصفحة، وكل معلومات الـ CSSOM اللي خاصة بكل عنصر (node). يعني المتصفح بياخد structure الصفحة ومعلومات التصميم عشان يعرف إزاي كل حاجة هتظهر للمستخدم
ده بيوضح قد إيه الـ Render Tree مهمة عشان المتصفح يعرف يرسم الصفحة بشكل صحيح وسريع.
عشان يبني المتصفح الـ (Render Tree)، بيعمل تقريبًا الآتي:
- بيبدأ من root شجرة الـ DOM وبيعدي على كل الـ nodes اللي ظاهرة في الصفحة
- في بعض الـ nodes مش بتكون ظاهرة زي الـ <script> والـ <meta>، ودي بيتم استبعادها لأنها مش بتظهر في الـ output النهائي اللي بيتعرض للمستخدم.
- كمان، في بعض الـ nodes بتكون مخفية باستخدام الـ CSS زي لما نستخدم display: none، ودي كمان بتتشال من الـ (Render Tree). مثال على كده: لو فيه عنصر <span> مخفي باستخدام display: none، مش هيظهر في الـ (Render Tree)
- لكل node ظاهرة، المتصفح بيدور على القواعد المناسبة من الـ CSSOM وبيطبقها
- في الآخر، المتصفح بيخرج الـ nodes اللي فيها محتوى والـ computed styles بتاعتها
النتيجة النهائية بتكون الـ (Render Tree) اللي فيها كل المحتوى ومعلومات التصميم الخاصة بالعناصر اللي ظاهرة على الشاشة. بعد ما شجرة العرض تبقى جاهزة، نقدر ندخل على مرحلة التخطيط (Layout).
لحد دلوقتي، المتصفح حسب إيه العناصر اللي المفروض تبقى ظاهرة، وحسب الـstyles بتاعتها، لكن لسه محسبش مكانها وحجمها بالظبط جوه شاشة الجهاز، ودي مهمة مرحلة الـLayout أو اللي بنسميها كمان Reflow عشان المتصفح يعرف الحجم والمكان الدقيق لكل عنصر في الصفحة، بيبدأ من root الـ(Render Tree) وبيعدي عليها كلها. خلينا نشوف المثال ده
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Critial Path: Hello world!</title>
</head>
<body>
<div style="width: 50%">
<div style="width: 50%">Hello world!</div>
</div>
</body>
</html>
في المثال اللي فات، الـ <body> فيه اتنين <div> جوا بعض: الأول هو الـ parent div، واللي بيحدد حجم العنصر بحيث يكون 50% من عرض الشاشة (viewport). الـ <div> التاني اللي جوا الـ parent بيحدد عرضه إنه يكون 50% من حجم الـ parent، يعني في النهاية هيكون 25% من عرض الشاشة (viewport)
نتيجة عملية التخطيط (Layout) بتكون في شكل حاجة اسمها "box model"، واللي بتحدد بدقة المكان والحجم لكل عنصر جوه الشاشة (viewport). كل القياسات النسبية اللي استخدمناها في الـ CSS زي النسب المئوية بتتحول لبكسلز حقيقية على الشاشةأخيرًا، بعد ما عرفنا إيه العناصر اللي ظاهرة، وحسبنا الـ computed styles بتاعتها والمكان والحجم، بنقدر نمرر المعلومات دي للمرحلة الأخيرة، اللي بتحوّل كل عنصر في شجرة العرض لـ بكسلز حقيقية على الشاشة. المرحلة دي بنسميها عادةً "الرسم (Painting)" أو "التقطيع (Rasterizing)".
Painting & Rasterizing
المرحلة دي ممكن تاخد وقت لأن المتصفح بيعمل شغل كتير عشان يرسم الصفحة بشكل صحيح. لكن باستخدام Chrome DevTools تقدر تشوف كل المراحل دي وتعرف التفاصيل عنها. تعال نشوف مرحلة الـ layout في مثال الـ "hello world" اللي اشتغلنا عليه:
الـ event بتاع الـ Layout بيكون مسؤول عن تسجيل عملية بناء الـ(Render Tree)، وحساب مكان وحجم كل عنصر في الـ Timeline ، ولما مرحلة الـ layout تخلص، المتصفح بيبدأ يعمل أحداث "Paint Setup" و**"Paint"**، واللي بتكون مسؤولة عن تحويل شجرة العرض لبكسلز على الشاشة
الوقت اللي المتصفح بياخده عشان يبني الـ(Render Tree) ، يحسب التخطيط (layout)، ويعمل الرسم (paint)، بيختلف حسب حجم الـ(document)، الـstyles اللي مطبقة عليه، والجهاز اللي الصفحة بتشتغل عليه. يعني لو الـdocument كبير، المتصفح هيحتاج شغل أكتر، ولو الـstyles معقدة زي الـ drop shadow.
الرسم هيكون أغلى من الـstyles البسيطة زي الألوان الثابتة اللي بيكون "مش expensive" عشان يحصله compute and render الصفحة اللي اشتغلنا عليها ممكن تبان بسيطة، لكنها بتتطلب شغل كبير من المتصفح.
لو حصل أي تعديل في الـ DOM أو الـ CSSOM، المتصفح هيحتاج يعيد العملية كلها عشان يعرف إيه البكسلز اللي محتاجة تتعمل لها re-render على الشاشةتحسين الـ (Critical Rendering Path). يعني إنك تقلل الوقت المستغرق في الخطوات دي كلها ، عشان تقدر تعرض المحتوى على الشاشة بأسرع وقت ممكن. ده كمان بيقلل الوقت بين تحديثات الشاشة بعد الـ initial render ، وبالتالي بيحسن معدل التحديث ويخلي المحتوى التفاعلي أسرع وأكتر سلاسة 🔥
في الختام
بكده نكون شوفنا مع بعض في المقال اللي فات والمقال ده ازاي الـ Browser بيعمل Render للـ Web Pages وشوفنا الرحلة كاملة بداية من الـ DOM والـ CSSOM لحد ما بنينا الـ Render Tree 🚀
Discussion