بناء مكتبة مكونات باستخدام SASS
بناء مكتبة مكونات باستخدام SASS
مكتبة المكونات هي مجموعة من عناصر واجهة المستخدم القابلة لإعادة الاستخدام مع أنماط وسلوك ووثائق متسقة. بناء مكتبة مكونات خاصة بك باستخدام SASS يسمح لك بإنشاء نظام تصميم موحد يمتد عبر تطبيقك بالكامل. في هذا الدرس الشامل، سنستكشف كيفية تصميم وبناء وتنفيذ مكتبة مكونات احترافية باستخدام ميزات SASS المتقدمة.
البنية القائمة على المكونات
البنية القائمة على المكونات هي نهج تصميم حيث يتم تقسيم واجهة المستخدم إلى أجزاء مستقلة قابلة لإعادة الاستخدام. كل مكون يغلف أنماطه وبنيته وأحياناً سلوكه الخاص.
فوائد التصميم القائم على المكونات
- إعادة الاستخدام: اكتب مرة واحدة، استخدم في كل مكان عبر تطبيقك
- الاتساق: يضمن الاتساق البصري والوظيفي عبر الصفحات
- سهولة الصيانة: التغييرات على المكون تطبق تلقائياً في كل مكان يستخدم فيه
- قابلية التوسع: سهل التوسيع بمتغيرات وحالات جديدة
- التعاون: يمكن للفرق العمل على مكونات مختلفة بشكل مستقل
- الاختبار: المكونات المعزولة أسهل في الاختبار
- التوثيق: المكونات تعمل كتوثيق حي
هيكل مكتبة المكونات
دعونا ننشئ بنية ملفات واضحة لمكتبة المكونات الخاصة بنا:
بنية ملفات مكتبة المكونات
scss/
├── abstracts/
│ ├── _variables.scss // رموز التصميم
│ ├── _mixins.scss // Mixins للمكونات
│ └── _functions.scss // دوال مساعدة
├── base/
│ ├── _reset.scss // إعادة تعيين CSS
│ └── _typography.scss // الطباعة الأساسية
├── components/
│ ├── _buttons.scss // مكونات الأزرار
│ ├── _cards.scss // مكونات البطاقات
│ ├── _forms.scss // مكونات النماذج
│ ├── _alerts.scss // مكونات التنبيهات
│ ├── _modals.scss // مكونات النوافذ المنبثقة
│ ├── _navs.scss // مكونات التنقل
│ └── _badges.scss // مكونات الشارات
└── main.scss // ملف الاستيراد الرئيسي
رموز التصميم (المتغيرات)
رموز التصميم هي أساس مكتبة المكونات الخاصة بك. إنها تحدد الألوان والمسافات والطباعة وقرارات التصميم الأخرى:
تكوين رموز التصميم
// abstracts/_variables.scss
// نظام الألوان
$primary: #007bff;
$secondary: #6c757d;
$success: #28a745;
$danger: #dc3545;
$warning: #ffc107;
$info: #17a2b8;
$light: #f8f9fa;
$dark: #343a40;
// متغيرات الألوان (درجات أفتح/أغمق)
$primary-light: lighten($primary, 10%);
$primary-dark: darken($primary, 10%);
$primary-lightest: lighten($primary, 30%);
// مقياس المسافات
$spacer: 1rem;
$spacers: (
0: 0,
1: $spacer * 0.25, // 4px
2: $spacer * 0.5, // 8px
3: $spacer, // 16px
4: $spacer * 1.5, // 24px
5: $spacer * 3, // 48px
);
// مقياس الطباعة
$font-family-base: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, monospace;
$font-size-base: 1rem;
$font-sizes: (
xs: $font-size-base * 0.75, // 12px
sm: $font-size-base * 0.875, // 14px
md: $font-size-base, // 16px
lg: $font-size-base * 1.25, // 20px
xl: $font-size-base * 1.5, // 24px
);
// نصف قطر الحدود
$border-radius: 0.25rem;
$border-radius-sm: 0.2rem;
$border-radius-lg: 0.3rem;
$border-radius-pill: 50rem;
// الظلال
$shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
$shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
$shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
// التحولات
$transition-base: all 0.2s ease-in-out;
$transition-fast: all 0.1s ease-in-out;
$transition-slow: all 0.3s ease-in-out;
بناء مكونات الأزرار
الأزرار هي واحدة من أكثر المكونات الأساسية. دعونا نبني نظام أزرار شامل:
أنماط الأزرار الأساسية
// components/_buttons.scss
// أنماط الأزرار الأساسية
.btn {
display: inline-block;
font-family: $font-family-base;
font-weight: 400;
text-align: center;
white-space: nowrap;
vertical-align: middle;
user-select: none;
border: 1px solid transparent;
padding: 0.375rem 0.75rem;
font-size: $font-size-base;
line-height: 1.5;
border-radius: $border-radius;
transition: $transition-base;
cursor: pointer;
text-decoration: none;
&:hover {
text-decoration: none;
}
&:focus {
outline: 0;
box-shadow: 0 0 0 0.2rem rgba($primary, 0.25);
}
&:disabled,
&.disabled {
opacity: 0.65;
cursor: not-allowed;
pointer-events: none;
}
}
متغيرات الأزرار باستخدام الخرائط
بدلاً من كتابة كل متغير زر يدوياً، نستخدم خرائط SASS لتوليدها تلقائياً:
مولد متغيرات الأزرار
// خريطة ألوان الأزرار
$button-colors: (
"primary": $primary,
"secondary": $secondary,
"success": $success,
"danger": $danger,
"warning": $warning,
"info": $info,
"light": $light,
"dark": $dark
);
// Mixin لتوليد متغيرات الأزرار
@mixin button-variant($background, $border: $background) {
background-color: $background;
border-color: $border;
color: color-contrast($background);
&:hover {
background-color: darken($background, 7.5%);
border-color: darken($border, 10%);
}
&:focus,
&.focus {
box-shadow: 0 0 0 0.2rem rgba($background, 0.5);
}
&:active,
&.active {
background-color: darken($background, 10%);
border-color: darken($border, 12.5%);
}
}
// توليد متغيرات الأزرار
@each $name, $color in $button-colors {
.btn-#{$name} {
@include button-variant($color);
}
}
// هذا يولد:
// .btn-primary, .btn-secondary, .btn-success, إلخ.
أحجام الأزرار
متغيرات أحجام الأزرار
// أحجام الأزرار باستخدام الخريطة
$button-sizes: (
"sm": (
padding: 0.25rem 0.5rem,
font-size: map-get($font-sizes, sm),
border-radius: $border-radius-sm
),
"md": (
padding: 0.375rem 0.75rem,
font-size: $font-size-base,
border-radius: $border-radius
),
"lg": (
padding: 0.5rem 1rem,
font-size: map-get($font-sizes, lg),
border-radius: $border-radius-lg
)
);
// توليد فئات الأحجام
@each $size, $properties in $button-sizes {
.btn-#{$size} {
padding: map-get($properties, padding);
font-size: map-get($properties, font-size);
border-radius: map-get($properties, border-radius);
}
}
متغيرات أزرار الخطوط والظلال
أنماط الأزرار المخططة
// Mixin للأزرار المخططة
@mixin button-outline-variant($color) {
color: $color;
background-color: transparent;
border-color: $color;
&:hover {
color: color-contrast($color);
background-color: $color;
border-color: $color;
}
&:focus,
&.focus {
box-shadow: 0 0 0 0.2rem rgba($color, 0.5);
}
}
// توليد المتغيرات المخططة
@each $name, $color in $button-colors {
.btn-outline-#{$name} {
@include button-outline-variant($color);
}
}
// زر كتلة (بعرض كامل)
.btn-block {
display: block;
width: 100%;
+ .btn-block {
margin-top: 0.5rem;
}
}
بناء مكونات البطاقات
البطاقات هي حاويات محتوى متعددة الاستخدامات. دعونا نبني نظام مكونات بطاقات مرن:
بنية مكون البطاقة
// components/_cards.scss
.card {
position: relative;
display: flex;
flex-direction: column;
min-width: 0;
word-wrap: break-word;
background-color: #fff;
background-clip: border-box;
border: 1px solid rgba(0, 0, 0, 0.125);
border-radius: $border-radius;
box-shadow: $shadow-sm;
// رأس البطاقة
&__header {
padding: 0.75rem 1.25rem;
margin-bottom: 0;
background-color: rgba(0, 0, 0, 0.03);
border-bottom: 1px solid rgba(0, 0, 0, 0.125);
border-radius: $border-radius $border-radius 0 0;
&:first-child {
border-radius: $border-radius $border-radius 0 0;
}
}
// جسم البطاقة
&__body {
flex: 1 1 auto;
padding: 1.25rem;
}
// عنوان البطاقة
&__title {
margin-bottom: 0.75rem;
font-size: 1.25rem;
font-weight: 500;
}
// عنوان فرعي للبطاقة
&__subtitle {
margin-top: -0.375rem;
margin-bottom: 0;
color: #6c757d;
}
// نص البطاقة
&__text {
&:last-child {
margin-bottom: 0;
}
}
// تذييل البطاقة
&__footer {
padding: 0.75rem 1.25rem;
background-color: rgba(0, 0, 0, 0.03);
border-top: 1px solid rgba(0, 0, 0, 0.125);
&:last-child {
border-radius: 0 0 $border-radius $border-radius;
}
}
// صورة البطاقة
&__img {
width: 100%;
border-radius: $border-radius $border-radius 0 0;
&--bottom {
border-radius: 0 0 $border-radius $border-radius;
}
}
// تراكب صورة البطاقة
&__img-overlay {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: 1.25rem;
border-radius: $border-radius;
}
}
متغيرات ومُعدلات البطاقات
متغيرات ألوان البطاقات
// متغيرات ألوان البطاقات
@each $name, $color in $button-colors {
.card-#{$name} {
background-color: $color;
border-color: $color;
color: color-contrast($color);
.card__header,
.card__footer {
background-color: darken($color, 5%);
border-color: darken($color, 10%);
}
}
}
// تخطيط بطاقة أفقي
.card-horizontal {
flex-direction: row;
.card__img {
border-radius: $border-radius 0 0 $border-radius;
max-width: 40%;
object-fit: cover;
}
}
// مجموعات البطاقات
.card-group {
display: flex;
flex-flow: row wrap;
.card {
flex: 1 0 0%;
+ .card {
margin-left: 0;
border-left: 0;
}
&:first-child {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
&:last-child {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
}
بناء مكونات النماذج
النماذج حيوية لتفاعل المستخدم. دعونا ننشئ نظام مكونات نماذج شامل:
أنماط أساسية لإدخال النماذج
// components/_forms.scss
// حاوية مجموعة النماذج
.form-group {
margin-bottom: 1rem;
}
// التسميات
.form-label {
display: inline-block;
margin-bottom: 0.5rem;
font-weight: 500;
}
// أنماط الإدخال الأساسية
.form-control {
display: block;
width: 100%;
padding: 0.375rem 0.75rem;
font-size: $font-size-base;
font-weight: 400;
line-height: 1.5;
color: #495057;
background-color: #fff;
background-clip: padding-box;
border: 1px solid #ced4da;
border-radius: $border-radius;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
&:focus {
color: #495057;
background-color: #fff;
border-color: lighten($primary, 25%);
outline: 0;
box-shadow: 0 0 0 0.2rem rgba($primary, 0.25);
}
&::placeholder {
color: #6c757d;
opacity: 1;
}
&:disabled,
&[readonly] {
background-color: #e9ecef;
opacity: 1;
}
}
// منطقة النص
textarea.form-control {
height: auto;
resize: vertical;
}
أحجام وحالات النماذج
أحجام الإدخال وحالات التحقق
// أحجام الإدخال
.form-control-sm {
padding: 0.25rem 0.5rem;
font-size: map-get($font-sizes, sm);
border-radius: $border-radius-sm;
}
.form-control-lg {
padding: 0.5rem 1rem;
font-size: map-get($font-sizes, lg);
border-radius: $border-radius-lg;
}
// حالات التحقق
$form-feedback-colors: (
"valid": $success,
"invalid": $danger
);
@each $state, $color in $form-feedback-colors {
.form-control.is-#{$state} {
border-color: $color;
&:focus {
border-color: $color;
box-shadow: 0 0 0 0.2rem rgba($color, 0.25);
}
}
.#{$state}-feedback {
display: none;
width: 100%;
margin-top: 0.25rem;
font-size: 0.875rem;
color: $color;
}
.form-control.is-#{$state} ~ .#{$state}-feedback {
display: block;
}
}
صناديق الاختيار والأزرار الدائرية المخصصة
عناصر تحكم نماذج مخصصة
// صندوق اختيار مخصص
.custom-checkbox {
position: relative;
display: block;
padding-left: 1.5rem;
input[type="checkbox"] {
position: absolute;
left: 0;
opacity: 0;
&:checked ~ .custom-checkbox__label::before {
background-color: $primary;
border-color: $primary;
}
&:checked ~ .custom-checkbox__label::after {
opacity: 1;
}
&:focus ~ .custom-checkbox__label::before {
box-shadow: 0 0 0 0.2rem rgba($primary, 0.25);
}
&:disabled ~ .custom-checkbox__label {
color: #6c757d;
cursor: not-allowed;
&::before {
background-color: #e9ecef;
}
}
}
&__label {
position: relative;
margin-bottom: 0;
cursor: pointer;
&::before {
content: "";
position: absolute;
left: -1.5rem;
display: block;
width: 1rem;
height: 1rem;
pointer-events: none;
background-color: #fff;
border: 1px solid #adb5bd;
border-radius: $border-radius-sm;
transition: $transition-base;
}
&::after {
content: "";
position: absolute;
left: -1.5rem;
top: 0.25rem;
display: block;
width: 1rem;
height: 1rem;
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%23fff' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: center;
background-size: 50% 50%;
opacity: 0;
transition: opacity 0.1s ease-in-out;
}
}
}
// زر دائري مخصص
.custom-radio {
@extend .custom-checkbox;
.custom-radio__label {
&::before {
border-radius: 50%;
}
&::after {
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e");
}
}
}
بناء مكونات التنبيهات
نظام مكونات التنبيهات
// components/_alerts.scss
.alert {
position: relative;
padding: 0.75rem 1.25rem;
margin-bottom: 1rem;
border: 1px solid transparent;
border-radius: $border-radius;
// عنوان التنبيه
&__heading {
color: inherit;
margin-bottom: 0.5rem;
font-weight: 500;
}
// رابط التنبيه
&__link {
font-weight: 700;
}
// تنبيه قابل للإغلاق
&--dismissible {
padding-right: 4rem;
.alert__close {
position: absolute;
top: 0;
right: 0;
padding: 0.75rem 1.25rem;
color: inherit;
background-color: transparent;
border: 0;
cursor: pointer;
opacity: 0.5;
&:hover {
opacity: 0.75;
}
}
}
}
// متغيرات التنبيهات
@mixin alert-variant($background, $border, $color) {
color: $color;
background-color: $background;
border-color: $border;
.alert__link {
color: darken($color, 10%);
}
}
$alert-colors: (
"primary": ($primary-lightest, $primary-light, $primary-dark),
"success": (lighten($success, 40%), lighten($success, 30%), darken($success, 10%)),
"danger": (lighten($danger, 40%), lighten($danger, 30%), darken($danger, 10%)),
"warning": (lighten($warning, 35%), lighten($warning, 25%), darken($warning, 10%)),
"info": (lighten($info, 40%), lighten($info, 30%), darken($info, 10%))
);
@each $name, $colors in $alert-colors {
.alert-#{$name} {
@include alert-variant(nth($colors, 1), nth($colors, 2), nth($colors, 3));
}
}
المسافات والأحجام المتسقة
للحفاظ على الاتساق عبر جميع المكونات، حدد أدوات المسافات والأحجام:
مولد أدوات المسافات
// توليد أدوات المسافات (الهامش والحشو)
$properties: (
"m": "margin",
"p": "padding"
);
$directions: (
"t": "top",
"r": "right",
"b": "bottom",
"l": "left"
);
@each $prop-abbr, $prop in $properties {
@each $size-name, $size-value in $spacers {
// جميع الجوانب: .m-1, .p-2, إلخ.
.#{$prop-abbr}-#{$size-name} {
#{$prop}: $size-value !important;
}
// جوانب فردية: .mt-1, .pr-2, إلخ.
@each $dir-abbr, $dir in $directions {
.#{$prop-abbr}#{$dir-abbr}-#{$size-name} {
#{$prop}-#{$dir}: $size-value !important;
}
}
// أفقي: .mx-1, .px-2, إلخ.
.#{$prop-abbr}x-#{$size-name} {
#{$prop}-left: $size-value !important;
#{$prop}-right: $size-value !important;
}
// عمودي: .my-1, .py-2, إلخ.
.#{$prop-abbr}y-#{$size-name} {
#{$prop}-top: $size-value !important;
#{$prop}-bottom: $size-value !important;
}
}
}
تنظيم ملفات المكونات
ملف استيراد SCSS الرئيسي
// main.scss - نقطة الدخول لمكتبة المكونات
// 1. التجريدات (بدون ناتج CSS)
@use "abstracts/variables" as *;
@use "abstracts/functions" as *;
@use "abstracts/mixins" as *;
// 2. أنماط أساسية
@use "base/reset";
@use "base/typography";
// 3. المكونات (مرتبة أبجدياً)
@use "components/alerts";
@use "components/badges";
@use "components/buttons";
@use "components/cards";
@use "components/forms";
@use "components/modals";
@use "components/navs";
// 4. الأدوات
@use "utilities/spacing";
@use "utilities/display";
@use "utilities/flexbox";
تمرين 1: بناء نظام أزرار كامل
أنشئ مكون أزرار شامل بالمتطلبات التالية:
- فئة زر أساسية مع طباعة وحشو مناسب
- 5 متغيرات ألوان: primary, secondary, success, danger, info
- 3 متغيرات أحجام: صغير، متوسط، كبير
- متغيرات أزرار مخططة لكل لون
- حالة معطلة لجميع المتغيرات
- مُعدل زر كتلة (بعرض كامل)
- اختبر جميع المجموعات في HTML
تمرين 2: إنشاء نظام مكونات البطاقات
ابنِ مكون بطاقة مرن مع:
- حاوية بطاقة مع ظل وحد
- أقسام رأس وجسم وتذييل البطاقة
- دعم لصور البطاقة (أعلى وأسفل)
- متغيرات ألوان البطاقة (primary, success, danger)
- مُعدل تخطيط بطاقة أفقي
- أنشئ 3 أمثلة بطاقات مختلفة تعرض ميزات متنوعة
تمرين 3: بناء عناصر تحكم نماذج مخصصة
أنشئ مكونات نماذج منسقة بما في ذلك:
- إدخال نص بـ 3 أحجام (صغير، متوسط، كبير)
- منطقة نص مع التحكم في تغيير الحجم
- حالات التحقق (صالح وغير صالح) مع حدود ملونة ورسائل ملاحظات
- صندوق اختيار مخصص مع علامة اختيار متحركة
- زر دائري مخصص مع تحديد دائري
- حالات معطلة لجميع عناصر تحكم النماذج
- ابنِ نموذج تسجيل كامل باستخدام هذه المكونات
الخلاصة
في هذا الدرس، تعلمت كيفية بناء مكتبة مكونات احترافية مع SASS. أنت الآن تفهم:
- مبادئ البنية القائمة على المكونات
- كيفية هيكلة مكتبة مكونات مع تنظيم ملفات مناسب
- بناء مكونات الأزرار مع المتغيرات والأحجام والحالات باستخدام الخرائط
- إنشاء مكونات بطاقات مرنة مع أقسام متعددة
- تطوير مكونات نماذج شاملة بما في ذلك عناصر تحكم مخصصة
- تنفيذ مكونات التنبيهات مع متغيرات الألوان
- استخدام رموز التصميم للمسافات والأحجام المتسقة
- تنظيم ملفات المكونات لقابلية التوسع وسهولة الصيانة
مكتبة مكونات مصممة جيداً تسرع التطوير، وتضمن الاتساق، وتجعل قاعدة الكود الخاصة بك أكثر قابلية للصيانة. مع SASS، يمكنك إنشاء مكونات قوية ومرنة تتكيف مع احتياجات مشروعك المتطورة.