CSS مدرن در Production؛ Baseline، Fallback و معماری


تیم فرانت‌اند یک داشبورد فارسی را با Container Query، :has() و رنگ‌های oklch() بازطراحی می‌کند. روی لپ‌تاپ‌های تیم همه‌چیز عالی است؛ اما در WebView قدیمی دستگاه انبار، کارت سفارش بی‌چیدمان می‌شود، دکمه روی پس‌زمینه خوانا نیست و هیچ‌کس نمی‌داند باید Feature را خاموش کند یا کل Release را برگرداند. مشکل «CSS جدید» نیست؛ مشکل، نبود قرارداد پذیرش، Fallback و مشاهده‌پذیری است.

CSS مدرن یک فهرست هیجان‌انگیز از Syntaxها نیست. یک قابلیت زمانی برای Production ارزش دارد که مسئله مشخصی را حل کند، در Browser matrix واقعی کاربران سنجیده شود، حالت بدون پشتیبانی قابل‌استفاده بماند، Accessibility و Performance آن آزموده شود و مالک Rollback داشته باشد. این راهنما همین مسیر را برای Nesting، Cascade layers، Container queries، :has()، Logical properties، Subgrid، OKLCH، View Transitions و چند ابزار مهم دیگر اجرا می‌کند.

خلاصه اجرایی: CSS مدرن را چگونه وارد Production کنیم؟

  1. ابتدا Job، کاربران، Browser/WebViewهای هدف و خطای قابل‌قبول را ثبت کنید.
  2. Baseline را نقطه شروع Evidence بدانید، نه جایگزین Analytics و Device lab خودتان.
  3. برای هر Feature یکی از سه راه را انتخاب کنید: Enhancement اختیاری، Fallback لازم یا Block تا عبور از Gate.
  4. معماری Cascade، Token و Component contract را قبل از Syntaxهای نمایشی تثبیت کنید.
  5. قابلیت را در Content، RTL، Zoom، Keyboard، Reduced motion و مرورگر واقعی آزمایش کنید.
  6. با Pilot محدود، Error/UX/Performance guardrail و Kill switch منتشر کنید.

نتیجه مطلوب «استفاده از تعداد بیشتری Feature» نیست؛ کاهش کد تکراری، افزایش استقلال کامپوننت، رفع Conflict، تجربه بهتر و نگهداری ارزان‌تر با Risk کنترل‌شده است.

مرز این راهنما با مقالات تخصصی دیگر

این صفحه مالک تصمیم پذیرش و معماری CSS مدرن است. پیاده‌سازی کامل Viewport، Media/Container query، تصویر تطبیقی و تست Device در راهنمای طراحی ریسپانسیو آمده است. Token، Component contract و Governance موضوع ساخت سیستم طراحی است؛ Shadow DOM و Styling API نیز در راهنمای Web Components پوشش داده می‌شوند. این تفکیک مانع می‌شود هر صفحه به فهرست تکراری ابزارهای فرانت‌اند تبدیل شود.

«CSS جدید» تاریخ انتشار ندارد؛ Target دارد

برچسب‌هایی مانند CSS3، CSS ۲۰۲۵ یا «آخرین CSS» برای تصمیم Production کافی نیستند. CSS از Moduleهای متعدد تکامل می‌یابد و وضعیت یک Feature می‌تواند در Engine، نسخه مرورگر، WebView، Syntax جزئی و باگ‌های پیاده‌سازی متفاوت باشد. بنابراین Target را با چهار مؤلفه تعریف کنید:

  • Audience: کاربر عمومی، پنل داخلی، کیوسک، اپ Hybrid یا Embedded WebView؛
  • Environment: مرورگر، نسخه، سیستم‌عامل، Device class، زبان/RTL و شبکه؛
  • Criticality: تزئین، خوانایی، Navigation، فرم، Checkout یا عملیات حیاتی؛
  • Failure mode: بدون انیمیشن، چیدمان ساده‌تر، رنگ جایگزین یا Flow مسدود.

