ترحيل CSS إلى SASS والكود القديم
مقدمة إلى ترحيل CSS إلى SASS
قد يبدو ترحيل قاعدة كود CSS موجودة إلى SASS أمراً شاقاً، ولكن مع نهج منهجي، يصبح قابلاً للإدارة ومجزياً. في هذا الدرس الشامل، سنستكشف استراتيجيات مثبتة لترحيل CSS القديم إلى SASS الحديث، ومعالجة بادئات البائعين، والترقية من @import إلى @use/@forward، وتجنب المزالق الشائعة أثناء عملية الترحيل.
استراتيجية ترحيل CSS الموجود إلى SASS
يتطلب الترحيل الناجح التخطيط ونهجاً خطوة بخطوة. التسرع في العملية غالباً ما يؤدي إلى أخطاء ومشاكل في الصيانة.
مرحلة التقييم
قبل البدء، قيّم CSS الحالي:
قائمة التحقق قبل الترحيل
□ توثيق بنية CSS الحالية
□ كم عدد ملفات CSS الموجودة؟
□ ما هو حجم الملف الإجمالي؟
□ هل هناك أنماط مكررة؟
□ هل هناك اتفاقية تسمية؟
□ تحديد نقاط الألم
□ أي أنماط متكررة؟
□ أي قيم مشفرة؟
□ أي محددات محددة جداً؟
□ هل هناك بادئات بائعين في كل مكان؟
□ تحديد أهداف الترحيل
□ تقليل تكرار الكود
□ تحسين قابلية الصيانة
□ إنشاء تسمية متسقة
□ إنشاء مكونات قابلة لإعادة الاستخدام
□ اختيار نهجك
□ الانفجار الكبير (ترحيل كل شيء دفعة واحدة)
□ تدريجي (ترحيل ملف تلو الآخر)
□ هجين (ترحيل الملفات الحرجة أولاً)
الخطوة 1: إعادة تسمية .css إلى .scss
الخطوة الأولى هي الأسهل: ببساطة أعد تسمية ملفات CSS إلى SCSS. كل CSS صالح هو SCSS صالح، لذا ستستمر أنماطك في العمل على الفور.
إعادة تسمية الملفات
# قبل
styles/
main.css
components.css
utilities.css
# بعد (الخطوة 1)
styles/
main.scss
components.scss
utilities.scss
تحديث عملية البناء
بعد إعادة التسمية، حدّث أدوات البناء لترجمة SCSS بدلاً من CSS:
package.json - تحديث سكريبتات البناء
{
"scripts": {
"build:css": "sass styles/main.scss dist/main.css --style=compressed",
"watch:css": "sass --watch styles:dist"
}
}
اختبار كل شيء
بعد إعادة التسمية وتحديث عملية البناء، تحقق من أن:
- جميع الأنماط تترجم بدون أخطاء
- إخراج CSS مطابق للأصل
- يبدو الموقع الإلكتروني مماثلاً تماماً
- جميع الصفحات والمكونات تعرض بشكل صحيح
الخطوة 2: استخراج المتغيرات
الخطوة الثانية هي تحديد القيم المتكررة واستخراجها في متغيرات. هنا تبدأ في رؤية فوائد SASS.
تحديد المرشحين للمتغيرات
قبل - القيم المشفرة
/* CSS الأصلي */
.header {
background-color: #3498db;
padding: 20px;
font-family: "Helvetica Neue", Arial, sans-serif;
}
.button-primary {
background-color: #3498db;
padding: 10px 20px;
font-family: "Helvetica Neue", Arial, sans-serif;
border-radius: 4px;
}
.card {
background-color: #ffffff;
padding: 20px;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.sidebar {
background-color: #f8f9fa;
padding: 20px;
}
إنشاء ملف متغيرات
_variables.scss - المتغيرات المستخرجة
// الألوان
$color-primary: #3498db;
$color-white: #ffffff;
$color-gray-light: #f8f9fa;
$color-shadow: rgba(0, 0, 0, 0.1);
// الطباعة
$font-family-base: "Helvetica Neue", Arial, sans-serif;
// التباعد
$spacing-base: 20px;
$spacing-small: 10px;
// الحدود
$border-radius-base: 4px;
// الظلال
$shadow-base: 0 2px 4px $color-shadow;
استبدال القيم المشفرة
بعد - استخدام المتغيرات
// استيراد المتغيرات
@use 'variables' as *;
.header {
background-color: $color-primary;
padding: $spacing-base;
font-family: $font-family-base;
}
.button-primary {
background-color: $color-primary;
padding: $spacing-small $spacing-base;
font-family: $font-family-base;
border-radius: $border-radius-base;
}
.card {
background-color: $color-white;
padding: $spacing-base;
border-radius: $border-radius-base;
box-shadow: $shadow-base;
}
.sidebar {
background-color: $color-gray-light;
padding: $spacing-base;
}
الخطوة 3: تقديم التداخل حيثما كان مناسباً
التداخل قوي ولكن يجب استخدامه بحكمة. قدّمه حيث يحسن القراءة دون إنشاء محددات محددة جداً.
المرشحون الجيدون للتداخل
قبل - CSS مسطح
/* CSS الأصلي */
.nav { }
.nav .nav-list { }
.nav .nav-item { }
.nav .nav-link { }
.nav .nav-link:hover { }
.nav .nav-link.active { }
.card { }
.card .card-header { }
.card .card-body { }
.card .card-footer { }
بعد - التداخل الاستراتيجي
// عمق تداخل جيد
.nav {
// أنماط Nav
.nav-list {
// أنماط القائمة
}
.nav-item {
// أنماط العنصر
}
.nav-link {
// أنماط الرابط الأساسية
&:hover {
// حالة التمرير
}
&.active {
// الحالة النشطة
}
}
}
.card {
// أنماط البطاقة الأساسية
.card-header {
// أنماط الرأس
}
.card-body {
// أنماط الجسم
}
.card-footer {
// أنماط التذييل
}
}
الخطوة 4: إنشاء ملفات جزئية وتقسيم الملف
ملفات CSS الضخمة والمتراصة يصعب صيانتها. قسّم SCSS إلى ملفات جزئية منطقية بناءً على الوظيفة.
تخطيط بنية الملفات الجزئية
استراتيجية تنظيم الملفات الجزئية
styles/
├── main.scss # ملف الدخول الرئيسي
├── abstracts/
│ ├── _variables.scss # جميع المتغيرات
│ ├── _mixins.scss # جميع Mixins
│ └── _functions.scss # جميع الدوال
├── base/
│ ├── _reset.scss # إعادة تعيين CSS
│ ├── _typography.scss # قواعد الطباعة
│ └── _global.scss # أنماط عامة
├── layout/
│ ├── _header.scss # أنماط الرأس
│ ├── _footer.scss # أنماط التذييل
│ ├── _sidebar.scss # أنماط الشريط الجانبي
│ └── _grid.scss # نظام الشبكة
├── components/
│ ├── _buttons.scss # أنماط الأزرار
│ ├── _cards.scss # أنماط البطاقات
│ ├── _forms.scss # أنماط النماذج
│ ├── _modals.scss # أنماط النوافذ المنبثقة
│ └── _navigation.scss # أنماط التنقل
└── pages/
├── _home.scss # خاص بالصفحة الرئيسية
├── _about.scss # خاص بصفحة حول
└── _contact.scss # خاص بصفحة الاتصال
تقسيم الملف الضخم
عملية التقسيم
// 1. حدد الأقسام المنطقية في CSS الخاص بك
/* أنماط التنقل - الأسطر 1-150 */
/* أنماط الأزرار - الأسطر 151-250 */
/* أنماط النماذج - الأسطر 251-400 */
/* أنماط البطاقات - الأسطر 401-500 */
// 2. أنشئ ملفات جزئية
components/_navigation.scss
components/_buttons.scss
components/_forms.scss
components/_cards.scss
// 3. انسخ الأنماط إلى الملفات الجزئية المناسبة
// (احتفظ بالملف الأصلي كنسخة احتياطية حتى اكتمال الترحيل)
// 4. أنشئ main.scss لاستيراد جميع الملفات الجزئية
@use 'abstracts/variables';
@use 'abstracts/mixins';
@use 'base/reset';
@use 'base/typography';
@use 'layout/header';
@use 'layout/footer';
@use 'components/navigation';
@use 'components/buttons';
@use 'components/forms';
@use 'components/cards';
// 5. الترجمة والاختبار
// 6. قارن الإخراج بـ CSS الأصلي
// 7. احذف الملف الضخم الأصلي عند الثقة
الخطوة 5: تقديم Mixins للأنماط المتكررة
ابحث عن أنماط أنماط متكررة واستخرجها في mixins قابلة لإعادة الاستخدام.
تحديد الأنماط المتكررة
قبل - الكود المتكرر
/* CSS الأصلي مع أنماط متكررة */
.box-1 {
display: flex;
justify-content: center;
align-items: center;
}
.box-2 {
display: flex;
justify-content: center;
align-items: center;
}
.modal-content {
display: flex;
justify-content: center;
align-items: center;
}
.button-primary {
padding: 10px 20px;
border-radius: 4px;
border: none;
cursor: pointer;
transition: all 0.3s ease;
}
.button-secondary {
padding: 10px 20px;
border-radius: 4px;
border: none;
cursor: pointer;
transition: all 0.3s ease;
}
إنشاء Mixins
abstracts/_mixins.scss - Mixins المستخرجة
// محاذاة المحتوى بـ flexbox
@mixin flex-center {
display: flex;
justify-content: center;
align-items: center;
}
// أنماط الزر الأساسية
@mixin button-base {
padding: 10px 20px;
border-radius: 4px;
border: none;
cursor: pointer;
transition: all 0.3s ease;
}
// نقطة توقف متجاوبة
@mixin respond-to($breakpoint) {
@if $breakpoint == tablet {
@media (min-width: 768px) {
@content;
}
} @else if $breakpoint == desktop {
@media (min-width: 1024px) {
@content;
}
}
}
استخدام Mixins
بعد - استخدام Mixins
@use 'abstracts/mixins' as *;
@use 'abstracts/variables' as *;
.box-1 {
@include flex-center;
}
.box-2 {
@include flex-center;
}
.modal-content {
@include flex-center;
}
.button-primary {
@include button-base;
background-color: $color-primary;
color: $color-white;
}
.button-secondary {
@include button-base;
background-color: $color-secondary;
color: $color-text;
}
.responsive-box {
width: 100%;
@include respond-to(tablet) {
width: 50%;
}
@include respond-to(desktop) {
width: 33.333%;
}
}
الخطوة 6: إضافة نظام وحدة @use/@forward
إذا كان مشروعك لا يزال يستخدم @import، فانتقل إلى نظام @use و @forward الحديث.
الترحيل من @import إلى @use
قبل - استخدام @import
// main.scss (النمط القديم)
@import 'variables';
@import 'mixins';
@import 'base/reset';
@import 'components/buttons';
// جميع المتغيرات و mixins عالمية
.box {
background: $primary-color; // يعمل لأن @import عالمي
}
بعد - استخدام @use
// main.scss (النمط الجديد)
@use 'variables' as *; // استيراد الكل بدون فضاء اسم
@use 'mixins' as *;
@use 'base/reset';
@use 'components/buttons';
// أو استخدم مع فضاء اسم
@use 'variables' as vars;
@use 'mixins' as mix;
.box {
background: vars.$primary-color;
@include mix.flex-center;
}
استخدام @forward لإعادة التصدير
abstracts/_index.scss - وحدة إعادة التوجيه
// إعادة توجيه جميع الملفات الجزئية المجردة من خلال نقطة دخول واحدة
@forward 'variables';
@forward 'mixins';
@forward 'functions';
// الآن يمكنك استيراد جميع التجريدات دفعة واحدة
// في ملفات أخرى:
@use 'abstracts' as *; // يحصل على المتغيرات و mixins والدوال
التعامل مع بادئات البائعين
أدوات البناء الحديثة تتعامل مع بادئات البائعين تلقائياً، لذا يجب عليك إزالتها من SASS والسماح لأدوات مثل Autoprefixer بالتعامل معها.
قبل الترحيل
CSS مع البادئات اليدوية
/* CSS القديم مع بادئات البائعين */
.box {
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
-webkit-transition: all 0.3s ease;
-moz-transition: all 0.3s ease;
-ms-transition: all 0.3s ease;
-o-transition: all 0.3s ease;
transition: all 0.3s ease;
}
بعد الترحيل
SASS بدون بادئات (Autoprefixer يتعامل معها)
// SCSS نظيف - دع Autoprefixer يضيف البادئات
.box {
transform: rotate(45deg);
transition: all 0.3s ease;
}
// يترجم إلى (مع Autoprefixer):
// .box {
// -webkit-transform: rotate(45deg);
// transform: rotate(45deg);
// -webkit-transition: all 0.3s ease;
// transition: all 0.3s ease;
// }
تكوين Autoprefixer
postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')({
overrideBrowserslist: [
'last 2 versions',
'> 1%',
'not dead'
]
})
]
};
المزالق الشائعة أثناء الترحيل
كن على دراية بهذه الأخطاء الشائعة عند الترحيل إلى SASS.
المأزق 1: التداخل المفرط
المشكلة والحل
// سيء: تداخل كثير جداً
.header {
.nav {
.menu {
.item {
.link {
color: blue; // 5 مستويات عمق!
}
}
}
}
}
// جيد: تسطيح البنية
.header { }
.nav { }
.menu-item { }
.menu-link {
color: blue;
}
المأزق 2: عدم استخدام المتغيرات باستمرار
المشكلة والحل
// سيء: استخدام متغيرات غير متسق
.button {
background: $primary-color;
color: #ffffff; // مشفر!
padding: 10px 20px; // مشفر!
border-radius: $border-radius;
}
// جيد: استخدم المتغيرات في كل مكان
.button {
background: $primary-color;
color: $color-white;
padding: $spacing-sm $spacing-base;
border-radius: $border-radius;
}
المأزق 3: إنشاء الكثير من المتغيرات
المشكلة والحل
// سيء: متغير لكل شيء
$header-padding-top: 20px;
$header-padding-right: 15px;
$header-padding-bottom: 20px;
$header-padding-left: 15px;
$button-padding-top: 10px;
$button-padding-right: 20px;
// ... 50 متغير حشو أكثر
// جيد: استخدم مقياساً ذا معنى
$spacing-xs: 5px;
$spacing-sm: 10px;
$spacing-md: 15px;
$spacing-lg: 20px;
$spacing-xl: 30px;
.header {
padding: $spacing-lg $spacing-md;
}
.button {
padding: $spacing-sm $spacing-lg;
}
المأزق 4: عدم الاختبار بعد كل خطوة
عملية الاختبار الموصى بها
# بعد كل خطوة ترحيل:
1. ترجمة SCSS إلى CSS
npm run build:css
2. قارن الإخراج بـ CSS الأصلي
diff original.css dist/output.css
3. اختبار الانحدار البصري
- افتح الموقع في المتصفح
- تحقق من جميع الصفحات والمكونات
- تحقق من السلوك المتجاوب
- اختبر العناصر التفاعلية
4. الاختبار الآلي (إذا كان متاحاً)
npm run test
5. انتقل فقط إلى الخطوة التالية عند التحقق من الخطوة الحالية
مثال على الجدول الزمني للترحيل
خطة ترحيل لمدة 6 أسابيع لمشروع متوسط
الأسبوع 1: التقييم والإعداد
- تدقيق CSS الموجود
- إعداد عملية بناء SASS
- إعادة تسمية .css إلى .scss
- اختبار الترجمة
الأسبوع 2: استخراج المتغيرات
- إنشاء _variables.scss
- استبدال الألوان
- استبدال قيم التباعد
- استبدال قيم الطباعة
الأسبوع 3: تقديم التداخل
- تحديد المكونات للتداخل
- تطبيق التداخل الاستراتيجي
- الاختبار والتحقق من الإخراج
الأسبوع 4: إنشاء ملفات جزئية
- تخطيط بنية الملفات
- تقسيم الملفات الضخمة
- إنشاء استيرادات @use
- اختبار جميع الصفحات
الأسبوع 5: إضافة Mixins والدوال
- تحديد الأنماط المتكررة
- إنشاء mixins
- إنشاء دوال مساعدة
- إعادة الصياغة لاستخدام mixins
الأسبوع 6: التلميع والتحسين
- إزالة بادئات البائعين
- إعداد Autoprefixer
- تحسين الإخراج
- الاختبار النهائي
- التوثيق
تمرين 1: ترحيل ملف CSS بسيط
خذ هذا CSS وهاجره من خلال جميع الخطوات:
/* styles.css */
.header {
background-color: #3498db;
padding: 20px;
font-family: Arial, sans-serif;
}
.header .logo {
color: #ffffff;
font-size: 24px;
}
.header .nav {
display: flex;
}
.header .nav .nav-item {
padding: 10px 15px;
color: #ffffff;
}
.button {
background-color: #3498db;
color: #ffffff;
padding: 10px 20px;
border-radius: 4px;
border: none;
}
.button:hover {
background-color: #2980b9;
}
أكمل الخطوات 1-5: إعادة التسمية إلى .scss، استخراج المتغيرات، إضافة التداخل، إنشاء ملفات جزئية، وتقديم mixins.
تمرين 2: إعادة صياغة بادئات البائعين
أزل بادئات البائعين وأعد Autoprefixer:
.animated-box {
-webkit-transform: translateX(100px) rotate(45deg);
-moz-transform: translateX(100px) rotate(45deg);
-ms-transform: translateX(100px) rotate(45deg);
transform: translateX(100px) rotate(45deg);
-webkit-animation: slide 1s ease-in-out;
-moz-animation: slide 1s ease-in-out;
animation: slide 1s ease-in-out;
}
@-webkit-keyframes slide { }
@-moz-keyframes slide { }
@keyframes slide { }
أزل جميع بادئات البائعين، أعد PostCSS مع Autoprefixer، وتحقق من أن الإخراج يتضمن البادئات الصحيحة.
تمرين 3: ترحيل @import إلى @use
حوّل بنية المشروع هذه من @import إلى @use/@forward:
// main.scss
@import 'variables';
@import 'mixins';
@import 'base';
@import 'components/buttons';
@import 'components/forms';
// الملفات الأخرى تستخدم أيضاً @import
// تحتاج المكونات إلى الوصول إلى المتغيرات و mixins
حوّل جميع تصريحات @import إلى @use، أنشئ ملف فهرس بـ @forward للتجريدات، وحدّث جميع ملفات المكونات لاستخدام نظام الوحدة.