Progressive Enhancement و Graceful Degradation؛ دو نگاه به یه مسئله‌ی مشترک

تو درس قبل، اسم «progressive enhancement» رو به‌عنوان استراتژی اصلی برای کنار اومدن با ناهماهنگی مرورگرها آوردیم. حالا وقتشه این مفهوم رو با جزئیات بیشتری بررسی کنیم و با خواهرش، «graceful degradation»، مقایسه‌ش کنیم؛ چون این دو، با این‌که خیلی وقت‌ها به‌جای هم به کار می‌رن، دقیقاً یه مسیر نیستن و جهت فکری متفاوتی دارن.

دو جهت فکری متفاوت برای یه هدف مشترک

هر دو رویکرد یه هدف مشترک دارن: سایت باید برای کاربرهایی با مرورگرهای مختلف (قدیمی و جدید) قابل‌استفاده باشه. اما نقطه‌ی شروع فکری‌شون برعکس همه:

رویکردنقطه‌ی شروعجهت حرکت
Progressive Enhancementیه تجربه‌ی پایه و ساده که همه‌جا کار می‌کنهاز ساده به پیشرفته اضافه می‌شه
Graceful Degradationیه تجربه‌ی کامل و پیشرفته برای مرورگرهای مدرناز پیشرفته به ساده کم می‌شه

یعنی تو Progressive Enhancement، اول به این فکر می‌کنید «حداقلی که باید کار کنه چیه؟» و بعد لایه‌های بهبود رو روش اضافه می‌کنید. تو Graceful Degradation، اول بهترین تجربه‌ی ممکن رو برای مرورگرهای جدید طراحی می‌کنید و بعد به این فکر می‌کنید «اگه یه ویژگی نبود، چیکار کنم که کاملاً خراب نشه؟»

مثال عملی: یه دکمه با گرادینت مدرن

/* رویکرد Progressive Enhancement */
.btn {
  background: #3b82f6; /* پایه: یه رنگ ساده که همه‌جا کار می‌کنه */
}

@supports (background: oklch(60% 0.15 260)) {
  .btn {
    background: oklch(60% 0.15 260); /* بهبود: رنگ مدرن‌تر اگه پشتیبانی بشه */
  }
}
/* رویکرد Graceful Degradation */
.btn {
  background: oklch(60% 0.15 260); /* هدف اصلی: رنگ مدرن */
  background: #3b82f6; /* fallback: اگه oklch نشناخته بشه، این خط جایگزینش می‌شه */
}

هر دو نتیجه‌ی نهایی مشابهی دارن، ولی ترتیب فکری‌شون برعکسه. تو مثال دوم، از تکنیک «نوشتن fallback قبل از مقدار اصلی» که تو فصل ۲۱ (رنگ‌های مدرن) دیدیم استفاده شده؛ مرورگر قدیمی خط دوم رو نادیده می‌گیره و به خط اول (که نمی‌شناسه) هم توجهی نمی‌کنه، پس همون #3b82f6 باقی می‌مونه.

چرا امروزه Progressive Enhancement بیشتر توصیه می‌شه؟

مزیت اصلی Progressive Enhancement اینه که تضمین می‌کنه یه نسخه‌ی کاربردی همیشه وجود داره، حتی برای مرورگرهایی که اصلاً پیش‌بینیشون نکرده بودید (مثل یه مرورگر خیلی قدیمی، یا یه ابزار دسترس‌پذیری غیرمعمول). چون نقطه‌ی شروع، همون حداقل کاره، هیچ‌وقت به یه حالت «کاملاً شکسته» نمی‌رسید؛ در بدترین حالت، کاربر فقط نسخه‌ی ساده‌تر رو می‌بینه. در مقابل، Graceful Degradation این ریسک رو داره که اگه یه سناریوی خاص رو موقع طراحی fallback فراموش کرده باشید، ممکنه نتیجه واقعاً خراب بشه، نه فقط ساده‌تر.

مثال دیگه: Grid Layout با fallback به Flexbox یا Block

/* Progressive Enhancement کامل‌تر: چند لایه‌ی پشت سر هم */
.gallery {
  display: block; /* پایه‌ترین حالت: همه‌ی مرورگرها، حتی خیلی قدیمی */
}

@supports (display: flex) {
  .gallery {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
  }
}

@supports (display: grid) {
  .gallery {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 16px;
  }
}

