Emmet: ID و Class

قدم الدرس 03 .class و #id بشكل موجز. يغطي هذا الدرس بشكل منهجي عاملي الاختصار "بأسلوب محدد CSS" هذين—إنهما يسمحان لاختصارات Emmet بـ التعبير عن الهيكل والسمات معًا. القاعدة الأكثر أهمية: حذف اسم الوسم في سياق HTML يكون افتراضيًا div، و Emmet لن "يخمن" عنصرًا مختلفًا بناءً على اسم الفئة (حتى لو كانت الفئة btn، لن تصبح <button>).

1. ما ستتعلمه


2. قصة حقيقية لمطور واجهة أمامية

(1) نقطة الألم: الوسوم والسمات دائمًا تحتاج إلى مرحلتين منفصلتين

كانت أليس تقوم بترقية تنسيق نموذج تسجيل دخول. احتاجت إلى إضافة class="btn btn-primary btn-lg" لكل <button> و id="loginForm" مع class="form-horizontal" للنموذج نفسه. يدويًا، كل وسم يتطلب كتابة الهيكل الكامل:

HTML
<button class="btn btn-primary btn-lg">Login</button>
<input id="username" class="form-control" type="text" name="user">

كل وسم يكرر اسم الوسم زائد السمات، وترتيب الوسوم والسمات يعتمد على الذاكرة. حسبت: نموذج تسجيل دخول من 8 أسطر يتطلب كتابة يدوية لـ 8 وسوم + 24 اسم سمة = 32 مقطع نصي متكرر. مجرد كتابة علامات الاقتباس وعلامات المساواة للسمات كان يجعل أصابعها تؤلمها.

الأسوأ: تذكرت مشروعًا سابقًا حيث افترضت خطأ أن .btn ستشغل تلقائيًا وسم <button>—سوء فهم أرسلها في رحلة استكشاف أخطاء. قاعدة الوسم الضمني في Emmet قطعًا لا تبدل أسماء الوسوم بناءً على أسماء الفئات.

(2) كيف يحلها اختصار .class و #id

يستخدم Emmet نفس الصيغة تمامًا مثل محددات CSS للتعبير عن السمات—.btn تضيف مباشرة إلى سمة الفئة للوسم الحالي، و #loginForm تضيف إلى سمة id. هذه الصيغة تتيح لك كتابة السمات في نفس وقت كتابة هيكل الوسم، دون التبديل بين "وضع الوسم" و "وضع السمة."

أعادت أليس كتابة نموذج تسجيل الدخول بالكامل بسطر Emmet واحد:

TEXT 📖 للعرض فقط
form#loginForm.form-horizontal>(input#username.form-control[type=text name=user])+(input#pwd.form-control[type=password name=pwd])+(button.btn.btn-primary.btn-lg{Login})

#loginForm.form-horizontal يعين كلًا من id و class في آن واحد. .btn.btn-primary.btn-lg يسلسل ثلاث فئات بـ . دفعة واحدة. 8 وسوم + 24 سمة، تمت معالجتها في سطر واحد. من 32 مقطع نصي متكرر إلى سطر واحد، من 5 دقائق إلى 12 ثانية.

(3) الفوائد

.class و #id هما العاملان الرئيسيان اللذان يدمجان "الهيكل" و "السمات" في واحد في Emmet. بعد هذا الدرس، تستطيع أليس كتابة سمات 80% من وسومها في آن واحد؛ صيغة الفئات المتعددة مطابقة لـ CSS، مع منحنى تعلم شبه معدوم؛ وتذكر قاعدة "حذف اسم الوسم → div" الضمنية (حتى لو كانت الفئة btn، تبقى div) يمنع اختصاراتها من أن تضلل بأسماء الفئات.


3. .class: سمة الفئة بأسلوب محدد CSS

.classname في Emmet مكافئ لإضافة class="classname" للوسم الحالي. عندما لا يُحدد وسم (قاعدة الدرس 03 الضمنية)، يكون افتراضيًا div.

