دليل شامل: بناء شريط تقدم تفاعلي وديناميكي باستخدام HTML و CSS وجافاسكريبت
دليل شامل: بناء شريط تقدم تفاعلي وديناميكي باستخدام HTML و CSS وجافاسكريبت
في عالم تطوير الويب المتسارع، تُعد أشرطة التقدم (Progress Bars) عناصر أساسية لتحسين تجربة المستخدم، حيث توفر تغذية بصرية حول حالة عملية معينة. مع تطور تقنيات الويب، أصبحت طرق بناء هذه الأشرطة أكثر كفاءة ومرونة. في هذا المقال، سنستعرض منهجية حديثة لبناء شريط تقدم تفاعلي وديناميكي باستخدام HTML و CSS وجافاسكريبت، مع التركيز على التخلص من التعقيدات السابقة مثل العناصر الزائفة (pseudo-elements) لتقديم كود أنظف وأسهل في القراءة والصيانة.
أهداف شريط التقدم الذي سنبنيه
يهدف هذا الدليل إلى بناء شريط تقدم بسيط وفعال يتميز بالخصائص التالية:
- يتكون من أربع خطوات لإكمال العملية.
- لكل خطوة ثلاث حالات رئيسية:
default(افتراضية)،active(نشطة)، وcomplete(مكتملة). - القدرة على التقدم خطوة بخطوة حتى اكتمال العملية.
يمكنك الاطلاع على مثال حي لهذا الشريط على CodePen.
بناء الهيكل الأساسي باستخدام HTML
لتقليل التكرار وزيادة قابلية إعادة الاستخدام، سنقوم بتتبع جميع حالات شريط التقدم ضمن مكون (component) في إطار عمل Vue.js. يقوم هذا المكون بإنشاء عدد الخطوات المطلوبة ديناميكيًا في نموذج كائن المستند (DOM).
ملاحظة: يمكن تحقيق نفس النتيجة باستخدام جافاسكريبت الأصلية (ECMAScript) أو أي إطار عمل آخر. استخدام Vue.js هنا هو لأغراض توضيحية فقط.
يستخدم شريط التقدم ترميزًا أساسيًا يتضمن:
- حاوية رئيسية (
container) بفئات (classes) محسوبة بناءً على الخطوة الحالية:progressClasses. - مسار خلفي ثابت (
static background track):progress__bg. - حلقة تكرارية (
loop) تمر عبر كل خطوة وتطبق فئاتstepClassesبناءً على الخطوة الحالية.
كل خطوة تتضمن:
- مؤشر تقدم (
progress__indicator) يحتوي على أيقونة علامة صح (check icon) تكون مرئية إذا كانت الخطوة مكتملة. - تسمية تقدم (
progress__label) تحتوي على نص التسمية لتلك الخطوة.
{{step.label}}
Step: {{currentStep ? currentStep.label : "Start"}}
لتبسيط الأمور، تم تضمين عناصر التحكم في الاتجاه (progress__actions) داخل شريط التقدم نفسه.
تطبيق الأنماط باستخدام CSS (SCSS)
هنا يكمن الجزء الأكبر من العمل، حيث سيتم تطبيق الفئات المحددة هنا ديناميكيًا بواسطة جافاسكريبت بناءً على الخطوة الحالية. لنبدأ باختيار بعض الألوان التي سنعمل بها:
$gray: #E5E5E5;
$gray2: #808080;
$blue: #2183DD;
$green: #009900;
$white: #FFFFFF;
تحديد الفئة .progress
هذه الفئة هي الحاوية التي تجمع محتويات شريط التقدم معًا. سيتم تحديد عرضها ديناميكيًا بواسطة جافاسكريبت.
.progress {
position: absolute;
top: 15vh;
width: 0%;
height: 10px;
background-color: $blue;
transition: width .2s;
}
تحديد الفئة .progress__bg
يحتاج شريط التقدم الخاص بنا إلى خلفية (.progress__bg) تعمل كمسار تسير عليه خطوات التقدم. ستكون هذه الخلفية باللون الرمادي، وتُغطى بالشريط الملون كلما تقدمت الخطوات.
.progress__bg {
position: absolute;
width: 100vw;
height: 10px;
background-color: $gray;
z-index: -1;
}
تحديد الفئة .progress__step
تحتوي كل فئة .progress__step على الدائرة التي تمثل الخطوة والتي ستضيء وتمتلئ باللون كلما تقدم شريط التقدم.
.progress__step {
position: absolute;
top: -8px;
left: 0;
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
@for $i from 1 through 5 {
&.progress__step--#{$i} {
left: calc(#{$i * 20}vw - 9px);
}
}
}
كما تحتوي هذه الفئة على المؤشر الدائري .progress__indicator ونص التسمية .progress__label. يتم تعريف أنماطها الافتراضية خارج الفئة .progress__step.
.progress__indicator {
width: 25px;
height: 25px;
border: 2px solid $gray2;
border-radius: 50%;
background-color: $white;
margin-bottom: 10px;
.fa {
display: none;
font-size: 16px;
color: $white;
}
}
.progress__label {
position: absolute;
top: 40px;
}
تحديد حالة الخطوة النشطة (active state)
الآن، لنستمر في التضمين داخل .progress__step مرة أخرى ونحدد الخطوة في حالتها النشطة.
&.progress__step--active {
color: $blue;
font-weight: 600;
}
تحديد حالة الخطوة المكتملة (complete state)
بعد ذلك، نحدد الخطوة في حالتها المكتملة. ملاحظة: يتم تجاوز الأنماط الافتراضية لكل من .progress__indicator و .progress__label عندما تكون الخطوة في حالة الاكتمال.
&.progress__step--complete {
.progress__indicator {
background-color: $green;
border-color: $blue;
color: $white;
display: flex;
align-items: center;
justify-content: center;
}
.progress__indicator .fa {
display: block;
}
.progress__label {
font-weight: 600;
color: $green;
}
}
إضافة الديناميكية باستخدام JavaScript
كما ذكرنا سابقًا، ستختلف طريقة تطبيق منطق الخطوات بناءً على السياق الأوسع الذي يتم فيه التنفيذ، وإطارات العمل والأنماط التي تستخدمها، وما إلى ذلك. يستخدم هذا المثال مكون Vue.js لتوضيح:
- حساب الفئات لشريط التقدم بناءً على الحالة الحالية.
- حساب الفئات لكل خطوة بناءً على الحالة الحالية.
var app = new Vue({
el: '#app',
data: {
currentStep: null,
steps: [
{"label": "one"},
{"label": "two"},
{"label": "three"},
{"label": "complete"}
]
},
methods: {
nextStep(next=true) {
const steps = this.steps;
const currentStep = this.currentStep;
const currentIndex = steps.indexOf(currentStep);
// handle back
if (!next) {
if (currentStep && currentStep.label === 'complete') {
return this.currentStep = steps[steps.length - 1];
}
if (steps[currentIndex - 1]) {
return this.currentStep = steps[currentIndex - 1];
}
return this.currentStep = { "label": "start" };
}
// handle next
if (this.currentStep && this.currentStep.label === 'complete') {
return this.currentStep = { "label": "start" };
}
if (steps[currentIndex + 1]) {
return this.currentStep = steps[currentIndex + 1];
}
this.currentStep = { "label": "complete" };
},
stepClasses(index) {
let result = `progress__step progress__step--${index + 1}`;
if (this.currentStep && this.currentStep.label === 'complete' || index < this.steps.indexOf(this.currentStep)) {
return result += ' progress step--complete';
}
if (index === this.steps.indexOf(this.currentStep)) {
return result += ' progress step--active';
}
return result;
}
},
computed: {
progressClasses() {
let result = 'progress ';
if (this.currentStep && this.currentStep.label === 'complete') {
return result += 'progress--complete';
}
return result += `progress--${this.steps.indexOf(this.currentStep) + 1}`;
}
}
});
الخلاصة التقنية
في نهاية هذا الدليل، نكون قد نجحنا في بناء شريط تقدم ديناميكي وتفاعلي بالكامل، يوضح التحولات بين الحالات المختلفة للخطوات بسلاسة. تمثل هذه الطريقة تحسينًا كبيرًا عن الأساليب السابقة، حيث توفر كودًا أنظف وأكثر قابلية للصيانة بفضل الاستغناء عن العناصر الزائفة والاعتماد على إدارة الحالة الفعالة. هذا النهج لا يعزز فقط من جمالية واجهة المستخدم، بل يساهم أيضًا في تحسين أداء التطبيق وسهولة تطويره وتعديله في المستقبل. إن القدرة على تتبع الحالة وتحديث الواجهة ديناميكيًا تجعل هذا النمط مثاليًا لمجموعة واسعة من التطبيقات التي تتطلب تفاعلًا مرئيًا مع تقدم المهام.
النتيجة النهائية ستكون كالتالي:

يمكنك مراجعة المثال الحي على CodePen لفهم أعمق لكيفية عمله.