یک Feature تازه ممکن است برای Transition تزئینی قابل‌قبول و برای دکمه پرداخت ممنوع باشد. Risk به نام Feature وابسته نیست؛ به محل استفاده و پیامد شکست وابسته است.

قرارداد پذیرش Feature را قبل از کدنویسی بنویسید

فیلدپرسش تصمیمنمونه
Jobچه مسئله قابل‌اندازه‌گیری حل می‌شود؟کارت در Sidebar و Grid بدون Variant دستی سازگار شود
Targetکدام Browser/WebView و چه سهمی؟Browser matrix بر پایه RUM سی روز گذشته
Criticalityشکست چه اثری دارد؟Layout فقط؛ Action و Content باقی می‌مانند
Fallbackدر نبود Support چه دیده می‌شود؟Card یک‌ستونه و قابل‌استفاده
EvidenceSupport و رفتار از کجا تأیید می‌شود؟Baseline/MDN + تست Device واقعی
Guardrailچه چیزی نباید بدتر شود؟Overflow، Contrast، CLS، Task completion
Owner/Exitچه کسی پایش و خاموش می‌کند؟Frontend platform؛ Flag سطح Theme

اگر Job فقط «مدرن‌شدن کد» است، Benefit هنوز تعریف نشده است. معیارهایی مثل کاهش Variantهای دستی، کاهش Override، زمان ساخت Component، تعداد باگ Layout یا حجم CSS تکراری Evidence بهتری می‌سازند.

Baseline چیست و چه چیزی را ثابت نمی‌کند؟

Baseline وضعیت دسترس‌پذیری Featureها در Browserهای اصلی را به زبان مشترک تبدیل می‌کند. راهنمای رسمی انتخاب Baseline target در web.dev بین Newly available، Widely available و Target ثابت تمایز می‌گذارد. Widely available پس از یک بازه زمانی مشخص از پیاده‌سازی سراسری، Adoption کم‌ریسک‌تری را نشان می‌دهد.

اما Baseline موارد زیر را تضمین نمی‌کند:

  • کاربران واقعی شما Browser یا WebView تازه دارند؛
  • همه زیرویژگی‌ها و Syntaxها یک سطح Support دارند؛
  • Feature بدون باگ Interop یا مشکل Accessibility است؛
  • Performance آن برای DOM، Content و Device شما مناسب است؛
  • یک ابزار Build، Minifier یا CSS-in-JS Syntax را درست عبور می‌دهد.

Baseline ورودی تصمیم است. خروجی تصمیم از تقاطع Baseline، RUM، Browser policy، Test matrix و Criticality به‌دست می‌آید.

Browser matrix را از داده خودتان بسازید

Global support درصد کاربران شما نیست. در یک فروشگاه ایرانی ممکن است Chrome Android غالب باشد؛ در سامانه سازمانی، WebView مدیریت‌شده یا نسخه ثابت Edge تعیین‌کننده باشد. حداقل این فیلدها را برای سی تا نود روز ثبت و به‌شکل Aggregate نگه دارید: Browser family/version، OS، Device class، WebView/standalone، Locale/direction، Page/flow و Outcome. جمع‌آوری باید با Notice، Purpose و Retention روشن انجام شود.

سه Cohort بسازید: Core که باید تجربه کامل بگیرد، Long tail که Fallback قابل‌استفاده می‌گیرد و Unsupported که پیام ارتقا یا مسیر جایگزین نیاز دارد. درصد به‌تنهایی کافی نیست؛ ده کاربر انبار با Device قدیمی ممکن است از نظر درآمد/عملیات مهم‌تر از هزار بازدید محتوایی باشند.

سه سطح Fallback: Cosmetic، Structural و Functional

