طريقة عمل المتصفِّحات

كواليس متصفّحات الويب الحديثة

تمهيد

هذا المرجع الشامل عن العمليات الداخلية لكل من WebKit وGecko هو نتيجة العديد من الأبحاث التي أجرتها المطوّرة الإسرائيلية تالا غارسيل. على مدار بضع سنوات، راجعت جميع البيانات المنشورة حول الوظائف الداخلية للمتصفّح وأمضت وقتًا طويلاً في قراءة رمز المصدر لمتصفّح الويب. كتبت:

بصفتك مطوّر ويب، يساعدك التعرّف على العمليات الداخلية للمتصفّح في اتخاذ قرارات أفضل ومعرفة مبرّرات أفضل الممارسات المتعلقة بالتطوير. على الرغم من أنّ هذا المستند طويل نوعًا ما، ننصحك بقضاء بعض الوقت في الاطّلاع عليه. سيسعدك ذلك حتمًا.

بول إيريش، مسؤول علاقات المطوّرين في Chrome

مقدمة

متصفحات الويب هي البرامج الأكثر استخدامًا على نطاق واسع. في هذا المرجع الأساسي، سأوضّح كيفية عملها من وراء الكواليس. سنرى ما يحدث عند كتابة google.com في شريط العناوين إلى أن تظهر لك صفحة Google على شاشة المتصفّح.

المتصفّحات التي سنتحدث عنها

هناك خمسة متصفّحات رئيسية يتم استخدامها على أجهزة الكمبيوتر المكتبي اليوم: Chrome وInternet Explorer وFirefox وSafari وOpera. على الأجهزة الجوّالة، تتوفّر المتصفحات الرئيسية التالية: متصفّح Android ومتصفّح iPhone ومتصفّح Opera Mini ومتصفّح Opera Mobile ومتصفّح UC ومتصفّحات Nokia S40/S60 ومتصفّح Chrome، وجميعها تستند إلى WebKit باستثناء متصفّحات Opera. سأقدّم أمثلة من متصفّحات Firefox وChrome وSafari (التي تعتمد على مصدر مفتوح جزئيًا). وفقًا لإحصاءات StatCounter (اعتبارًا من حزيران (يونيو) 2013)، يشكّل Chrome وFirefox وSafari حوالي% 71 من استخدام المتصفّحات على أجهزة الكمبيوتر المكتبي على مستوى العالم. على الأجهزة الجوّالة، يشكّل متصفّح Android وiPhone وChrome حوالي% 54 من معدّل الاستخدام.

الوظيفة الرئيسية للمتصفّح

تتمثّل الوظيفة الرئيسية للمتصفّح في عرض مورد الويب الذي تختاره، وذلك من خلال طلبه من الخادم وعرضه في نافذة المتصفّح. يكون المرجع عادةً مستند HTML، ولكن قد يكون أيضًا ملف PDF أو صورة أو نوعًا آخر من المحتوى. يحدّد المستخدم موقع المورد باستخدام معرّف موارد منتظم (URI).

يتم تحديد طريقة تفسير المتصفّح لملفات HTML وعرضها في مواصفات HTML وCSS. تُعدّ هذه المواصفات من قِبل مؤسسة W3C (اتحاد شبكة الويب العالمية)، وهي مؤسسة المعايير على الويب. لعدة سنوات، كانت المتصفّحات متوافقة مع جزء من المواصفات فقط وطوّرت إضافاتها الخاصة. وقد أدّى ذلك إلى حدوث مشاكل خطيرة في التوافق لدى مؤلفي الويب. تتوافق معظم المتصفّحات اليوم مع المواصفات بشكل أو بآخر.

تتشارك واجهات مستخدم المتصفّحات الكثير من العناصر. تشمل عناصر واجهة المستخدم الشائعة ما يلي:

  1. شريط العناوين لإدراج معرّف موارد منتظم
  2. زرّا الرجوع والانتقال إلى الأمام
  3. خيارات وضع إشارة مرجعية
  4. زرّا إعادة التحميل والإيقاف لإعادة تحميل المستندات الحالية أو إيقافها
  5. زر الصفحة الرئيسية الذي ينقلك إلى صفحتك الرئيسية

من الغريب أنّ واجهة مستخدِم المتصفّح غير محدّدة في أي مواصفات رسمية، بل تأتي من الممارسات الجيدة التي تم تشكيلها على مدار سنوات من الخبرة ومن خلال المتصفحات التي تحاكي بعضها البعض. لا تحدّد مواصفات HTML5 عناصر واجهة المستخدم التي يجب أن يتضمّنها المتصفّح، ولكنها تسرد بعض العناصر الشائعة. ومن بين هذه الأشرطة شريط العناوين وشريط الحالة وشريط الأدوات. هناك بالطبع ميزات فريدة لمتصفّح معيّن، مثل مدير عمليات التنزيل في Firefox.

البنية الأساسية العالية المستوى

تشمل المكونات الرئيسية للمتصفّح ما يلي:

  1. واجهة المستخدم: يشمل ذلك شريط العناوين وزر الرجوع/التقديم وقائمة الإشارات المرجعية وما إلى ذلك. كل جزء من شاشة المتصفّح باستثناء النافذة التي تظهر فيها الصفحة المطلوبة.
  2. محرك المتصفّح: يوجّه الإجراءات بين واجهة المستخدم ومحرك العرض.
  3. محرك العرض: مسؤول عن عرض المحتوى المطلوب. على سبيل المثال، إذا كان المحتوى المطلوب هو HTML، يحلّل محرّك العرض HTML وCSS ويعرض المحتوى الذي تم تحليله على الشاشة.
  4. الشبكات: لطلبات الشبكة، مثل طلبات HTTP، باستخدام عمليات تنفيذ مختلفة لأنظمة التشغيل المختلفة من خلال واجهة مستقلة عن النظام الأساسي
  5. الخلفية في واجهة المستخدم: تُستخدَم لرسم التطبيقات المصغّرة الأساسية، مثل مربّعات الاختيار والنوافذ. تعرِض هذه الخلفية واجهة عامة ليست خاصة بالنظام الأساسي. وتحت ذلك، يتم استخدام طرق واجهة المستخدم لنظام التشغيل.
  6. مترجم JavaScript تُستخدَم لتحليل رمز JavaScript وتنفيذه.
  7. تخزين البيانات: هذه طبقة ثبات. قد يحتاج المتصفّح إلى حفظ جميع أنواع البيانات محليًا، مثل ملفات تعريف الارتباط. تتيح المتصفّحات أيضًا آليات التخزين، مثل localStorage وIndexedDB وWebSQL وFileSystem.
مكونات المتصفّح
الشكل 1: مكوّنات المتصفّح

من المهمّ الإشارة إلى أنّ المتصفّحات، مثل Chrome، تشغّل عدّة نُسخ من محرّك العرض: نسخة لكل علامة تبويب. يتم تشغيل كل علامة تبويب في عملية منفصلة.

محرّكات العرض

تقع على عاتق محرّك العرض مسؤولية العرض، أي عرض المحتوى المطلوب على شاشة المتصفّح.

يمكن لمحرك العرض عرض مستندات وصور HTML وXML تلقائيًا. ويمكنه عرض أنواع أخرى من البيانات من خلال الإضافات أو الإضافات، على سبيل المثال، عرض مستندات PDF باستخدام مكوّن إضافي لعارض PDF. ومع ذلك، سنركّز في هذا الفصل على حالة الاستخدام الرئيسية: عرض صفحات HTML والصور التي تم تنسيقها باستخدام CSS.

تستخدم المتصفحات المختلفة محرّكات عرض مختلفة: يستخدم Internet Explorer محرّك Trident، ويستخدم Firefox محرّك Gecko، ويستخدم Safari محرّك WebKit. يستخدم Chrome وOpera (بدءًا من الإصدار 15) Blink، وهو نسخة من WebKit.

WebKit هو محرّك عرض مفتوح المصدر بدأ كمحرك لنظام التشغيل Linux وتم تعديله من قِبل Apple ليتوافق مع نظامَي التشغيل Mac وWindows.

المسار الرئيسي

سيبدأ محرّك العرض في الحصول على محتوى المستند المطلوب من طبقة الشبكة. وسيتم ذلك عادةً في أجزاء بحجم 8 كيلوبايت.

بعد ذلك، إليك الخطوات الأساسية لمحرك العرض:

خطوات عمل محرّك العرض الأساسية
الشكل 2: العملية الأساسية لمحرك العرض

سيبدأ محرّك العرض في تحليل مستند HTML وتحويل العناصر إلى عقد نموذج DOM في شجرة تُعرف باسم "شجرة المحتوى". سيحلّل المحرّك بيانات الأنماط، سواء في ملفات CSS الخارجية أو في عناصر الأنماط. سيتم استخدام معلومات التصميم مع التعليمات المرئية في HTML لإنشاء شجرة أخرى: شجرة العرض.

تحتوي شجرة العرض على مستطيلات تتضمّن سمات مرئية مثل اللون والسمات. المستطيلات بالترتيب الصحيح ليتم عرضها على الشاشة

بعد إنشاء شجرة العرض، يتمّ عرضها في عملية "التنسيق". وهذا يعني منح كل عقدة الإحداثيات الدقيقة التي يجب أن تظهر بها على الشاشة. المرحلة التالية هي الرسم، حيث سيتمّ التنقّل في شجرة العرض وسيتمّ رسم كلّ عقدة باستخدام طبقة الواجهة الخلفية لواجهة المستخدم.

من المهمّ فهم أنّ هذه عملية تدريجية. لتوفير تجربة أفضل للمستخدم، سيحاول محرّك العرض عرض المحتوى على الشاشة في أقرب وقت ممكن. ولن تنتظر حتى يتم تحليل كل علامات HTML قبل بدء إنشاء شجرة العرض وتنسيقها. سيتم تحليل أجزاء من المحتوى وعرضها، بينما تستمر العملية مع بقية المحتوى الذي يستمر وصوله من الشبكة.

أمثلة على مسارات المستخدمين الرئيسية

مسار WebKit الرئيسي
الشكل 3: العملية الرئيسية لمحرك WebKit
التدفق الرئيسي لمحرّك العرض Gecko من Mozilla
الشكل 4: العملية الرئيسية لمحرك عرض المحتوى Gecko من Mozilla

من الشكلَين 3 و4، يمكنك ملاحظة أنّه على الرغم من أنّ WebKit وGecko يستخدمان مصطلحات مختلفة قليلاً، إلا أنّ الخطوات متشابهة بشكل أساسي.

يُطلق محرّك Gecko على شجرة العناصر المنسَّقة بصريًا اسم "شجرة الإطارات". كل عنصر هو إطار. يستخدم WebKit مصطلح "شجرة التقديم" ويتألف من "عناصر التقديم". يستخدم WebKit مصطلح "التنسيق" لوضع العناصر، بينما يُطلق عليه Gecko اسم "إعادة التدفق". "المرفق" هو مصطلح WebKit لربط عقد نموذج DOM والمعلومات المرئية لإنشاء شجرة العرض. هناك اختلاف بسيط غير دلالي وهو أنّ Gecko يحتوي على طبقة إضافية بين HTML وشجرة DOM. ويُطلق على هذا العنصر اسم "وحدة معالجة المحتوى"، وهو عبارة عن مصنع لإنشاء عناصر DOM. سنتحدث عن كل جزء من هذه العملية:

التحليل - العام

بما أنّ التحليل هو عملية مهمة جدًا في محرّك العرض، سنتناوله بمزيد من التفصيل. لنبدأ بمقدمة صغيرة عن التحليل.

ويعني تحليل المستند ترجمته إلى بنية يمكن للرمز البرمجي استخدامها. وتكون نتيجة التحليل عادةً شجرة من العقد التي تمثّل بنية المستند. ويُطلق على ذلك اسم شجرة التحليل أو شجرة البنية النحوية.

على سبيل المثال، يمكن أن يؤدي تحليل التعبير 2 + 3 - 1 إلى عرض هذه الشجرة:

عقدة شجرة التعبير الرياضي
الشكل 5: عقدة شجرة التعبير الحسابي

