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

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

تمهيد

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

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

"بول أيرش"، فريق علاقات مطوّري برامج Chrome

مقدمة

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

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

هناك خمسة متصفحات رئيسية تستخدم اليوم على أجهزة الكمبيوتر المكتبية: Chrome وInternet Explorer وFirefox وSafari وOpera. وعلى الجوال، المتصفحات الرئيسية هي متصفح Android، وiPhone، وOpera Mini، وOpera Mobile، وUC، ومتصفِّح 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. شريط العناوين لإدراج عنوان URI
  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 يستخدمان مصطلحات مختلفة قليلاً، فإن التدفق هو نفسه في الأساس.

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

التحليل - عام

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

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

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

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

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

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

محلّل لغوي - تركيبة ليكسر

يمكن فصل التحليل إلى عمليتين فرعيتين: التحليل المعجم وتحليل بناء الجملة.

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

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

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

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

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

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

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

ترجمة

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

مسار التحويل البرمجي
الشكل 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
تعبير -

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

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

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

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

محلل HTML اللغوي

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

قواعد HTML

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

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

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

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

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

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

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

ملفات HTML DTD

تعريف HTML بتنسيق DTD. يُستخدَم هذا التنسيق لتحديد لغات مجموعة SGML. يتضمّن التنسيق تعريفات لجميع العناصر المسموح بها وسماتها وتسلسلها الهرمي. كما رأينا سابقًا، لا تشكل 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: شجرة نموذج العناصر في المستند (DOM) لمثال الترميز

كما هو الحال في HTML، يتم تحديد DOM بواسطة مؤسسة W3C. يمكنك الاطّلاع على 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)، وكذلك حزمة العناصر المفتوحة. وتُستخدم هذه الحزمة لتصحيح حالات عدم التطابق في التداخل والعلامات غير المغلقة. يتم وصف الخوارزمية أيضًا بوصفها جهاز حالة. تُسمى الحالات "أوضاع الإدراج".

لنطّلع على عملية تأسيس الشجرة للمثال الذي تمّ إدخاله:

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

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

ستتغير الحالة إلى "قبل الرأس". "الجسم" استلام الرمز المميز. سيتم إنشاء HTMLHeadElement ضمنيًا على الرغم من عدم وجود "head" وستتم إضافته إلى الشجرة.

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

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

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

إنشاء شجرة لمثال 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>. ولكي يكون WebKit متوافقًا مع 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}*

&quot;ident&quot; وهو اختصار للمعرِّف، مثل اسم الفئة. "الاسم" عبارة عن معرّف عنصر (يُشار إليه بـ "#")

يتم وصف قواعد بناء الجملة في 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 إلى المسافة البيضاء). تحتوي مجموعة القواعد على أقواس معقوفة وداخلها تصريح أو اختياريًا عدد من التصريحات مفصولة بفاصلة منقوطة. "البيان" و"selector" في تعريفات BNF التالية.

محلّل CSS في WebKit

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

تحليل CSS.
الشكل 12: تحليل CSS

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

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

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

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

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

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

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

عرض بناء الأشجار

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

يُطلق على العناصر في شجرة العرض اسم "الإطارات" في 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. ويتضمن معلومات هندسية مثل العرض والارتفاع والموضع.

يتأثر نوع المربّع بسمة "الشاشة" قيمة سمة النمط ذات الصلة بالعقدة (راجع القسم حساب النمط). في ما يلي رمز 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 غير المرئية في شجرة العرض. مثال هو "الرأس" العنصر. العناصر أيضًا التي تم تعيين قيمة عرضها إلى "none" لن تظهر في الشجرة (في حين تظهر العناصر ذات مستوى الرؤية "المخفي" في الشجرة).

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

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

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

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

تدفق صياغة الشجرة

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

في WebKit، تسمى عملية حل النمط وإنشاء عارض "مرفق". كل عقدة DOM تحتوي على "مرفق" . المرفق متزامن، ويستدعي إدراج العقدة في شجرة نموذج العناصر في المستند العقدة الجديدة "attach" .

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

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

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

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

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

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

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

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

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

    div div div div{
    ...
    }
    

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

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

لنرى كيف تواجه المتصفّحات هذه المشاكل:

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

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

  1. يجب أن تكون العناصر في حالة الماوس نفسها (على سبيل المثال، لا يمكن أن يكون أحدهما في حالة التمرير :بينما الآخر غير موجود)
  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. سيكون لدينا الآن عمل أقل للقيام به.

لنرى كيف توفر لنا الشجرة العمل.

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

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

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

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

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

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

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

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

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

لنطّلع على مثال: لنفترض أن لدينا هذا 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، وهي العقدة العلوية التي حددت قواعد الهامش.

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

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

