HTML وCSS وJavaScript للمبتدئين: بناء صفحة ويب تفاعلية

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

فهم دور كل لغة

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

فصل هذه المسؤوليات مفيد جدًا. فلتغيير ألوان الموقع كله تعدّل ملف CSS فقط دون أن تمس البنية. ولإضافة تفاعل تكتب JavaScript دون أن تغيّر المظهر. وهذا يجعل الكود أسهل قراءة وصيانة على المدى الطويل.

بنية المشروع

أنشئ مجلدًا باسم `interactive-demo` يحتوي على ثلاثة ملفات.

ضع الملفات الثلاثة في المجلد نفسه، حتى تعمل الإشارات داخل HTML دون الحاجة إلى عناوين كاملة.

الخطوة الأولى: بنية HTML

<!DOCTYPE html>
<html lang="ar">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>عدّاد النقاط التفاعلي</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <main class="card">
    <h1>عدّاد النقاط</h1>
    <p id="score-text">النقاط الحالية: <span id="score">0</span></p>
    <div class="buttons">
      <button id="add-btn" type="button">+1 نقطة</button>
      <button id="reset-btn" type="button">إعادة الضبط</button>
    </div>
    <p id="message" aria-live="polite"></p>
  </main>
  <script src="script.js"></script>
</body>
</html>

يحتوي هذا الكود على ثلاث مجموعات مهمة من العناصر: رقم النقاط الذي يحمل `id="score"`، وزران لكل منهما `id` خاص به، وفقرة الرسائل `id="message"` التي تعرض التنبيهات. تخبر الخاصية `aria-live="polite"` قارئات الشاشة بأن تقرأ النص الجديد عند تغيّره، فيحصل من لا يرى الشاشة على المعلومات نفسها التي يحصل عليها غيره.

وضع الوسم `<script>` في نهاية `<body>` يعني أن JavaScript يبدأ العمل بعد تحميل جميع عناصر الصفحة، فيمكنه البحث عنها بواسطة `id` دون أخطاء.

الخطوة الثانية: التنسيق بـ CSS

:root {
  --bg: #f0f4fb;
  --card: #ffffff;
  --accent: #2255aa;
  --text: #1a1a1a;
}

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  color: var(--text);
  font-family: system-ui, sans-serif;
}

.card {
  background: var(--card);
  padding: 32px;
  border-radius: 12px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
  text-align: center;
  width: min(90vw, 360px);
}

.buttons {
  display: flex;
  gap: 12px;
  justify-content: center;
}

button {
  padding: 10px 18px;
  border: none;
  border-radius: 8px;
  background: var(--accent);
  color: #fff;
  font-size: 16px;
  cursor: pointer;
  transition: transform 0.1s ease, opacity 0.2s ease;
}

button:hover {
  opacity: 0.9;
}

button:active {
  transform: scale(0.96);
}

#reset-btn {
  background: #8a94a8;
}

لنقرأ القواعد واحدة تلو الأخرى:

الفرق بين class وid مهم. فالـ class يجمع العناصر ذات التنسيق الواحد، أما الـ id فيحدد عنصرًا بعينه.

الخطوة الثالثة: جعل الصفحة تفاعلية بـ JavaScript

const scoreEl = document.getElementById("score");
const addBtn = document.getElementById("add-btn");
const resetBtn = document.getElementById("reset-btn");
const messageEl = document.getElementById("message");

let score = 0;

function render() {
  scoreEl.textContent = score;
  if (score >= 10) {
    messageEl.textContent = "رائع! وصلت إلى 10 نقاط.";
  } else {
    messageEl.textContent = "";
  }
}

addBtn.addEventListener("click", function () {
  score = score + 1;
  render();
});

resetBtn.addEventListener("click", function () {
  score = 0;
  render();
});

render();

ينقسم هذا الملف إلى أجزاء واضحة.

1. تبحث `document.getElementById` عن العناصر في HTML بواسطة الـ id، وتخزنها في متغيرات. البحث عنها مرة واحدة في البداية يجعل الكود أسرع وأسهل قراءة.

2. يحتفظ `let score = 0` بحالة البرنامج. هذه القيمة هي المصدر الوحيد للحقيقة الذي يستخدمه البرنامج كله.

3. تقرأ الدالة `render` قيمة `score` وتحدّث الشاشة لتطابقها. يُسمى هذا العرض المبني على الحالة. فبدلًا من تعديل النص على الشاشة في كل عملية، نغيّر القيمة ونترك دالة الرسم تحدّث العرض.

4. يربط `addEventListener("click", ...)` دالة بحدث النقر. كلما نقر المستخدم الزر، تُنفَّذ هذه الدالة.

5. يعرض الاستدعاء الأخير `render()` النقاط الابتدائية وهي صفر فور تحميل الصفحة.

جرّب ذلك: كل ضغطة على +1 تزيد الرقم، والوصول إلى 10 يظهر الرسالة، وزر إعادة الضبط يعيد العداد إلى الصفر.

