تطوير الويب: HTML وCSS وJavaScript
خروج

الدرس 2 من 17 · HTML وCSS

HTML: بنية الصفحة، الوسوم الدلالية، الروابط والصور

45 د Node.js 22 (Debian, git, npm, python3)

الهدف

أن تكتب يدويًا صفحة HTML صحيحة وجيدة البنية: الهيكل الإلزامي، والعناوين والفقرات، والقوائم، والمناطق الدلالية الكبرى (header، nav، main، footer)، والروابط والصور. في النهاية، ستكون لديك الصفحة الرئيسية وصفحة «Nos chambres» (غرفنا) لـ Riad Yasmine في مراكش.

أهم النقاط

  • يصف HTML المحتوى ومعناه («هذا عنوان»، «هذه قائمة تنقّل»)، لا مظهره: المظهر من شأن CSS.
  • العنصر = وسم فتح + محتوى + وسم إغلاق: <p>Bonjour</p>. والسمات (attributes) تدقّق العنصر: <a href="chambres.html">.
  • كل صفحة تبدأ بـ <!doctype html>، ثم <html lang="fr">، و<head> (معلومات عن الصفحة) و<body> (ما يُعرَض).
  • تساعد الوسوم الدلالية (semantic) (header، nav، main، article، section، aside، footer) قارئات الشاشة ومحركات البحث.
  • عنوان h1 واحد فقط في كل صفحة، ثم h2 وh3… بالترتيب، دون القفز على مستوى.
  • كل صورة تحمل سمة alt تصف ما تُظهره.

1. تشريح عنصر

<a href="chambres.html" title="Voir les chambres">Nos chambres</a>
<!-- └ balise ouvrante avec deux attributs ┘└ contenu ┘└ fermante ┘ -->

(balise ouvrante avec deux attributs = وسم فتح بسمتين، contenu = المحتوى، fermante = وسم الإغلاق.)

  • تُكتب السمات على شكل nom="valeur" داخل وسم الفتح، مفصولة بمسافات.
  • تتداخل العناصر مثل الدمى الروسية، وتُغلق بالترتيب المعاكس: <p>Un <strong>prix</strong> imbattable</p> صحيح، و<p>Un <strong>prix</p></strong> غير صحيح.
  • بعض العناصر فارغة (لا محتوى ولا وسم إغلاق): <img>، <br>، <meta>، <link>، <input>، <hr>.
  • <!-- ... --> تعليق: يظهر في الشيفرة المصدرية، ولا يظهر أبدًا على الشاشة.
  • يتجاهل HTML المسافات وأسطر الرجوع المتعددة: نسّق شيفرتك بالإزاحة من أجلك أنت، لا من أجل المتصفح.

2. هيكل الصفحة

<!doctype html>
<html lang="fr">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="Riad de charme dans la médina de Marrakech, six chambres, patio et terrasse.">
  <title>Riad Yasmine — Maison d'hôtes à Marrakech</title>
  <link rel="stylesheet" href="style.css">
  <link rel="icon" href="favicon.png">
</head>
<body>
  <!-- كل ما يُعرَض على الشاشة -->
</body>
</html>
السطر الدور
<!doctype html> «هذا HTML حديث»؛ وبدونه ينتقل المتصفح إلى وضع التوافق
lang="fr" لغة الصفحة: النطق في قارئات الشاشة، والترجمة، والفهرسة في محركات البحث. لصفحة بالعربية: lang="ar" dir="rtl"
<meta charset="utf-8"> الترميز: بدونه تظهر «Fès» و«مرحبا» بمحارف غريبة
viewport ضروري لعرض صحيح على الهاتف (الدرس 1.6)
description الملخّص المعروض تحت العنوان في نتائج البحث
<title> نص التبويب والرابط في Google: دقيق وفريد لكل صفحة
<link rel="stylesheet"> يربط ورقة أنماط CSS

لا يُعرَض <head>: فهو يحتوي على بيانات وصفية (metadata)، أي معلومات عن الصفحة.

3. العناوين والفقرات والإبراز

<h1>Riad Yasmine</h1>
<p>Une maison d'hôtes de six chambres, à cinq minutes de la place Jemaa el-Fna.</p>

<h2>Le riad</h2>
<p>Construit au <strong>XVIIIᵉ siècle</strong>, entièrement restauré en 2023.</p>