سطحنمونهرفتار نبود SupportGate
CosmeticOKLCH، Blur یا Transitionرنگ sRGB یا بدون Motionخوانایی و Brand حفظ شود
StructuralSubgrid یا Container queryGrid/Flex ساده، بدون OverflowOrder و Content سالم بماند
Functionalنمایش Error یا Action بر پایه StateHTML/JS state صریحFlow حیاتی هرگز فقط به CSS متکی نباشد

CSS error handling باعث می‌شود Declaration ناشناخته نادیده گرفته شود، اما این به‌معنای Fallback خوب نیست. اگر رنگ دوم نادیده گرفته شود شاید رنگ اول کار کند؛ اگر کل Layout بر Container query بنا شده باشد، باید Base layout از قبل قابل‌استفاده باشد.

Progressive Enhancement با ترتیب Declaration و @supports

مستند رسمی MDN درباره Feature queries توضیح می‌دهد که @supports توان Parseکردن Property/Value را می‌سنجد، نه نبود باگ یا کامل‌بودن پیاده‌سازی. Base را ابتدا بنویسید و Enhancement را مشروط اضافه کنید:

.price-badge {
  background: #2547d0;
  color: #fff;
}

@supports (color: oklch(60% 0.2 260)) {
  .price-badge {
    background: oklch(55% 0.2 260);
  }
}

@supports not (container-type: inline-size) {
  .product-card {
    display: block;
  }
}

برای رفتارهای حیاتی، فقط Feature detection کافی نیست؛ یک Smoke test در Browser واقعی و Acceptance test Flow لازم است. Polyfill نیز رایگان نیست: حجم، Runtime، Security، Semantics ناقص و هزینه نگهداری دارد.

Build-time و Runtime را با هم اشتباه نگیرید

PostCSS یا Compiler می‌تواند بعضی Syntaxهای قابل‌تبدیل را به CSS قدیمی‌تر تبدیل کند، اما هر Feature قابل Transpile کامل نیست. مقدار ثابت color-mix() ممکن است در Build محاسبه شود؛ مقدار Dynamic وابسته به Custom property ممکن است رفتار Runtime بخواهد. Container query یا View Transition نیز صرفاً با تبدیل Syntax به همان Semantics در Browser قدیمی تبدیل نمی‌شود.

در ماتریس Toolchain ثبت کنید: Source syntax، خروجی Build، Target browsers، Prefix/transform، Source map، Minification و رفتار Development/Production. Snapshot خروجی CSS را در CI نگه دارید تا Upgrade ابزار Build بدون دیده‌شدن Cascade را عوض نکند.

معماری Cascade پیش از Featureهای نمایشی

بخش بزرگی از بدهی CSS از جنگ Specificity می‌آید، نه کمبود Syntax. @layer ترتیب Origin داخلی کد را صریح می‌کند. برای نمونه:

@layer reset, tokens, base, components, utilities, overrides;

@layer components {
  :where(.button) {
    padding-inline: var(--space-3);
    padding-block: var(--space-2);
  }
}

@layer utilities {
  .u-hidden { display: none; }
}

ترتیب Layer را یک‌بار در Entry point تعریف کنید. توجه کنید Styleهای Normal بدون Layer از Layerها اولویت بیشتری دارند و ترتیب !important در Layerها معکوس می‌شود؛ بنابراین مهاجرت تصادفی نصف فایل‌ها به Layer می‌تواند Surprise بسازد. ابتدا Inventory، سپس Pilot یک Slice و در پایان Migration rule داشته باشید.

@scope؛ مرز DOM بدون Selectorهای شکننده

@scope اجازه می‌دهد Ruleها در زیردرخت مشخص اعمال شوند و Scoping proximity را وارد Cascade می‌کند. این قابلیت برای Widget، ناحیه و Component مفید است، اما Shadow DOM یا Security boundary نیست. DOM همچنان مشترک است و Global custom property/Inheritance می‌تواند وارد Scope شود.