الخطوة الرابعة: جعل الكود أكثر متانة

يعمل المثال، لكن هذه العادات تجعل الكود أقوى.

مثال على التحقق الآمن:

if (!scoreEl) {
  console.error("لم يتم العثور على العنصر #score في HTML");
}

يعرض `console.error` الرسالة في تبويب Console في المتصفح (اضغط F12)، وهذا يساعدك على تحديد المشكلة بسرعة.

CSS أم JavaScript؟ قاعدة بسيطة

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

على سبيل المثال، يمكن تغيير لون الزر عند تمرير المؤشر باستخدام `:hover` في CSS، لكن إحصاء عدد مرات الضغط على الزر يحتاج إلى JavaScript.

تبديل المظهر باستخدام class

لنفترض أنك تريد أن يتغير لون البطاقة عند وصول النقاط إلى 10. بدلًا من كتابة قواعد التنسيق داخل JavaScript، أضف class من JavaScript وعرّف المظهر في CSS.

.card.success {
  background: #e6f7ec;
  border: 2px solid #2e9e5b;
}
const cardEl = document.querySelector(".card");

function render() {
  scoreEl.textContent = score;
  if (score >= 10) {
    messageEl.textContent = "رائع! وصلت إلى 10 نقاط.";
    cardEl.classList.add("success");
  } else {
    messageEl.textContent = "";
    cardEl.classList.remove("success");
  }
}

يحافظ هذا الأسلوب على وضوح المسؤوليات. فـ JavaScript يقول "الحالة الآن ناجحة"، وCSS يقرر شكل النجاح. ويمكنك إعادة تصميم المظهر دون تعديل JavaScript.

مثال إضافي: قائمة تبويبات بسيطة

يوضح هذا المثال تغيير المحتوى عند النقر، وهو نمط شائع في مواقع الويب الحقيقية.

<nav>
  <button class="tab-btn active" data-tab="home">الرئيسية</button>
  <button class="tab-btn" data-tab="about">من أنا</button>
</nav>
<section class="tab-panel active" id="home">مرحبًا بك في موقعي.</section>
<section class="tab-panel" id="about">أنا طالب أتعلم بناء مواقع الويب.</section>
.tab-panel { display: none; }
.tab-panel.active { display: block; }
.tab-btn.active { background: #2255aa; color: #fff; }
const buttons = document.querySelectorAll(".tab-btn");
const panels = document.querySelectorAll(".tab-panel");

buttons.forEach(function (btn) {
  btn.addEventListener("click", function () {
    const target = btn.dataset.tab;
    buttons.forEach(b => b.classList.remove("active"));
    panels.forEach(p => p.classList.remove("active"));
    btn.classList.add("active");
    document.getElementById(target).classList.add("active");
  });
});

تعيد `querySelectorAll` قائمة بكل العناصر المطابقة للمحدد، ويمر `forEach` على القائمة ليربط معالج النقر بكل زر. تقرأ `btn.dataset.tab` قيمة الخاصية `data-tab`، فتكفي دالة واحدة لجميع الأزرار بدلًا من كتابة دالة منفصلة لكل زر.

أخطاء شائعة في JavaScript

نصائح للمبتدئين

طريقة الحفظ والتشغيل

1. أنشئ مجلدًا جديدًا باسم `interactive-demo`.

2. أنشئ الملفات الثلاثة داخل هذا المجلد وهي `index.html` و`style.css` و`script.js`، والصق فيها الكود من كل خطوة.

3. احفظ الملفات بترميز UTF-8. في المفكرة اختر "حفظ باسم" واضبط الترميز على UTF-8، وإلا فقد تظهر الحروف العربية مشوهة.

4. تحقق من أسماء الملفات. في ويندوز فعّل إظهار امتدادات الملفات أولًا، حتى لا تنتهي بملف اسمه `script.js.txt`.

5. انقر نقرًا مزدوجًا على `index.html`، أو اسحبه إلى نافذة المتصفح.

6. إذا كنت تستخدم VS Code فثبّت الإضافة Live Server، ثم انقر بزر الفأرة الأيمن على `index.html` واختر "Open with Live Server". ستُحدَّث الصفحة تلقائيًا في كل مرة تحفظ فيها.

نتائج تشغيل فعلي

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

جرى اختبار مثال قائمة التبويبات في المتصفح أيضًا. بدأت من تبويب الرئيسية، وعند الضغط على "เกี่ยวกับ (من أنا)" ظهرت لوحته وتمييز الزر، وعند الضغط على "หน้าแรก (الرئيسية)" عادت لوحة الرئيسية. كانت الرسائل في هذا الاختبار بالتايلاندية أيضًا، لكن السلوك واحد في أي لغة.

الخطوات التالية

بعد أن تألف هذه اللغات الثلاث، يمكنك استكشاف Flexbox وGrid في CSS للتخطيطات المتقدمة، و`fetch` وJSON لتحميل البيانات من الخادم، وGit لإدارة الكود، وأطر العمل مثل React عندما تكبر المشاريع.

الخلاصة

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