در یکی از پروژه‌های بازبینی سرعت، با موردی روبرو شدم که تا آن روز ندیده بودم: سروری با منابع کافی، پایگاه‌داده بهینه، کش فعال، قالب سبک، اما صفحه همچنان در مرورگر کاربر بیش از پنج ثانیه طول می‌کشید تا ظاهر شود. اول به افزونه‌ها شک کردم، بعد به تصاویر. اما وقتی Performance Tab را باز کردم، فهمیدم گلوگاه جای دیگری است: خود فایل HTML بیش از ۹۰۰ کیلوبایت حجم داشت و درخت DOM از ۵٬۲۰۰ گره عبور کرده بود. آن پروژه، تصور من از «بهینه‌سازی سرعت» را برای همیشه تغییر داد. حتی بهترین سرور و بهترین پایگاه‌داده، در برابر یک HTML بدساختار، تسلیم می‌شوند. آن تجربه نقطه‌ی شروع مسیر من در بهینه‌سازی HTML شد — لایه‌ای که در ده‌ها پروژه‌ی بازبینی‌شده، کمترین توجه و بیشترین اثر را دارد.

بهینه‌سازی HTML (HTML Performance Optimization) غالباً در سایه‌ی بهینه‌سازی CSS و JavaScript گم می‌شود. در حالی که HTML اولین و مهم‌ترین لایه‌ی مسیر رندر (Critical Rendering Path) است. مرورگر برای دیدن هر پیکسل از سایت شما، ابتدا باید کل HTML را پارس کند، درخت DOM را بسازد و بعد به سراغ CSS و JS برود. اگر این لایه کند باشد، هیچ بهینه‌سازی بعدی نمی‌تواند آن را جبران کند. اگر در مسیر آموزش HTML از صفر هستید و مقالات HTML5 چیست و HTML سمنتیک را خوانده‌اید، این نوشته لایه‌ی سرعت و کارایی همان مباحث را باز می‌کند.

چرا بهینه‌سازی HTML لایه‌ی مغفول است؟

وقتی صحبت از بهینه‌سازی سرعت سایت به میان می‌آید، اکثر تیم‌ها به سراغ CSS، JavaScript و تصاویر می‌روند. HTML غالباً یک «ثابت» فرض می‌شود که «مشکلی ندارد». اما تجربه‌ی میدانی من در ده‌ها پروژه نشان می‌دهد که سه دلیل، HTML را به یک لایه‌ی پرخطر تبدیل می‌کند:

  • HTML اولین لایه‌ی مسیر رندر است: مرورگر قبل از هر چیز باید HTML را دریافت، پارس و به DOM تبدیل کند. اگر این مرحله کند باشد، هیچ‌کدام از بهینه‌سازی‌های بعدی نمی‌توانند آن را جبران کنند. مطالعه‌ی این لایه در Core Web Vitals چیست و LCP چیست آمده است.
  • حجم HTML می‌تواند غیرمنتظره بزرگ باشد: در سایت‌های وردپرسی با افزونه‌های متعدد، خروجی HTML گاهی از ۵۰۰ کیلوبایت عبور می‌کند. این حجم، پیش از هر چیز باید دانلود شود و بعد پارس. مطالعه‌ی موازی این لایه با افزونه‌ها در تأثیر افزونه‌ها بر سرعت سایت آمده است.
  • ساختار HTML روی رفتار مرورگر اثر می‌گذارد: عمق درخت DOM، تعداد گره‌ها، تعداد منابع خارجی، همه‌ی این‌ها مستقیم روی زمان پارس و زمان محاسبه‌ی چیدمان اثر دارند. این موضوع به‌طور ویژه در بهینه سازی CSS و بهینه سازی جاوااسکریپت به آن پرداخته‌ام.

در پروژه‌ای که یک فروشگاه اینترنتی داشتیم، بازبینی نشان داد که ۴۲٪ از حجم اولیه‌ی صفحه، فقط از HTML می‌آید. بخش عمده‌ی این حجم، اسکریپت‌های inline، مینی‌کارت محصولات، و پنل‌های مخفی بود که در هر صفحه بارگذاری می‌شدند بدون اینکه به کار بیایند. با کاهش این اجزا، LCP از ۴.۱ ثانیه به ۲.۳ ثانیه رسید — بدون یک خط تغییر در سرور یا پایگاه‌داده. این یکی از آن مواردی است که به‌طور جدی یادآوری می‌کند: بهینه‌سازی HTML، پایه‌ای‌ترین لایه‌ی کارایی است.

