اخیراً کریس کویر در یک پست وبلاگی این سوال را مطرح کرد:
اکنون که کوئری های کانتینر در همه موتورهای مرورگر پشتیبانی می شوند، چرا توسعه دهندگان بیشتری از آنها استفاده نمی کنند؟
پست کریس تعدادی از دلایل بالقوه را فهرست می کند (به عنوان مثال، عدم آگاهی، عادات قدیمی سخت می میرند)، اما یک دلیل خاص وجود دارد که برجسته است.
برخی از توسعه دهندگان می گویند اکنون می خواهند از پرس و جوهای کانتینر استفاده کنند، اما فکر می کنند نمی توانند این کار را انجام دهند زیرا هنوز باید از مرورگرهای قدیمی پشتیبانی کنند.
همانطور که ممکن است از عنوان حدس زده باشید، ما فکر می کنیم این امکان برای اکثر توسعه دهندگان وجود دارد که از پرس و جوهای کانتینر در حال حاضر - در حال تولید - استفاده کنند، حتی اگر مجبور به پشتیبانی از مرورگرهای قدیمی باشید. این پست شما را با روشی که ما برای انجام آن توصیه می کنیم راهنمایی می کند.
یک رویکرد عمل گرایانه
اگر میخواهید هماکنون از پرسوجوهای کانتینر در کد خود استفاده کنید، اما میخواهید تجربه در همه مرورگرها یکسان به نظر برسد، میتوانید برای مرورگرهایی که کوئریهای کانتینری را پشتیبانی نمیکنند، یک نسخه بازگشتی مبتنی بر جاوا اسکریپت پیادهسازی کنید.
سپس این سؤال پیش میآید: نسخه بازگشتی چقدر باید جامع باشد؟
مانند هر بازگشتی دیگری، چالش ایجاد تعادل مناسب بین سودمندی و عملکرد است. برای ویژگیهای CSS، اغلب غیرممکن است که از API کامل پشتیبانی کنید (ببینید چرا از polyfill استفاده نمیکنید ). با این حال، میتوانید با شناسایی مجموعه اصلی از عملکردهایی که بیشتر توسعهدهندگان میخواهند از آن استفاده کنند، و سپس بهینهسازی نسخه بازگشتی فقط برای آن ویژگیها، بسیار پیشرفت کنید.
اما "مجموعه اصلی عملکرد" که اکثر توسعه دهندگان برای جستجوهای کانتینر می خواهند چیست؟ برای پاسخ به این سوال، در نظر بگیرید که چگونه اکثر توسعهدهندگان سایتهای واکنشگرا را در حال حاضر با پرس و جوهای رسانهای میسازند.
تقریباً تمام سیستمهای طراحی مدرن و کتابخانههای مؤلفهها بر اساس اصول موبایل اول استاندارد شدهاند و با استفاده از مجموعهای از نقاط شکست از پیش تعریفشده (مانند SM
، MD
، LG
، XL
) پیادهسازی شدهاند. کامپوننتها بهطور پیشفرض برای نمایش خوب در صفحهنمایشهای کوچک بهینهسازی میشوند، و سپس سبکها بهطور مشروط لایهبندی میشوند تا از مجموعه ثابتی از عرضهای صفحه نمایش بزرگتر پشتیبانی کنند. (برای نمونه هایی از این به مستندات Bootstrap و Tailwind مراجعه کنید.)
این رویکرد به همان اندازه که با سیستمهای طراحی مبتنی بر کانتینر مرتبط است ، به سیستمهای طراحی مبتنی بر ویوپورت مربوط میشود، زیرا در بیشتر موارد، چیزی که به طراحان مربوط میشود این نیست که صفحه نمایش یا نما چقدر بزرگ است، بلکه میزان فضای در دسترس قطعه است. در زمینه ای که قرار داده شده است. به عبارت دیگر، به جای اینکه نقاط شکست نسبت به کل دیدگاه (و قابل اعمال برای کل صفحه) باشد، نقاط شکست در قسمتهای محتوای خاصی مانند نوارهای کناری، دیالوگهای مدال یا متنهای پست اعمال میشوند.
اگر میتوانید در چارچوب محدودیتهای یک رویکرد مبتنی بر نقطه شکست (که اکثر توسعهدهندگان در حال حاضر انجام میدهند) کار کنید، پس پیادهسازی یک بازگشت مبتنی بر کانتینر برای آن رویکرد بهطور قابلتوجهی آسانتر از اجرای پشتیبانی کامل برای هر درخواست کانتینر است. ویژگی
بخش بعدی دقیقاً نحوه عملکرد همه اینها را توضیح می دهد، همراه با یک راهنمای گام به گام که به شما نشان می دهد چگونه آن را در یک سایت موجود پیاده سازی کنید.
چگونه کار می کند
مرحله 1: سبک های مؤلفه خود را به روز کنید تا از قوانین @container
به جای قوانین @media
استفاده کنید
در این مرحله اول، هر مؤلفهای را در سایت خود شناسایی کنید که فکر میکنید از اندازهگذاری مبتنی بر کانتینر به جای اندازهگیری مبتنی بر viewport بهره میبرد.
ایده خوبی است که فقط با یک یا دو جزء شروع کنید تا ببینید این استراتژی چگونه کار می کند، اما اگر می خواهید 100٪ اجزای خود را به یک ظاهر طراحی مبتنی بر ظرف تبدیل کنید، این نیز خوب است! نکته مهم در مورد این استراتژی این است که در صورت نیاز می توانید آن را به صورت تدریجی اتخاذ کنید.
هنگامی که مؤلفه هایی را که می خواهید به روز کنید شناسایی کردید، باید هر قانون @media
را در CSS آن مؤلفه ها به یک قانون @container
تغییر دهید.
در اینجا نمونهای از نحوه ظاهر شدن آن در یک مؤلفه .photo-gallery
است که بهطور پیشفرض، یک ستون است، و سپس از قوانین @media
برای بهروزرسانی طرحبندی خود برای تبدیل شدن به دو و سه ستون در نقاط شکست MD و XL (به ترتیب) استفاده میکند. :
.photo-gallery {
display: grid;
grid-template-columns: 1fr;
}
/* Styles for the `MD` breakpoint */
@media (min-width: 800px) {
.photo-gallery {
grid-template-columns: 1fr 1fr;
}
}
/* Styles for the `XL` breakpoint */
@media (min-width: 1200px) {
.photo-gallery {
grid-template-columns: 1fr 1fr 1fr;
}
}
برای به روز رسانی مولفه .photo-gallery
برای استفاده از قوانین @container
، ابتدا رشته @media
با رشته @container
در CSS جایگزین کنید. دستور زبان این دو قانون به اندازه کافی مشابه است که در بسیاری از موارد، ممکن است این تنها چیزی باشد که باید تغییر دهید.
بسته به طراحی سایت خود، ممکن است لازم باشد شرایط اندازه را نیز به روز کنید، به خصوص اگر قوانین @media
سایت شما فرضیات خاصی را در مورد میزان فضای موجود برای اجزای خاص در اندازه های مختلف نمای در نظر گرفته باشد.
برای مثال، اگر استایلهای CSS .photo-gallery
در نقاط شکست MD
و XL
در مثال قبلی فرض کنند که یک نوار کناری با عرض 200 پیکسل در آن نقاط شکست نمایش داده میشود، آنگاه شرایط اندازه برای قوانین @container
باید حدود 200 باشد. پیکسل کمتر - با فرض اینکه عنصر "محفظه" برای مؤلفه .photo-gallery
شامل نوار کناری نمی شود.
در مجموع، برای تبدیل CSS .photo-gallery
از قوانین @media
به قوانین @container
، مجموعه کامل تغییرات به شرح زیر است:
/* Before, using the original breakpoint sizes: */
@media (min-width: 800px) { /* ... */ }
@media (min-width: 1200px) { /* ... */ }
/* After, with the breakpoint sizes reduced by 200px: */
@container (min-width: 600px) { /* ... */ }
@container (min-width: 1000px) { /* ... */ }
توجه داشته باشید که لازم نیست هیچ یک از سبکهای داخل بلوک اعلان را تغییر دهید، زیرا این سبکها به جای اینکه چه زمانی باید سبکهای خاص اعمال شوند، نمایانگر ظاهر مؤلفه هستند.
هنگامی که استایل های اجزای خود را از قوانین @media
به قوانین @container
به روز کردید، گام بعدی پیکربندی عناصر کانتینر است.
مرحله 2: عناصر ظرف را به HTML خود اضافه کنید
مرحله قبل سبک های مؤلفه ای را تعریف کرد که بر اساس اندازه یک عنصر ظرف است. گام بعدی این است که تعریف کنید کدام عناصر در صفحه شما باید آن عناصر کانتینری باشند که قواعد @container
نسبت به اندازه آنها باشد.
شما می توانید هر عنصری را به عنوان یک عنصر Container در CSS با تنظیم خاصیت container-type
آن به size
یا inline-size
اعلام کنید. اگر قوانین کانتینر شما مبتنی بر عرض است، inline-size
معمولاً همان چیزی است که می خواهید استفاده کنید.
سایتی را با ساختار HTML اصلی زیر در نظر بگیرید:
<body>
<div class="sidebar">...</div>
<div class="content">...</div>
</body>
برای ایجاد کانتینرهای .sidebar
و .content
در این سایت، این قانون را به CSS خود اضافه کنید:
.content, .sidebar {
container-type: inline-size;
}
برای مرورگرهایی که از پرس و جوهای کانتینر پشتیبانی می کنند، این CSS تمام چیزی است که شما نیاز دارید تا سبک های مؤلفه تعریف شده در مرحله قبل را نسبت به ناحیه محتوای اصلی یا نوار کناری، بسته به عنصری که اتفاقاً در آن قرار دارند، بسازید.
با این حال، برای مرورگرهایی که از پرس و جوهای کانتینر پشتیبانی نمی کنند، کارهای بیشتری برای انجام دادن وجود دارد.
شما باید کدی اضافه کنید که تشخیص دهد اندازه عناصر ظرف تغییر می کند و سپس DOM را بر اساس این تغییرات به گونه ای به روز می کند که CSS شما بتواند به آن متصل شود.
خوشبختانه، کد مورد نیاز برای انجام این کار حداقل است، و می توان آن را به طور کامل در یک جزء مشترک که می توانید در هر سایت و در هر منطقه محتوایی استفاده کنید، انتزاع کرد.
کد زیر یک عنصر <responsive-container>
قابل استفاده مجدد را تعریف می کند که به طور خودکار به تغییرات اندازه گوش می دهد و کلاس های نقطه شکست را اضافه می کند که CSS شما می تواند بر اساس آن استایل کند:
// A mapping of default breakpoint class names and min-width sizes.
// Redefine these (or add more) as needed based on your site's design.
const defaultBreakpoints = {SM: 400, MD: 600 LG: 800, XL: 1000};
// A resize observer that monitors size changes to all <responsive-container>
// elements and calls their `updateBreakpoints()` method with the updated size.
const ro = new ResizeObserver((entries) => {
entries.forEach((e) => e.target.updateBreakpoints(e.contentRect));
});
class ResponsiveContainer extends HTMLElement {
connectedCallback() {
const bps = this.getAttribute('breakpoints');
this.breakpoints = bps ? JSON.parse(bps) : defaultBreakpoints;
this.name = this.getAttribute('name') || '';
ro.observe(this);
}
disconnectedCallback() {
ro.unobserve(this);
}
updateBreakpoints(contentRect) {
for (const bp of Object.keys(this.breakpoints)) {
const minWidth = this.breakpoints[bp];
const className = this.name ? `${this.name}-${bp}` : bp;
this.classList.toggle(className, contentRect.width >= minWidth);
}
}
}
self.customElements.define('responsive-container', ResponsiveContainer);
این کد با ایجاد یک ResizeObserver کار می کند که به طور خودکار به تغییرات اندازه هر عنصر <responsive-container>
در DOM گوش می دهد. اگر تغییر اندازه با یکی از اندازه های نقطه شکست تعریف شده مطابقت داشته باشد، کلاسی با آن نام نقطه شکست به عنصر اضافه می شود (و اگر شرط دیگر مطابقت نداشته باشد حذف می شود).
به عنوان مثال، اگر width
عنصر <responsive-container>
بین 600 تا 800 پیکسل باشد (بر اساس مقادیر نقطه شکست پیشفرض تنظیم شده در کد)، کلاسهای SM
و MD
اضافه میشوند، مانند این:
<responsive-container class="SM MD">...</responsive-container>
این کلاسها به شما امکان میدهند سبکهای بازگشتی را برای مرورگرهایی که از پرسوجوهای Container پشتیبانی نمیکنند، تعریف کنید ( مرحله 3 را ببینید: اضافه کردن سبکهای بازگشتی به CSS خود ).
برای بهروزرسانی کد HTML قبلی برای استفاده از این عنصر ظرف، نوار کناری و عناصر محتوای اصلی <div>
را به عناصر <responsive-container>
تغییر دهید:
<body>
<responsive-container class="sidebar">...</responsive-container>
<responsive-container class="content">...</responsive-container>
</body>
در بیشتر مواقع، میتوانید از عنصر <responsive-container>
بدون هیچ گونه سفارشیسازی استفاده کنید، اما اگر نیاز به سفارشیسازی آن دارید، گزینههای زیر در دسترس هستند:
- اندازههای نقطه شکست سفارشی: این کد از مجموعهای از نامهای کلاس نقطه شکست پیشفرض و اندازههای حداقل عرض استفاده میکند، اما شما این پیشفرضها را به هر چیزی که دوست دارید تغییر میدهید. همچنین می توانید این مقادیر را بر اساس هر عنصر با استفاده از ویژگی
breakpoints
لغو کنید. - کانتینرهای نامدار: این کد از کانتینرهای نامگذاری شده نیز با ارسال ویژگی
name
پشتیبانی می کند. اگر نیاز به لانه سازی عناصر ظرف دارید، این می تواند مهم باشد. برای جزئیات بیشتر به بخش محدودیت ها مراجعه کنید.
در اینجا یک مثال است که هر دو گزینه پیکربندی را تنظیم می کند:
<responsive-container
name='sidebar'
breakpoints='{"bp4":400,"bp5":500,"bp6":600,"bp7":700,"bp8":800,"bp9":900,"bp10":1000}'>
</responsive-container>
در نهایت، هنگام بستهبندی این کد، مطمئن شوید که از تشخیص ویژگی و import()
پویا استفاده میکنید تا فقط در صورتی که مرورگر از پرسوجوهای Container پشتیبانی نمیکند، آن را بارگیری کنید.
if (!CSS.supports('container-type: inline-size')) {
import('./path/to/responsive-container.js');
}
مرحله 3: سبک های بازگشتی را به CSS خود اضافه کنید
آخرین مرحله در این استراتژی، اضافه کردن سبک های بازگشتی برای مرورگرهایی است که سبک های تعریف شده در قوانین @container
را نمی شناسند. این کار را با کپی کردن آن قوانین با استفاده از کلاس های نقطه شکست که روی عناصر <responsive-container>
تنظیم می شوند، انجام دهید.
در ادامه با مثال .photo-gallery
از قبل، استایل های بازگشتی برای دو قانون @container
ممکن است به شکل زیر باشد:
/* Container query styles for the `MD` breakpoint. */
@container (min-width: 600px) {
.photo-gallery {
grid-template-columns: 1fr 1fr;
}
}
/* Fallback styles for the `MD` breakpoint. */
@supports not (container-type: inline-size) {
:where(responsive-container.MD) .photo-gallery {
grid-template-columns: 1fr 1fr;
}
}
/* Container query styles for the `XL` breakpoint. */
@container (min-width: 1000px) {
.photo-gallery {
grid-template-columns: 1fr 1fr 1fr;
}
}
/* Fallback styles for the `XL` breakpoint. */
@supports not (container-type: inline-size) {
:where(responsive-container.XL) .photo-gallery {
grid-template-columns: 1fr 1fr 1fr;
}
}
در این کد، برای هر قانون @container
یک قانون معادل وجود دارد که به صورت شرطی با عنصر <responsive-container>
مطابقت دارد، اگر کلاس نقطه شکست مربوطه وجود داشته باشد.
بخشی از انتخابگر که با عنصر <responsive-container>
مطابقت دارد در یک انتخابگر کلاس شبه عملکردی :where() پیچیده شده است تا ویژگی انتخابگر بازگشتی معادل ویژگی انتخابگر اصلی در قانون @container
باشد.
هر قانون بازگشتی نیز در یک اعلان @supports
پیچیده می شود. در حالی که این امر برای کارکردن مجدد ضروری نیست، به این معنی است که مرورگر در صورت پشتیبانی از پرس و جوهای کانتینری، این قوانین را کاملاً نادیده می گیرد، که می تواند عملکرد تطبیق سبک را به طور کلی بهبود بخشد. همچنین به طور بالقوه به ابزارهای ساخت یا CDN ها اجازه می دهد تا آن اعلان ها را حذف کنند اگر بدانند مرورگر از پرس و جوهای کانتینر پشتیبانی می کند و به آن سبک های بازگشتی نیاز ندارد.
نقطه ضعف اصلی این استراتژی بازگشتی این است که از شما میخواهد اعلام سبک را دو بار تکرار کنید، که هم خستهکننده و هم مستعد خطا است. با این حال، اگر از یک پیش پردازنده CSS استفاده میکنید، میتوانید آن را به یک mixin انتزاعی کنید که هم قانون @container
و هم کد بازگشتی را برای شما ایجاد میکند. در اینجا یک مثال با استفاده از Sass آورده شده است:
@use 'sass:map';
$breakpoints: (
'SM': 400px,
'MD': 600px,
'LG': 800px,
'XL': 1000px,
);
@mixin breakpoint($breakpoint) {
@container (min-width: #{map.get($breakpoints, $breakpoint)}) {
@content();
}
@supports not (container-type: inline-size) {
:where(responsive-container.#{$breakpoint}) & {
@content();
}
}
}
سپس، هنگامی که این میکس را دارید، میتوانید استایلهای اصلی کامپوننت .photo-gallery
را به چیزی شبیه به این بهروزرسانی کنید، که تکرار را کاملاً از بین میبرد:
.photo-gallery {
display: grid;
grid-template-columns: 1fr;
@include breakpoint('MD') {
grid-template-columns: 1fr 1fr;
}
@include breakpoint('XL') {
grid-template-columns: 1fr 1fr 1fr;
}
}
و این تمام چیزی است که در آن وجود دارد!
خلاصه
بنابراین، برای جمع بندی، در اینجا نحوه به روز رسانی کد خود برای استفاده از پرس و جوهای کانتینر با استفاده از یک مرورگر متقاطع آورده شده است.
- مؤلفههایی را که میخواهید به آنها استایل دهید نسبت به کانتینرشان شناسایی کنید و قوانین
@media
را در CSS آنها بهروزرسانی کنید تا از قوانین@container
استفاده کنید. همچنین (اگر قبلاً این کار را نکردهاید)، مجموعهای از نامهای نقطه شکست را استاندارد کنید تا با شرایط اندازه در قوانین ظرف شما مطابقت داشته باشد. - جاوا اسکریپت را اضافه کنید که عنصر
<responsive-container>
سفارشی را تقویت می کند، و سپس عنصر<responsive-container>
را به هر قسمت محتوایی در صفحه خود که می خواهید اجزای شما نسبت به آن باشند، اضافه کنید. - برای پشتیبانی از مرورگرهای قدیمیتر، سبکهای بازگشتی را به CSS خود اضافه کنید که با کلاسهای نقطه شکست که بهطور خودکار به عناصر
<responsive-container>
در HTML شما اضافه میشوند، مطابقت دارند. در حالت ایدهآل از میکسین پیشپردازنده CSS استفاده کنید تا از نوشتن دوبار سبکهای مشابه اجتناب کنید.
نکته مهم در مورد این استراتژی این است که هزینه راه اندازی یکباره دارد، اما پس از آن اضافه کردن اجزای جدید و تعریف سبک های کانتینری برای آنها نیازی به تلاش اضافی ندارد.
دیدن آن در عمل
احتمالاً بهترین راه برای درک اینکه چگونه همه این مراحل با هم تطبیق داده می شوند، دیدن نسخه نمایشی آن در عمل است.
این نسخه آزمایشی یک نسخه به روز شده از سایتی است که در سال 2019 (قبل از وجود پرس و جوهای کانتینر) ایجاد شده است تا به توضیح اینکه چرا پرس و جوهای کانتینر برای ساخت کتابخانه های مؤلفه واقعاً پاسخگو ضروری هستند، کمک می کند.
از آنجایی که این سایت قبلاً دارای سبکهایی بود که برای دستهای از «کامپوننتهای پاسخگو» تعریف شده بود، کاندیدای عالی برای آزمایش استراتژی معرفیشده در اینجا در یک سایت غیر ضروری بود. به نظر می رسد، در واقع به روز رسانی آن بسیار ساده بود و تقریباً نیازی به تغییر در سبک های اصلی سایت نداشت.
میتوانید کد منبع کامل نسخه آزمایشی را در GitHub بررسی کنید، و حتماً به طور خاص به CSS مؤلفه آزمایشی نگاه کنید تا ببینید سبکهای بازگشتی چگونه تعریف میشوند. اگر میخواهید فقط رفتار بازگشتی را آزمایش کنید، یک نسخه آزمایشی فقط بازگشتی وجود دارد که فقط آن نوع را شامل میشود - حتی در مرورگرهایی که از پرسوجوهای کانتینر پشتیبانی میکنند.
محدودیت ها و بهبودهای بالقوه
همانطور که در ابتدای این پست ذکر شد، استراتژی ذکر شده در اینجا برای اکثر موارد استفاده که توسعه دهندگان در هنگام جستجوی پرس و جوهای کانتینر واقعاً به آنها اهمیت می دهند به خوبی کار می کند.
با این حال، موارد استفاده پیشرفته تری وجود دارد که این استراتژی عمداً سعی در پشتیبانی از آنها ندارد، که در ادامه به آنها اشاره می شود:
واحدهای جستجوی کانتینر
مشخصات مربوط به پرس و جوهای کانتینر تعدادی واحد جدید را تعریف می کند که همگی با اندازه کانتینر مرتبط هستند. در حالی که در برخی موارد به طور بالقوه مفید است، اکثر طرحهای واکنشگرا احتمالاً از طریق ابزارهای موجود، مانند درصد یا استفاده از طرحبندی شبکهای یا انعطافپذیر قابل دستیابی هستند.
گفته شد، اگر نیاز به استفاده از واحدهای جستجوی کانتینر دارید، میتوانید به راحتی با استفاده از ویژگیهای سفارشی ، پشتیبانی از آنها را اضافه کنید. به طور خاص، با تعریف یک ویژگی سفارشی برای هر واحد مورد استفاده در عنصر کانتینر، مانند این:
responsive-container {
--cqw: 1cqw;
--cqh: 1cqh;
}
و سپس هر زمان که نیاز به دسترسی به واحدهای جستجوی کانتینر داشتید، به جای استفاده از خود واحد، از آن خصوصیات استفاده کنید:
.photo-gallery {
font-size: calc(10 * var(--cqw));
}
سپس، برای پشتیبانی از مرورگرهای قدیمی، مقادیر آن خصوصیات سفارشی را در عنصر کانتینر در پاسخ به تماس ResizeObserver
تنظیم کنید.
class ResponsiveContainer extends HTMLElement {
// ...
updateBreakpoints(contentRect) {
this.style.setProperty('--cqw', `${contentRect.width / 100}px`);
this.style.setProperty('--cqh', `${contentRect.height / 100}px`);
// ...
}
}
این به طور موثر به شما امکان میدهد آن مقادیر را از جاوا اسکریپت به CSS منتقل کنید و سپس قدرت کامل CSS را دارید (به عنوان مثال calc()
, min()
, max()
, clamp()
) تا در صورت نیاز آنها را دستکاری کنید.
ویژگی های منطقی و پشتیبانی از حالت نوشتن
ممکن است در برخی از این نمونههای CSS متوجه استفاده از inline-size
به جای width
در اعلانهای @container
شده باشید. ممکن است شما نیز متوجه واحدهای جدید cqi
و cqb
شده باشید (به ترتیب برای اندازه های درون خطی و بلوک). این ویژگی های جدید منعکس کننده تغییر CSS به خواص و مقادیر منطقی به جای ویژگی های فیزیکی یا جهت دار است.
متأسفانه، API هایی مانند Resize Observer هنوز مقادیر width
و height
را گزارش می دهند، بنابراین اگر طرح های شما به انعطاف پذیری ویژگی های منطقی نیاز دارند، باید خودتان آن را بفهمید.
در حالی که دریافت حالت نوشتن با استفاده از چیزی مانند getComputedStyle()
در عنصر کانتینر ممکن است، انجام این کار هزینه دارد و واقعاً راه خوبی برای تشخیص تغییر حالت نوشتن وجود ندارد.
به همین دلیل، بهترین رویکرد این است که خود عنصر <responsive-container>
یک ویژگی حالت نوشتن را بپذیرد که صاحب سایت می تواند در صورت نیاز تنظیم کند (و به روز کند). برای پیاده سازی این، شما باید همان رویکردی را که در بخش قبل نشان داده شده است، دنبال کنید و در صورت نیاز width
و height
تعویض کنید.
ظروف تو در تو
ویژگی container-name
به شما امکان می دهد نامی برای یک کانتینر بدهید، که سپس می توانید به یک قانون @container
ارجاع دهید. ظروف نامگذاری شده در صورتی مفید هستند که ظروف داخل ظروف تو در تو داشته باشید و به قوانین خاصی نیاز داشته باشید که فقط با ظروف خاصی مطابقت داشته باشد (نه فقط نزدیکترین ظرف اجدادی).
استراتژی بازگشتی که در اینجا به آن اشاره شده است، از ترکیبکننده نسل برای استایل دادن به عناصری که با کلاسهای نقطه شکست خاص مطابقت دارند، استفاده میکند. اگر کانتینرهای تو در تو داشته باشید، ممکن است خراب شود، زیرا هر تعداد کلاس نقطه شکست از چندین اجداد عنصر کانتینر می تواند همزمان با یک جزء معین مطابقت داشته باشد.
برای مثال، در اینجا دو عنصر <responsive-container>
وجود دارد که جزء .photo-gallery
را میپیچد، اما از آنجایی که ظرف بیرونی بزرگتر از ظرف داخلی است، کلاسهای نقطه شکست متفاوتی به آنها اضافه شده است.
<responsive-container class="SM MD LG">
...
<responsive-container class="SM">
...
<div class="photo-gallery">...</div class="photo-gallery">
</responsive-container>
</responsive-container>
در این مثال، کلاس MD
و LG
در کانتینر بیرونی بر قوانین سبک مطابق با مؤلفه .photo-gallery
تأثیر میگذارد، که با رفتار جستجوهای کانتینر مطابقت ندارد (زیرا آنها فقط با نزدیکترین ظرف اجداد مطابقت دارند).
برای مقابله با این، یا:
- مطمئن شوید که همیشه کانتینریهایی را که تودرتو میکنید نامگذاری میکنید، و سپس مطمئن شوید که کلاسهای نقطه شکست شما با نام ظرف پیشوند هستند تا از درگیری جلوگیری شود.
- از ترکیبکننده فرزند بهجای ترکیبکننده نزول در انتخابگرهای بازگشتی خود استفاده کنید (که کمی محدودتر است).
بخش کانتینرهای تودرتو در سایت آزمایشی نمونهای از این کار با استفاده از کانتینرهای نامگذاری شده، همراه با میکس Sass را دارد که در کد برای تولید استایلهای بازگشتی برای قوانین @container
نامدار و بدون نام استفاده میکند.
در مورد مرورگرهایی که :where()
، Custom Elements یا Resize Observer را پشتیبانی نمی کنند چطور؟
در حالی که این APIها ممکن است نسبتا جدید به نظر برسند، اما همه آنها بیش از سه سال است که در همه مرورگرها پشتیبانی می شوند و همه آنها بخشی از Baseline هستند که به طور گسترده در دسترس هستند.
بنابراین، مگر اینکه دادههایی داشته باشید که نشان میدهد بخش قابل توجهی از بازدیدکنندگان سایت شما در مرورگرهایی هستند که یکی از این ویژگیها را پشتیبانی نمیکنند، هیچ دلیلی وجود ندارد که آزادانه از آنها بدون بازگشت استفاده نکنید.
حتی در آن صورت، برای این مورد خاص، بدترین اتفاقی که میتواند بیفتد این است که بازگشت مجدد برای درصد بسیار کمی از کاربران شما کار نخواهد کرد، به این معنی که آنها نمای پیشفرض را به جای یک نمای بهینهسازی شده برای اندازه کانتینر مشاهده خواهند کرد.
عملکرد سایت همچنان باید کار کند، و این چیزی است که واقعا اهمیت دارد.
چرا فقط از polyfill پرس و جوی کانتینر استفاده نمی کنید؟
ویژگیهای CSS بسیار دشوار است که چندپر شوند ، و عموماً نیاز به پیادهسازی مجدد کل تجزیهکننده CSS و منطق آبشار مرورگر در جاوا اسکریپت دارند. در نتیجه، نویسندگان CSS polyfill مجبورند معاوضههای زیادی را انجام دهند که تقریباً همیشه با محدودیتهای ویژگیهای متعدد و همچنین سربار عملکرد قابل توجهی همراه است.
به این دلایل، ما معمولاً استفاده از CSS polyfills را در تولید توصیه نمیکنیم، از جمله container-query-polyfill از Google Chrome Labs، که دیگر نگهداری نمیشود (و اساساً برای اهداف نمایشی در نظر گرفته شده بود).
استراتژی بازگشتی که در اینجا مورد بحث قرار میگیرد محدودیتهای کمتری دارد، به کد بسیار کمتری نیاز دارد، و عملکرد قابلتوجهی بهتر از هر پرس و جوی کانتینری polyfill دارد.
آیا حتی نیاز به پیاده سازی مجدد برای مرورگرهای قدیمی دارید؟
اگر نگران هر یک از محدودیتهای ذکر شده در اینجا هستید، احتمالاً ارزش این را دارد که از خود بپرسید که آیا در وهله اول نیاز به پیادهسازی مجدد دارید یا خیر. پس از همه، ساده ترین راه برای جلوگیری از این محدودیت ها این است که فقط از این ویژگی بدون هیچ گونه بازگشتی استفاده کنید. صادقانه بگویم، در بسیاری از موارد، ممکن است یک انتخاب کاملا منطقی باشد.
با توجه به caniuse.com ، پرس و جوهای کانتینر توسط 90٪ از کاربران جهانی اینترنت پشتیبانی می شوند، و برای بسیاری از افرادی که این پست را می خوانند، این تعداد برای پایگاه کاربری آنها احتمالاً کمی بیشتر است. بنابراین مهم است که به خاطر داشته باشید که اکثر کاربران شما نسخه Container Query UI شما را خواهند دید. و برای 10 درصد از کاربرانی که این کار را نمی کنند، اینطور نیست که تجربه ای شکسته داشته باشند. هنگام پیروی از این استراتژی، در بدترین حالت، این کاربران طرح پیشفرض یا «موبایل» را برای برخی از مؤلفهها مشاهده میکنند که پایان دنیا نیست.
هنگام ایجاد معاوضه، بهینهسازی برای اکثر کاربران شما یک تمرین خوب است - به جای پیشفرض رویکردی با کمترین مخرج مشترک که به همه کاربران تجربهای ثابت، اما پایینتر از همتراز را میدهد.
بنابراین قبل از اینکه فرض کنید به دلیل عدم پشتیبانی مرورگر نمیتوانید از پرسوجوهای کانتینر استفاده کنید، در واقع زمان بگذارید و در نظر بگیرید که اگر آنها را بپذیرید، تجربه چگونه خواهد بود. معاوضه ممکن است ارزش آن را داشته باشد، حتی بدون هیچ گونه بازگشتی.
چشم به راه است
امیدواریم این پست شما را متقاعد کرده باشد که اکنون می توان از پرس و جوهای کانتینر در تولید استفاده کرد و لازم نیست سال ها منتظر بمانید تا تمام مرورگرهای غیر پشتیبانی به طور کامل ناپدید شوند.
در حالی که استراتژی ذکر شده در اینجا نیاز به کمی کار اضافی دارد، باید به اندازه کافی ساده و سرراست باشد که اکثر مردم بتوانند آن را در سایت خود اتخاذ کنند. با این حال، مطمئناً فضایی برای آسانتر کردن پذیرش آن وجود دارد. یک ایده می تواند این باشد که بسیاری از قطعات متفاوت را در یک جزء واحد ادغام کنید - بهینه شده برای یک چارچوب یا پشته خاص - که تمام کار چسب را برای شما انجام دهد. اگر شما چیزی شبیه به این می سازید، به ما اطلاع دهید و ما می توانیم به ترویج آن کمک کنیم!
در نهایت، فراتر از پرس و جوهای کانتینر، بسیاری از ویژگیهای CSS و UI شگفتانگیز وجود دارد که اکنون در تمام موتورهای مرورگر اصلی قابل اجرا هستند. به عنوان یک جامعه، بیایید بفهمیم که چگونه میتوانیم از این ویژگیها استفاده کنیم تا کاربران ما بتوانند از آن بهره ببرند.
بهروزرسانی (25 ژوئیه 2024): در ابتدا دستورالعمل «مرحله 1» پیشنهاد میکرد که پرسشهای رسانه و درخواستهای ظرف میتوانند از شرایط اندازه یکسان استفاده کنند. این اغلب درست است اما نه همیشه (همانطور که برخی دلایل به درستی اشاره کردند ). راهنمای بهروزرسانیشده اکنون این موضوع را روشن میکند و مواردی را ارائه میکند که ممکن است شرایط اندازه نیاز به تغییر داشته باشد.
بهروزرسانی (۲ ژوئیه ۲۰۲۴): در ابتدا همه نمونههای کد CSS از Sass استفاده میکردند (برای سازگاری با توصیه نهایی). بر اساس بازخورد خوانندگان، چند CSS اول به CSS ساده به روز شده اند و Sass فقط در نمونه کدهایی استفاده می شود که نیاز به استفاده از میکسین دارند.