چرا PageSpeed Insights هنوز میگوید «Eliminate render-blocking resources»؟
شما فایل CSS را minify کردهاید، تصاویر را فشردهاید، حتی از CDN استفاده میکنید. اما گزارش PageSpeed Insights هنوز همان خط قرمز همیشگی را نشان میدهد: «Eliminate render-blocking resources». و زیرش لیستی از فایلهای CSS و جاوااسکریپت که ظاهراً هیچکدامشان هم «ضروری» به نظر نمیرسند.
این خطا یعنی مرورگر، قبل از اینکه بتواند اولین پیکسل صفحه را رسم کند، منتظر دانلود و پردازش این فایلها میماند. نه دانلود شدنشان، بلکه پردازش کاملشان. یک فایل CSS ۲۰ کیلوبایتی که فقط استایل یک اسلایدر را در پایین صفحه تعیین میکند، میتواند رندر کل صفحه را ۳۰۰ میلیثانیه عقب بیندازد. در یک اتصال با تأخیر ۱۰۰ میلیثانیه، همین یک فایل، سه دور رفتوبرگشت اضافه به بارگذاری تحمیل میکند.
مشکل فقط سرعت نیست. گوگل از سال ۲۰۲۱ معیارهای Core Web Vitals را در نتایج جستجو اعمال میکند و LCP یکی از سه معیار اصلی است. render blocking مستقیم روی LCP اثر میگذارد. پس این خطا، یک پیشنهاد سئویی نیست؛ یک فاکتور رتبهبندی است.
راهحل هم حذف فایلها نیست. راهحل، فهمیدن این است که کدام منابع واقعاً برای رندر اولیه لازماند و کدامها میتوانند صبر کنند. در این مقاله، هر سه ابزار را با جزئیات فنی بررسی میکنیم: critical CSS، صفتهای defer و async، و preload. و مهمتر از همه، میگوییم هرکدام کجا جواب میدهد و کجا دردسر میسازد.
critical CSS: فقط آنچه برای رندر اولیه لازم است
critical CSS یعنی استایلهای مربوط به محتوای بالای صفحه (above-the-fold) را جدا کنید و بهصورت inline در HTML بیاورید. بقیه استایلها را در فایل جدا نگه دارید و با بارگذاری غیرهمزمان (async) اضافه کنید.
یک مثال واقعی. فرض کنید فایل style.css شما ۴۵ کیلوبایت است. مرورگر باید کل این فایل را دانلود و parse کند تا بتواند صفحه را رسم کند. اما از این ۴۵ کیلوبایت، شاید فقط ۸ کیلوبایت مربوط به هدر، منوی اصلی و ناحیه اول صفحه باشد. آن ۸ کیلوبایت را در <style> داخل <head> بگذارید. مرورگر دیگر منتظر هیچ فایل خارجی نمیماند.
ابزارهای مختلفی برای تولید خودکار critical CSS وجود دارد. ابزار رایگان critical از npm یکی از معروفهاست:
npm install -g critical
critical --base https://example.com --width 1366 --height 768 --inline
این دستور صفحه را با ابعاد مشخص render میکند و CSS مربوط به همان ناحیه را استخراج میکند. خروجی را در <head> قرار دهید و بقیه CSS را با روش زیر بارگذاری کنید:
<link rel="stylesheet" href="/css/style.css" media="print" onload="this.media='all'">
این ترفند قدیمی اما مؤثر، به مرورگر میگوید فایل را با اولویت پایین (print) دانلود کند و بعد از load، آن را به حالت عادی برگرداند. مرورگرهای مدرن این الگو را میشناسند و فایل را بدون مسدود کردن رندر دانلود میکنند.
اینجا اشتباه میکنند
رایجترین اشتباهی که دیدهام این است: توسعهدهنده کل CSS را inline میکند. فایل خارجی را حذف میکند و همه ۴۵ کیلوبایت را میریزد توی <style>. نتیجه؟ HTML صفحه از ۳۰ کیلوبایت میشود ۷۵ کیلوبایت. حالا مرورگر باید HTML بیشتری دانلود کند و زمان تا اولین بایت (TTFB) بالا میرود. و چون CSS داخل HTML است، هیچ کشی هم نمیشود. هر بازدید، همان ۷۵ کیلوبایت را دوباره دانلود میکند.
نشانه این اشتباه: حجم HTML شما بهطور غیرعادی بالا رفته و LCP بهبود نیافته یا حتی بدتر شده است. critical CSS یعنی فقط استایلهای بالای صفحه، نه همه استایلها.
یک نکته دیگر: اگر سایت شما تکصفحهای (SPA) است یا از فریمورکی مثل React استفاده میکند، تولید critical CSS دستی تقریباً غیرممکن است. در آن حالت، ابزارهای خودکار داخل فریمورک (مثل Next.js که بهصورت پیشفرض CSS را بهصورت inline در میآورد) را ترجیح دهید.
defer و async: دو صفت، دو رفتار متفاوت
برای جاوااسکریپت، دو صفت دارید که هرکدام رفتار متفاوتی دارند. تفاوتشان ظریف است اما نتیجهاش در سرعت بارگذاری کاملاً محسوس است.
صفت defer به مرورگر میگوید: فایل را موازی با HTML دانلود کن، اما اجرایش را تا پایان parse شدن HTML به تأخیر بینداز. اسکریپتهای defer به ترتیب ظاهر شدن در HTML اجرا میشوند. این صفت برای اسکریپتهایی که به DOM وابستهاند مناسب است.
صفت async یعنی: فایل را موازی دانلود کن و به محض آماده شدن، اجرایش کن. ترتیب اجرا تضمین نمیشود. اسکریپتی که زودتر دانلود شود، زودتر اجرا میشود. این صفت برای اسکریپتهای مستقل مثل آنالیتیکس یا اسکریپت تزریق تبلیغ مناسب است.
کدام را انتخاب کنید؟ قانون ساده: اگر اسکریپت شما به DOM نیاز دارد و ترتیب اجرا مهم است، defer. اگر اسکریپت مستقل است و وابستگی به چیز دیگری ندارد، async. اگر هیچکدام را نگذارید، اسکریپت شما render blocking میشود و مرورگر تا دانلود و اجرای کامل آن، رندر را متوقف میکند.
یک مثال از کاربرد درست. فرض کنید دو اسکریپت دارید: jquery.js و main.js که به jQuery وابسته است. هر دو را با defer بارگذاری کنید. ترتیب اجرا حفظ میشود و رندر مسدود نمیشود. حالا فرض کنید اسکریپت چت آنلاین دارید که مستقل است. آن را با async بارگذاری کنید.
<script src="/js/jquery.js" defer></script>
<script src="/js/main.js" defer></script>
<script src="/js/live-chat.js" async></script>
موردی که defer جواب نمیدهد
اسکریپتهایی که در حین parse سند، عناصری را تزریق میکنند (مثل برخی اسکریپتهای تبلیغاتی قدیمی) با defer به هم میریزند. چون defer اجرا را به بعد از parse موکول میکند و آن اسکریپتها انتظار دارند در میانه parse اجرا شوند. اگر بعد از افزودن defer متوجه شدید محتوای خاصی در صفحه ظاهر نمیشود یا ترتیب عناصر به هم ریخته، احتمالاً با یکی از همین اسکریپتها طرفاید. در آن حالت، اسکریپت را در انتهای <body> بگذارید و صفت defer را حذف کنید. بله، این کار ایدهآل نیست، اما گاهی تنها راهحل عملی برای اسکریپتهای شخص ثالث است.
preload: ابزاری که خودش گلوگاه میشود
صفت rel="preload" به مرورگر میگوید: این منبع را همین حالا با اولویت بالا دانلود کن، چون بهزودی به آن نیاز پیدا میکنی. کاربرد اصلیاش برای فونتها و تصاویر hero است که مرورگر تا زمان مواجهه با CSS مربوطه، از وجودشان خبر ندارد.
<link rel="preload" href="/fonts/vazir.woff2" as="font" type="font/woff2" crossorigin>
اینجا دقیقاً همانجاست که preload به درد میخورد. فونت وزیر را در نظر بگیرید. مرورگر تا وقتی CSS را نخواند و متوجه نشود که فونت موردنیاز است، دانلود فونت را شروع نمیکند. با preload، دانلود فونت از همان ابتدا شروع میشود و همزمان با CSS جلو میرود.
اما اینجا اشتباه میکنند: preload را برای همه چیز استفاده میکنند. هر تصویر، هر فایل CSS، هر اسکریپت. نتیجه؟ مرورگر دارد همه چیز را با اولویت بالا دانلود میکند و پهنای باند محدود مرورگر بین این منابع تقسیم میشود. منابع واقعاً حیاتی (مثل CSS اصلی) کندتر دانلود میشوند. LCP بدتر میشود. و شما یک warning جدید در PageSpeed Insights میگیرید: «Preload key requests».
قانون من این است: preload را فقط برای فونتها و حداکثر یک یا دو منبع حیاتی که مرورگر دیر متوجهشان میشود استفاده کنید. اگر بیش از ۳-۴ مورد preload دارید، دارید به سیستم اولویتبندی مرورگر آسیب میزنید.
یک نکته فنی دیگر: برای فونتها، حتماً صفت crossorigin را بگذارید. بدون آن، فونت دانلود نمیشود و در کنسول مرورگر خطای CORS میبینید. این خطا را بارها دیدهام: توسعهدهنده preload را درست اضافه کرده اما crossorigin را فراموش کرده و فونت همچنان دیر بارگذاری میشود.
ترتیب درست: کجا شروع کنیم
اگر سایت شما وردپرسی است، افزونههایی مثل WP Rocket یا Perfmatters این کارها را خودکار انجام میدهند. اما اگر سایت سفارشی دارید یا میخواهید دستی این کار را بکنید، ترتیب پیشنهادی من این است:
- ابتدا با PageSpeed Insights یا ابزار تست سرعت و ابزارهای سئو گزارش بگیرید و ببینید دقیقاً کدام فایلها render blocking هستند.
- فایلهای CSS را بررسی کنید. اگر فایل CSS شما بزرگ است (بیش از ۲۰ کیلوبایت) و فقط بخشی از آن برای رندر اولیه لازم است، critical CSS را پیاده کنید.
- اسکریپتهای جاوااسکریپت را دستهبندی کنید: کدامها به DOM نیاز دارند (defer)، کدامها مستقلاند (async)، کدامها باید در میانه parse اجرا شوند (هیچکدام، بگذارید در انتهای body).
- فونتها را با preload بارگذاری کنید و crossorigin را فراموش نکنید.
- دوباره تست کنید و اعداد را مقایسه کنید.
یک نکته مهم: بعد از هر تغییر، حتماً تست کنید که سایت از نظر بصری سالم است. ابزارهای خودکار گاهی CSS اشتباهی را critical تشخیص میدهند و نتیجه میشود صفحهای که استایلاش بهمرور زمان و با تأخیر اعمال میشود. کاربر صفحه را بدون CSS میبیند و بعد ناگهان همه چیز جا میافتد. این تجربه بدتر از کندی بارگذاری است.
اگر با معیارهای Core Web Vitals تازه شروع کردهاید، پیشنهاد میکنم اول راهنمای عملی Core Web Vitals را بخوانید تا تصویر کاملتری از معیارها داشته باشید. و اگر مشکل شما فراتر از render blocking است و سرعت کلی سایت افت کرده، راهنمای کامل افزایش سرعت سایت مسیر گامبهگام را نشان میدهد.
حذف render blocking یک کار یکباره نیست. هر بار که یک افزونه جدید نصب میکنید یا یک اسکریپت جدید اضافه میکنید، ممکن است یک منبع مسدودکننده جدید وارد صفحه شود. یک بررسی ماهانه با PageSpeed Insights یا ابزار مشابه، جلوی بازگشت تدریجی مشکل را میگیرد.
اگر این کارها را انجام دادید و هنوز LCP شما بالاست، مشکل جای دیگری است. شاید تصاویر سنگیناند یا سرور پاسخدهی کندی دارد. در آن صورت، راهنمای بهبود LCP را ببینید و سراغ بهینهسازی تصویر با فرمتهای WebP و AVIF بروید. render blocking فقط یک بخش از پازل است؛ اما بخشی که معمولاً اولین و سادهترین جایی است که میتوانید امتیاز بگیرید.
و اگر این کارها را برای سایت مشتری انجام میدهید و زمان کافی برای پیادهسازی دستی ندارید، خدمات سئو میتواند این بخش از بهینهسازی فنی را برای شما مدیریت کند. اما اگر خودتان دستی کار میکنید، همین الان شروع کنید: یک فایل CSS را بردارید و ببینید اگر آن را با media="print" بارگذاری کنید، چه اتفاقی میافتد.
پرسشهای پرتکرار
فرق defer و async چیست و کدام را استفاده کنم؟
defer اسکریپت را بعد از parse کامل HTML اجرا میکند و ترتیب اجرا را حفظ میکند. async اسکریپت را به محض آماده شدن اجرا میکند و ترتیب تضمینی ندارد. برای اسکریپتهای وابسته به DOM از defer و برای اسکریپتهای مستقل مثل آنالیتیکس از async استفاده کنید.
آیا حذف render blocking روی سئو تأثیر دارد؟
بله. render blocking مستقیماً روی LCP اثر میگذارد که یکی از معیارهای Core Web Vitals است. گوگل این معیارها را در رتبهبندی موبایل لحاظ میکند. بهبود LCP میتواند هم تجربه کاربری و هم رتبه شما را بهبود دهد.
آیا میتوانم همه CSS را inline کنم؟
نه. inline کردن همه CSS حجم HTML را بهشدت بالا میبرد و امکان کش شدن را از بین میبرد. فقط استایلهای مربوط به بالای صفحه (critical CSS) را inline کنید و بقیه را با روشهای غیرهمزمان بارگذاری کنید.
چرا preload فونت کار نمیکند؟
محتملترین دلیل، نبود صفت crossorigin در تگ preload است. فونتها بهصورت CORS بارگذاری میشوند و بدون crossorigin، مرورگر درخواست را رد میکند. حتماً crossorigin را به تگ اضافه کنید.
دیدگاهها ۰
هنوز دیدگاهی ثبت نشده؛ اولین نفر باشید!