<h2>Les services</h2>
<h3>Petit-déjeuner</h3>
<p>Msemen, baghrir, amlou et jus d'orange pressé, <em>servis sur la terrasse</em>.</p>
<h3>Hammam</h3>
<p>Sur réservation, la veille.</p>
  • تشكّل h1 إلى h6 مخطّط الصفحة. تتيح قارئة الشاشة القفز من عنوان إلى آخر: وهذا هو سبب وجودها الحقيقي. لا تختر عنوانًا أبدًا بسبب حجمه (الحجم يُضبط بـ CSS).
  • <p>: فقرة. لرجوع بسيط إلى السطر داخل عنوان بريدي، <br>؛ ولفصل الأفكار، <p> جديدة.
  • <strong>: الأهمية (تُعرض بخط عريض افتراضيًا)؛ <em>: التوكيد (مائل). هذه وسوم معنى؛ أما <b> و<i> فلا تحملان إلا نمطًا.

4. القوائم

<ul>                         <!-- قائمة نقطية: الترتيب غير مهم -->
  <li>Wi-Fi gratuit</li>
  <li>Terrasse avec vue sur l'Atlas</li>
  <li>Navette depuis l'aéroport Marrakech-Ménara</li>
</ul>

<ol>                         <!-- قائمة مرقّمة: الترتيب مهم -->
  <li>Choisissez vos dates</li>
  <li>Choisissez votre chambre</li>
  <li>Confirmez par e-mail</li>
</ol>

<dl>                         <!-- قائمة تعريفات: مصطلح / وصف -->
  <dt>Arrivée</dt><dd>à partir de 14 h</dd>
  <dt>Départ</dt><dd>avant 11 h</dd>
</dl>

قائمة التنقّل هي في الأساس قائمة روابط: كثير من المواقع تكتبها <nav><ul><li><a …></a></li>…</ul></nav>.

5. وسوم البنية الدلالية

قبل HTML5، كان كل شيء مصنوعًا من <div> مجهولة. أما اليوم، فنسمّي المناطق:

<body>
  <header>                       <!-- ترويسة الموقع: الشعار، الاسم، القائمة -->
    <h1>Riad Yasmine</h1>
    <nav>                        <!-- قائمة التنقّل الرئيسية -->
      <a href="index.html">Accueil</a>
      <a href="chambres.html">Chambres</a>
      <a href="#contact">Contact</a>
    </nav>
  </header>

  <main>                         <!-- المحتوى الرئيسي (واحد فقط في كل صفحة) -->
    <section>                    <!-- جزء موضوعاتي، بعنوانه -->
      <h2>Le riad</h2> …
    </section>
    <article>                    <!-- محتوى مستقل: رأي، مقال مدوّنة -->
      <h2>« Un séjour inoubliable »</h2>
      <p>Accueil chaleureux, chambre impeccable. — Sophie, Lyon</p>
    </article>
    <aside>                      <!-- محتوى ثانوي: إطار جانبي، روابط ذات صلة -->
      <p>Offre : -15 % pour 5 nuits et plus.</p>
    </aside>
  </main>

  <footer>                       <!-- تذييل الصفحة: العنوان، البيانات القانونية -->
    <p>Derb Sidi Bouloukat, Marrakech</p>
  </footer>
</body>
الوسم متى نستعمله
header مقدّمة صفحة أو قسم
nav مجموعة روابط تنقّل مهمة (لا كل رابط)
main المحتوى الخاص بالصفحة، مرة واحدة فقط
section جزء موضوعاتي له عنوان
article محتوى له معنى وحده (رأي، بطاقة منتج)
aside محتوى ثانوي
footer تذييل صفحة أو قسم
div حاوية بلا معنى، للتنسيق فقط

لماذا هذا مهم: تعلن قارئة الشاشة «تنقّل» و«محتوى رئيسي» وتتيح الذهاب إليهما مباشرة؛ ويفهم Google صفحتك بشكل أفضل؛ وتصبح شيفرة CSS أوضح.

6. الروابط

<!-- رابط مطلق: نحو موقع آخر -->
<a href="https://www.visitmorocco.com/fr">Office national marocain du tourisme</a>

<!-- روابط نسبية: نحو صفحة من الموقع نفسه -->
<a href="chambres.html">Nos chambres</a>          <!-- المجلد نفسه -->
<a href="chambres/suite-atlas.html">Suite Atlas</a> <!-- مجلد فرعي -->
<a href="../index.html">Accueil</a>               <!-- المجلد الأب -->
<a href="/tarifs.html">Tarifs</a>                 <!-- انطلاقًا من جذر الموقع -->