بالنسبة إلى البِنى التي تحتوي على قواعد مكتسَبة من العنصر الرئيسي، يتم التخزين المؤقت على شجرة السياق (تكون خاصية اللون موروثة في الواقع، ولكن يعاملها 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 قواعد ذات صلة في خريطة id (المفتاح هو المعرّف) وخريطة العلامة. إذًا، العمل الوحيد المتبقي هو معرفة أي من القواعد التي استخرجتها المفاتيح تتطابق حقًا.

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

table div {margin: 5px}

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

وينفذ كل من WebKit وFirefox هذا التلاعب.

الترتيب التدريجي لورقة الأنماط

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

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

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

  1. بيانات تعريف المتصفِّح
  2. نماذج البيانات العادية للمستخدِم
  3. إنشاء إقرارات عادية
  4. إنشاء تصريحات مهمة
  5. تصريحات المستخدمين المهمة

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

الدقة

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

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

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

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

على سبيل المثال، إذا كان a=14، يمكنك استخدام الأساس السداسي العشري. في الحالة النادرة، حيث a=17 ستحتاج إلى قاعدة أرقام مكوّنة من 17 رقمًا. يمكن أن يحدث الموقف الأخير باستخدام أداة اختيار مثل هذا: html body 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 عملية الترتيب من خلال تجاوز عامل التشغيل > للقواعد:

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 علامة تشير إلى ما إذا كان قد تم تحميل جميع أوراق أنماط المستوى الأعلى (بما في ذلك عمليات الاستيراد @). إذا لم يتم تحميل النمط بالكامل عند إرفاقه، يتم استخدام عناصر نائبة ووضع علامة عليها في المستند، وستتم إعادة حسابها بمجرد تحميل أوراق الأنماط.

التنسيق

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

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

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

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

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

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

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

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

هناك علامتان: "غير نظيف" و"الأطفال متسخون" وهو ما يعني أنه على الرغم من أن العارض نفسه قد يكون جيدًا، إلا أن هناك فرعًا واحدًا على الأقل يحتاج إلى تنسيق.

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

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

  1. يشير ذلك المصطلح إلى تغيير نمط عام يؤثر في جميع برامج العرض، مثل تغيير حجم الخط.
  2. بسبب تغيير حجم الشاشة

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

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

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

التخطيط غير المتزامن والمتزامن

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

النصوص البرمجية التي تطلب معلومات عن النمط، مثل "offsetHeight" تشغيل التخطيط التزايدي بشكل متزامن.

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

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

تحسينات

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

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

عملية التخطيط

يكون التخطيط عادةً على النحو التالي:

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

يستخدم فايرفوكس "حالة" الكائن(nsHTMLReflowState) كمعلمة للتنسيق (يطلق عليها "reflow"). وتتضمن الولاية عرض الوالدين من بين بقية المدن.

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

حساب العرض

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

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

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

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

  • عرض الحاوية هو الحد الأقصى للحاويات المتاحة "العرض" و0. في هذه الحالة، تكون قيمة السمة available قيمًا هي عرض المحتوى ويتم احتسابها على النحو التالي:
clientWidth() - paddingLeft() - paddingRight()

يمثل clientالعرض و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);

النموذج المرئي CSS2

اللوحة

وفقًا لمواصفات 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" هو "كتلة".

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

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

هناك ثلاثة مخططات:

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

يتم تعيين نظام تحديد الموضع حسب "الموضع" و"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. المربّعات التي تحتوي على "فهرس z" تشكل الخاصية مكدسًا محليًا. يحتوي إطار العرض على المكدس الخارجي.

مثال:

<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 باللون الأحمر تسبق الرمز الأخضر في الترميز، وكان من الممكن أن يتم صياغتها من قبل في التدفق العادي، فإن خاصية z-index أعلى، لذا فهي تقدم بشكل أكبر في الحزمة التي يحتفظ بها مربع الجذر.

الموارد

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

    1. غروسكورث، آلان. بنية مرجعية لمتصفّحات الويب (pdf)
    2. غوبتا، فينيت. طريقة عمل المتصفّحات - الجزء 1 - البنية
  2. التحليل

    1. Aho، وSethi، وأولمان، وCompilers: مبادئ، وتقنيات، وأدوات (يُعرف أيضًا باسم "كتاب التنين")، وأديسون ويسلي، 1986
    2. ريك جيليف. الخط الغامق والجميل: مسودتان جديدتان للغة HTML 5
  3. Firefox

    1. L. "ديفيد بارون"، Faster HTML and CSS: Layout Engine داخليةs for Web Developers
    2. L. "ديفيد بارون"، مقالة Faster HTML and CSS: Layout Engine Inters for Web Developers (فيديو عن Google Tech Talk)
    3. L. "ديفيد بارون"، محرك تنسيق Mozilla
    4. L. "ديفيد بارون"، وثائق نظام أنماط Mozilla
    5. "كريس واترسون"، Notes on HTML Reflow
    6. "كريس واترسون"، نظرة عامة على Gecko
    7. "ألكسندر لارسون"، تجربة طلب HTTP بتنسيق HTML
  4. WebKit

    1. ديفيد حياة، تنفيذ CSS(الجزء 1)
    2. ديفيد حياة، نظرة عامة على WebCore
    3. ديفيد حياة، عرض WebCore
    4. "ديفيد حياة"، مشكلة FOUC
  5. مواصفات W3C

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

    1. فَيَرفُكس https://developer.mozilla.org/Build_Documentation
    2. WebKit. http://webkit.org/building/build.html

الترجمات

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

يمكنك عرض الترجمات المستضافة خارجيًا لـ الكورية التركية

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