چون @scope نسبت به قابلیت‌های قدیمی‌تر جدیدتر است، Adoption آن را جداگانه بسنجید. اگر هدف فقط جلوگیری از Collision نام کلاس است، Naming convention، CSS Modules یا Layer شاید با Target فعلی Fit بهتری داشته باشد.

CSS Nesting؛ خوانایی بدون وعده کاهش خودکار حجم

طبق راهنمای رسمی CSS Nesting در MDN، Nesting بومی در Browser Parse می‌شود و با Preprocessor متفاوت است. مزیت اصلی Locality و کاهش تکرار نویسندگی است؛ خروجی شبکه لزوماً کوچک‌تر یا Runtime لزوماً سریع‌تر نمی‌شود. Nesting عمیق همچنین Coupling و Specificity را پنهان می‌کند.

.card {
  border: 1px solid var(--border);

  &:hover { border-color: var(--accent); }

  > .card__title {
    margin-block: 0 var(--space-2);
  }
}

قاعده عملی: عمق را کم نگه دارید، رابطه والد را با & روشن کنید، Nested selector تولیدشده را در DevTools ببینید و با Selector listهای پرSpecificity محتاط باشید. Nesting جای Mixin، Loop یا همه قابلیت‌های Sass نیست و دلیل حذف فوری Build pipeline هم محسوب نمی‌شود.

Container Query؛ استقلال Layout در سطح کامپوننت

MDN درباره Size و Style container queries توضیح می‌دهد که @container ویژگی Container را می‌سنجد، نه Viewport را. برای کارت قابل‌استفاده در Main، Sidebar و Modal، این مدل از Breakpoint سراسری دقیق‌تر است:

.product-region {
  container: product / inline-size;
}

.product-card {
  display: grid;
  gap: 1rem;
}

@container product (min-width: 34rem) {
  .product-card {
    grid-template-columns: minmax(10rem, 1fr) 2fr;
  }
}

اما container-type نوعی Containment اعمال می‌کند و Size باید از Context یا مقدار صریح بیاید؛ انتخاب Container اشتباه می‌تواند Query را به Ancestor دیگری وصل یا اندازه را غیرمنتظره کند. Media query هنوز برای Viewport، Preference، Input و Environment لازم است. Container query آن را حذف نمی‌کند.

:has() فقط «Parent selector» نیست

:has() یک Relational pseudo-class است: Element را بر اساس وجود/وضعیت Relative selector انتخاب می‌کند. برای Card دارای Media، Form group دارای Field نامعتبر یا List دارای Item فعال مفید است. اما State کسب‌وکار را فقط از DOM حدس نزنید؛ «پرداخت موفق» باید در Data/ARIA/HTML state صریح باشد.

.field:has(input:user-invalid) {
  border-color: var(--danger);
}

.card:has(> .card__media) {
  grid-template-areas: "media body";
}

Specificity خود :has() صفر اضافه نمی‌کند؛ سنگین‌ترین Selector آرگومان در Weight اثر می‌گذارد. راهنمای رسمی Specificity در MDN همین رفتار را برای :is()، :not() و Nesting نیز شرح می‌دهد. برای API قابل Override از :where()، Layer و Selector ساده استفاده کنید. Selectorهای Relational گسترده را روی DOM بزرگ Profile کنید؛ «CSS بومی» مترادف «هزینه صفر» نیست.

Logical Properties؛ پیش‌فرض بهتر برای فارسی و RTL

CSS Logical properties در MDN به‌جای چپ/راست فیزیکی، محور Inline/Block و جهت نوشتار را مدل می‌کند. برای محصول فارسی از margin-inline-start، padding-inline، inset-inline-end و border-start-start-radius استفاده کنید.

بااین‌حال Mirroring کامل نیست. لوگو، نمودار زمان، آیکون Play، شماره تلفن، کد، قیمت و رشته Mixed-direction قواعد جدا دارند. Fixture فارسی شامل نیم‌فاصله، ی/ک، عدد لاتین/فارسی، تومان/ریال، URL، Email و متن طولانی بسازید و با dir="rtl"/dir="ltr" واقعی تست کنید.

