خلاصه و تحلیل مقاله: اجتناب از چیدمان‌های بزرگ، پیچیده و Layout Thrashing

مقاله ارائه‌شده از وب‌سایت web.dev به بررسی مشکلات مرتبط با چیدمان (Layout) یا Reflow در مرورگرها و تأثیر آن بر تأخیر تعاملات (Interaction Latency) و معیار Interaction to Next Paint (INP) می‌پردازد. همچنین، راهکارهایی برای کاهش چیدمان‌های غیرضروری، چیدمان‌های اجباری همزمان (Forced Synchronous Layouts) و Layout Thrashing ارائه می‌دهد. در ادامه، خلاصه‌ای جامع از مقاله به همراه توضیحات تکمیلی ارائه می‌شود.


چیدمان (Layout) چیست؟

چیدمان (Layout) یا Reflow فرآیندی است که مرورگر طی آن اطلاعات هندسی عناصر صفحه (مانند اندازه و موقعیت) را محاسبه می‌کند. این اطلاعات می‌توانند از CSS، محتوای عنصر، یا عناصر والد به‌صورت صریح یا ضمنی تعیین شوند. این فرآیند در مرورگرهای مختلف نام‌های متفاوتی دارد: - Chrome و Edge: Layout - Firefox و Safari: Reflow

عوامل اصلی تأثیرگذار بر هزینه چیدمان: 1. تعداد عناصر DOM: اندازه DOM (تعداد عناصر) مستقیماً بر زمان چیدمان تأثیر می‌گذارد. 2. پیچیدگی چیدمان: استفاده از ویژگی‌های پیچیده CSS یا ساختارهای DOM بزرگ می‌تواند فرآیند را سنگین‌تر کند.

تاریخ انتشار: 20 مارس 2015
آخرین به‌روزرسانی: 7 مه 2025
نویسندگان: جرمی واگنر، پل لوئیس، بری پولارد


خلاصه نکات کلیدی

  • تأثیر چیدمان بر تأخیر تعامل: چیدمان می‌تواند تأخیر ارائه (Presentation Delay) را افزایش دهد، که بخشی از تأخیر کلی تعامل است و در معیار INP اندازه‌گیری می‌شود.
  • دامنه چیدمان: معمولاً کل سند (document) را در بر می‌گیرد، بنابراین DOM بزرگ‌تر هزینه بیشتری دارد.
  • اجتناب از چیدمان غیرضروری: باید تا حد ممکن از محاسبات چیدمان پرهیز کرد.
  • اجتناب از چیدمان‌های اجباری همزمان و Layout Thrashing: خواندن و نوشتن ویژگی‌های DOM به‌صورت پشت‌سرهم می‌تواند باعث مشکلات عملکردی جدی شود.

تأثیر چیدمان بر تأخیر تعامل

تأخیر تعامل (Interaction Latency) مدت زمانی است که از شروع تعامل کاربر (مانند کلیک یا تایپ) تا ارائه فریم بعدی توسط مرورگر طول می‌کشد. این شامل تأخیر ارائه (Presentation Delay) است که به‌روزرسانی‌های بصری (مانند تغییر موقعیت یا اندازه عناصر) را در بر می‌گیرد. چیدمان‌های سنگین می‌توانند این تأخیر را افزایش دهند و باعث شوند INP از محدوده مطلوب (زیر 200 میلی‌ثانیه) خارج شود.

برای بهینه‌سازی INP: - از چیدمان‌های غیرضروری اجتناب کنید. - اگر چیدمان اجتناب‌ناپذیر است، آن را به حداقل برسانید تا مرورگر بتواند فریم بعدی را سریع‌تر ارائه کند.

منبع پیشنهادی برای مطالعه: Interaction to Next Paint (INP)


چگونه از چیدمان غیرضروری اجتناب کنیم؟

تغییر ویژگی‌های هندسی مانند width، height، left، یا top باعث تحریک چیدمان می‌شود:

.box {
  width: 20px;
  height: 20px;
}