الاختصار التوسيع ملاحظات
.box <div class="box"></div> div ضمني
p.text <p class="text"></p> p صريح
section.hero <section class="hero"></section> section صريح
a.link <a href="" class="link"></a> a صريح، a يضيف href تلقائيًا

نصيحة: الفئات المتعددة تتسلسل بـ . مع عدم وجود مسافات بين أسماء الفئات.btn.btn-primary تعني فئتين: btn و btn-primary. المسافات في Emmet هي رموز إيقاف؛ يتم تحليلها كاختصارات مستقلة متعددة.


4. #id: سمة id بأسلوب محدد CSS

#idname في Emmet مكافئ لإضافة id="idname" للوسم الحالي. الاستخدام متناظر تمامًا مع .class ويقابل محدد id في CSS (#id).

الاختصار التوسيع
#main <div id="main"></div>
header#top <header id="top"></header>
form#login <form id="login"></form>
div#app <div id="app"></div>

(1) يمكن خلط id و class

#id و .class على نفس الوسم ليس لهما متطلب ترتيب ويمكن دمجهما بحرية:

الاختصار التوسيع
#main.container <div id="main" class="container"></div>
.container#main <div class="container" id="main"></div>
header#top.nav <header id="top" class="nav"></header>
nav.main.dark <nav class="main dark"></nav>

نقطة أساسية: #id و .class في Emmet يأتيان من صيغة محدد CSS، لكن الدلالات معكوسة—CSS يستخدم # و . لتحديد العناصر الموجودة، بينما Emmet يستخدم # و . لتوليد عناصر بهذه السمات. نفس الصيغة، غرض معاكس.


5. أمثلة عملية

تغطي الأمثلة الخمسة التالية جميع السيناريوهات الأساسية لـ .class و #id—من فئة مفردة أساسية، إلى فئات متعددة، إلى سلاسل سمات في هياكل متداخلة.

▶ مثال: فئة مفردة .container (الصعوبة ★)

أبسط اختصار فئة: احذف اسم الوسم ويكون افتراضيًا div.

الاختصار:

HTML
.container

التوسيع:

HTML
<div class="container"></div>

الناتج:

TEXT 📖 للعرض فقط
وسم div ضمني + فئة واحدة. هذا الاختصار شائع للغاية في أطر عمل الفئات المساعدة مثل Bootstrap و Tailwind. .container في Bootstrap هو حاوية عرض ثابت؛ في Tailwind هو أداة max-width. ملاحظة: عندما تكتب .container داخل أصل ul، .container لا يزال يصبح ضمنيًا div—إلا إذا كان موضع اختصارك يتطلب حقًا li ابنًا لـ ul، .container لن يتحول تلقائيًا إلى عنصر دلالي مثل li (قواعد الدرس 06 الضمنية).

▶ مثال: id مفرد #main (الصعوبة ★)

أبسط اختصار id.

الاختصار:

HTML
#main

التوسيع:

HTML
<div id="main"></div>

الناتج:

TEXT 📖 للعرض فقط
div فارغ مع id="main". في HTML، يجب أن تكون ids فريدة عالميًا، لذا يستخدم هذا الاختصار غالبًا لـ "حاوية الصفحة الرئيسية" أو "نقطة تثبيت المسار." ملاحظة: Emmet لا يتحقق من تفرد id—عدة اختصارات #main كلها تتوسع إلى id="main"؛ سواء كان ذلك يسبب تعارضًا أم لا متروك لك للتحقق يدويًا.

▶ مثال: سلسلة فئات متعددة .btn.btn-primary.btn-lg (الصعوبة ★★)

تسلسل فئات متعددة بـ .—ملاحظة: الافتراضي لا يزال <div>؛ لن يصبح <button> فقط لأن اسم الفئة يحتوي على "btn."

الاختصار:

HTML
.btn.btn-primary.btn-lg

التوسيع:

HTML
<div class="btn btn-primary btn-lg"></div>

الناتج:

TEXT 📖 للعرض فقط
هذا هو الاختصار الذي يسيء المبتدئون فهمه أكثر: لأن اسم الفئة هو `btn`، يفترض الكثيرون أن Emmet سيتعرف على `.btn` كـ `<button>`. لكن قواعد Emmet الضمنية لا تعتمد على قيم class/id—تعتمد فقط على سياق العنصر الأصلي (انظر الدرس 06). عندما لا يكون هناك سياق أصلي ولا وسم صريح، Emmet دائمًا يكون افتراضيًا `div`. للحصول على `<button class="btn btn-primary btn-lg">`، يجب أن تكتب بشكل صريح `button.btn.btn-primary.btn-lg` أو `button.btn.btn-primary.btn-lg{Login}` (مع محتوى نصي، الدرس 09). تحقق بنفسك: اكتب `.btn` في محررك واضغط Tab لترى ما إذا كان يتوسع إلى `div` أو `button`.

▶ مثال: تركيبة id + class #header.nav (الصعوبة ★)

خلط #id و .class—الترتيب لا يؤثر على نتيجة التوسيع.

الاختصار:

HTML
#header.nav

التوسيع:

HTML
<div id="header" class="nav"></div>

الناتج:

TEXT 📖 للعرض فقط
يعين كلًا من id="header" و class="nav" مرة واحدة. هذا هو الاختصار الكلاسيكي لتنقل رأس الصفحة. يمكن تبديل ترتيب id و class (.nav#header ينتج نفس النتيجة)، لكن كتابة id أولاً تتوافق مع العادة الدلالية "تأسيس هوية فريدة، ثم وصف النوع." هذا الاختصار مهم في التطبيقات متعددة الصفحات—id #header يبقى نفسه عبر الصفحات، لذا يمكن لـ CSS استهدافه بشكل موحد.

▶ مثال: سلسلة سمات متداخلة div#main.container>section.content>p.text (الصعوبة ★★)

توزيع id و class عبر كل مستوى من التداخل—3 مستويات م�� الوسوم، لكل منها سماته الخاصة.

الاختصار:

HTML
div#main.container>section.content>p.text

التوسيع:

HTML
<div id="main" class="container">
  <section class="content">
    <p class="text"></p>
  </section>
</div>

الناتج:

TEXT 📖 للعرض فقط
التفصيل: div يحمل id="main" و class="container"، ينزل مستوى واحدًا إلى section (مع class="content")، ثم ينزل إلى p (مع class="text"). كل مستوى يعين سماته الخاصة عبر #id أو .class. هذا هو استخدام Emmet النموذجي لـ "هيكل قائم على المكونات"—كل مستوى يمثل حاوية أو مكونًا واضحًا دلاليًا. إذا أردت فقط تعيين سمات على مستوى واحد (تاركًا البقية فارغة)، ببساطة احذف #/. من تلك المستويات—مثل div>section>p هو فقط 3 مستويات تداخل فارغة.

6. مثال كامل: نموذج تسجيل دخول + سلسلة سمات

ادمج .class و #id مع عاملي > و + من الدروس السابقة لبناء نموذج تسجيل دخول كامل في سطر واحد.

▶ مثال: نموذج تسجيل دخول كامل (الصعوبة ★★)

الاختصار:

HTML
form#loginForm.form-horizontal>(input#user.form-control[type=text name=user placeholder="Username"])+(input#pwd.form-control[type=password name=pwd placeholder="Password"])+(button.btn.btn-primary.btn-lg{Login})

التوسيع:

HTML
<form id="loginForm" class="form-horizontal">
  <input id="user" class="form-control" type="text" name="user" placeholder="Username">
  <input id="pwd" class="form-control" type="password" name="pwd" placeholder="Password">
  <button class="btn btn-primary btn-lg">Login</button>
</form>

الناتج:

TEXT 📖 للعرض فقط
التفصيل: form يحصل على كل من id و class. داخله، + يضيف inputين أخوين، ثم + يضيف button. كل من inputs و buttons يحصلون على فئات تنسيق عبر .class، و inputs بالإضافة إلى ذلك يستخدمون #id (اختياري) و [type=name=placeholder=] (مغطى في الدرس التالي) للسمات. لاحظ أن مستوى button يكتب بشكل صريح `<button>`، لذا .btn.btn-primary.btn-lg تصبح فئة على button بدلاً من div ضمني. هذا هو النمط القياسي لـ "استخدام الوسوم الصريحة لتجنب سوء التقدير."

❓ أسئلة شائعة

س هل .btn.btn-primary يتوسع إلى <button> أم <div>؟ لماذا؟
ج <div>. قواعد الوسم الضمني في Emmet تعتمد فقط على سياق العنصر الأصلي، وليس على القيمة الحرفية لأسماء class/id. ما لم تكتب button.btn.btn-primary بشكل صريح، الافتراضي عندما لا يكون هناك وسم صريح هو دائمًا div. هذا هو الفخ الأكثر شيوعًا للمبتدئين—يفترض الكثيرون أن .btn يجب أن يتحول إلى button، ثم يعتقدون أن توسيع div هو خطأ.
س هل الشرطات في #my-id تحتاج إلى تهريب؟
ج لا. الشرطات في #my-id و .my-class هي رموز محدد CSS صالحة؛ يعاملها Emmet كجزء من اسم id/class. ومع ذلك، الشرطة الابتدائية (مثل #-main) ليست صيغة CSS صالحة وقد يرمي Emmet خطأ أو يحلل بشكل غير متوقع.
س كم مرة يمكن خلط # و . على نفس الوسم؟
ج نظريًا غير محدود. #a.b.c.d.e.f.g صالح تمامًا ويتوسع إلى <div id="a" class="b c d e f g"></div>. عمليًا، يجب أن تكون ids فريدة ومحدودة العدد، والعديد جدًا من الفئات يجعل إدارة الأنماط أصعب. توصية: 1 id + 2–4 فئات هو "حد أعلى معقول" شائع.
س ما الفرق بين #header و .header بعد التوسيع؟
ج .header<div class="header"></div> (class هو "لنوع" قابل لإعادة الاستخدام)؛ #header<div id="header"></div> (id هو "للهوية الفريدة"). على مستوى محدد CSS: .header يمكنه مطابقة عناصر متعددة، #header يمكنه مطابقة عنصر واحد فقط. على المستوى الدلالي لـ HTML: class تستخدم نموذجيًا لـ "نوع المكون" (زر، بطاقة، نموذج)، بينما id تستخدم نموذجيًا لـ "مرساة صفحة أو خطاف JS."

📖 ملخص


📝 تمارين

  1. أساسي (الصعوبة ★): اكتب 5 اختصارات Emmet تتوسع إلى: (أ) .alert؛ (ب) #app؛ (ج) .btn.btn-danger؛ (د) #header.nav.dark؛ (هـ) a.btn.
  2. متوسط (الصعوبة ★★): حلل هيكل التوسيع لـ header#top.navbar>nav.main>ul.nav-list>li.nav-item*3>a.nav-link (سمِّ كل وسم وسمة في كل مست��ى)، وتحقق من أن توسيع Emmet يطابق تحليلك.
  3. متقدم (الصعوبة ★★★): اكتب "شبكة بطاقات" كاملة بأسلوب Bootstrap: خارجي div.container، يحتوي على div.row، الذي يحتوي على 3 عناصر .card. كل بطاقة ت��ضمن img.card-img-top، div.card-body، h5.card-title، p.card-text، و a.btn.btn-primary. اكتب الهيكل بالكامل في سطر Emmet واحد، واشرح لماذا .btn.btn-primary هنا تصبح تلقائيًا <a> بدلاً من div ضمني (تلميح: هل هناك وسم صريح في الاختصار؟).
Web-Tutorial.com

فريق Web-Tutorial التقني

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

100%