Subgrid؛ هم‌ترازی فرزندان بدون Grid تودرتوی مستقل

وقتی Cardهای یک Listing باید عنوان، توضیح، قیمت و Action را در ردیف‌های مشترک هم‌تراز کنند، subgrid خطوط Grid والد را به Grid فرزند منتقل می‌کند. این Feature برای Layout رابطه‌ای مفید است، نه هر کامپوننت.

Fallback می‌تواند Grid مستقل یا Flex column باشد. Acceptance را با عنوان یک‌خطی/پنج‌خطی، تصویر Missing، قیمت تخفیف‌دار، Badge، زبان فارسی و Zoom آزمایش کنید. Pixel-perfect برابر در Browser قدیمی لازم نیست؛ Reading order و Action باید سالم بماند.

Custom Properties و @property؛ Token، Type و Animation

Custom propertyها Token runtime، Theme، Context و Composition را ممکن می‌کنند. @property می‌تواند Syntax، Inheritance و Initial value را ثبت کند و برخی مقادیر را قابل Animation کند. ولی هر متغیر CSS نباید Public API شود. نام، Type، Fallback، Scope، Owner و Deprecation را مشخص کنید.

این ساختار باید با قرارداد Token و Component هماهنگ باشد، نه با نام رنگ خام در هر صفحه. برای معماری سه‌لایه Primitive→Semantic→Component و Versioning به راهنمای سیستم طراحی لینک‌شده مراجعه کنید.

OKLCH و color-mix؛ رنگ ادراکی با Fallback و تست Contrast

oklch() تنظیم Lightness/Chroma/Hue را برای ساخت پالت ادراکی منظم‌تر می‌کند و color-mix() ترکیب رنگ را در فضای مشخص انجام می‌دهد. یک مقدار sRGB قبل از مقدار مدرن بگذارید تا Browser قدیمی Declaration اول را نگه دارد:

.notice {
  background: #eaf0ff;
  background: color-mix(in oklch, var(--brand) 14%, white);
  color: #17214a;
}

Wide gamut روی همه Displayها یکسان دیده نمی‌شود و بعضی رنگ‌ها خارج از Gamut مقصد Map می‌شوند. Contrast را با زوج رنگ نهایی و Stateهای Hover/Focus/Disabled آزمایش کنید. نام قدیمی color-contrast() را نسخه Production فرض نکنید؛ قابلیت جدید contrast-color() نیز فقط سفید یا سیاه برمی‌گرداند و برای Mid-toneها تضمین خوانایی کامل نیست. Fallback و تست WCAG همچنان لازم‌اند.

Fluid Type و Layout با clamp؛ Constraint، نه جادوی Responsive

clamp(min, preferred, max) برای Typography و Space سیال مفید است، به‌شرطی که Minimum/Maximum بر اساس خوانایی و Layout تعریف شوند. فرمول Viewport-only ممکن است در Zoom، نمایشگر بسیار عریض یا متن فارسی بلند خروجی بد بدهد. Line length، Line height، Reflow و Content stress را همراه اندازه فونت بسنجید.

Token سیال باید در Design system مالک داشته باشد. استفاده پراکنده از ده‌ها فرمول clamp() Debug و هماهنگی را سخت‌تر می‌کند.

View Transitions؛ Enhancement برای تداوم، نه شرط Navigation

View Transition API بین Stateهای یک Document و Navigation اسناد، Snapshot و Transition می‌سازد. طبق راهنمای رسمی MDN، SPA برای DOM update معمولاً document.startViewTransition() می‌خواهد؛ MPA هم‌Origin می‌تواند با Opt-in هر دو صفحه در @view-transition { navigation: auto; } بدون JavaScript پایه کار کند.