/* تغییر عرض و ارتفاع باعث تحریک چیدمان می‌شود */
.box--expanded {
  width: 200px;
  height: 350px;
}
  • مشکل DOM بزرگ: چیدمان معمولاً کل سند را در بر می‌گیرد. DOM بزرگ‌تر (تعداد عناصر بیشتر) باعث افزایش زمان چیدمان می‌شود.
  • راهکار:
  • از ویژگی‌های CSS که چیدمان را تحریک نمی‌کنند (مانند transform به‌جای top یا left) استفاده کنید.
  • اندازه DOM را با حذف عناصر غیرضروری یا رندر تدریجی کاهش دهید.
  • از Chrome DevTools (تب Timeline یا Performance) برای شناسایی زمان صرف‌شده در چیدمان استفاده کنید:
    • مثال: در یک نمونه، چیدمان برای هر فریم 28 میلی‌ثانیه طول کشید که برای انیمیشن‌های 60 فریم در ثانیه (16 میلی‌ثانیه به ازای هر فریم) بیش از حد است.
    • DevTools همچنین اندازه درخت DOM (مثلاً 1618 عنصر) و تعداد گره‌های نیازمند چیدمان را نشان می‌دهد.

منبع پیشنهادی برای مطالعه: اندازه DOM و تعاملات

تصویر DevTools نشان‌دهنده زمان چیدمان


اجتناب از چیدمان‌های اجباری همزمان (Forced Synchronous Layouts)

چیدمان اجباری همزمان زمانی رخ می‌دهد که جاوااسکریپت مرورگر را مجبور می‌کند چیدمان را زودتر از زمان معمول (قبل از محاسبات استایل و چیدمان عادی) انجام دهد. این اتفاق معمولاً زمانی می‌افتد که: 1. یک ویژگی هندسی (مانند offsetHeight یا getComputedStyle) خوانده می‌شود. 2. این خواندن پس از تغییر استایل‌ها (مانند افزودن کلاس یا تغییر ویژگی‌های CSS) انجام می‌شود.

مثال مشکل‌ساز:

function logBoxHeight() {
  box.classList.add('super-big'); // تغییر استایل
  console.log(box.offsetHeight); // خواندن ویژگی هندسی، باعث چیدمان اجباری
}

در این کد، مرورگر باید ابتدا استایل super-big را اعمال کند، سپس چیدمان را اجرا کند تا offsetHeight را محاسبه کند، که این کار پرهزینه است.

راهکار: دسته‌بندی خواندن و نوشتن: - ابتدا تمام ویژگی‌های موردنیاز را بخوانید (از مقادیر فریم قبلی استفاده می‌شود). - سپس تغییرات استایل را اعمال کنید.

function logBoxHeight() {
  console.log(box.offsetHeight); // خواندن
  box.classList.add('super-big'); // نوشتن
}
  • نکته کلیدی: ویژگی‌های متعددی (مانند offsetWidth، clientHeight، getBoundingClientRect) می‌توانند چیدمان اجباری را تحریک کنند. برای لیست کامل، به منبع Paul Irish مراجعه کنید.

اجتناب از Layout Thrashing

Layout Thrashing زمانی رخ می‌دهد که چیدمان‌های اجباری همزمان به‌صورت مکرر و پشت‌سرهم (مثلاً در یک حلقه) اجرا شوند، که باعث افت شدید عملکرد می‌شود.

مثال مشکل‌ساز:

function resizeAllParagraphsToMatchBlockWidth() {
  for (let i = 0; i < paragraphs.length; i++) {
    paragraphs[i].style.width = `${box.offsetWidth}px`; // خواندن و نوشتن در هر چرخه
  }
}
  • در هر چرخه حلقه، خواندن offsetWidth باعث چیدمان می‌شود، زیرا استایل‌ها در چرخه قبلی تغییر کرده‌اند. این فرآیند برای هر پاراگراف تکرار می‌شود و باعث Layout Thrashing می‌شود.