القواعد اللغوية

يستند التحليل إلى قواعد البنية التي يلتزم بها المستند: اللغة أو التنسيق الذي كتب به. يجب أن يتضمّن كل تنسيق يمكنك تحليله قواعد نحوية محدّدة تتألف من المفردات وقواعد التركيب. ويُعرف هذا النوع من اللغات باسم قواعد نحوية غير مستندة إلى السياق. ولا تندرج اللغات البشرية ضمن هذا النوع من اللغات، وبالتالي لا يمكن تحليلها باستخدام تقنيات التحليل التقليدية.

مجموعة المحلّل اللغوي - أداة تحليل البنية

يمكن تقسيم التحليل إلى عمليتين فرعيتين: التحليل المعجمي والتحليل النحوي.

التحليل اللفظي هو عملية تقسيم الإدخال إلى وحدات. الرموز هي مفردات اللغة: مجموعة من الوحدات الأساسية الصالحة. وستتألف من جميع الكلمات الواردة في القاموس الخاص بهذه اللغة.

تحليل البنية هو تطبيق قواعد بنية اللغة.

عادةً ما تقسم برامج التحليل العمل بين مكوّنين: أداة تحليل البنية (يُشار إليها أحيانًا باسم أداة تقسيم السلسلة إلى وحدات) المسؤولة عن تقسيم الإدخال إلى وحدات صالحة، وأداة التحليل المسؤولة عن إنشاء شجرة التحليل من خلال تحليل بنية المستند وفقًا لقواعد بنية اللغة.

يعرف أداة تحليل البنية كيفية إزالة الأحرف غير ذات الصلة، مثل المسافات البيضاء وفواصل الأسطر.

من المستند المصدر إلى أشجار التحليل
الشكل 6: من المستند المصدر إلى أشجار التحليل

عملية التحليل تكرارية. سيطلب المُحلِّل عادةً من أداة تحليل البنية رمزًا مميزًا جديدًا وسيحاول مطابقة الرمز المميّز مع إحدى قواعد البنية. في حال تطابق إحدى القواعد، ستتم إضافة عقدة تشير إلى الرمز المميّز إلى شجرة التحليل وسيطلب منك المُحلِّل رمزًا مميّزًا آخر.

في حال عدم تطابق أي قاعدة، سيخزِّن المحلِّل الرمز المميّز داخليًا، وسيستمر في طلب الرموز المميّزة إلى أن يتم العثور على قاعدة تتطابق مع جميع الرموز المميّزة المخزّنة داخليًا. في حال عدم العثور على أي قاعدة، سيُنشئ المُحلِّل استثناءً. وهذا يعني أنّ المستند غير صالح وكان يتضمّن أخطاء في البنية.

ترجمة

في كثير من الحالات، لا يكون شجرة التحليل هي المنتج النهائي. غالبًا ما يتم استخدام التحليل في الترجمة: تحويل مستند الإدخال إلى تنسيق آخر. ومن الأمثلة على ذلك عملية التجميع. إنّ المُجمِّع الذي يُجمِّع الرمز المصدر إلى رمز آلي يفكّكه أولاً إلى شجرة تحليل ثم يترجم الشجرة إلى مستند رمز آلي.

مسار التحويل البرمجي
الشكل 7: تسلسل عملية التجميع

مثال على التحليل

في الشكل 5، أنشأنا شجرة تحليل من تعبير رياضي. لنحاول تحديد لغة رياضية بسيطة والاطّلاع على عملية التحليل.

البنية:

  1. الوحدات الأساسية لبنية اللغة هي التعبيرات والعبارات والعمليات.
  2. يمكن أن تتضمّن لغتنا أي عدد من التعبيرات.
  3. يتم تعريف التعبير على أنّه "تعبير" متبوعًا بـ "عملية" متبوعة بتعبير آخر.
  4. العملية هي رمز مميز موجب أو رمز مميز سالب.
  5. العبارة هي رمز عدد صحيح أو تعبير.

لنحلّل الإدخال 2 + 3 - 1.

أول سلسلة فرعية تتطابق مع قاعدة هي 2: وفقًا للقاعدة رقم 5، هي عبارة. المطابقة الثانية هي 2 + 3: تتطابق مع القاعدة الثالثة: عبارة متبوعة بعملية متبوعة بعبارة أخرى. ولن يتم إجراء المطابقة التالية إلا في نهاية الإدخال. 2 + 3 - 1 هو تعبير لأنّنا نعلم أنّ 2 + 3 عبارة، لذا لدينا عبارة متبوعة بعملية متبوعة بعبارة أخرى. لن تتطابق 2 + + مع أي قاعدة، وبالتالي فإنّها إدخال غير صالح.

تعريفات رسمية للمفردات والبنية

يتم عادةً التعبير عن المفردات باستخدام التعابير العادية.

على سبيل المثال، سيتم تعريف لغتنا على النحو التالي:

INTEGER: 0|[1-9][0-9]*
PLUS: +
MINUS: -

كما ترى، يتم تعريف الأعداد الصحيحة من خلال تعبير عادي.

يتم عادةً تعريف البنية بتنسيق يُعرف باسم BNF. سيتم تعريف لغتنا على النحو التالي:

expression :=  term  operation  term
operation :=  PLUS | MINUS
term := INTEGER | expression

سبق أن ذكرنا أنّه يمكن لفواصل التحليل العادية تحليل لغة إذا كانت قواعدها النحوية قواعد نحوية غير مرتبطة بالسياق. يمكن تعريف قواعد النحو غير المرتبطة بالسياق ببساطة على أنّها قواعد نحوية يمكن التعبير عنها بالكامل باستخدام بنية BNF. للاطّلاع على تعريف رسمي، يُرجى الاطّلاع على مقالة ويكيبيديا حول القواعد النحوية غير المحدودة بالسياق.

أنواع الأدوات التحليلية

هناك نوعان من برامج التحليل: برامج التحليل من الأعلى إلى الأسفل وبرامج التحليل من الأسفل إلى الأعلى. يمكن تقديم تفسير بسيط مفاده أنّ الأدوات التي تعمل من الأعلى للأسفل تفحص البنية العالية المستوى لبنية الجملة وتحاول العثور على مطابقة للقاعدة. تبدأ برامج التحليل من الأسفل إلى الأعلى بالنص وتحوّله تدريجيًا إلى قواعد النحو، بدءًا من القواعد ذات المستوى المنخفض إلى أن يتم استيفاء القواعد ذات المستوى العالي.

لنرى كيف سيحلّل نوعا المُحلِّلَين مثالنا.

سيبدأ المُحلِّل من الأعلى للأسفل من القاعدة ذات المستوى الأعلى: سيحدِّد 2 + 3 كتعبير. سيحدّد بعد ذلك 2 + 3 - 1 كتعبير (تتطوّر عملية تحديد التعبير، وتتطابق مع القواعد الأخرى، ولكن نقطة البداية هي قاعدة المستوى الأعلى).

سيفحص المُحلِّل من الأسفل إلى الأعلى الإدخال إلى أن تتم مطابقة قاعدة. وسيتم بعد ذلك استبدال الإدخال المطابق بالقاعدة. سيستمر ذلك إلى أن تنتهي عملية الإدخال. يتم وضع التعبير الذي تمت مطابقته جزئيًا في حزمة المُحلِّل.

تكديس الإدخال
2 + 3 - 1
عبارة 3 + 1 -
عملية العبارة 3 - 1
تعبير - 1
عملية التعبير 1
تعبير -

يُعرف هذا النوع من التحليل من الأسفل إلى الأعلى باسم التحليل من خلال خفض الترتيب، لأنّه يتم خفض الإدخال إلى اليمين (تخيّل مؤشرًا يشير أولاً إلى بداية الإدخال وينتقل إلى اليمين) ويتم خفضه تدريجيًا إلى قواعد النحو.

إنشاء برامج تحليل تلقائيًا

هناك أدوات يمكنها إنشاء أداة تحليل. ويمكنك تزويدها بقواعد لغتك، أي مفرداتها وقواعد النحو، وتنشئ هذه الأدوات معرِّفًا نحويًا صالحًا. يتطلّب إنشاء محلِّل فهمًا عميقًا للتحليل، وليس من السهل إنشاء محلِّل محسّن يدويًا، لذا يمكن أن تكون أدوات إنشاء المحلِّلين مفيدة جدًا.

يستخدم WebKit أداتَي إنشاء معروفتَين للمحلِّل: Flex لإنشاء أداة تحليل البنية وBison لإنشاء محلِّل (قد تظهر لك باسمَي Lex وYacc). إدخال Flex هو ملف يحتوي على تعريفات التعبيرات العادية للرموز المميّزة. تتمثل مدخلات Bison في قواعد بنية اللغة بتنسيق BNF.

محلّل HTML

وظيفة محلِّل HTML هي تحليل ترميز HTML إلى شجرة تحليل.

قواعد HTML

يتم تحديد مفردات HTML وبنيتها في المواصفات التي أنشأتها مؤسسة W3C.

كما رأينا في مقدّمة التحليل، يمكن تعريف بنية القواعد النحوية رسميًا باستخدام تنسيقات مثل BNF.

لا تنطبق جميع مواضيع التحليل التقليدية على HTML (لم أذكرها للمتعة فقط، بل سيتم استخدامها في تحليل CSS وJavaScript). لا يمكن تعريف HTML بسهولة باستخدام قواعد نحوية خالية من السياق التي تحتاج إليها أدوات التحليل.

هناك تنسيق رسمي لتعريف HTML، وهو DTD (تعريف نوع المستند)، ولكنّه ليس قواعد نحوية خالية من السياق.

قد يبدو هذا الأمر غريبًا للوهلة الأولى، لأنّ HTML قريب من XML. هناك الكثير من برامج تحليل ملفات XML المتاحة. هناك اختلاف في تنسيق XML عن HTML، وهو XHTML، فما هو الفرق الكبير بينهما؟

والفرق هو أنّ نهج HTML أكثر "تسامحًا": فهو يتيح لك حذف علامات معيّنة (تُضاف بعد ذلك بشكل ضمني)، أو حذف علامات البداية أو النهاية في بعض الأحيان، وما إلى ذلك. بشكل عام، يُعدّ هذا التنسيق "لينًا"، على عكس تنسيق XML الجامد والمتطلّب.

تُحدث هذه التفاصيل الصغيرة فرقًا كبيرًا. من ناحية أخرى، هذا هو السبب الرئيسي لانتشار لغة HTML بشكل كبير: فهي تتجاهل الأخطاء وتُسهّل حياة مؤلف الويب. من ناحية أخرى، يجعل ذلك من الصعب كتابة قواعد نحوية رسمية. باختصار، لا يمكن تحليل HTML بسهولة باستخدام أدوات التحليل التقليدية، لأنّ قواعده النحوية ليست خالية من السياق. لا يمكن لأدوات تحليل XML تحليل صفحات HTML.

DTD في HTML

تعريف HTML بتنسيق DTD يُستخدَم هذا التنسيق لتحديد لغات عائلة SGML. يحتوي التنسيق على تعريفات لجميع العناصر المسموح بها وسمات هذه العناصر وترتيبها الهرمي. كما رأينا سابقًا، لا يشكّل DTD في HTML بنية نحوية خالية من السياق.

هناك بعض الصيغ المختلفة لـ DTD. يمتثل الوضع الصارم للمواصفات فقط، ولكن تحتوي الأوضاع الأخرى على علامات متوافق معها كانت تستخدمها المتصفّحات في السابق. ويهدف ذلك إلى التوافق مع الإصدارات السابقة من المحتوى. يمكنك العثور على DTD الصارم الحالي على الرابط التالي: www.w3.org/TR/html4/strict.dtd

نموذج العناصر في المستند (DOM)

شجرة الإخراج (المعروفة باسم "شجرة التحليل") هي شجرة لعناصر DOM وعقد السمات. اختصار DOM يشير إلى نموذج تمثيل المستندات. وهو تمثيل الكائن لمستند HTML وواجهة عناصر HTML للعالم الخارجي، مثل JavaScript.