<!-- مرساة: نحو موضع في الصفحة -->
<a href="#contact">Nous contacter</a>
<section id="contact"> … </section>

<!-- بريد إلكتروني -->
<a href="mailto:contact@riad-yasmine.ma">contact@riad-yasmine.ma</a>

<!-- الفتح في تبويب جديد: يُخصَّص للروابط الخارجية -->
<a href="https://maps.example.com/riad" target="_blank" rel="noopener">Plan d'accès</a>

قواعد الجودة:

  • يجب أن يقول نص الرابط إلى أين يقود: «Voir nos chambres» (شاهد غرفنا) أفضل من «cliquez ici» (انقر هنا) (فقارئات الشاشة تسرد الروابط خارج سياقها)؛
  • فضّل الروابط النسبية داخل موقعك: سيستمر في العمل محليًا، وفي الاختبار، وفي الإنتاج؛
  • يجب أن يكون id فريدًا في الصفحة.

7. الصور

<img src="images/patio.jpg"
     alt="Le patio du riad et sa fontaine en zellige vert"
     width="800" height="533">
  • src: مسار الصورة (القواعد نفسها كالروابط)؛
  • alt: النص البديل، تقرؤه قارئات الشاشة ويُعرض إذا لم تُحمَّل الصورة. صِف ما تضيفه الصورة. لصورة زخرفية محضة: alt="" (فارغ، لكنه موجود)؛
  • width وheight: الأبعاد الحقيقية بالبكسل. يحجز المتصفح المكان قبل التحميل، فلا «تقفز» الصفحة (الدرس 4.2).

صورة مع تعليق توضيحي:

<figure>
  <img src="images/terrasse.webp" alt="Terrasse au coucher du soleil, vue sur la Koutoubia" width="1200" height="800">
  <figcaption>La terrasse, où le thé est servi à 17 h.</figcaption>
</figure>

صيغ يجب معرفتها: JPEG (الصور الفوتوغرافية)، PNG (الشعارات، الشفافية)، WebP / AVIF (صور أخف، يُفضَّل استعمالها)، SVG (رسوم متجهية، أيقونات: واضحة في كل الأحجام).

8. المحارف الخاصة والتحقق من الصحة

لبعض المحارف معنى في HTML؛ ولعرضها نستعمل الكيانات (entities):

المحرف الكيان
< &lt;
> &gt;
& &amp;
" &quot;
مسافة غير قابلة للكسر (1 200 DH على سطر واحد) &nbsp;

بفضل utf-8، تُكتب الحروف المشكولة بالفرنسية والعربية مباشرة، دون كيانات.

للتحقق من صفحة، يشير مدقّق W3C (validator.w3.org) إلى الوسوم المغلقة بشكل خاطئ، والسمات غير المعروفة، أو id المكرّر. أما المتصفح فـ«يصلح» الأخطاء بصمت… على طريقته، التي تختلف من متصفح إلى آخر.

9. تنظيم ملفات موقع

riad/
├── index.html          ← la page d'accueil (nom attendu par les serveurs web)
├── chambres.html
├── style.css
├── app.js
└── images/
    ├── patio.jpg
    └── terrasse.webp