این API CSS خالص برای همه سناریوها نیست. Navigation، URL، Focus، Scroll، Loading و Error باید بدون Transition درست بمانند. view-transition-name یکتا، Snapshotهای بزرگ، تصاویر دیررس و State ناپایدار را آزمایش کنید. تصمیم Duration/Easing/Purpose و مرز CSS/WAAPI/Library در راهنمای UI Motion عمیق‌تر شده است.

Reduced Motion بخشی از Definition of Done است

مستند prefers-reduced-motion در MDN می‌گوید Preference سیستم‌عامل برای کاهش Motion غیرضروری قابل شناسایی است. برای Scale، Pan، Parallax و Transitionهای بزرگ جایگزین کم‌حرکت یا بدون حرکت بدهید:

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*) {
    animation-duration: 0.01ms;
  }

  .decorative-motion {
    animation: none;
    transform: none;
  }
}

Global rule کور با !important ممکن است Feedback ضروری یا State transition را هم حذف کند. Motion inventory را به Essential، Helpful و Decorative تقسیم و هرکدام را آگاهانه Reduce/Replace/Remove کنید.

CSS بومی تضمین Performance نیست

حذف JavaScript ممکن است Bundle و Main-thread work را کم کند، اما Performance به Selector matching، Style recalculation، Layout، Paint، Compositing، DOM size و Frequency تغییر State وابسته است. :has() گسترده، Filter/Backdrop، Shadowهای بزرگ یا Animation Layout property می‌تواند هزینه بسازد.

قبل/بعد را با RUM و Lab روی Device ضعیف مقایسه کنید: LCP، INP، CLS، Long task، Style/Layout time، FPS در Interaction و Memory. راهنمای Core Web Vitals و RUM قرارداد اندازه‌گیری را پوشش می‌دهد. اگر Component به JavaScript سنگین وابسته است، تحلیل Loading/Rendering/Memory در راهنمای Performance اپلیکیشن JavaScript مکمل این صفحه است.

content-visibility؛ بهینه‌سازی مشروط، نه کلاس عمومی

content-visibility: auto می‌تواند Layout/Paint محتوای خارج از Viewport را به تعویق بیندازد و همراه contain-intrinsic-size فضای تخمینی نگه دارد. روی صفحه بلند ممکن است مفید باشد، اما مقدار تخمینی بد، Jump و Scrollbar ناپایدار می‌سازد. Search-in-page، Focus، Fragment navigation، Print و Accessibility tree را در Browserهای هدف تست کنید.

آن را روی Header، Above-the-fold، Error/Toast، Form فعال یا محتوایی که با اندازه Ancestor ارتباط پیچیده دارد کورکورانه اعمال نکنید. Benefit باید با Profile واقعی ثابت شود.

Accessibility با Syntax حل نمی‌شود

:has(:invalid) می‌تواند Border را قرمز کند، اما Error قابل‌دسترس به Label، متن، Association، Focus management و Announcement نیاز دارد. Container query می‌تواند Visual order را عوض کند، اما DOM/Reading order باید منطقی بماند. رنگ ادراکی زیبا جای Contrast، Non-color cue و State test را نمی‌گیرد.

Keyboard، Screen reader، Zoom ۲۰۰/۴۰۰، Reflow، Forced colors، High contrast، Reduced motion، Touch target، RTL و Content stress را در Acceptance بگذارید. برای فرآیند کامل Automated+Manual+Assistive Technology از راهنمای ممیزی دسترس‌پذیری وب و برای نگاه Inclusive از طراحی وب فراگیر استفاده کنید.

Test matrix؛ Support با Screenshot دسکتاپ اثبات نمی‌شود

بعدحداقل Fixtureشاهد
BrowserCore + قدیمی‌ترین Supported + WebView واقعیFunctional/visual diff
Viewport/Containerباریک، میانی، عریض و Containerهای واقعیبدون Overflow/Overlap
Contentکوتاه، بلند، Missing، Error، LoadingReading/Action سالم
Localeفارسی RTL، Mixed-direction، عدد/ارز/تاریخOrder و Alignment صحیح
AccessKeyboard، Zoom، Screen reader، Reduced motionTask completion
PerformanceDevice ضعیف و صفحه Production-likeBudget و RUM guardrail
FallbackFeature disabled/unsupportedBase experience قابل‌استفاده