اینجا سه لایه داریم: پایه (block ساده که همه‌جا کار می‌کنه)، بهبود اول (flexbox برای مرورگرهایی که grid رو نمی‌شناسن ولی flex رو می‌شناسن)، و بهبود نهایی (grid برای مرورگرهای کاملاً مدرن). هر لایه، تجربه رو کمی بهتر می‌کنه، ولی هیچ‌کدوم برای کارکرد پایه‌ای صفحه حیاتی نیست؛ حتی تو حالت block، کاربر همچنان می‌تونه محتوا رو ببینه و اسکرول کنه.

کِی Graceful Degradation منطقی‌تره؟

با این‌که Progressive Enhancement امروزه رویکرد پیش‌فرضه، Graceful Degradation هنوز تو بعضی موقعیت‌ها منطقیه؛ مثلاً وقتی مخاطب پروژه از قبل مشخصه که تقریباً صد درصدشون مرورگر مدرن دارن (مثل یه ابزار داخلی شرکتی که همه از یه مرورگر خاص و به‌روز استفاده می‌کنن)، و فقط می‌خواید یه شبکه‌ی اطمینان کوچیک برای موارد استثنایی داشته باشید، نه یه تجربه‌ی کاملاً جایگزین.

Feature Detection در برابر Browser Detection

یه نکته‌ی مهم که هر دو رویکرد بهش وابسته‌ن: تشخیص باید بر اساس «آیا این ویژگی پشتیبانی می‌شه» (feature detection، دقیقاً همون کاری که @supports انجام می‌ده) باشه، نه بر اساس «کدوم مرورگر و کدوم نسخه‌ست» (browser detection). دلیلش اینه که تعداد مرورگرها و نسخه‌هاشون بی‌نهایته و امکان پیش‌بینی همه‌شون نیست، ولی تعداد ویژگی‌هایی که واقعاً استفاده می‌کنید محدوده؛ چک کردن مستقیم همون ویژگی، همیشه دقیق‌تر و پایدارتر از حدس زدن بر اساس اسم مرورگره.

لایه‌بندی: نه همه‌چیز یا هیچ‌چیز

یه سوءتفاهم رایج اینه که فکر کنیم Progressive Enhancement یعنی «همیشه ساده‌ترین نسخه‌ی ممکن رو بساز». در واقع، هدف لایه‌بندی هوشمنده: مشخص کردن این‌که کدوم بخش‌ها واقعاً «حیاتی» هستن (باید تو همه‌جا کار کنن) و کدوم بخش‌ها «بهبود» محسوب می‌شن (اگه نباشن، تجربه بدتر می‌شه ولی خراب نمی‌شه). مثلاً خوندن متن یه مقاله حیاتیه؛ یه انیمیشن ظریف موقع اسکرول، یه بهبوده.

نکته مهم: تست کردن Progressive Enhancement به این معنی نیست که حتماً باید یه مرورگر واقعاً قدیمی نصب کنید. می‌تونید با غیرفعال کردن CSS تو DevTools (یا فقط بخشی از استایل‌ها) شبیه‌سازی کنید که آیا محتوای اصلی سایت، حتی بدون هیچ استایلی، همچنان قابل‌خوندن و قابل‌استفاده‌ست یا نه.

اشتباه رایج: طراحی کامل و بعد فکر کردن به fallback

یه اشتباه رایج، خصوصاً تو تیم‌هایی که عادت به Graceful Degradation دارن، اینه که کل UI رو با آخرین ویژگی‌های CSS طراحی و پیاده‌سازی کنن، و فقط تو آخر پروژه (اگه اصلاً وقت بمونه) به فکر fallback بیفتن. این رویکرد معمولاً منجر به fallback های ناقص یا فراموش‌شده می‌شه. طراحی درست از همون اول، لایه‌ی پایه رو به‌عنوان بخشی جدایی‌ناپذیر از فرآیند در نظر می‌گیره، نه یه وظیفه‌ی اضافه‌ی آخر کار.

جمع‌بندی

Progressive Enhancement از یه پایه‌ی ساده و همه‌جاکاربر شروع می‌کنه و لایه‌های بهبود رو روش اضافه می‌کنه؛ Graceful Degradation از یه تجربه‌ی کامل شروع می‌کنه و برای شرایط استثنایی fallback می‌سازه. امروزه رویکرد اول معمولاً امن‌تره چون تضمین می‌کنه هیچ‌وقت به یه حالت کاملاً شکسته نمی‌رسید. هر دو رویکرد باید بر پایه‌ی feature detection (مثل @supports) کار کنن، نه حدس زدن بر اساس اسم مرورگر.