بهینه‌سازی HTML را می‌توان مثل پی‌ریزیِ ساختمان دانست: اگر پایه ضعیف باشد، بهترین دکوراسیون هم نمی‌تواند آن را نجات دهد.

مسیر رندر بحرانی و سهم HTML

برای درک درست بهینه‌سازی HTML، باید مسیر رندر بحرانی (Critical Rendering Path) را بشناسید. این مسیر، دنباله‌ای از مراحل است که مرورگر برای نمایش اولین پیکسل روی صفحه طی می‌کند:

  1. دریافت HTML: مرورگر درخواست HTTP می‌فرستد و اولین بایت را دریافت می‌کند (TTFB).
  2. پارس HTML: مرورگر HTML را به‌صورت متوالی پارس می‌کند و درخت DOM را می‌سازد.
  3. دریافت CSS: با رسیدن به تگ <link rel="stylesheet">، مرورگر CSS را دانلود می‌کند (در بعضی مرورگرها پارس HTML متوقف می‌شود).
  4. ساخت CSSOM: درخت استایل‌های محاسبه‌شده ساخته می‌شود.
  5. ساخت Render Tree: DOM و CSSOM با هم ترکیب می‌شوند.
  6. Layout و Paint: موقعیت و ابعاد هر عنصر محاسبه و رنگ‌آمیزی می‌شود.

در این مسیر، HTML در دو مرحله‌ی اول نقش مستقیم دارد و در بقیه‌ی مراحل، ساختار آن به‌عنوان پایه عمل می‌کند. تجربه‌ی من نشان می‌دهد که در ۴۰٪ پروژه‌هایی که سرعت پایین داشتند، گلوگاه در همان مراحل اولیه بود: HTML کند دریافت می‌شد، پارس سنگینی داشت، یا منابع مسدودکننده‌ی رندر را در جای اشتباه قرار داده بود. مطالعه‌ی این مسیر در چارچوب سرعت کل سایت در بهینه‌سازی سرعت سایت و افزایش سرعت وردپرس آمده است.

حجم DOM: قاتل خاموش سرعت

یکی از پرتکرارترین مشکلاتی که در پروژه‌ها می‌بینم، تورم درخت DOM است. هر عنصر HTML، یک گره در درخت DOM است. مرورگر برای هر گره، حافظه تخصیص می‌دهد و در زمان Layout و Paint، هزینه‌ی محاسباتی می‌پردازد. سه عدد که در Lighthouse به‌عنوان آستانه‌های هشدار شناخته می‌شوند:

سنجهمقدار خوبمقدار هشدارمقدار بحرانی
تعداد گره‌های DOMزیر ۸۰۰۸۰۰ تا ۱۴۰۰بالای ۱۴۰۰
عمق درخت DOMزیر ۱۶ سطح۱۶ تا ۲۴ سطحبالای ۲۴ سطح
گره‌های فرزند یک والدزیر ۶۰۶۰ تا ۹۰بالای ۹۰

در پروژه‌ای که یک داشبورد مدیریتی داشتیم، درخت DOM صفحه‌ی گزارش‌ها از ۴٬۸۰۰ گره عبور کرده بود. نتیجه: هر بار که کاربر فیلتری را فعال می‌کرد، زمان Layout به بیش از ۴۰۰ میلی‌ثانیه می‌رسید و صفحه برای چند لحظه یخ می‌زد. با بازنویسی ساختار و کاهش تعداد گره‌ها به زیر ۹۰۰ گره، زمان Layout به ۶۰ میلی‌ثانیه رسید — یک بهبود شش‌برابری با تغییر ساختار HTML.