(la page d'accueil = الصفحة الرئيسية؛ nom attendu par les serveurs web = الاسم الذي تنتظره خوادم الويب.)

نصائح: أسماء الملفات بحروف صغيرة، دون مسافات ولا حروف مشكولة (suite-atlas.html، وليس Suite Atlas.html)؛ يميّز خادم Linux بين Patio.jpg وpatio.jpg، بينما لا يفعل Windows ذلك: وهذا هو السبب الأول للصور المعطوبة بعد النشر على الإنترنت.

أخطاء متكررة

  • نسيان <meta charset="utf-8">: تظهر الحروف المشكولة بشكل خاطئ بمجرد النشر.
  • اختيار عنوان بسبب حجمه (h4 لأنه «أصغر»): يصبح مخطّط الصفحة غير متماسك. احترم الترتيب المنطقي واضبط الحجم بـ CSS.
  • صور بدون alt أو مع alt="image": لا فائدة منها للكفيف، وسيئة للفهرسة في محركات البحث.
  • صنع كل شيء بـ <div>: تعمل الصفحة، لكنها صامتة بالنسبة لقارئات الشاشة ومحركات البحث.

التطبيق العملي (Lab)

ستبني، خطوة بخطوة، صفحتين لـ Riad Yasmine في /root/riad:

  1. هيكل index.html؛
  2. بنيتها الدلالية، مع h1 واحد فقط؛
  3. القائمة (روابط نسبية ومرساة) وقسم الاتصال؛
  4. صورة مع نص بديل وأبعاد؛
  5. الصفحة chambres.html مع قائمة ورابط عودة.

لكتابة ملف، أبسط طريقة هي cat > /root/riad/index.html <<'EOF'، ثم المحتوى، ثم سطر EOF. أعد قراءة ملفك باستعمال cat.

اختبار قصير

  1. ما الأسطر الثلاثة التي يجب أن توجد في <head> كل صفحة؟
  2. ما الفرق بين <section> و<div>؟
  3. اكتب رابطًا نحو الصفحة tarifs.html الموجودة في المجلد الأب.
  4. ماذا نضع في السمة alt لصورة زخرفية محضة؟
  5. لماذا يجب تحديد width وheight لصورة؟
الأجوبة
  1. <meta charset="utf-8">، و<meta name="viewport" content="width=device-width, initial-scale=1"> و<title>…</title>.
  2. لـ <section> معنى (جزء موضوعاتي، بعنوان)؛ أما <div> فلا معنى له ولا يُستعمل إلا للتجميع من أجل التنسيق.
  3. <a href="../tarifs.html">Nos tarifs</a>.
  4. نصًا فارغًا، alt="": السمة موجودة، وتتجاهل قارئة الشاشة الصورة.
  5. لكي يحجز المتصفح مكان الصورة قبل تحميلها: فلا تنزاح الصفحة أثناء العرض.

مصادر مرجعية: MDN Web Docs بالفرنسية (رخصة CC BY-SA 2.5). نص أصلي من MasterLinux.

تمارين تطبيقية

تُنجَز على Node.js 22 (Debian, git, npm, python3)

الطرفية عبر الإنترنت قادمة قريبًا. في انتظار ذلك، أنجِز هذه المهام على جهازك بنظام لينكس أو على آلة افتراضية أو WSL.

  1. أنشئ /root/riad/index.html بالهيكل الكامل لصفحة: doctype الخاص بـ HTML5، والعنصر html باللغة الفرنسية (lang="fr")، وhead يحتوي على مجموعة المحارف utf-8 وعنوانًا (title) يتضمّن «Riad Yasmine»، ثم body.
    عرض تلميحاستعمل cat > /root/riad/index.html <<'EOF' … EOF، أو printf مع سطر لكل معامل.
    عرض الحل
    printf '%s\n' '<!doctype html>' '<html lang="fr">' '<head>' '  <meta charset="utf-8">' '  <title>Riad Yasmine — Marrakech</title>' '</head>' '<body>' '  <p>Site en construction</p>' '</body>' '</html>' > /root/riad/index.html

    التحقق : grep -qi '<!doctype html>' /root/riad/index.html && grep -q '<html lang="fr"' /root/riad/index.html && grep -qi '<meta charset="utf-8"' /root/riad/index.html && grep -q '<title>[^<]*Riad Yasmine[^<]*</title>' /root/riad/index.html && grep -q '<body' /root/riad/index.html

  2. نظّم body في /root/riad/index.html بالوسوم الدلالية header وnav وmain وfooter. يجب أن تحتوي الصفحة على عنوان h1 واحد فقط (اسم الرياض).
    عرض تلميحيحتوي header على h1؛ وسيستقبل nav القائمة؛ وmain المحتوى الرئيسي؛ وfooter العنوان البريدي.
    عرض الحل
    printf '%s\n' '<!doctype html>' '<html lang="fr">' '<head>' '  <meta charset="utf-8">' '  <title>Riad Yasmine — Marrakech</title>' '</head>' '<body>' '  <header>' '    <h1>Riad Yasmine</h1>' '    <nav></nav>' '  </header>' '  <main>' '    <p>Un riad de six chambres au cœur de la médina.</p>' '  </main>' '  <footer>' '    <p>Derb Sidi Bouloukat, Marrakech</p>' '  </footer>' '</body>' '</html>' > /root/riad/index.html

    التحقق : f=/root/riad/index.html; for b in header nav main footer; do grep -q "<$b" $f || exit 1; done; test "$(grep -o "<h1" $f | wc -l)" -eq 1

  3. داخل nav، أضف رابطًا نسبيًا نحو chambres.html ورابطًا نحو المرساة #contact. وداخل main، أضف section معرّفها contact (id="contact") مع عنوان h2.
    عرض تلميح<a href="chambres.html">Chambres</a> و<section id="contact"><h2>Contact</h2>…</section>
    عرض الحل
    printf '%s\n' '<!doctype html>' '<html lang="fr">' '<head>' '  <meta charset="utf-8">' '  <title>Riad Yasmine — Marrakech</title>' '</head>' '<body>' '  <header>' '    <h1>Riad Yasmine</h1>' '    <nav>' '      <a href="index.html">Accueil</a>' '      <a href="chambres.html">Chambres</a>' '      <a href="#contact">Contact</a>' '    </nav>' '  </header>' '  <main>' '    <p>Un riad de six chambres au cœur de la médina.</p>' '    <section id="contact">' '      <h2>Contact</h2>' '      <p>Écrivez-nous : <a href="mailto:contact@riad-yasmine.ma">contact@riad-yasmine.ma</a></p>' '    </section>' '  </main>' '  <footer>' '    <p>Derb Sidi Bouloukat, Marrakech</p>' '  </footer>' '</body>' '</html>' > /root/riad/index.html

    التحقق : f=/root/riad/index.html; grep -q 'href="chambres.html"' $f && grep -q 'href="#contact"' $f && grep -q 'id="contact"' $f && grep -q '<h2' $f

  4. داخل main، أضف الصورة images/patio.jpg مع نص بديل (alt) يصف الصورة فعلًا، وكذلك أبعادها (width وheight).
    عرض تلميح<img src="images/patio.jpg" alt="Le patio et sa fontaine en zellige" width="800" height="533">
    عرض الحل
    sed -i 's#<p>Un riad de six chambres au cœur de la médina.</p>#&\n    <img src="images/patio.jpg" alt="Le patio du riad et sa fontaine en zellige vert" width="800" height="533">#' /root/riad/index.html

    التحقق : grep -o '<img[^>]*>' /root/riad/index.html | grep 'images/patio.jpg' | grep 'width=' | grep 'height=' | grep -Eq 'alt="[^"]+"'

  5. أنشئ /root/riad/chambres.html (الهيكل نفسه، lang="fr"): عنوان h1 هو «Nos chambres»، وقائمة نقطية تضم ثلاث غرف على الأقل، ورابط عودة نحو index.html.
    عرض تلميح<ul> <li>Suite Atlas</li> <li>Chambre Majorelle</li> <li>Chambre Ourika</li> </ul>
    عرض الحل
    printf '%s\n' '<!doctype html>' '<html lang="fr">' '<head>' '  <meta charset="utf-8">' '  <title>Nos chambres — Riad Yasmine</title>' '</head>' '<body>' '  <h1>Nos chambres</h1>' '  <ul>' '    <li>Suite Atlas — 1 200 DH la nuit</li>' '    <li>Chambre Majorelle — 900 DH la nuit</li>' '    <li>Chambre Ourika — 750 DH la nuit</li>' '  </ul>' '  <p><a href="index.html">Retour à l’accueil</a></p>' '</body>' '</html>' > /root/riad/chambres.html

    التحقق : f=/root/riad/chambres.html; grep -q '<html lang="fr"' $f && grep -q '<h1>Nos chambres</h1>' $f && grep -q '<ul' $f && test "$(grep -o '<li' $f | wc -l)" -ge 3 && grep -q 'href="index.html"' $f

المراجع الرسمية المعتمدة: Syntaxe de base du HTML — https://developer.mozilla.org/fr/docs/Learn_web_development/Core/Structuring_content/Basic_HTML_syntax ; Qu'y a-t-il dans l'en-tête ? Métadonnées d'une page Web — https://developer.mozilla.org/fr/docs/Learn_web_development/Core/Structuring_content/Webpage_metadata ; Structurer des documents — https://developer.mozilla.org/fr/docs/Learn_web_development/Core/Structuring_content/Structuring_documents ; Création d'hyperliens — https://developer.mozilla.org/fr/docs/Learn_web_development/Core/Structuring_content/Creating_links ; Les images en HTML — https://developer.mozilla.org/fr/docs/Learn_web_development/Core/Structuring_content/HTML_images. نص أصلي من MasterLinux.