راهکار: دسته‌بندی خواندن و نوشتن: - ابتدا تمام مقادیر را بخوانید و ذخیره کنید، سپس تغییرات را اعمال کنید:

// خواندن
const width = box.offsetWidth;

function resizeAllParagraphsToMatchBlockWidth() {
  for (let i = 0; i < paragraphs.length; i++) {
    // نوشتن
    paragraphs[i].style.width = `${width}px`;
  }
}

این روش تعداد چیدمان‌ها را به حداقل می‌رساند.


شناسایی چیدمان‌های اجباری و Thrashing

  • ابزار Chrome DevTools:
  • از تب Performance یا Timeline برای شناسایی چیدمان‌های طولانی استفاده کنید.
  • قابلیت Forced Reflow Insight در DevTools به‌طور خودکار چیدمان‌های اجباری را شناسایی می‌کند: تصویر Forced Reflow Insight
  • این ابزار می‌تواند تابع یا کد خاصی (مانند تابع w) که باعث چیدمان اجباری شده را مشخص کند.
  • در دنیای واقعی (Field):
  • از Long Animation Frame API و ویژگی forcedStyleAndLayoutDuration برای شناسایی چیدمان‌های اجباری در داده‌های واقعی کاربران استفاده کنید: Long Animation Frame API

نمودار پیشنهادی برای تجسم تأثیر چیدمان

برای درک بهتر تأثیر چیدمان و Layout Thrashing، می‌توان نموداری ایجاد کرد که زمان صرف‌شده در چیدمان را در دو سناریو (با و بدون بهینه‌سازی) مقایسه کند. با این حال، مقاله داده‌های عددی دقیقی ارائه نمی‌دهد، بنابراین نمودار زیر فرضی است:

{
  "type": "bar",
  "data": {
    "labels": ["With Layout Thrashing", "Optimized Layout"],
    "datasets": [{
      "label": "Layout Time (milliseconds)",
      "data": [28, 5],
      "backgroundColor": ["#FF3B30", "#34C759"],
      "borderColor": ["#CC2E2A", "#2E865F"],
      "borderWidth": 1
    }]
  },
  "options": {
    "scales": {
      "y": {
        "beginAtZero": true,
        "title": {
          "display": true,
          "text": "Layout Time (milliseconds)"
        }
      },
      "x": {
        "title": {
          "display": true,
          "text": "Scenario"
        }
      }
    },
    "plugins": {
      "legend": {
        "display": false
      },
      "title": {
        "display": true,
        "text": "Impact of Layout Thrashing on Performance"
      }
    }
  }
}

توضیح: این نمودار فرضی نشان می‌دهد که Layout Thrashing می‌تواند زمان چیدمان را به 28 میلی‌ثانیه افزایش دهد (مثال از مقاله)، در حالی که با بهینه‌سازی (دسته‌بندی خواندن و نوشتن)، این زمان به 5 میلی‌ثانیه کاهش می‌یابد. مقادیر باید با داده‌های واقعی جایگزین شوند.


جمع‌بندی

چیدمان‌های بزرگ و پیچیده و Layout Thrashing می‌توانند به‌طور قابل‌توجهی تأخیر تعامل را افزایش دهند و معیار INP را از محدوده مطلوب خارج کنند. برای بهینه‌سازی: - از چیدمان‌های غیرضروری با استفاده از ویژگی‌های CSS غیرهندسی (مانند transform) اجتناب کنید. - چیدمان‌های اجباری همزمان را با دسته‌بندی خواندن و نوشتن ویژگی‌های DOM کاهش دهید. - از ابزارهای Chrome DevTools و Long Animation Frame API برای شناسایی و رفع مشکلات استفاده کنید. - اندازه DOM را به حداقل برسانید تا هزینه چیدمان کاهش یابد.

با اعمال این تکنیک‌ها، می‌توانید پاسخگویی وب‌سایت را بهبود بخشید و تجربه کاربری بهتری ارائه دهید.

منابع پیشنهادی برای مطالعه: - Interaction to Next Paint (INP) - اندازه DOM و تعاملات - Long Animation Frame API