راه‌های کاهش تعداد گره‌های DOM

  • حذف wrapperهای اضافه: در قالب‌های وردپرسی، معمولاً سه یا چهار لایه <div> بدون دلیل وجود دارد. هر لایه، یکی دو گره اضافه می‌کند.
  • استفاده از تگ‌های معنایی به‌جای div: یک <article> جای چند لایه div را می‌گیرد. مطالعه‌ی بیشتر در HTML سمنتیک.
  • حذف المان‌های مخفی از DOM: اگر با display: none محتوایی را مخفی می‌کنید اما در DOM نگه می‌دارید، همان محتوا هنوز گره‌های DOM را اشغال می‌کند. راه‌حل: با تگ <template> یا lazy rendering، محتوای مخفی را به‌موقع اضافه کنید.
  • کاهش تعداد محصولات اولیه در لیست‌ها: در فروشگاه‌ها، اگر بیست محصول در صفحه‌ی اول نمایش می‌دهید اما کاربر فقط پنج‌تای اول را می‌بیند، بقیه را به‌موقع اسکرول اضافه کنید. الگوی virtual scrolling برای جدول‌های داده‌ای بزرگ.
  • حذف HTML بلااستفاده: در پروژه‌های وردپرسی، بعضی افزونه‌ها HTML خود را در هر صفحه تزریق می‌کنند حتی اگر آن صفحه از آن افزونه استفاده نکند. با بررسی خروجی، این‌ها را حذف کنید.

حجم فایل HTML و راه‌های کاهش آن

حجم فایل HTML امروز به‌طور غیرمنتظره‌ای بزرگ شده. در قالب‌های وردپرسی با افزونه‌های متعدد، حجم یک صفحه‌ی HTML می‌تواند از ۳۰۰ کیلوبایت عبور کند. سه دسته‌ی اصلی که در این حجم سهم دارند:

۱. اسکریپت‌های inline

بسیاری از افزونه‌ها کد جاوااسکریپت خود را مستقیم داخل HTML تزریق می‌کنند. این کدها نه compress می‌شوند و نه cache. در پروژه‌ای که یک قالب پرمخاطب داشت، ۱۳۰ کیلوبایت از HTML فقط مربوط به اسکریپت‌های inline بود. راه‌حل: انتقال این اسکریپت‌ها به فایل‌های خارجی با استفاده از wp_enqueue_script. مطالعه‌ی موازی این لایه با کارایی در بهینه سازی جاوااسکریپت آمده است.

۲. داده‌های JSON تزریق‌شده

در سایت‌های مدرن با فریم‌ورک‌های JS، اغلب داده‌های اولیه به‌صورت JSON در HTML تزریق می‌شوند تا در سمت کلاینت hydrate شوند. در بعضی پروژه‌ها این داده‌ها تا چند صد کیلوبایت می‌رسند. راه‌حل: کاهش داده‌های اولیه، lazy loading بخش‌های داینامیک، و استفاده از HTTP/2 server push برای کاهش تکرار.

۳. تکرار محتوای بی‌مصرف

در قالب‌های آماده، هر صفحه ممکن است شامل پنل‌های مخفی، منوهای موبایل، مودال‌ها و ویجت‌های مختلف باشد که همه در HTML اولیه بارگذاری می‌شوند. بسیاری از این‌ها در واقع استفاده نمی‌شوند اما همه‌شان دانلود می‌شوند. راه‌حل: با <template> محتوای مخفی را در زمان نیاز اضافه کنید.

هر بایت اضافه در HTML، نه‌فقط پهنای باند بلکه زمان پارس و ساخت DOM را هم می‌خورد. حذف یک کیلوبایت HTML ارزش دو کیلوبایت تصویر را دارد.

منابع مسدودکننده‌ی رندر

یکی از پرتکرارترین مشکلات HTML در پروژه‌ها، وجود منابع مسدودکننده‌ی رندر (Render-Blocking Resources) در جای اشتباه است. سه دسته‌ی اصلی:

۱. CSS در head

تگ <link rel="stylesheet"> در head به‌طور پیش‌فرض پارس HTML را متوقف می‌کند تا CSS دانلود و CSSOM ساخته شود. این برای جلوگیری از FOUC (Flash of Unstyled Content) ضروری است اما اگر CSS شما حجیم باشد، این توقف طولانی می‌شود. راه‌حل: inline critical CSS + defer non-critical CSS. مطالعه‌ی بیشتر در بهینه سازی CSS.

۲. JS در head بدون defer یا async

اسکریپت بدون defer یا async در head، پارس HTML را متوقف می‌کند تا دانلود و اجرا شود. این یکی از پرتکرارترین اشتباهات در قالب‌های وردپرسی است. راه‌حل: همیشه از defer استفاده کنید مگر اینکه اسکریپت باید قبل از رندر اجرا شود.

۳. فونت‌های بدون font-display

فونت‌های وب به‌طور پیش‌فرض پارس را متوقف می‌کنند تا دانلود شوند. با font-display: swap، مرورگر از فونت سیستم استفاده می‌کند و بعد فونت وب را جایگزین می‌کند. این الگو، LCP را به‌طور محسوسی بهبود می‌دهد. مطالعه‌ی بیشتر در بهترین فونت‌های فارسی برای وب.

preload، prefetch و preconnect

سه نشانه‌ی HTML که به مرورگر کمک می‌کنند منابع مهم را سریع‌تر دریافت کند:

preload

به مرورگر می‌گوید این منبع را با اولویت بالا دانلود کن، چون در همین صفحه استفاده می‌شود:

<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="hero.webp" as="image">

کاربرد اصلی preload: فونت‌های اصلی سایت، تصویر شاخص (LCP)، و CSS بحرانی. توجه: preload برای منابعی است که در همین صفحه استفاده می‌شوند. مطالعه‌ی بیشتر در LCP چیست.

prefetch

به مرورگر می‌گوید این منبع احتمالاً در صفحه‌ی بعدی استفاده می‌شود، پس در زمان بیکاری دانلود کن:

<link rel="prefetch" href="/next-page-resource.js">

کاربرد اصلی: منابع صفحه‌ی بعدی در مسیر کاربری. مثلاً در یک فرایند چندمرحله‌ای (فرم ثبت‌نام، فرایند خرید)، صفحات بعدی را prefetch کنید.

preconnect

به مرورگر می‌گوید اتصال TCP، TLS و DNS با این دامنه را زودتر برقرار کن:

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="dns-prefetch" href="https://cdn.example.com">

کاربرد اصلی: دامنه‌های CDN، Google Fonts، Analytics و هر منبع خارجی که در همین صفحه استفاده می‌شود. این یک بهبود کوچک اما قابل توجه است چون تأخیر DNS و TLS قابل چشم‌پوشی نیستند.

در پروژه‌ای که یک فروشگاه لوازم آرایشی داشت، اضافه کردن preconnect به CDN و preload به فونت اصلی، LCP را حدود ۵۵۰ میلی‌ثانیه بهبود داد. یک تغییر چند دقیقه‌ای که اثر قابل اندازه‌گیری داشت.

defer و async: مدیریت اسکریپت‌ها

دو ویژگی مهم تگ <script> که در پروژه‌ها به‌طور مداوم استفاده می‌کنم:

defer

<script src="app.js" defer></script>

اسکریپت را دانلود می‌کند (به‌صورت موازی با پارس HTML) اما اجرا را به بعد از تکمیل پارس HTML موکول می‌کند. ترتیب اجرای چند اسکریپت defer حفظ می‌شود. کاربرد: اکثر اسکریپت‌های سایت که برای تعامل UI لازم‌اند اما لازم نیست پارس را متوقف کنند. الگوی پیش‌فرض من برای ۹۰٪ اسکریپت‌ها.

async

<script src="analytics.js" async></script>

اسکریپت را دانلود می‌کند و به‌محض آماده شدن اجرا می‌کند، بدون توجه به اینکه پارس HTML تمام شده یا نه. ترتیب اجرا تضمین نمی‌شود. کاربرد: اسکریپت‌های مستقل مثل Google Analytics یا تبلیغات که به ترتیب وابسته نیستند.

تفاوت عملی

در پروژه‌ای که یک فروشگاه اینترنتی بود، اسکریپت اصلی افزونه‌ی سبد خرید در head بدون defer یا async بود و پارس HTML را حدود ۴۰۰ میلی‌ثانیه متوقف می‌کرد. با اضافه کردن defer، این توقف حذف شد و FCP به‌طور محسوسی بهبود یافت.

Inline critical CSS و مدیریت فونت

یکی از پرقدرت‌ترین تکنیک‌های بهینه‌سازی HTML، inline کردن CSS بحرانی است. ایده ساده است: استایل‌های بالای صفحه را مستقیم در HTML بگذارید تا مرورگر بدون انتظار برای دانلود CSS، رندر را شروع کند:

<head>
  <style>
    /* CSS بحرانی برای بالای صفحه */
    body { font-family: system-ui; margin: 0; }
    .header { display: flex; padding: 1rem; }
    .hero { font-size: clamp(1.5rem, 4vw, 3rem); }
  </style>
  <link rel="preload" href="/styles/main.css" as="style"
        onload="this.rel='stylesheet'">
  <noscript>
    <link rel="stylesheet" href="/styles/main.css">
  </noscript>
</head>

این الگو در پروژه‌های وردپرسی با افزونه‌هایی مثل WP Rocket و Perfmatters خودکار می‌شود. اما اگر دستی پیاده کنید، نکات مهم:

  • Critical CSS باید کوچک باشد (زیر ۱۴ کیلوبایت)؛ در غیر این صورت مزیتش از بین می‌رود.
  • باید با تغییرات قالب همگام باشد؛ در غیر این صورت FOUC در اولین بازدید دیده می‌شود.
  • برای صفحات مختلف، Critical CSS متفاوت لازم است؛ یک صفحه‌ی محصول با یک صفحه‌ی مقاله، ساختار متفاوتی دارند.

در حوزه‌ی فونت، سه نکته‌ی مهم که در پروژه‌ها به‌کارم آمده:

  1. font-display: swap برای جلوگیری از FOIT (Flash of Invisible Text).
  2. Subset فونت: اگر فونت شما شامل هزاران گلیف عربی و لاتین است اما شما فقط کاراکترهای فارسی استفاده می‌کنید، نسخه‌ی subset بسازید. در پروژه‌های وردپرسی، فونت‌های subset شده می‌توانند از ۲۰۰ کیلوبایت به ۳۰ کیلوبایت برسند. مطالعه‌ی بیشتر در بهترین فونت‌های فارسی برای وب.
  3. preload فونت اصلی: با <link rel="preload">، فونت اصلی را سریع‌تر آماده کنید. مطالعه‌ی موازی در بهینه سازی CSS.

Lazy loading مرورگر و تصاویر

ویژگی loading="lazy" روی تصاویر و iframeها، به مرورگر می‌گوید این منبع را فقط زمانی بارگذاری کن که نزدیک به دید کاربر باشد:

<!-- تصویر LCP - eager load -->
<img src="hero.webp" alt="هدر" width="1200" height="675" fetchpriority="high">

<!-- تصاویر پایین صفحه - lazy load -->
<img src="gallery-1.webp" alt="گالری" width="600" height="400" loading="lazy">

نکته‌ی مهم: هرگز lazy loading را روی تصویر LCP اعمال نکنید. چون این تصویر باید سریع‌ترین عضو مسیر رندر باشد. مطالعه‌ی کامل این موضوع در تصاویر در HTML و سئوی تصویر آمده است.

اگرام‌های iframe

iframeهای مربوط به YouTube، Google Maps و سایر سرویس‌ها، حجم زیادی از منابع را به صفحه اضافه می‌کنند. برای این‌ها دو راه‌حل داریم:

  • loading="lazy": اگرام تا رسیدن به دید کاربر بارگذاری نمی‌شود.
  • یوتیوب با thumbnail و کلیک برای پخش: به‌جای iframe یوتیوب، یک تصویر thumbnail نمایش دهید و با کلیک کاربر، iframe را اضافه کنید. این الگو می‌تواند حجم اولیه‌ی صفحه را چند صد کیلوبایت کاهش دهد.

سمنتیک HTML و تأثیر آن بر سرعت

یکی از نکات ظریف که کمتر دیده می‌شود، تعامل بین سمنتیک HTML و سرعت است. برخلاف تصور رایج، سمنتیک فقط برای دسترس‌پذیری و سئو نیست؛ ساختار معنایی می‌تواند روی رفتار مرورگر و کارایی اثر بگذارد:

  • ساختار تخت به‌جای nested عمیق: هر سطح تودرتو، یک لایه محاسبه‌ی Layout اضافه می‌کند. استفاده از تگ‌های سمنتیک به‌جای چند لایه div، عمق درخت را کاهش می‌دهد.
  • استفاده از <template> برای محتوای مخفی: محتوای درون template تا زمان فعال‌سازی، رندر نمی‌شود. این برای مودال‌ها، تب‌های مخفی و هر محتوایی که فقط با تعامل نمایش داده می‌شود، یک بهبود محسوس است.
  • استفاده از <details> به‌جای آکاردئون‌های JS: این تگ بومی هم دسترس‌پذیری بهتری دارد و هم رفتار بومی مرورگر، سریع‌تر از پیاده‌سازی با JS است. مطالعه‌ی این تگ در تگ های پرکاربرد HTML.
  • پرهیز از جدول‌های چیدمانی: جدول‌های تودرتو، گران‌ترین ساختارها برای موتور رندر هستند. مطالعه‌ی جایگزین در گرید در CSS و فلکس باکس در CSS.
  • کاهش عمق لیست‌های تودرتو: لیست‌های تودرتوی چند سطحی (مثل منوهای پیچیده) می‌توانند زمان Layout را افزایش دهند. مطالعه‌ی بیشتر در لیست ها در HTML.

در پروژه‌ای که یک سایت سازمانی داشتیم، تبدیل منوی چندسطحی از div به ul، و از آکاردئون‌های JS به <details>، حدود ۲۵۰ کیلوبایت از حجم اولیه‌ی صفحه و ۱۵۰ میلی‌ثانیه از زمان Layout را کاهش داد. تغییرات کوچک HTML، اثر قابل اندازه‌گیری روی تجربه‌ی کاربری داشتند.

اندازه‌گیری و پروفایلینگ HTML

بدون اندازه‌گیری، هر بهینه‌سازی حدس است. سه ابزاری که در پروژه‌های خودم به‌کار می‌برم:

  1. Performance Tab در Chrome DevTools: با ضبط کامل چرخه‌ی بارگذاری، می‌توانید دقیقاً ببینید کدام مرحله (پارس HTML، ساخت DOM، Layout، Paint) وقت می‌خورد. بخش «Recalculate Style» و «Layout» نشان می‌دهد که گلوگاه در کدام لایه است.
  2. Coverage Tab: نشان می‌دهد چه مقدار از HTML، CSS و JS بارگذاری‌شده استفاده نشده است. نقطه‌ی شروع برای حذف محتوای بی‌مصرف.
  3. Lighthouse: با بخش‌های «Diagnostics» و «Opportunities»، مستقیماً روی مسائل HTML انگشت می‌گذارد. مثلاً «Avoid an excessive DOM size» و «Eliminate render-blocking resources».

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

اشتباهاتی که در پروژه‌ها دیدم

  • اسکریپت در head بدون defer یا async: پارس HTML را متوقف می‌کند. یکی از پرتکرارترین اشتباهات در قالب‌های وردپرسی.
  • اضافه کردن preload برای همه‌ی منابع: preload بی‌رویه، اولویت‌ها را به‌هم می‌ریزد و می‌تواند سرعت را کاهش دهد. فقط برای دو یا سه منبع حیاتی استفاده کنید.
  • inline کردن تمام CSS: اگر کل CSS را inline کنید، هر صفحه‌ی سایت حجم بالایی پیدا می‌کند و قابل کش شدن نیست. فقط critical CSS را inline کنید.
  • نادیده گرفتن عمق DOM: ساختارهای nested عمیق با div، زمان Layout را افزایش می‌دهند. همیشه ساده‌ترین ساختار ممکن را انتخاب کنید.
  • نبود width و height روی تصاویر: باعث پرش چیدمان (CLS) می‌شود. مطالعه‌ی کامل در تصاویر در HTML.
  • lazy loading روی LCP image: برعکس عمل می‌کند و تجربه‌ی اولیه‌ی کاربر را خراب می‌کند.
  • استفاده از چند جدول چیدمانی nested: گران‌ترین ساختار برای موتور رندر. مطالعه‌ی جایگزین در جدول در HTML.
  • تزریق اسکریپت و CSS inline بیش‌ازحد از افزونه‌ها: حجم HTML را چند برابر می‌کند. مطالعه‌ی موازی در تأثیر افزونه‌ها بر سرعت سایت.
  • عدم بررسی درخت DOM در بازبینی‌های سرعت: بسیاری از تیم‌ها فقط به CSS و JS و تصاویر نگاه می‌کنند. HTML و DOM، گاهی بزرگ‌ترین گلوگاه است.
  • تست فقط روی دسکتاپ پرقدرت: HTML سنگین روی دسکتاپ سریع دیده می‌شود اما در موبایل میان‌رده، تفاوت محسوس است.

لایه‌ای پایین‌تر از سینتکس HTML

اینجا وارد لایه‌ای می‌شوم که در پروژه‌های معمولی به آن نگاه نمی‌شود اما برای مهندسان پلتفرم و توسعه‌دهنده‌های ارشد اهمیت دارد. آنچه موتور مرورگر با HTML شما می‌کند، در پنج مفهوم خلاصه می‌شود:

  1. Incremental HTML Parsing و Speculative Parsing: مرورگر HTML را به‌صورت تدریجی پارس می‌کند و همزمان با دیدن منابع جدید (CSS، JS، تصاویر)، یک «پارسر پیش‌بینی‌کننده» را فعال می‌کند که آن‌ها را از قبل کشف و شروع به دانلود می‌کند. این یعنی هرچه منابع زودتر در HTML ظاهر شوند، سریع‌تر دانلود می‌شوند. الگوی عملی: منابع بحرانی (critical CSS، فونت) را در ۱۰۰ خط اول HTML قرار دهید تا پارسر پیش‌بینی‌کننده زودتر آن‌ها را کشف کند. برای مطالعه‌ی موازی این لایه با CSS، بهینه سازی CSS را ببینید.
  2. DOM Tree Construction و Memory Allocation: هر گره در درخت DOM، در مرورگر یک شیء C++ (در Chromium) یا Swift (در WebKit) است که حافظه تخصیص می‌دهد. در پروژه‌های با ۵٬۰۰۰ گره DOM، مصرف حافظه به‌تنهایی می‌تواند به چند مگابایت برسد. این حافظه در دستگاه‌های محدود موبایل، می‌تواند باعث خاتمه‌ی فرایند مرورگر شود. مطالعه‌ی موازی این لایه با JavaScript در مفاهیم پیشرفته جاوااسکریپت آمده است.
  3. Preload Scanner و Priority Hints: مرورگر یک اسکنر مستقل به‌نام Preload Scanner دارد که HTML را سریع‌تر از پارسر اصلی می‌خواند و منابع مهم را کشف می‌کند. اما این اسکنر نمی‌تواند منابعی که با JS ساخته می‌شوند را ببیند. به همین دلیل، اضافه کردن fetchpriority="high" روی تصاویر LCP و rel="preload" برای فونت‌ها، سیگنال مستقیم به این اسکنر است. این یک اصلاح کوچک با اثر مستقیم روی LCP.
  4. Incremental Layout و Interaction با DOM Mutations: وقتی DOM تغییر می‌کند (مثلاً با جاوااسکریپت)، مرورگر باید بخشی از Layout را بازمحاسبه کند. اگر درخت DOM عمیق باشد، دامنه‌ی این بازمحاسبه بزرگ‌تر می‌شود. این توضیح می‌دهد چرا درخت‌های تخت و کم‌عمق، هم سریع‌تر رندر می‌شوند و هم در برابر تغییرات داینامیک، پاسخگوترند. مطالعه‌ی موازی این لایه با چیدمان در فلکس باکس در CSS و گرید در CSS آمده است.
  5. Interaction با HTTP/2 Server Push و Early Hints: HTTP/2 و HTTP/3 امکان ارسال منابع قبل از درخواست مرورگر را فراهم می‌کنند. تگ <link rel="preload"> و هدرهای Link در سرور، می‌توانند این فرایند را تسریع کنند. در پروژه‌های وردپرسی، هدر 103 Early Hints می‌تواند CSS و JS بحرانی را قبل از آماده شدن کامل HTML ارسال کند. مطالعه‌ی موازی این لایه با زیرساخت در تأثیر هاست بر سرعت سایت و بهینه‌سازی سرعت سایت آمده است.

یک تجربه‌ی واقعی از پروژه‌ای که با مسئله‌ی Preload Scanner روبرو شدیم: در یک سایت فروشگاهی، تصویر LCP در انتهای HTML ظاهر می‌شد چون از یک ویجت صفحه‌ساز تولید می‌شد. نتیجه: پارسر پیش‌بینی‌کننده دیر به آن می‌رسید و LCP حدود ۳.۵ ثانیه بود. راه‌حل: افزودن <link rel="preload" as="image"> در ابتدای head به همان تصویر. با این یک خط، LCP به ۲.۱ ثانیه رسید. تفاوت بین یک سایت «کند» و یک سایت «سریع»، گاهی در همین یک خط نهفته است.

اگر روی پروژه‌های وردپرسی هستید و می‌خواهید این لایه‌ها را در قالب خود اعمال کنید، پیشنهاد می‌کنم ابتدا به قالب سبک مهاجرت کنید و بعد ساختار HTML را بازبینی کنید. برای مطالعه‌ی موازی با استانداردها و معماری، استانداردهای HTML و CSS و CSS مدرن از Flexbox تا Grid دید وسیع‌تری می‌دهند. برای درک این لایه در چارچوب معیارهای گوگل، Core Web Vitals چیست، LCP چیست و CLS چیست منابع کلیدی هستند. اگر روی دسترس‌پذیری و سمنتیک متمرکز هستید، HTML سمنتیک و استانداردهای دسترس‌پذیری وب را هم ببینید.

بهینه‌سازی HTML، پنهان‌ترین لایه‌ی سرعت است: کسی به آن نگاه نمی‌کند، اما وقتی درست انجام شود، تفاوت را همه حس می‌کنند.

سخن پایانی این مسیر

بهینه‌سازی HTML را می‌توان در یک جمله خلاصه کرد: «کاهش حجم، کاهش عمق، و مدیریت درست منابع مسدودکننده.» سه درس که از این مسیر با خودم بردم:

  1. HTML را جدی بگیرید. در مسیر بهینه‌سازی سرعت، اکثر تیم‌ها مستقیم به سراغ CSS، JS و تصاویر می‌روند. اما HTML اولین لایه‌ی مسیر رندر است. اگر این لایه کند باشد، بقیه‌ی بهینه‌سازی‌ها بی‌اثر می‌شوند.
  2. عمق DOM را کاهش دهید. ساختار تخت با تگ‌های معنایی، هم سریع‌تر رندر می‌شود و هم دسترس‌پذیرتر است. هر لایه div اضافه، یک هزینه‌ی پنهان است.
  3. منابع مسدودکننده‌ی رندر را مدیریت کنید. inline critical CSS، defer اسکریپت‌ها و preload فونت، سه تکنیک با اثر مستقیم روی FCP و LCP. هرکدام از این‌ها چند دقیقه کار است و اثرش هفته‌ها باقی می‌ماند.

مسیر یادگیری وب با این نوشته تمام نمی‌شود. اگر می‌خواهید مرحله‌ی بعدی را بردارید، آموزش CSS از صفر، آموزش جاوااسکریپت از صفر و متا تگ ها در HTML سه قدم منطقی بعدی هستند. اگر روی سرعت متمرکز هستید، افزایش سرعت وردپرس، بهینه سازی CSS و بهینه سازی جاوااسکریپت منابع کلیدی هستند. اگر هم به سمت معیارهای گوگل می‌روید، Core Web Vitals چیست و بهینه‌سازی سرعت سایت دید وسیع‌تری می‌دهند.

اگر در پروژه‌ای با یک مورد عجیب HTML روبرو شده‌اید — مثلاً صفحه‌ای که حجم CSS و JS آن کم است اما همچنان کند بار می‌شود، یا موردی که با کاهش تعداد گره‌های DOM به یک بهبود محسوس در TTI رسیده‌اید — جزئیات سناریو را در دیدگاه بنویسید. مخصوصاً اگر با اضافه کردن fetchpriority یا تغییر ترتیب منابع در HTML، LCP به‌طور محسوسی بهبود یافته، همان تجربه برای خواننده‌ی بعدی از هر توضیح کلی ارزشمندتر است.