جذر الشجرة هو عنصر المستند.

ترتبط عناصر DOM بعناصر الترميز بشكل مباشر تقريبًا. على سبيل المثال:

<html>
  <body>
    <p>
      Hello World
    </p>
    <div> <img src="example.png"/></div>
  </body>
</html>

سيتم ترجمة هذا الترميز إلى شجرة نموذج DOM التالية:

شجرة نموذج العناصر في المستند لنموذج الترميز
الشكل 8: شجرة نموذج عناصر المستند لمثال الترميز

مثل HTML، تحدّد مؤسسة W3C لغة DOM. يُرجى الاطّلاع على www.w3.org/DOM/DOMTR. وهي مواصفة عامة لمعالجة المستندات. تصف وحدة معيّنة عناصر معيّنة في HTML. يمكن العثور على تعريفات HTML هنا: www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/idl-definitions.html.

عندما أقول أنّ الشجرة تحتوي على عقد DOM، أقصد أنّ الشجرة تم إنشاؤها من عناصر تنفِّذ إحدى واجهات DOM. تستخدم المتصفّحات عمليات تنفيذ محدّدة لها سمات أخرى يستخدمها المتصفّح داخليًا.

خوارزمية التحليل

كما رأينا في الأقسام السابقة، لا يمكن تحليل صفحات HTML باستخدام برامج التحليل العادية من الأعلى إلى الأسفل أو من الأسفل إلى الأعلى.

في ما يلي الأسباب:

  1. طبيعة اللغة المرنة
  2. حقيقة أنّ المتصفّحات تتضمّن سعة تقليدية للخطأ لتتوافق مع الحالات المعروفة لصفحات HTML غير الصالحة
  3. عملية التحليل قابلة لإعادة الدخول. بالنسبة إلى اللغات الأخرى، لا يتغيّر المصدر أثناء التحليل، ولكن في HTML، يمكن للرمز الديناميكي (مثل عناصر النصوص البرمجية التي تحتوي على طلبات document.write()) إضافة وحدات ترميز إضافية، لذا تعدّل عملية التحليل الإدخال فعليًا.

لا يمكن استخدام تقنيات التحليل العادية، لذا تنشئ المتصفّحات أدوات تحليل مخصّصة لتحليل HTML.

يتم وصف خوارزمية التحليل بالتفصيل في مواصفات HTML5. تتألف الخوارزمية من مرحلتين: إنشاء الرموز وإنشاء الشجرة.

التجزئة هي التحليل المعجمي، أي تحليل الإدخال إلى وحدات ترميز. تشمل الرموز المميّزة في HTML علامات البداية والنهاية وأسماء السمات وقيمها.

يتعرّف أداة تقسيم السلسلة إلى كلمات على الرمز المميّز ويقدّمه إلى أداة إنشاء الشجرة ويستهلك الحرف التالي للتعرّف على الرمز المميّز التالي، وهكذا إلى نهاية الإدخال.

مسار تحليل HTML (مأخوذ من مواصفات HTML5)
الشكل 9: عملية تحليل HTML (مأخوذة من مواصفات HTML5)

خوارزمية تقسيم المحتوى إلى رموز مميّزة

الناتج الذي تقدّمه الخوارزمية هو رمز مميّز بتنسيق HTML. يتم التعبير عن الخوارزمية على أنّها آلة حالات. تستهلك كل حالة حرفًا واحدًا أو أكثر من بث الإدخال وتُعدّل الحالة التالية وفقًا لهذه الأحرف. ويتأثر القرار بحالة تقسيم المحتوى إلى وحدات حاليًا وحالة إنشاء الشجرة. وهذا يعني أنّ الحرف المستهلك نفسه سيؤدي إلى نتائج مختلفة للحالة التالية الصحيحة، استنادًا إلى الحالة الحالية. إنّ الخوارزمية معقّدة جدًا ولا يمكن وصفها بالكامل، لذا لنلقِ نظرة على مثال بسيط يساعدنا في فهم المبدأ.

مثال أساسي: تقسيم رمز HTML التالي إلى وحدات:

<html>
  <body>
    Hello world
  </body>
</html>

الحالة الأولية هي "حالة البيانات". عند العثور على الحرف <، يتم تغيير الحالة إلى "حالة فتح العلامة". يؤدي استخدام الحرف a-z إلى إنشاء "رمز بدء العلامة"، ويتم تغيير الحالة إلى "حالة اسم العلامة". نبقى في هذه الحالة إلى أن يتم استخدام الحرف >. تتم إضافة كل حرف إلى اسم الرمز المميّز الجديد. في حالتنا، الرمز المميّز الذي تم إنشاؤه هو رمز html.

عند الوصول إلى علامة >، يتم بث الرمز المميّز الحالي وتعود الحالة إلى "حالة البيانات". سيتم التعامل مع علامة <body> بالخطوات نفسها. تمّ حتى الآن عرض علامتَي html وbody. لقد عدنا الآن إلى "حالة البيانات". سيؤدي استخدام الحرف H من Hello world إلى إنشاء رمز تعبيري للحرف وإصداره، ويستمر ذلك إلى أن يتم الوصول إلى < من </body>. سنُنشئ رمزًا مميزًا لكل حرف من Hello world.

لقد عدنا الآن إلى "حالة العلامة المفتوحة". سيؤدي استخدام الإدخال التالي / إلى إنشاء end tag token والانتقال إلى "حالة اسم العلامة". سنبقى في هذه الحالة مرة أخرى إلى أن نصل إلى >.بعد ذلك، سيتمّ إصدار رمز العلامة الجديد وسنعود إلى "حالة البيانات". سيتم التعامل مع الإدخال </html> كما في الحالة السابقة.

تقسيم مثال الإدخال إلى وحدات
الشكل 10: تقسيم مثال الإدخال إلى وحدات ترميز

خوارزمية إنشاء الشجرة

عند إنشاء المُحلِّل، يتم إنشاء عنصر المستند. خلال مرحلة إنشاء الشجرة، سيتم تعديل شجرة نموذج DOM التي تحتوي على المستند في جذرها وسيتمّ إضافة عناصر إليها. ستتم معالجة كل عقدة يُنشئها أداة تقسيم الكلمات بواسطة أداة إنشاء الشجرة. بالنسبة إلى كل رمز مميّز، تحدّد المواصفة عنصر نموذج عناصر المستند (DOM) ذي الصلة به والذي سيتم إنشاؤه لهذا الرمز المميّز. تتم إضافة العنصر إلى شجرة نموذج عناصر المستند (DOM) وكذلك إلى حزمة العناصر المفتوحة. تُستخدَم هذه الحزمة لتصحيح عدم تطابق التداخل والعلامات غير المغلقة. وتُعرف الخوارزمية أيضًا باسم آلة الحالات. تُعرف الحالات باسم "أوضاع الإدراج".

لنطّلِع على عملية إنشاء الشجرة لمثال الإدخال التالي:

<html>
  <body>
    Hello world
  </body>
</html>

إنّ الإدخال في مرحلة إنشاء الشجرة هو تسلسل من الرموز المميزة من مرحلة إنشاء الرموز المميزة. الوضع الأول هو "الوضع الأوّلي". سيؤدي تلقّي الرمز المميّز "html" إلى الانتقال إلى وضع "قبل html" وإعادة معالجة الرمز المميّز في هذا الوضع. سيؤدي ذلك إلى إنشاء عنصر HTMLHtmlElement، الذي سيتم إلحاقه بكائن المستند الجذر.

سيتم تغيير الحالة إلى "قبل العنوان". بعد ذلك، يتم استلام الرمز المميّز "body". سيتم إنشاء عنصر HTMLHeadElement بشكل ضمني على الرغم من عدم توفّر رمز مميز "head"، وسيتمّت إضافته إلى الشجرة.

ننتقل الآن إلى وضع "في العنوان" ثم إلى وضع "بعد العنوان". تتم إعادة معالجة الرمز المميّز للنص الأساسي، ويتم إنشاء عنصر HTMLBodyElement وإدراجه، ويتم نقل الوضع إلى "in body".

تم الآن استلام الرموز المميّزة للحروف في سلسلة "مرحبًا بالجميع". سيؤدي الحرف الأول إلى إنشاء عقدة "نص" وإدراجها، وسيتم إلحاق الأحرف الأخرى بهذه العقدة.

سيؤدي استلام الرمز المميّز لنهاية النص إلى نقل البيانات إلى وضع "بعد النص". سنتلقّى الآن علامة نهاية html التي ستنقلنا إلى وضع "بعد body". سيؤدي تلقّي رمز مميز لنهاية الملف إلى إنهاء عملية التحليل.

إنشاء شجرة لمثال على ملف HTML
الشكل 11: إنشاء شجرة لمثال على ملف HTML

الإجراءات عند انتهاء التحليل

في هذه المرحلة، سيضع المتصفّح علامة على المستند بأنّه تفاعلي وسيبدأ في تحليل النصوص البرمجية التي تكون في الوضع "المؤجّل": تلك التي يجب تنفيذها بعد تحليل المستند. سيتم بعد ذلك ضبط حالة المستند على "مكتمل" وسيتم تنشيط حدث "تحميل".

يمكنك الاطّلاع على الخوارزميات الكاملة لتجزئة المحتوى وإنشاء الشجرة في مواصفات HTML5.

مدى التسامح مع الأخطاء في المتصفّحات

لا تظهر لك أبدًا رسالة الخطأ "البنية غير صالحة" في صفحة HTML. تعمل المتصفّحات على حلّ أي محتوى غير صالح ومواصلة العمل.

خذ رمز HTML هذا على سبيل المثال:

<html>
  <mytag>
  </mytag>
  <div>
  <p>
  </div>
    Really lousy HTML
  </p>
</html>

من المؤكد أنّني انتهكت حوالي مليون قاعدة ("mytag" ليست علامة عادية، وتداخل عناصر "p" و"div" بشكل خاطئ وغير ذلك)، ولكن لا يزال المتصفّح يعرضها بشكل صحيح ولا يُبلغ عن أي مشكلة. وبالتالي، فإنّ الكثير من رموز التحليل تعمل على تصحيح أخطاء مؤلفي HTML.

إنّ معالجة الأخطاء متّسقة تمامًا في المتصفّحات، ولكن من المدهش أنّها لم تكن جزءًا من مواصفات HTML. مثل أزرار وضع الإشارات المرجعية والرجوع/التقديم، هذا زر تم تطويره في المتصفّحات على مدار السنوات. هناك بنى HTML معروفة غير صالحة تتكرّر على العديد من المواقع الإلكترونية، ويحاول المتصفّحات إصلاحها بطريقة متوافقة مع المتصفّحات الأخرى.

وتحدّد مواصفات HTML5 بعض هذه المتطلبات. (يلخِّص WebKit ذلك بشكل جيد في التعليق في بداية فئة معالج HTML).

يحلّل المُحلِّل الإدخال المُقسَّم إلى وحدات في المستند، ما يؤدّي إلى إنشاء شجرة المستند. إذا كان المستند منظَّمًا بشكل جيد، يكون تحليله بسيطًا.

علينا التعامل مع العديد من ملفات HTML غير المنسَّقة بشكل جيد، لذا يجب أن يكون محلل النحو متسامحًا مع الأخطاء.

علينا الانتباه إلى حالات الخطأ التالية على الأقل:

  1. العنصر الذي تتم إضافته محظور صراحةً داخل بعض العلامات الخارجية. في هذه الحالة، علينا إغلاق جميع العلامات حتى العلامة التي تحظر العنصر، ثم إضافته بعد ذلك.
  2. لا يُسمح لنا بإضافة العنصر مباشرةً. من المحتمل أنّ الشخص الذي كتب المستند نسي إدراج علامة بين العلامتَين (أو أنّ العلامة بين العلامتَين اختيارية). قد يحدث ذلك مع العلامات التالية: HTML HEAD BODY TBODY TR TD LI (هل نسيت أي علامة؟).
  3. نريد إضافة عنصر مربّع داخل عنصر مضمّن. أغلِق جميع العناصر المضمّنة حتى العنصر التالي من النوع "كتلة".
  4. إذا لم يساعد ذلك، أغلِق العناصر إلى أن يُسمح لنا بإضافة العنصر أو تجاهل العلامة.