Visual regression را به چند Pixel ثابت محدود نکنید؛ DOM state، Font loading، Dynamic content و Browser rendering Noise را کنترل کنید. Acceptance انسانی برای خوانایی، Motion و Interaction همچنان لازم است.

Rollout، Observability و Kill switch

یک Vertical slice انتخاب کنید: یک Card پرتکرار اما غیرحیاتی. Base/Fallback و Enhancement را جدا Commit کنید، Browser matrix را در CI اجرا کنید و با درصد محدود یا Theme flag منتشر کنید. Release marker بگذارید و Guardrailهای Error، Overflow report، Task completion، CWV و Support ticket را قبل/بعد ببینید.

Kill switch می‌تواند Class سطح Root، Flag سمت سرور یا CSS bundle قبلی باشد. Rollback باید Asset cache/CDN و Versioning را هم در نظر بگیرد؛ فقط Revert کد منبع کافی نیست. Owner، Threshold و Expiry Feature flag را در Change record بنویسید.

سناریوی ایران: پنل سفارش روی موبایل و WebView انبار

فروشگاه ایرانی کارت سفارش را در موبایل پشتیبانی، نمایشگر رومیزی مالی و WebView دستگاه انبار استفاده می‌کند. تیم ابتدا Container query را روی کارت فعال می‌کند، اما Base layout را Flex column نگه می‌دارد. Logical properties جهت فارسی را مدیریت و Fixture شامل نام طولانی، کد رهگیری لاتین، مبلغ تومان، تاریخ شمسی و Status چندخطی ساخته می‌شود.

در Browserهای تازه کارت دو/سه‌ستونه می‌شود؛ WebView قدیمی همان نسخه یک‌ستونه را می‌گیرد. :has() فقط Highlight ظاهری Order دارای هشدار را انجام می‌دهد؛ State هشدار در HTML و API صریح است. View Transition برای جابه‌جایی Detail تزئینی است و با Reduced motion حذف می‌شود. Pilot روی ده کاربر انبار اجرا و زمان انجام سفارش، خطای لمس، Overflow و Ticket ثبت می‌شود. اگر Guardrail رد شود، Flag Enhancement خاموش می‌شود بدون آنکه عملیات متوقف شود.

Roadmap نودروزه پذیرش CSS مدرن

روز ۱ تا ۳۰: Baseline، Inventory و Contract

  • Browser/WebView matrix را از RUM و Device inventory بسازید.
  • CSS architecture، Specificity، Override، Bundle و باگ‌های پرتکرار را Baseline کنید.
  • سه Feature با Job روشن انتخاب و قرارداد Adoption/Fallback/Owner بنویسید.
  • Fixture فارسی/RTL/Accessibility و Browser test suite را آماده کنید.

روز ۳۱ تا ۶۰: Pilot و Failure Test

  • Layer order و یک Component pilot را پیاده کنید.
  • حالت Feature unsupported، Content extreme، Zoom و Reduced motion را عمداً اجرا کنید.
  • Build output، Visual/functional test و Performance budget را در CI قرار دهید.
  • با Flag محدود منتشر و Evidence کیفی/کمی جمع کنید.

روز ۶۱ تا ۹۰: Scale، Hold یا Stop

  • Benefit و Guardrail را با Baseline مقایسه و Decision record منتشر کنید.
  • Pattern موفق را در Design system، Lint rule و Documentation ثبت کنید.
  • Feature کم‌ارزش یا پرریسک را Hold/Stop و Code path اضافه را حذف کنید.
  • Browser policy، Deprecation و Review فصلی را مالک‌دار کنید.