لنطّلِع على بعض أمثلة التسامح مع الأخطاء في WebKit:

</br> بدلاً من <br>

تستخدم بعض المواقع الإلكترونية </br> بدلاً من <br>. لكي يكون متوافقًا مع IE وFirefox، يتعامل WebKit مع هذا العنصر على أنّه <br>.

الرمز:

if (t->isCloseTag(brTag) && m_document->inCompatMode()) {
     reportError(MalformedBRError);
     t->beginTag = true;
}

يُرجى العلم أنّ معالجة الأخطاء داخلية، ولن يتم عرضها للمستخدم.

جدول غير مرغوب فيه

الجدول الضال هو جدول داخل جدول آخر، ولكن ليس داخل خلية جدول.

على سبيل المثال:

<table>
  <table>
    <tr><td>inner table</td></tr>
  </table>
  <tr><td>outer table</td></tr>
</table>

سيغيّر WebKit التدرّج الهرمي إلى جدولَين متشابهَين:

<table>
  <tr><td>outer table</td></tr>
</table>
<table>
  <tr><td>inner table</td></tr>
</table>

الرمز:

if (m_inStrayTableContent && localName == tableTag)
        popBlock(tableTag);

يستخدم WebKit حِزمة لمحتوى العنصر الحالي: سيُخرج الجدول الداخلي من حِزمة الجدول الخارجي. ستصبح الجداول الآن أخوة.

عناصر النماذج المُدمجة

في حال وضع المستخدم نموذجًا داخل نموذج آخر، يتم تجاهل النموذج الثاني.

الرمز:

if (!m_currentFormElement) {
        m_currentFormElement = new HTMLFormElement(formTag,    m_document);
}

تسلسل هرمي للعلامات عميق جدًا

يوضّح التعليق ذلك بوضوح.

bool HTMLParser::allowNestedRedundantTag(const AtomicString& tagName)
{

unsigned i = 0;
for (HTMLStackElem* curr = m_blockStack;
         i < cMaxRedundantTagDepth && curr && curr->tagName == tagName;
     curr = curr->next, i++) { }
return i != cMaxRedundantTagDepth;
}

علامات نهاية html أو نص غير صحيحة

مرة أخرى، يوضّح التعليق نفسه.

if (t->tagName == htmlTag || t->tagName == bodyTag )
        return;

لذا، يجب على مؤلفي الويب الانتباه إلى كتابة رمز HTML صحيح، ما لم يريدوا أن يظهروا كمثال في مقتطف رمز WebKit للتسامح مع الأخطاء.

تحليل CSS

هل تذكر مفاهيم التحليل في المقدمة؟ على عكس HTML، لغة CSS هي قواعد نحوية لا تعتمد على السياق ويمكن تحليلها باستخدام أنواع التحليلات الموضّحة في المقدّمة. في الواقع، تحدّد مواصفات CSS قواعد النحو والمفردات في CSS.

لنلقِ نظرة على بعض الأمثلة:

يتم تعريف القواعد اللغوية (المفردات) من خلال التعبيرات العادية لكل رمز:

comment   \/\*[^*]*\*+([^/*][^*]*\*+)*\/
num       [0-9]+|[0-9]*"."[0-9]+
nonascii  [\200-\377]
nmstart   [_a-z]|{nonascii}|{escape}
nmchar    [_a-z0-9-]|{nonascii}|{escape}
name      {nmchar}+
ident     {nmstart}{nmchar}*

"ident" هي اختصار لكلمة معرّف، مثل اسم فئة. "name" هو رقم تعريف عنصر (يُشار إليه بالرمز "#").

يتم وصف قواعد البنية في BNF.

ruleset
  : selector [ ',' S* selector ]*
    '{' S* declaration [ ';' S* declaration ]* '}' S*
  ;
selector
  : simple_selector [ combinator selector | S+ [ combinator? selector ]? ]?
  ;
simple_selector
  : element_name [ HASH | class | attrib | pseudo ]*
  | [ HASH | class | attrib | pseudo ]+
  ;
class
  : '.' IDENT
  ;
element_name
  : IDENT | '*'
  ;
attrib
  : '[' S* IDENT S* [ [ '=' | INCLUDES | DASHMATCH ] S*
    [ IDENT | STRING ] S* ] ']'
  ;
pseudo
  : ':' [ IDENT | FUNCTION S* [IDENT S*] ')' ]
  ;

الشرح:

قاعدة القواعد هي هذه البنية:

div.error, a.error {
  color:red;
  font-weight:bold;
}

div.error وa.error هما أداتا اختيار. يحتوي الجزء داخل الأقواس المتعرجة على القواعد التي تطبّقها مجموعة القواعد هذه. يتم تحديد هذه البنية رسميًا في هذا التعريف:

ruleset
  : selector [ ',' S* selector ]*
    '{' S* declaration [ ';' S* declaration ]* '}' S*
  ;

وهذا يعني أنّ قاعدة القواعد هي أداة اختيار أو عدد اختياري من أدوات الاختيار مفصولة بفواصل ومسافات (يرمز S إلى المسافة البيضاء). تحتوي مجموعة القواعد على قوسين معقوفين وداخلهما بيان أو اختياريًا عدد من البيانات مفصولة بفاصلة منقوطة. سيتم تعريف "البيان" و "أداة الاختيار" في تعريفات BNF التالية.

محلل لغة CSS في WebKit

يستخدم WebKit أدات إنشاء برامج تحليل Flex وBison لإنشاء برامج تحليل تلقائيًا من ملفات قواعد CSS. كما تذكّر من مقدمة المُحلِّل، ينشئ Bison مُحلِّلًا للتحويل والاختزال من الأسفل إلى الأعلى. يستخدم Firefox منظِّمًا نحويًا من الأعلى إلى الأسفل مكتوبًا يدويًا. وفي كلتا الحالتَين، يتم تحليل كل ملف CSS إلى عنصر StyleSheet. يحتوي كل عنصر على قواعد CSS. تحتوي عناصر قواعد CSS على عناصر محددات وعناصر تعريفات وعناصر أخرى تتوافق مع قواعد لغة CSS النحوية.

تحليل صفحات الأنماط المتتالية (CSS)
الشكل 12: تحليل CSS

معالجة طلب النصوص البرمجية وأوراق الأنماط

النصوص البرمجية

نموذج الويب متزامن. يتوقّع المؤلفون أن يتم تحليل النصوص البرمجية وتنفيذها على الفور عندما يصل المحلّل إلى علامة <script>. ويتم إيقاف تحليل المستند إلى أن يتم تنفيذ النص البرمجي. إذا كان النص البرمجي خارجيًا، يجب أولاً جلب المورد من الشبكة، ويتم ذلك أيضًا بشكل متزامن، وتتوقّف عملية التحليل إلى أن يتم جلب المورد. وقد كان هذا النموذج مستخدمًا لعدة سنوات، وهو محدّد أيضًا في مواصفات HTML4 و5. يمكن للمؤلفين إضافة السمة "defer" إلى نص برمجي، وفي هذه الحالة لن يؤدي ذلك إلى إيقاف تحليل المستند وسيتم تنفيذه بعد تحليل المستند. تضيف لغة HTML5 خيارًا لتمييز النص البرمجي على أنّه غير متزامن حتى يتم تحليله وتنفيذه من خلال سلسلة محادثات مختلفة.

التحليل التوقّعي

يُجري كلّ من WebKit وFirefox هذا التحسين. أثناء تنفيذ النصوص البرمجية، تُحلِّل سلسلة محادثات أخرى بقية المستند وتتعرّف على الموارد الأخرى التي يجب تحميلها من الشبكة وتحملها. بهذه الطريقة، يمكن تحميل الموارد على اتصالات متوازية وتحسين السرعة الإجمالية. ملاحظة: لا يفكّك المُحلِّل التوقّعي سوى الإشارات إلى الموارد الخارجية، مثل النصوص البرمجية الخارجية وأوراق الأنماط والصور، ولا يعدّل شجرة DOM، بل يترك ذلك للمُحلِّل الرئيسي.

أوراق الأنماط

من ناحية أخرى، تتّبع جداول الأنماط نموذجًا مختلفًا. من الناحية النظرية، يبدو أنّه ما مِن سبب للانتظار إلى أن يتم تحميل أوراق الأنماط وإيقاف تحليل المستند، لأنّ أوراق الأنماط لا تغيّر شجرة DOM. ومع ذلك، هناك مشكلة في النصوص البرمجية التي تطلب معلومات النمط أثناء مرحلة تحليل المستند. إذا لم يتم تحميل النمط وتحليله بعد، سيحصل النص البرمجي على إجابات خاطئة، ويبدو أنّ ذلك سبّب الكثير من المشاكل. يبدو أنّه حالة نادرة، ولكنّها شائعة جدًا. يحظر Firefox جميع النصوص البرمجية عندما يكون هناك جدول أسلوب لا يزال يتم تحميله وتحليله. لا يحظر WebKit النصوص البرمجية إلا عند محاولة الوصول إلى خصائص نمط معيّنة قد تتأثر بجداول الأنماط غير المحمَّلة.

إنشاء شجرة العرض

أثناء إنشاء شجرة نموذج DOM، ينشئ المتصفّح شجرة أخرى، وهي شجرة العرض. تتضمّن هذه الشجرة العناصر المرئية بالترتيب الذي ستظهر به. وهو التمثيل المرئي للمستند. الغرض من هذه الشجرة هو السماح برسم المحتوى بالترتيب الصحيح.

يُطلق Firefox على العناصر في شجرة العرض اسم "اللقطات". يستخدم WebKit مصطلح "العارض" أو "كائن التقديم".

يعرف العارض كيفية ترتيب نفسه وعناصره الفرعية ورسمها.

تحتوي فئة RenderObject في WebKit، وهي الفئة الأساسية لأدوات التحويل، على التعريف التالي:

class RenderObject{
  virtual void layout();
  virtual void paint(PaintInfo);
  virtual void rect repaintRect();
  Node* node;  //the DOM node
  RenderStyle* style;  // the computed style
  RenderLayer* containgLayer; //the containing z-index layer
}

يمثّل كلّ مُنشئ رسومات منطقة مستطيلة تتوافق عادةً مع مربّع CSS للعقدة، كما هو موضّح في مواصفات CSS2. ويتضمّن معلومات هندسية مثل العرض والارتفاع والموضع.

يتأثّر نوع المربّع بقيمة "display" لسمة style ذات الصلة بالعقدة (راجِع قسم احتساب التنسيق). في ما يلي رمز WebKit لتحديد نوع أداة العرض التي يجب إنشاؤها لعقدة DOM، وفقًا لسمة العرض:

RenderObject* RenderObject::createObject(Node* node, RenderStyle* style)
{
    Document* doc = node->document();
    RenderArena* arena = doc->renderArena();
    ...
    RenderObject* o = 0;

    switch (style->display()) {
        case NONE:
            break;
        case INLINE:
            o = new (arena) RenderInline(node);
            break;
        case BLOCK:
            o = new (arena) RenderBlock(node);
            break;
        case INLINE_BLOCK:
            o = new (arena) RenderBlock(node);
            break;
        case LIST_ITEM:
            o = new (arena) RenderListItem(node);
            break;
       ...
    }

    return o;
}

يتم أيضًا مراعاة نوع العنصر: على سبيل المثال، تحتوي عناصر التحكّم في النماذج والجداول على إطارات خاصة.

في WebKit، إذا أراد عنصر إنشاء أداة عرض خاصة، سيتم إلغاء طريقة createRenderer(). تشير عناصر العرض إلى عناصر الأنماط التي تحتوي على معلومات غير هندسية.

علاقة شجرة العرض بشجرة نموذج العناصر في المستند

تتطابق عناصر العرض مع عناصر نموذج DOM، ولكن العلاقة ليست بين عنصرَين فقط. لن يتم إدراج عناصر نموذج DOM غير المرئية في شجرة العرض. ومن الأمثلة على ذلك عنصر "head". ولن تظهر أيضًا في الشجرة العناصر التي تم ضبط قيمة العرض لها على "none" (في حين ستظهر في الشجرة العناصر التي تكون مستوى ظهورها "مخفي").

هناك عناصر DOM تتوافق مع العديد من العناصر المرئية. وعادةً ما تكون هذه العناصر ذات بنية معقّدة لا يمكن وصفها باستخدام مستطيل واحد. على سبيل المثال، يحتوي العنصر select على ثلاثة عناصر عرض: واحد لمنطقة العرض، وواحد لمربّع القائمة المنسدلة، وواحد للزر. بالإضافة إلى ذلك، عند تقسيم النص إلى أسطر متعددة لأنّ العرض غير كافٍ لسطر واحد، ستتم إضافة الأسطر الجديدة كمعدّلات عرض إضافية.

ومن الأمثلة الأخرى على أدوات التحويل المتعددة علامات HTML غير الصالحة. وفقًا لمواصفات CSS، يجب أن يحتوي العنصر المضمّن على عناصر كتلة فقط أو عناصر مضمّنة فقط. في حال المحتوى المختلط، سيتم إنشاء عناصر عرض كتل مجهولة الهوية لتغليف العناصر المضمّنة.

تتطابق بعض عناصر العرض مع عقدة نموذج عناصر في المستند، ولكن ليس في المكان نفسه في الشجرة. تكون العناصر العائمة والعناصر ذات الموضع المطلق خارج التدفق، ويتم وضعها في جزء مختلف من الشجرة، ويتم ربطها بالإطار الفعلي. إطار نائب في المكان الذي كان من المفترض أن يظهر فيه

شجرة العرض وشجرة نموذج العناصر في المستند المقابلة
الشكل 13: شجرة العرض وشجرة نموذج DOM المقابلة لها "مساحة العرض" هي العنصر الأساسي الذي يحتوي على المحتوى. في WebKit، سيكون الكائن "RenderView"

خطوات إنشاء الشجرة

في Firefox، يتم تسجيل العرض التقديمي كمستمع لتعديلات DOM. يفوِّض العرض التقديمي إنشاء الإطار إلى FrameConstructor ويحلّ المُنشئ النمط (راجِع حساب النمط) وينشئ إطارًا.

في WebKit، تُعرف عملية حلّ النمط وإنشاء أداة عرض باسم "الربط". تحتوي كل عقدة DOM على طريقة "attach". يكون الربط متزامنًا، ويؤدي إدراج العقدة إلى شجرة DOM إلى استدعاء طريقة "الربط" للعقدة الجديدة.

تؤدي معالجة علامتَي html وbody إلى إنشاء جذر شجرة العرض. يتطابق عنصر العرض الجذر مع ما تُطلق عليه مواصفات CSS اسم "الوحدة المُحتوية": وهي الوحدة العلوية التي تحتوي على جميع الوحدات الأخرى. وتكون أبعاده هي إطار العرض: أبعاد منطقة عرض نافذة المتصفح. يُطلق Firefox على هذا العنصر اسم ViewPortFrame ويُطلق WebKit عليه اسم RenderView. هذا هو عنصر العرض الذي يشير إليه المستند. يتم إنشاء بقية الشجرة على شكل إدراج عقد DOM.

اطّلِع على مواصفات CSS2 حول نموذج المعالجة.

احتساب الأنماط

يتطلّب إنشاء شجرة العرض احتساب السمات المرئية لكلّ عنصر عرض. ويتم ذلك من خلال احتساب سمات الأنماط لكل عنصر.

يتضمّن النمط أوراق أنماط من أصول مختلفة وعناصر أنماط مضمّنة وسمات مرئية في HTML (مثل السمة bgcolor)، ويتم تحويل هذه السمات لاحقًا إلى سمات أنماط CSS مطابقة.

تعود أصول جداول الأنماط إلى جداول الأنماط التلقائية للمتصفّح وجداول الأنماط التي يقدّمها مؤلف الصفحة وجداول الأنماط الخاصة بالمستخدم، وهي جداول أنماط يقدّمها مستخدم المتصفّح (تسمح لك المتصفّحات بتحديد أنماطك المفضّلة). في Firefox، على سبيل المثال، يتم ذلك عن طريق وضع جدول أسلوب في مجلد "ملف تعريف Firefox").

تؤدي عملية احتساب الأنماط إلى ظهور بعض الصعوبات:

  1. بيانات الأنماط هي بنية كبيرة جدًا، تحتوي على العديد من سمات الأنماط، ما قد يتسبب في حدوث مشاكل في الذاكرة.
  2. يمكن أن يؤدي العثور على قواعد المطابقة لكل عنصر إلى حدوث مشاكل في الأداء في حال عدم تحسينها. إنّ تصفُّح قائمة القواعد بالكامل لكل عنصر للعثور على المطابقات هو مهمة صعبة. يمكن أن يكون للمُحدّدات بنية معقّدة يمكن أن تؤدي إلى بدء عملية المطابقة على مسار يبدو واعدًا ولكن تبيّن أنّه غير مجدٍ، ويجب تجربة مسار آخر.

    على سبيل المثال، أداة الاختيار المركبة هذه:

    div div div div{
    ...
    }
    

    يعني ذلك أنّ القواعد تنطبق على <div> الذي هو أحد العناصر الفرعية لثلاثة عناصر div. لنفترض أنّك تريد التحقّق مما إذا كانت القاعدة تنطبق على عنصر <div> معيّن. يمكنك اختيار مسار معيّن في التسلسل الهرمي للتحقّق منه. قد تحتاج إلى الانتقال إلى أعلى شجرة العقد لمعرفة أنّ هناك قسمَين فقط من div وأنّ القاعدة لا تنطبق. بعد ذلك، عليك تجربة مسارات أخرى في الشجرة.

  3. يتضمن تطبيق القواعد قواعد متسلسلة معقّدة للغاية تحدّد التسلسل الهرمي للقواعد.

لنلقِ نظرة على كيفية تعامل المتصفّحات مع هذه المشاكل:

مشاركة بيانات الأنماط

تشير عقد WebKit إلى عناصر الأنماط (RenderStyle). يمكن مشاركة هذه العناصر من خلال العقد في بعض الحالات. تكون العقدة هي أخت أو قريبة، ويجب استيفاء الشروط التالية:

  1. يجب أن تكون العناصر في حالة الماوس نفسها (على سبيل المثال، لا يمكن أن يكون أحدهما في حالة hover بينما الآخر ليس كذلك).
  2. يجب ألا يحتوي أيّ من العنصرَين على معرّف.
  3. يجب أن تتطابق أسماء العلامات.
  4. يجب أن تتطابق سمات الفئة
  5. يجب أن تكون مجموعة السمات المرتبطة متطابقة.
  6. يجب أن تتطابق حالات الربط.
  7. يجب أن تتطابق حالات التركيز
  8. يجب ألا يتأثّر أيّ من العنصرَين بأدوات اختيار السمات، حيث يتمّ تعريف التأثّر على أنّه توفّر أيّ مطابقة محدّد تستخدِم أداة اختيار سمة في أيّ موضع ضمن المحدّد على الإطلاق.
  9. يجب ألا تحتوي العناصر على سمة نمط مضمّن.
  10. يجب عدم استخدام أيّ محدّدات أشقاء على الإطلاق. يُجري WebCore تبديلًا عامًا عند العثور على أيّ أداة اختيار لأخوة ويوقف مشاركة الأنماط للمستند بأكمله عند توفّرها. ويشمل ذلك أداة الاختيار + وأدوات الاختيار مثل :first-child و :last-child.

شجرة قواعد Firefox

يحتوي Firefox على شجرتين إضافيتين لتسهيل احتساب الأنماط: شجرة القواعد وشجرة سياق الأنماط. يحتوي WebKit أيضًا على عناصر أنماط، ولكن لا يتم تخزينها في شجرة مثل شجرة سياق الأنماط، وتشير عقدة DOM فقط إلى النمط ذي الصلة.

شجرة سياق بأسلوب Firefox
الشكل 14: شجرة السياق بأسلوب Firefox

تحتوي سياقات الأنماط على قيم نهاية. ويتم احتساب القيم من خلال تطبيق جميع قواعد المطابقة بالترتيب الصحيح وإجراء عمليات تحويل تحوّلها من قيم منطقية إلى قيم ملموسة. على سبيل المثال، إذا كانت القيمة المنطقية هي نسبة مئوية من الشاشة، سيتم احتسابها وتحويلها إلى وحدات مطلقة. إنّ فكرة شجرة القواعد ذكية جدًا. ويتيح ذلك مشاركة هذه القيم بين العقد لتجنُّب احتسابها مرة أخرى. ويؤدي ذلك أيضًا إلى توفير مساحة.

يتم تخزين جميع القواعد المطابقة في شجرة. تكون للعقد السفلية في المسار أولوية أعلى. تحتوي الشجرة على جميع مسارات مطابقات القواعد التي تم العثور عليها. يتم تخزين القواعد بشكلٍ غير فعّال. لا يتم احتساب الشجرة في البداية لكل عقدة، ولكن كلما كان من الضروري احتساب نمط عقدة، تتم إضافة المسارات المحسوبة إلى الشجرة.

والفكرة هي عرض مسارات الشجرة ككلمات في قاموس. لنفترض أنّنا سبق أن احتسبنا شجرة القواعد هذه:

العرض التدرّجي للقاعدة المحسوبة
الشكل 15: العرض التدرّجي للقاعدة المحسوبة

لنفترض أنّنا نحتاج إلى مطابقة قواعد لعنصر آخر في شجرة المحتوى، ونجد أنّ القواعد المطابقة (بالترتيب الصحيح) هي B-E-I. لدينا هذا المسار في الشجرة لأنّنا سبق أن احتسبنا المسار A-B-E-I-L. سيكون لدينا الآن عمل أقل.

لنطّلِع على كيفية توفير الشجرة للوقت والجهد.

التقسيم إلى بنى

تنقسم سياقات الأنماط إلى بنى. تحتوي هذه البنى على معلومات نمط لفئة معيّنة، مثل الحدود أو اللون. تكون جميع السمات في البنية إما مُكتسَبة أو غير مكتسَبة. السمات المكتسَبة هي السمات التي يتم اكتسابها من العنصر الرئيسي ما لم يتم تحديدها من خلال العنصر. تستخدم السمات غير المُكتسَبة (المعروفة باسم سمات "إعادة الضبط") القيم التلقائية في حال عدم تحديدها.

تساعدنا الشجرة من خلال تخزين البنى بأكملها (التي تحتوي على القيم النهائية المحسوبة) في الشجرة. الفكرة هي أنّه إذا لم تقدّم العقدة السفلية تعريفًا لبنية، يمكن استخدام بنية محفوظة مؤقتًا في عقدة أعلى.

احتساب سياقات الأنماط باستخدام شجرة القواعد

عند احتساب سياق النمط لعنصر معيّن، نحسب أولاً مسارًا في شجرة القواعد أو نستخدم مسارًا حاليًا. نبدأ بعد ذلك بتطبيق القواعد في المسار لملء البنى في سياق الأسلوب الجديد. نبدأ من عقدة أسفل المسار، وهي العقدة ذات الأولوية الأعلى (عادةً العنصر المحدّد الأكثر تحديدًا)، وننتقل في الشجرة إلى أن تكتمل البنية. إذا لم تتوفّر مواصفات للبنية في عقدة القاعدة هذه، يمكننا تحسينها بشكل كبير، وذلك من خلال الانتقال إلى أعلى الشجرة إلى أن نعثر على عقدة تحدّدها بالكامل وتشير إليها، ما يشكّل أفضل تحسين، حيث تتم مشاركة البنية بأكملها. ويؤدي ذلك إلى توفير الذاكرة وحساب القيم النهائية.

إذا عثرنا على تعريفات جزئية، ننتقل للأعلى في الشجرة إلى أن يتم ملء البنية.

إذا لم نعثر على أيّ تعريفات لبنية البيانات، سنشير إلى بنية البيانات الرئيسية في شجرة السياق إذا كانت بنية البيانات من النوع "المكتسَب". وفي هذه الحالة، نجحنا أيضًا في مشاركة البنى. إذا كانت بنية إعادة الضبط، سيتم استخدام القيم التلقائية.

إذا كانت العقدة الأكثر تحديدًا تضيف قيمًا، علينا إجراء بعض العمليات الحسابية الإضافية لتحويلها إلى قيم فعلية. بعد ذلك، نخزِّن النتيجة في عقدة الشجرة ليتمكّن الأطفال من استخدامها.

إذا كان للعنصر عنصر شقيق يشير إلى عقدة الشجرة نفسها، يمكن مشاركة سياق النمط بأكمله بينهما.

لنلقِ نظرة على مثال: لنفترض أنّ لدينا رمز HTML التالي:

<html>
  <body>
    <div class="err" id="div1">
      <p>
        this is a <span class="big"> big error </span>
        this is also a
        <span class="big"> very  big  error</span> error
      </p>
    </div>
    <div class="err" id="div2">another error</div>
  </body>
</html>

والقواعد التالية:

div {margin: 5px; color:black}
.err {color:red}
.big {margin-top:3px}
div span {margin-bottom:4px}
#div1 {color:blue}
#div2 {color:green}

لتبسيط الأمور، لنفترض أنّنا نحتاج إلى ملء عنصرَين فقط: بنية اللون وبنية الهامش. لا تحتوي بنية اللون على عنصر واحد إلا: اللون تحتوي بنية الهامش على الجوانب الأربعة.

ستظهر شجرة القواعد الناتجة على النحو التالي (يتم وضع علامة على العقد باسم العقدة: رقم القاعدة التي تشير إليها):

شجرة القواعد
الشكل 16: شجرة القواعد

سيظهر سياق الشجرة على النحو التالي (اسم العقدة: عقدة القاعدة التي تشير إليها):

العرض التدرّجي للسياق
الشكل 17: شجرة السياق

لنفترض أنّنا نفكّر رمز HTML ونصل إلى علامة <div> الثانية. نحتاج إلى إنشاء سياق أسلوب لهذه العقدة وملء هياكل أسلوبها.

سنطابق القواعد وسنجد أنّ قواعد المطابقة للعنصر <div> هي 1 و2 و6. هذا يعني أنّ هناك مسارًا حاليًا في الشجرة يمكن لعنصرنا استخدامه، ونحتاج فقط إلى إضافة عقدة أخرى إليه للقاعدة 6 (العقدة F في شجرة القواعد).

سننشئ سياق نمط ونضعه في شجرة السياق. سيشير سياق النمط الجديد إلى العقدة F في شجرة القواعد.

نحتاج الآن إلى ملء بنية الأنماط. سنبدأ بملء بنية الهامش. بما أنّ عقدة القاعدة الأخيرة (F) لا تُضيف إلى بنية الهامش، يمكننا الانتقال للأعلى في الشجرة إلى أن نعثر على بنية محفوظة مؤقتًا تم احتسابها في عملية إدراج عقدة سابقة واستخدامها. سنجدها في العقدة B، وهي العقدة العلوية التي حدّدت قواعد الهامش.

لدينا تعريف لهيكل اللون، لذا لا يمكننا استخدام بنية محفوظة في ذاكرة التخزين المؤقت. بما أنّ اللون يحتوي على سمة واحدة، لا نحتاج إلى الانتقال إلى أعلى الشجرة لملء السمات الأخرى. سنحسب القيمة النهائية (تحويل السلسلة إلى RGB وما إلى ذلك) وسنخزّن البنية المحسوبة في هذه العقدة.

إنّ العمل على العنصر <span> الثاني أسهل. سنطابق القواعد ونصل إلى استنتاج بأنّها تشير إلى القاعدة "ص"، مثل النطاق السابق. بما أنّ لدينا عناصر متسلسلة تشير إلى العقدة نفسها، يمكننا مشاركة سياق النمط بالكامل والإشارة إلى سياق النطاق السابق فقط.

بالنسبة إلى العناصر التي تحتوي على قواعد مكتسَبة من العنصر الرئيسي، يتم تخزينها مؤقتًا في شجرة السياق (يتم اكتساب سمة اللون في الواقع، ولكن يتعامل Firefox معها على أنّها تمّت إعادة ضبطها ويخزّنها مؤقتًا في شجرة القواعد).

على سبيل المثال، إذا أضفنا قواعد للخطوط في فقرة:

p {font-family: Verdana; font size: 10px; font-weight: bold}

بعد ذلك، يمكن أن يكون عنصر الفقرة، وهو عنصر فرعي لعنصر div في شجرة السياق، قد شارك بنية الخط نفسها مع العنصر الرئيسي. يحدث ذلك في حال عدم تحديد أي قواعد للخط في الفقرة.

في WebKit، الذي لا يتضمّن شجرة قواعد، يتمّ عبور البيانات المطابقة أربع مرّات. أولاً، يتم تطبيق الخصائص غير المهمة ذات الأولوية العالية (الخصائص التي يجب تطبيقها أولاً لأنّ غيرها يعتمد عليها، مثل العرض)، ثم الخصائص المهمة ذات الأولوية العالية، ثم الخصائص غير المهمة ذات الأولوية العادية، ثم الخصائص المهمة ذات الأولوية العادية. وهذا يعني أنّه سيتم حلّ المواقع التي تظهر عدة مرات وفقًا لترتيب التسلسل الصحيح. يفوز آخر لاعب.

باختصار، يؤدي مشاركة عناصر الأنماط (بالكامل أو بعض البنى داخلها) إلى حلّ المشكلةَين 1 و3. تساعد أيضًا شجرة قواعد Firefox في تطبيق السمات بالترتيب الصحيح.

التلاعب بالقواعد لإجراء مطابقة سهلة

هناك عدة مصادر لقواعد الأنماط:

  1. قواعد CSS، سواء في أوراق الأنماط الخارجية أو في عناصر الأنماط css p {color: blue}
  2. سمات الأنماط المضمّنة، مثل html <p style="color: blue" />
  3. السمات المرئية لـ HTML (التي يتم ربطها بقواعد الأنماط ذات الصلة) html <p bgcolor="blue" /> يمكن مطابقة السمتَين الأخيرتَين بسهولة مع العنصر لأنّه يملك سمات الأنماط ويمكن ربط سمات HTML باستخدام العنصر كمفتاح.

كما ذكرنا سابقًا في المشكلة رقم 2، يمكن أن يكون مطابقة قواعد CSS أكثر تعقيدًا. لحلّ هذه المشكلة، يتم التلاعب بالقواعد لتسهيل الوصول.

بعد تحليل جدول الأنماط، تتم إضافة القواعد إلى إحدى خرائط التجزئة المتعددة، وفقًا لعنصر الاختيار. تتوفّر خرائط حسب المعرّف واسم الفئة واسم العلامة وخرائط عامة لأي عناصر لا تندرج ضمن هذه الفئات. إذا كان أداة الاختيار هي معرّف، ستتم إضافة القاعدة إلى خريطة المعرّفات، وإذا كانت فئة، ستتم إضافتها إلى خريطة الفئات، وما إلى ذلك.

تجعل هذه المعالجة مطابقة القواعد أسهل بكثير. ليس من الضروري البحث في كل بيان: يمكننا استخراج القواعد ذات الصلة بعنصر من الخرائط. تؤدي عملية التحسين هذه إلى إزالة أكثر من% 95 من القواعد، بحيث لا يلزم حتى النظر فيها أثناء عملية المطابقة(4.1).

لنطّلِع على قواعد الأنماط التالية على سبيل المثال:

p.error {color: red}
#messageDiv {height: 50px}
div {margin: 5px}

سيتم إدراج القاعدة الأولى في خريطة الفئات. والثاني في خريطة الأرقام التعريفية والثالث في خريطة العلامات.

بالنسبة إلى مقتطف HTML التالي:

<p class="error">an error occurred</p>
<div id=" messageDiv">this is a message</div>

سنحاول أولاً العثور على قواعد للعنصر p. ستحتوي خريطة الفئة على مفتاح "خطأ" يتم العثور على قاعدة "p.error" ضمنه. سيحتوي عنصر div على قواعد ذات صلة في خريطة المعرّفات (المفتاح هو المعرّف) وخريطة العلامات. وبالتالي، فإنّ العمل الوحيد المتبقّي هو معرفة القواعد التي تم استخراجها بواسطة المفاتيح التي تتطابق حقًا.

على سبيل المثال، إذا كانت قاعدة العنصر div هي:

table div {margin: 5px}

وسيظلّ يتم استخراجه من خريطة العلامات، لأنّ المفتاح هو أداة الاختيار الأيمن، ولكنّه لن يتطابق مع عنصر div الذي لا يتضمّن سلفًا للجدول.

يُجري كلٌّ من WebKit وFirefox هذا التلاعب.

ترتيب تسلسلي لأوراق الأنماط

يحتوي عنصر التصميم على خصائص تتوافق مع كل سمة مرئية (جميع سمات CSS ولكن بشكل أكثر عمومية). إذا لم يتم تحديد السمة من خلال أيّ من القواعد المطابقة، يمكن أن يتم اكتساب بعض السمات من خلال عنصر نمط العنصر الرئيسي. تحتوي السمات الأخرى على قيم تلقائية.

تبدأ المشكلة عندما يكون هناك أكثر من تعريف واحد، وهنا يأتي الترتيب التدرّجي لحلّ المشكلة.

يمكن أن يظهر بيان لسمة نمط في عدة جداول أسلوب، وعدة مرات داخل جدول أسلوب. وهذا يعني أنّ ترتيب تطبيق القواعد مهم جدًا. ويُعرف هذا الترتيب باسم "الترتيب التدرّجي". وفقًا لمواصفات CSS2، يكون ترتيب التسلسل على النحو التالي (من الأدنى إلى الأعلى):

  1. بيانات المتصفّح
  2. تعريفات المستخدم العادية
  3. التصريحات العادية للمؤلف
  4. مؤلفات التصريحات المهمة
  5. بيانات المستخدم المهمة

تكون بيانات المتصفّح هي الأقل أهمية، ولا يتجاوز المستخدم المؤلف إلا إذا تم وضع علامة على البيان على أنّه مهم. سيتم ترتيب البيانات التي لها الترتيب نفسه حسب التحديد ثم حسب الترتيب الذي تم تحديدها به. يتم ترجمة السمات المرئية لـ HTML إلى إعلانات CSS مطابقة . ويتم التعامل معها كقواعد مؤلفين ذات أولوية منخفضة.

الدقة

يتم تحديد مدى دقة أداة الاختيار من خلال مواصفات CSS2 على النحو التالي:

  1. يتم احتساب 1 إذا كان البيان الذي ينتمي إليه هو سمة "style" بدلاً من قاعدة تحتوي على أداة اختيار، و0 بخلاف ذلك (= a).
  2. احتساب عدد سمات المعرّفات في أداة الاختيار (= ب)
  3. احتساب عدد السمات والفئات الزائفة الأخرى في أداة الاختيار (= c)
  4. احتساب عدد أسماء العناصر والعناصر الزائفة في المحدّد (= d)

تؤدي تسلسل الأرقام الأربعة a-b-c-d (في نظام رقمي بقاعدة كبيرة) إلى تحديد القيمة المحددة.

يتم تحديد قاعدة الأعداد التي تحتاج إلى استخدامها حسب أكبر عدد لديك في إحدى الفئات.

على سبيل المثال، إذا كان a=14، يمكنك استخدام قاعدة سداسية عشرية. في حال كان a=17، ستحتاج إلى قاعدة رقمية من 17 رقمًا. يمكن أن يحدث الموقف الأخير باستخدام عنصر اختيار مثل هذا: html body div div p… (17 علامة في عنصر الاختيار… من غير المرجّح حدوث ذلك).

إليك بعض الأمثلة:

 *             {}  /* a=0 b=0 c=0 d=0 -> specificity = 0,0,0,0 */
 li            {}  /* a=0 b=0 c=0 d=1 -> specificity = 0,0,0,1 */
 li:first-line {}  /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
 ul li         {}  /* a=0 b=0 c=0 d=2 -> specificity = 0,0,0,2 */
 ul ol+li      {}  /* a=0 b=0 c=0 d=3 -> specificity = 0,0,0,3 */
 h1 + *[rel=up]{}  /* a=0 b=0 c=1 d=1 -> specificity = 0,0,1,1 */
 ul ol li.red  {}  /* a=0 b=0 c=1 d=3 -> specificity = 0,0,1,3 */
 li.red.level  {}  /* a=0 b=0 c=2 d=1 -> specificity = 0,0,2,1 */
 #x34y         {}  /* a=0 b=1 c=0 d=0 -> specificity = 0,1,0,0 */
 style=""          /* a=1 b=0 c=0 d=0 -> specificity = 1,0,0,0 */

ترتيب القواعد

بعد مطابقة القواعد، يتم ترتيبها وفقًا لقواعد التسلسل. يستخدم WebKit ترتيب الفقاعات للقوائم الصغيرة وترتيب الدمج للقوائم الكبيرة. ينفِّذ WebKit الترتيب من خلال إلغاء عامل التشغيل > للقواعد:

static bool operator >(CSSRuleData& r1, CSSRuleData& r2)
{
    int spec1 = r1.selector()->specificity();
    int spec2 = r2.selector()->specificity();
    return (spec1 == spec2) : r1.position() > r2.position() : spec1 > spec2;
}

عملية تدريجية

يستخدم WebKit علامة تشير إلى ما إذا تم تحميل جميع أوراق الأنماط ذات المستوى الأعلى (بما في ذلك @imports). إذا لم يتم تحميل النمط بالكامل عند إرفاقه، يتم استخدام العناصر النائبة ويتم وضع علامة عليها في المستند، وسيتم إعادة احتسابها بعد تحميل جداول الأنماط.

التنسيق

عند إنشاء أداة التقديم وإضافتها إلى الشجرة، لا يكون لها موضع وحجم. ويُطلق على عملية احتساب هذه القيم اسم التنسيق أو إعادة التدفق.

يستخدم HTML نموذج تخطيط مستندًا إلى التدفق، ما يعني أنّه في معظم الأحيان، يمكن حساب الأشكال الهندسية في مرّة واحدة. لا تؤثر العناصر اللاحقة "في التدفق" عادةً في شكل العناصر الأقدم "في التدفق"، لذا يمكن أن يستمر التنسيق من اليمين إلى اليسار ومن الأعلى إلى الأسفل في المستند. هناك استثناءات: على سبيل المثال، قد تتطلّب جداول HTML أكثر من جولة واحدة.

يكون نظام الإحداثيات نسبيًا لإطار الجذر. يتم استخدام الإحداثيات العلوية واليسرى.

التنسيق هو عملية تكرارية. تبدأ العملية من عارض الجذر الذي يتوافق مع عنصر <html> في مستند HTML. يستمرّ التنسيق بشكلٍ متكرّر من خلال بعض أو كل التسلسل الهرمي للإطار، ويحسب المعلومات الهندسية لكلّ أداة عرض تتطلّب ذلك.

موضع أداة عرض الجذر هو 0,0 وأبعادها هي إطار العرض، أي الجزء المرئي من نافذة المتصفّح.

تحتوي جميع أدوات العرض على طريقة "تنسيق" أو "إعادة تدفق"، ويُطلِق كلّ مُعرِّف طريقة التنسيق لعناصره الفرعية التي تحتاج إلى تنسيق.

نظام البتات غير النظيفة

لكي لا تُجري المتصفّحات تنسيقًا كاملاً لكل تغيير صغير، تستخدم نظام "الجزء غير النظيف". يضع عارض الرسومات الذي تم تغييره أو إضافته علامة "غير محدَّث" على نفسه وعلى عناصره الفرعية، ما يعني أنّه يحتاج إلى تنسيق.

هناك علامتَان: "غير صالح" و "العناصر الثانوية غير صالحة"، ما يعني أنّه على الرغم من أنّ أداة العرض نفسها قد تكون صالحة، إلا أنّها تحتوي على عنصر ثانوي واحد على الأقل يحتاج إلى تنسيق.

التنسيق الشامل والتدريجي

يمكن تشغيل التنسيق على شجرة العرض بالكامل، وهذا هو التنسيق "العمومي". يمكن أن يحدث ذلك نتيجةً لأحد الأسباب التالية:

  1. تغيير نمط عام يؤثر في جميع أدوات العرض، مثل تغيير حجم الخط
  2. نتيجةً لتغيير حجم الشاشة

يمكن أن يكون التنسيق متزايدًا، ولن يتم عرض سوى عناصر العرض غير الصالحة (قد يؤدي ذلك إلى بعض الأضرار التي تتطلّب تنسيقات إضافية).

يتم بدء التنسيق المتزايد (بشكل غير متزامن) عندما تكون أدوات التقديم غير محدَّثة. على سبيل المثال، عند إلحاق أدوات عرض جديدة بشجرة العرض بعد أن يصل محتوى إضافي من الشبكة ويتمّ إضافته إلى شجرة DOM.

التنسيق المتزايد
الشكل 18: التنسيق المتزايد: يتمّ ترتيب عناصر العرض غير الصالحة وعناصر العرض الفرعية فقط

التنسيق غير المتزامن والمتزامن

يتمّ تنفيذ التنسيق المتزايد بشكل غير متزامن. يضع Firefox "أوامر إعادة التدفق" في "قائمة الانتظار" للتصاميم المتزايدة، ويشغّل جدول التشغيل تنفيذ هذه الأوامر بشكل مجمّع. يحتوي WebKit أيضًا على موقّت ينفّذ تنسيقًا متزايدًا، ويتمّ تنقّل الشجرة وتنسيق عناصر العرض "غير الصالحة".

يمكن أن تؤدي النصوص البرمجية التي تطلب معلومات عن التصميم، مثل "offsetHeight"، إلى بدء التنسيق المتزايد بشكل متزامن.

سيتم عادةً تشغيل التنسيق العام بشكل متزامن.

في بعض الأحيان، يتم بدء التنسيق كإجراء استدعاء بعد تنسيق أولي بسبب تغيير بعض السمات، مثل موضع التمرير.

تحسينات

عند بدء تنسيق من خلال "تغيير الحجم" أو تغيير في موضع أداة التحويل(وليس حجمها)، يتم أخذ أحجام عمليات التحويل من ذاكرة التخزين المؤقت ولا تتم إعادة احتسابها.

في بعض الحالات، يتم تعديل شجرة فرعية فقط ولا يبدأ التنسيق من الجذر. ويمكن أن يحدث ذلك في الحالات التي يكون فيها التغيير موضعيًا ولا يؤثر في العناصر المحيطة به، مثل النص الذي يتم إدراجه في حقول النص (وإلا ستؤدي كل ضغطة مفتاح إلى بدء تنسيق بدءًا من الجذر).

عملية التنسيق

يتّبع التنسيق عادةً النمط التالي:

  1. يحدِّد مُنشئ العرض الرئيسي عرضه الخاص.
  2. يراجع أحد الوالدَين الإعدادات الخاصة بالطفل وينفّذ ما يلي:
    1. ضَع وحدة عرض الطفل (اضبط x وy).
    2. تُستخدَم لطلب تنسيق الطفل إذا لزم الأمر، أي إذا كان التنسيق غير صحيح أو إذا كان التنسيق العام قيد الاستخدام أو لأي سبب آخر، ما يؤدي إلى احتساب ارتفاع الطفل.
  3. يستخدم العنصر الرئيسي الارتفاعات التراكمية للعناصر الفرعية وارتفاعات الهوامش والحشو لضبط ارتفاعه الخاص، وسيتم استخدام هذا الارتفاع من قِبل العنصر الرئيسي لعنصر العرض الرئيسي.
  4. ضبط القيمة "غير محفوظة" على "خطأ"

يستخدم Firefox عنصر "الحالة" (nsHTMLReflowState) كمَعلمة لتنسيق الصفحة (يُشار إليها باسم "إعادة التدفق"). من بين غيرها، تتضمّن الحالة عرض العناصر الرئيسية.

ناتج تنسيق Firefox هو عنصر "مقاييس" (nsHTMLReflowMetrics). وسيحتوي على الارتفاع المحسوب للعارض.

حساب العرض

يتم احتساب عرض أداة التحويل باستخدام عرض كتلة الحاوية، وخاصية "العرض" لأسلوب أداة التحويل، والهوامش والحدود.

على سبيل المثال، عرض العنصر div التالي:

<div style="width: 30%"/>

سيتم احتسابه بواسطة WebKit على النحو التالي(طريقة calcWidth لفئة RenderBox):

  • عرض الحاوية هو الحد الأقصى لعرض الحاوية المتاح و0. إنّ availableWidth في هذه الحالة هو contentWidth الذي يتم احتسابه على النحو التالي:
clientWidth() - paddingLeft() - paddingRight()

يمثّل clientWidth وclientHeight الجزء الداخلي من العنصر باستثناء الحدود وشريط التمرير.

  • عرض العناصر هو سمة التصميم "width". وسيتم احتسابها كقيمة مطلقة من خلال احتساب النسبة المئوية لعرض الحاوية.

  • تمت إضافة الحدود الأفقية والحشوات الآن.

لقد كان هذا حتى الآن هو حساب "العرض المفضّل". سيتم الآن احتساب الحد الأدنى والأقصى للعرض.

إذا كان العرض المفضّل أكبر من الحد الأقصى للعرض، يتم استخدام الحد الأقصى للعرض. وإذا كان العرض أقل من الحد الأدنى (أصغر وحدة غير قابلة للكسر)، يتم استخدام الحد الأدنى للعرض.

يتم تخزين القيم مؤقتًا في حال الحاجة إلى تنسيق، ولكن لا يتغيّر العرض.

فاصل السطر

عندما يقرر مُعرِّف العناصر في منتصف تنسيق أنّه يجب تقسيمه، يتوقف المُعرِّف عن العمل ويُرسِل إلى العنصر الرئيسي للتنسيق أنّه يجب تقسيمه. ينشئ العنصر الرئيسي عناصر المعالجة الإضافية ويطلب تنسيقها.

رسم

في مرحلة الرسم، يتمّ التنقّل في شجرة التقديم ويتمّ استدعاء طريقة "paint()" لعارض الرسومات لعرض المحتوى على الشاشة. يستخدم الرسم مكوّن بنية واجهة المستخدم.

عالمية ومتصاعدة

مثل التنسيق، يمكن أن يكون الرسم أيضًا شاملاً - يتم رسم الشجرة بأكملها - أو متزايدًا. في عملية الرسم المتزايد، يتغيّر بعض مُنشئِي الصور بطريقة لا تؤثّر في الشجرة بأكملها. يبطل مُنشئ العرض الذي تم تغييره المستطيل الذي يظهر على الشاشة. يؤدي ذلك إلى اعتبار نظام التشغيل أنّها "منطقة غير محدَّدة" وإنشاء حدث "رسم". ويُجري نظام التشغيل ذلك بذكاء ويدمج عدة مناطق في منطقة واحدة. في Chrome، تكون العملية أكثر تعقيدًا لأنّ وحدة المعالجة الرسومية تكون في عملية مختلفة عن العملية الرئيسية. يحاكي Chrome سلوك نظام التشغيل إلى حدٍّ ما. يستمع العرض التقديمي إلى هذه الأحداث ويفوّض الرسالة إلى جذر العرض. يتمّ التنقّل في الشجرة إلى أن يتمّ الوصول إلى أداة التقديم ذات الصلة. ستعيد رسم نفسها (وعادةً ما تعيد رسم العناصر الفرعية).

ترتيب اللوحة

تحدّد CSS2 ترتيب عملية الرسم. وهذا هو ترتيب تجميع العناصر في سياقات التجميع. يؤثر هذا الترتيب في عملية الطلاء لأنّه يتم طلاء الحِزم من الخلف إلى الأمام. ترتيب تجميع عارض العناصر هو:

  1. لون الخلفية
  2. صورة الخلفية
  3. border
  4. الأطفال
  5. مخطط

قائمة عرض Firefox

يفحص Firefox شجرة العرض وينشئ قائمة عرض للشكل المستطيل المرسوم. يحتوي على عناصر العرض ذات الصلة بالشكل المستطيل، وذلك بالترتيب الصحيح للرسم (خلفيات عناصر العرض، ثم الحدود وما إلى ذلك).

بهذه الطريقة، لا يلزم التنقّل في الشجرة إلا مرة واحدة لإعادة الطلاء بدلاً من عدة مرات، أي طلاء جميع الخلفيات، ثم جميع الصور، ثم جميع الحدود وما إلى ذلك.

يحسِّن Firefox العملية من خلال عدم إضافة عناصر ستتم إخفاؤها، مثل العناصر التي تكون أسفل عناصر غير شفافة تمامًا.

مساحة تخزين المستطيل في WebKit

قبل إعادة الطلاء، يحفظ WebKit المستطيل القديم كصورة نقطية. بعد ذلك، يتم رسم الفرق فقط بين المستطيلَين الجديد والقديم.

التغييرات الديناميكية

تحاول المتصفّحات تنفيذ الحد الأدنى من الإجراءات الممكنة استجابةً للتغيير. وبالتالي، فإنّ التغييرات التي تطرأ على لون العنصر لن تؤدي إلا إلى إعادة رسم العنصر. ستؤدي التغييرات في موضع العنصر إلى إعادة ترتيبه ورسمه، بالإضافة إلى عناصره الثانوية وربما العناصر الشقيقة. ستؤدي إضافة عقدة DOM إلى إعادة تصميم العقدة وإعادة رسمها. إنّ التغييرات الرئيسية، مثل زيادة حجم الخط في عنصر html، ستؤدي إلى إلغاء ذاكرة التخزين المؤقت وإعادة تصميم الشجرة بأكملها وإعادة رسمها.

سلاسل تعليمات محرّك العرض

محرك العرض أحادي السلسلة. تحدث كل العمليات تقريبًا، باستثناء عمليات الشبكة، في سلسلة محادثات واحدة. في Firefox وSafari، هذه هي سلسلة المحادثات الرئيسية للمتصفّح. في Chrome، يكون هذا الخيط هو سلسلة المهام الرئيسية لمعالجة علامة التبويب.

يمكن تنفيذ عمليات الشبكة من خلال عدة سلاسل مهام متوازية. يكون عدد عمليات الاتصال المتوازي محدودًا (عادةً من اتصالَين إلى 6 عمليات اتصال).

حلقة الأحداث

سلسلة المهام الرئيسية للمتصفّح هي حلقة أحداث. وهو عبارة عن حلقة لا نهائية تحافظ على استمرار العملية. وينتظر هذا المعالج الأحداث (مثل أحداث التنسيق والرسم) ويعالجها. في ما يلي رمز Firefox لحلقة الأحداث الرئيسية:

while (!mExiting)
    NS_ProcessNextEvent(thread);

النموذج المرئي لصفحات الأنماط المتتالية 2

اللوحة

وفقًا لمواصفات CSS2، يصف مصطلح "لوحة الرسم" "المساحة التي يتم فيها عرض بنية التنسيق": حيث يرسم المتصفّح المحتوى.

تكون اللوحة غير محدودة لكل سمة من سمات المساحة، ولكنّ المتصفّحات تختار عرضًا أوليًا استنادًا إلى سمات مساحة العرض.

وفقًا لموقع www.w3.org/TR/CSS2/zindex.html، تكون اللوحة شفافة إذا كانت مضمّنة في لوحة أخرى، ويتم منحها لونًا يحدّده المتصفّح إذا لم يكن الأمر كذلك.

نموذج CSS Box

يصف نموذج مربّعات CSS المربّعات المستطيلة التي يتم إنشاؤها للعناصر في شجرة المستند ويتم ترتيبها وفقًا لنموذج التنسيق المرئي.

يحتوي كل مربّع على منطقة محتوى (مثل نص أو صورة أو غير ذلك) ومناطق اختيارية للتباعد والحدود والهوامش المحيطة.

نموذج المربّعات في CSS2
الشكل 19: نموذج المربّع في CSS2

تُنشئ كل عقدة من 0 إلى n مربّعًا من هذا النوع.

تحتوي كل العناصر على سمة display التي تحدّد نوع المربّع الذي سيتم إنشاؤه.

أمثلة:

block: generates a block box.
inline: generates one or more inline boxes.
none: no box is generated.

الإعداد التلقائي هو مضمّن، ولكن قد تضبط جدول أسلوب المتصفّح إعدادات تلقائية أخرى. على سبيل المثال، العرض التلقائي للعنصر "div" هو "block".

يمكنك العثور على مثال على جدول الأنماط التلقائي هنا: www.w3.org/TR/CSS2/sample.html.

مخطّط تحديد الموضع

هناك ثلاثة أنظمة:

  1. عادي: يتم وضع العنصر وفقًا لموقعه في المستند. وهذا يعني أنّ مكانه في شجرة العرض يشبه مكانه في شجرة DOM ويتمّ ترتيبه وفقًا لنوع المربّع وقياساته.
  2. تطفو: يتم عرض العنصر أولاً مثل التدفق العادي، ثم يتم نقله إلى أقصى يمين أو يسار الشاشة
  3. مطلق: يتم وضع العنصر في شجرة العرض في مكان مختلف عن مكانه في شجرة نموذج DOM

يتمّ ضبط مخطّط تحديد الموضع من خلال السمة "position" والسمة "float".

  • تؤدي القيم الثابتة والنسبية إلى تدفق طبيعي.
  • تؤدي القيم المطلقة والثابتة إلى تحديد موضع مطلق.

في وضع تحديد الموضع الثابت، لا يتم تحديد موضع معيّن ويتم استخدام موضع تحديد الموضع التلقائي. في المخططات الأخرى، يحدّد المؤلف الموضع: أعلى أو أسفل أو يسار أو يمين.

يتم تحديد طريقة عرض المربّع من خلال:

  • نوع العلبة
  • أبعاد العلبة
  • مخطّط تحديد الموضع
  • المعلومات الخارجية، مثل حجم الصورة وحجم الشاشة

أنواع الحزم

مربّع الكتلة: يشكّل كتلة - له مستطيل خاص به في نافذة المتصفّح.

مربّع الحظر
الشكل 20: مربّع الحظر

المربّع المضمّن: لا يتضمّن مربّعًا خاصًا به، بل يكون داخل مربّع يحتوي عليه.

المربّعات المضمّنة
الشكل 21: المربّعات المضمّنة

يتم تنسيق القوالب رأسيًا واحدة تلو الأخرى. يتم تنسيق العناصر المضمّنة أفقيًا.

التنسيقات المجمّعة والمضمّنة
الشكل 22: التنسيقات المجمّعة والمضمّنة

يتم وضع المربّعات المضمّنة داخل الخطوط أو "مربّعات الخطوط". تكون الخطوط بنفس ارتفاع أعلى مربّع على الأقل، ولكن يمكن أن تكون أطول، وذلك عندما تكون المربّعات محاذية "للخط الأساسي"، ما يعني أنّ الجزء السفلي من العنصر يكون محاذًا لنقطة في مربّع آخر غير الجزء السفلي. إذا لم يكن عرض الحاوية كافيًا، سيتم وضع العناصر المضمّنة على عدة أسطر. وهذا ما يحدث عادةً في الفقرة.

الخطوط
الشكل 23: الأسطر

المكانة في السوق

قريب

الوضع النسبي: يتم وضع العنصر كالمعتاد ثم نقله حسب القيمة المطلوبة.

تحديد الموضع النسبي
الشكل 24: ضبط الموضع نسبيًا

عائمة

يتم نقل مربّع عائم إلى يمين أو يسار سطر. والميزة المثيرة للاهتمام هي أنّ المربّعات الأخرى تتدفق حوله. رمز HTML:

<p>
  <img style="float: right" src="images/image.gif" width="100" height="100">
  Lorem ipsum dolor sit amet, consectetuer...
</p>

سيظهر على النحو التالي:

انتظر.
الشكل 25: قيمة عددية قابلة للتغيير

مطلقة وثابتة

يتم تحديد التنسيق بدقة بغض النظر عن التدفق العادي. لا يشارك العنصر في التدفق العادي. تكون السمات نسبية إلى الحاوية. في الوضع الثابت، تكون الحاوية هي إطار العرض.

موضع ثابت
الشكل 26: موضع ثابت

التمثيل المتعدّد الطبقات

يتم تحديد ذلك من خلال خاصية z-index في CSS. ويمثّل السمة الثالثة للمربّع: موضعه على طول "محور z".

تنقسم المربّعات إلى حِزم (تُعرف باسم سياقات التجميع). في كل حزمة، سيتم أولاً رسم العناصر الخلفية ثم العناصر الأمامية في الأعلى، أي أقرب إلى المستخدم. في حال التداخل، سيخفي العنصر الأهم العنصر السابق.

يتم ترتيب الحِزم وفقًا لسمة z-index. تشكل المربّعات التي تحتوي على السمة z-index حزمة محلية. يحتوي إطار العرض على الحزمة الخارجية.

مثال:

<style type="text/css">
  div {
    position: absolute;
    left: 2in;
    top: 2in;
  }
</style>

<p>
  <div
    style="z-index: 3;background-color:red; width: 1in; height: 1in; ">
  </div>
  <div
    style="z-index: 1;background-color:green;width: 2in; height: 2in;">
  </div>
</p>

ستكون النتيجة على النحو التالي:

موضع ثابت
الشكل 27: موضع ثابت

على الرغم من أنّ div الأحمر يسبق div الأخضر في الترميز، وكان من المفترض أن يتم رسمه قبل ذلك في التدفق العادي، تكون قيمة السمة z-index أعلى، لذا يكون أكثر تقدّمًا في الحزمة التي يحتفظ بها مربّع الجذر.

الموارد

  1. بنية المتصفّح

    1. Grosskurth, Alan. A Reference Architecture for Web Browsers (pdf)
    2. غوبتا، فينيت طريقة عمل المتصفّحات - الجزء 1: البنية
  2. التحليل

    1. Aho, Sethi, Ullman, Compilers: Principles, Techniques, and Tools (المعروفة أيضًا باسم "كتاب التنين")، Addison-Wesley، 1986
    2. ريك جيليف The Bold and the Beautiful: مسودتان جديدتان لـ HTML 5
  3. Firefox

    1. L. ديفيد بارون، Faster HTML and CSS: Layout Engine Internals for Web Developers (تحسين أداء HTML وCSS: العناصر الداخلية لمحرك التنسيق لمطوّري الويب)
    2. L. ديفيد بارون، تحسين أداء HTML وCSS: التعرّف على آلية عمل Layout Engine لمطوّري الويب (فيديو محادثة تقنية من Google)
    3. L. "ديفيد بارون"، محرك تنسيق Mozilla
    4. L. "ديفيد بارون"، مستندات نظام نمط Mozilla
    5. كريس ووترسون، ملاحظات حول إعادة تدفق HTML
    6. كريس ووترسون، نظرة عامة على Gecko
    7. ألكسندر لارسون، مسار طلب HTTP في HTML
  4. WebKit

    1. ديفيد هايات، Implementing CSS(part 1)
    2. ديفيد هايات، نظرة عامة على WebCore
    3. "ديفيد هايات"، WebCore Rendering
    4. David Hyatt, The FOUC Problem
  5. مواصفات W3C

    1. مواصفات HTML 4.01
    2. مواصفات HTML5 من W3C
    3. مواصفات صفحات الأنماط المتتالية، المستوى 2، المراجعة 1 (CSS 2.1)
  6. تعليمات إنشاء المتصفّحات

    1. Firefox: https://developer.mozilla.org/Build_Documentation
    2. WebKit‏: http://webkit.org/building/build.html

الترجمات

تمت ترجمة هذه الصفحة إلى اليابانية مرتين:

يمكنك الاطّلاع على الترجمات المستضافة خارجيًا للغتين الكورية و التركية.

شكرًا للجميع.