چک‌لیست Definition of Done

  • Job، Target، Criticality و Outcome مشخص است.
  • Browser matrix از داده کاربران و نیاز کسب‌وکار ساخته شده است.
  • Baseline/MDN/Specification و تاریخ بررسی ثبت شده‌اند.
  • Base experience بدون Feature قابل‌استفاده است.
  • @supports یا ترتیب Fallback فقط جایی استفاده شده که لازم است.
  • Build tool و CSS خروجی Production بررسی شده‌اند.
  • Specificity، Layer و Scope با معماری موجود سازگارند.
  • RTL، Mixed direction، Zoom، Keyboard و Screen reader تست شده‌اند.
  • Reduced motion و Contrast حالت‌های واقعی دارند.
  • Performance قبل/بعد روی Device ضعیف و RUM سنجیده شده است.
  • Fallback و Failure mode عمداً تست شده‌اند.
  • Pilot، Owner، Guardrail، Kill switch و Rollback ثبت شده‌اند.

پرسش‌های متداول

آیا باید همه قابلیت‌های جدید CSS را فوراً استفاده کنیم؟

خیر. Feature را بر اساس Job، Browser matrix کاربران، Criticality و هزینه Fallback انتخاب کنید. قابلیت Widely available نیز اگر مسئله‌ای حل نکند فقط Surface نگهداری را زیاد می‌کند؛ قابلیت Newly available هم برای Enhancement کم‌خطر ممکن است مناسب باشد.

Baseline Widely available یعنی دیگر تست مرورگر لازم نیست؟

خیر. Baseline نشانه قوی Compatibility عمومی است، اما Browser/WebView کاربران، باگ‌های Interop، Toolchain، Accessibility و Performance پروژه شما را تضمین نمی‌کند. تست واقعی و RUM همچنان لازم‌اند.

آیا CSS Nesting جای Sass را می‌گیرد؟

فقط اگر نیاز پروژه به Sass عمدتاً Nesting بوده باشد. Sass همچنان Mixin، Function، Loop و Build-time logic دارد. تصمیم حذف باید بر Inventory قابلیت‌های مصرف‌شده، خروجی Build، Migration cost و Benefit نگهداری تکیه کند.

Container Query بهتر است یا Media Query؟

هیچ‌کدام جای دیگری را به‌طور کامل نمی‌گیرد. Container query برای Layout وابسته به فضای Component مناسب است؛ Media query برای Viewport، Preference، Orientation/Input و محیط. بسیاری از محصولات هر دو را در دو سطح متفاوت استفاده می‌کنند.

آیا CSS مدرن همیشه JavaScript کمتر و سایت سریع‌تر می‌سازد؟

نه به‌صورت خودکار. بعضی رفتارهای Styling/Layout را می‌توان بدون JavaScript انجام داد، اما هزینه Selector، Style recalculation، Layout، Paint و Animation باقی است. سرعت باید با Lab و RUM قبل/بعد ثابت شود و رفتار کسب‌وکار همچنان ممکن است JavaScript یا Server state بخواهد.

جمع‌بندی: Modern CSS یعنی تصمیم قابل‌بازگشت

بهترین تیم CSS تیمی نیست که زودتر از همه Syntax تازه را وارد کند؛ تیمی است که می‌داند کدام مسئله را برای کدام کاربر حل می‌کند، نبود Support چگونه Fail می‌شود و چه زمانی باید Feature را خاموش کند. Baseline و مستندات رسمی Evidence اولیه می‌دهند؛ Progressive enhancement، معماری Cascade، Test matrix، Accessibility، RUM و Rollback آن را به قابلیت Production تبدیل می‌کنند.

از یک Component و یک Job شروع کنید. Base سالم بسازید، Enhancement را اضافه کنید، Failure را عمداً ببینید و فقط با Evidence Scale کنید. در این مدل، CSS مدرن دیگر موج سالانه نیست؛ بخشی کنترل‌شده از مهندسی محصول است.

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *