Галоўная / Артыкулы

Запыткі контэйнера проты запытак медыя: рашэнні ўзгалі для сторанцы і рашэнні для складовых элементаў

Дазвольце дазнаць, калі лепш выкарыстоўваць media query, а калі — container query, на прыкладах з картакамі, панелямі керування і елементамі адзінкай вялічыны, якія дапамагаюць адаптаваць компоненты для падзейнае выкарыстоўвання.

Выдавец: REACTAPP.TOP16 хв чытання3602 слоў

Крыніцы: Container Queries vs Media Queries: How Modern CSS Changes Responsive Design

Большая частка CSS, які забезпечаюць адаптыванне, все ўсё ж залежыць ад аднаго параметра — шырыны вікна браузера. Це добра працюе для всіяго сторанкі, але не падходзіць для повтарна викорыстоўваных компонентав, таму што карточка, якая адрасаванае ў боковай панелі, і тая ж карточка, якая адрасаванае ў шырокай галоўнай колонцы, бачаюць абодве той самы прэўьюпарт, хоця у іх зусім разны прыём для контэнту. У гэтым кярыянтэ показана, як контейнерныя запыты закрываюць гэтую праслойку, дзе медыя-запыты застаюцца кращым інструментам, а таксама як можна сумаваць іх з флуіднымі елементамі, стварыўшы адаптываную систему, яю можна легка кераваць.

Класычная правіла, якія залежыць ад прэўьюпарту, выглядае так: калі шырына вікна зменшыцца нижэй за певны рубік, карточка складае свой контэнт вертыкальна.

@media (max-width: 768px) {
  .card {
    flex-direction: column;
  }
}

Нічага тут не зламана. Слабасць якраз у концэпцыі: правіла вывучаюць, насколькі шырока вікна, але ніколі — насколькі шырока карточка. У маленькай дэманстрацыі этыя значэння супараднуюцца; у прыемнасці, заполненай сеткамі, бокавымі панелямі та іншымі элементамі, яны розходзяцца, і самэў гэты прыем стае прычыной багоў у макетацыі. Кэнтэйнерныя запиты дазволяюць компаненту запытацца "сколькі прастора у мяне на самай працоўцы?" замест "насколькі шырока экран?"

Чаму пункт перерыву вікна вводзіць у глухое становішча перадаўальную карточку

Возьмім простую карточку продукту: адпраўка па боку ад блока тексту з заглавлём, короткым описам і заклекчаннем да дзеяння. Маркап знаходзіцца тут у двух фрагментах, але ён являе сабою адны элемент.

<article class="product-card">
  <img src="product.jpg" alt="Product">
  <div class="product-info">
    <h2>Wireless Headphones</h2>
    <p>Noise cancellation with 30-hour battery life.</p>
    <button>Buy now</button>
  </div>
</article>

Першы этап стайлізацыі зазвычай размешчае адпраўку і текст па боку ад другога за дапамогою flexbox, а потым дадае пункт перерыву вікна, каб на маленькіх экранах яны былі размешчаны ў ряд.

.product-card {
  display: flex;
  gap: 1rem;
}
@media (max-width: 768px) {
  .product-card {
    flex-direction: column;
  }
}

Усё выглядае цяпла, пакуль карточка не вжываецца знову. На шырокай старонцы рабочага стола ёсць достатнько горызонтальнага прастору, і макет па бокі выглядае правільна.

Desktop page
┌───────────────────────────────────────────┐
│                                           │
│   Product Card                            │
│   ┌──────────┐  ┌─────────────────────┐   │
│   │  Image   │  │ Product information │   │
│   └──────────┘  └─────────────────────┘   │
│                                           │
└───────────────────────────────────────────┘

Якщо падаць тую ж карточку ў вузкі бокавы панель, яй потрэбен макет у шарах, нават як вікно залишаецца розмерам рабочага стола.

┌───────────────┐
│               │
│   Sidebar     │
│               │
│ ┌───────────┐ │
│ │   Image   │ │
│ ├───────────┤ │
│ │   Info    │ │
│ └───────────┘ │
│               │
└───────────────┘

Якщо размістыць калькі з іх у ряд на панелі керування, кожная карточка отрымае разны частак шыроці залежна ад свайго столбца.

┌───────────────────────────────────────────┐
│ ┌─────────────┐ ┌──────────────────────┐ │
│ │   Card      │ │       Card           │ │
│ └─────────────┘ └──────────────────────┘ │
└───────────────────────────────────────────┘

Тры месцы размешчэння, тры розныя шыроці, а вікно застаецца незменным. Правіла, заснованыя на размерах вікна, не можуць ўжо разлічыць іх, таму карточка ў бокавай панелі застаецца тыснёной.

У чаму насправді ўмелыя медыа-запиты

Запиты медыа аналізуюць параметры среды, у якой показваецца стораніца: размеры відобразавальнай зоны, оріўентацыю, палітру кольцаў, тип курсора, настройкі зменшання руху і так далей. Звычным прыкладам є запит на шырыню.

@media (max-width: 768px) {
  ...
}

Прабег інформацыі прост: браузер вимервае відобразавальную зону, запит падходзіць чы не, і макет реагуе на гэта.

Viewport
    ↓
Media Query
    ↓
Layout changes

Гэта робіць запиты медыа правым інструментам для прыняцьця рашэнняў, якія насправды стосуюцца всей стораніцы. Тыповым прыкладам є дваколонковая структура з фіксаванай шырошчынай боковай панелі:

.page-layout {
  display: grid;
  grid-template-columns: 1fr 300px;
}

Пад шырошчынай вікна, менейшай за певную значэння, структура ператвараецца ў адну колонку:

@media (max-width: 900px) {
  .page-layout {
    grid-template-columns: 1fr;
  }
}

Гэта ўсунуты спосаб выкарыстоўвання запита медыа: чы є у стораніцы месца для боковай панелі, насправды є пытаннем відобразавальной зоны. Проблемы пачынаюцца, калі той самы механізм вялікія пра тое, як окремы компонент аранжуе своі внутрашняя элементы.

Як працюють запиты кантэйнера

Запит кантэйнера дазваляе элементу рэагаваць на размер абяцеля, які вы явна пазначылі як кантэйнер для запитаў. Яго настройка выконуецца за два крокі. Першы — адзначыць кантэйнер:

.card-container {
  container-type: inline-size;
}

Значэнне inline-size паведамляе браузеру, што наследнікі могу запытаць пра інлайн-размер кантэйнера, тыяму ў горадзе напісаў. Другі — запісаць правілу для гэтага кантэйнера:

@container (max-width: 500px) {
  .product-card {
    flex-direction: column;
  }
}

Тепер інфармацыя надходзіць з кантэйнера, а не з вікна:

Container
    ↓
Container Query
    ↓
Component layout

Карточка больш не залежыць ад таго, чы рэзультат відвідаваець застаўляе тэлфон чы большы манітар; яна рэагуе на прастор, які дае ёй абяцель.

Адна деталі, якая плутае людзей

Запит даўніка стылюе наследнікі даўніка, а не сам даўнік. Самэй тым у прыкладах завжды аднаўляецца пакрытак (.card-container, .card-wrapper) разам з внутранім элементам (.product-card). Якщо вы задаеце container-type для .product-card і пасля таго запрашваеце яго, каб змяніць flex-direction самога .product-card, ніч не будзе. Храніце пакрытак і компонент як аднальныя элементы.

Другі деталі: параметр inline-size значыць, шырыню контэйнера больш нельзя вычысляць на адказе ў ягонай зместоўкі. Контэйнер, які ёсць элементам блак-рэвю ў звычным лейауте, нічога страшнага не мае, адколі яго шырыня вылучаецца з шырыні ягоя абяцелі. Контэйнер, які выкарыстоўвае метод зменшэння да падходячай шырыні, напрыклад элемент типу inline-block або элемент з абсалютным распадзелам без явна заданай шырыні, можа зменшыцца да нульовай шырыні, калі будзе застосавана праблема контэйнеравання.

Шырыня відобразча працоўнай плошчы проты шырыні компаненту

Разлік стае болей зрозумелым у панелі керування з шырокай галоўной колонкай і вузкаяй боковай колонкай:

.dashboard {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: 1rem;
}

Праўімся, што вікна мае шырыню 1440 пкс. Правіла, заснованыя на відобразча працоўнай плошчы, для карточкі будуць выглядаць так:

@media (max-width: 768px) {
  .card {
    flex-direction: column;
  }
}

У такім вікні гэтае правіла ніколі не будуць падходзячымі. Аднак карточка, якая знаходзіцца ў вузкай колонцы, можа мячыць шырыню апошнія 350 пкс. У запитах да медыа выкарыстоўваецца толькі адна цыфра:

Viewport = 1440px

Карточка знаходзіцца разам з іншай:

Component width = 350px

Толькі другая цифра паказвае рэальны стан карточкі, і толькі запит контейнера можа на гэта адказаць.

Мінімальная наладка запиту контейнера

Рэалізацыя ўсьмохнутая. Пазначыце обгортку як контейнер:

.card-wrapper {
  container-type: inline-size;
}

Даўце карточцы сітку з двумя столбцамі, калі ўсё яе контейнер мае шырыню не менее 600 пкс:

@container (min-width: 600px) {
  .product-card {
    display: grid;
    grid-template-columns: 200px 1fr;
  }
}

У разе проблемы перайдзіце на простую лейяут-структуру:

@container (max-width: 599px) {
  .product-card {
    display: block;
  }
}

У маркапе патрэбны толькі элемент-обгортка навакол карточкі:

<div class="card-wrapper">
  <article class="product-card">
    ...
  </article>
</div>

Тепер шырока карткі вылучаецца з яе контэйнера, таму перасунুць её у іншы столбец автаматычна дае правильную шыроку. Заўважкай, што два правілы выкарыстоўваюць min-width: 600px і max-width: 599px; калі шырокасць ў дзяловым выразе, контэйнер можа знаходзіцца межы гэтымі значэннямі. Новейшая синтаксіс дыяпазонаў, @container (width >= 600px) і @container (width < 600px), усуне гэты прыем і ў меру можа быць выбраная для новага коду.

Чаму гэта падходзіць для архітектуры на базе компанентаў

Запыткі контэйнераў маюць большое значэнне, чым звычная новая функцыя CSS, адтолькі ўсёлькі сучасныя фронтэнды складаюцца з перадпрацоўваных элементаў — будзь то компоненты фрэймворкаў у React, Vue чы Angular, Web Components без фрэймворкаў, або базовыя елементы спільной системы дизайна. Ніхто з іх не павінен ведаць, у якай частыне стораніцы ён будзе выкарыстоўвацца. Разглядзім элемент user-card. Ён можа быть адрасаваны ў галоўную зону контэнту:

<main>
  <user-card></user-card>
</main>

Ён таксама можа быть адрасаваны ў додатковую зону:

<aside>
  <user-card></user-card>
</aside>

Або ж ён можа быть павтараны ў сітцы дашборда:

<div class="dashboard-grid">
  <user-card></user-card>
  <user-card></user-card>
  <user-card></user-card>
</div>

Жорсткая прыкладка пункта перерыву відваротнай паверхні ў гэты компонент уключае прыпуск, які немагчыма падтвердзіць:

@media (max-width: 768px) {
  ...
}

Чысло 768 нічога не сказвае пра рэальны контекст компаненту. Контейнер-запыт працоўвае краща: якщо є столькі прастору, то выкарыстаць такую распаковку. Якщо вашы компаненты ўжо є незалежнымі блакамі для будавання, тады обсужчэнне таго, дзе паўінна знаходзіцца межа фрэймворку ў перадпрацоўванай структуре UI є корыстным дапаможнікам для гэтай ідеі.

Дазволаць карточцы прафілю адаптавацца да свайго арэалу

Ёсць кампактная карточка прафілю, якая размешчае аватарку падле імені та ролі:

.profile-card {
  display: flex;
  gap: 1rem;
  align-items: center;
}

Їё обгорак стае контейнерам-запытам:

.profile-container {
  container-type: inline-size;
}

Калі шырыня гэтага контейнера становіць 400 пкс або меней, карточка складаецца і центруе свой контэнт:

@container (max-width: 400px) {
  .profile-card {
    flex-direction: column;
    text-align: center;
  }
}

У просторым контейнере аватарка знаходзіцца падле тексту:

┌──────────────────────────────────────┐
│ [Avatar]  John Smith                 │
│           Senior Developer           │
└──────────────────────────────────────┘

У складных ситуаціях той самы компонент перакрываецца верткая формай:

┌──────────────────┐
│                  │
│     [Avatar]     │
│                  │
│    John Smith    │
│ Senior Developer │
│                  │
└──────────────────┘

Няма ні спазыравача размеру, ні другай «компактной» версіі, ні класу, які могаў бы змяніцца пад вплывам старшай сторанкі.

У медыя-запитах все ўсё ж такі застосованы

Запиты контэйнера не заменяюць медыя-запиты; яны адпавядаюць на іншыя запитанні. Швейны спосаб для класыфікаціі частых рашэнняў:

  • Складванне галоўнага навігацыйнага меню: медыя-запит.
  • Адключэнне бокавай панелі на рэвэлі: медыя-запит.
  • Змена распаложэння карточкі з гораздка на верткае: запит контэйнера.
  • Адаптаванне компонента, які можа быць викорыстаны па-разным чынам, да яго месца: запит контэйнера.
  • Корэктаванне форматування тэкста на всій станцыі: медыя-запит.
  • Дазвол часткі панелі керування рэагаваць на шырыню свайго столбца: запит контэйнера.
  • Змена распаложэння всей аплікацыі на іншае: медыя-запит.
  • Змена повадків компаненту ў межах вузкага «родніка»: запиты контэйнера.
  • Ментальная модель: глобальныя рашэнні і рашэнні компанентаў

    Найяснейшы спосаб раздзеліць роботу — аддзельна прызначыць тое, што рашае стораніца, і тое, што рашае кожны компанент.

    Запиты медыя прабуюць з’ясаваць параметры вікна перагляду

    Пытанне, якое стоіць за запитам медыя, ёсьць:

    "What is the viewport doing?"
    

    Яны падходзяць:

    • Структуре стораніцы
    • Навігацыі
    • Глобальнам расстоянням між элементамі
    • Глобальной типаграфіі
    • Серьозным змянам у лейауте

    Запиты контэйнера прабуюць з’ясаваць архітектуру оточэння компанента

    Пытанне, якое стоіць за запитам контэйнера, ёсьць:

    "What is my component's environment doing?"
    

    Яны падходзяць:

    • Карточкам
    • Віджэтам
    • Панелям
    • Павторным компанентам інтэрфейсу
    • Модулям панелі керавання
    • Компанентам дизайн-сістэмы

    Змена размаху з выкарыстоўваннем ейкаваў запитаў контэйнера

    Запиты к контейнерам — это не толькі умовныя блакі. CSS таксама визначае единіцы дужоў, якія залежнаць ад найбліжэйшага контейнера запиту, таму значэнняя можна масштабаваць паступова, а не пры перашыранні межы:

    .title {
      font-size: 5cqi;
    }
    

    Тут cqi паводзіцца пра адзин процэнт розмеру контейнера, таму 5cqi — адзін пяць процэнаў яго шыроцы. Полны набор единіцаў:

    cqw  → container width
    cqh  → container height
    cqi  → container inline size
    cqb  → container block size
    cqmin → smaller container dimension
    cqmax → larger container dimension
    

    Паўзучы шаблон — это абгортка единіцы контейнера ў clamp(), так што значэння масштабаваецца разам з контейнерам, але ніколі не выходзіць за разумны дыапазон:

    .card-title {
      font-size: clamp(1rem, 4cqi, 2rem);
    }
    

    Тэтадзь напамяцо прадаецца з прасторам компаненты, а не з вікнам, што не можа выразіцьі такіе елементы відображэння, як vw. Є два застережэння. Якщо элемент не мае контейнера-запыткі, гэтыя елементы пераходзяць на маленькія елементы відображэння, таму яны все раве даюць значэнне, проста не тое, якое вы хацелі. А наявнасць значэнняў ніжней і верхней межы для rem унутроць clamp(), як паказана вышэй, мае значэнне для доступнасці: розмер шрыфта, які кантролюецца выключна шыроўкай контейнера, не реагуе на настройкі розмеру текста корыстніка.

    Называнне контейнераў у большых прыкладнах

    Для маленькай стораніцы дапаможае анонімны контейнер:

    .container {
      container-type: inline-size;
    }
    

    Калі контэйнеры нараджаюцца ўнутры адзін другога, простая правіла @container падходзіць да найбліжэйшага аднаковага контэйнера, які можа не быть тым, каго вы мелі на увазе. Скрацення container дазволяе прызначыць контэйнеру імя разам з яго типам:

    .dashboard {
      container: dashboard / inline-size;
    }
    

    Пасля чаго правіла можаць цялком спецыфічна нацелівацца на гэты контэйнер:

    @container dashboard (min-width: 700px) {
      .widget {
        grid-template-columns: 1fr 1fr;
      }
    }
    

    Порашчыце безіменную умову:

    @container (min-width: 700px)
    

    з іменаванай умовай:

    @container dashboard (min-width: 700px)
    

    Іменаваная версія чытальна ў сваёй мэці і продовжвае працаваць нават якщо хтось пазней дадае ўсё новы контэйнер між панеллю керування і віджэтом.

    Рашуча выбірайце межы контэйнероў

    Запиты да контэйнераў ёсць моцнымі, але гэта не прычына дадаваць такую декларацію кожнам элементу:

    container-type: inline-size;
    

    Кожны контэйнер прыкладвае правілы макетавання, стылю і розмеру элемента, што зменшвае можлівасць настройкі розмеру таго элемента; таму контэйнеры павінны вказываць чысткія межы складовых, а не распалювацца па всім месцы. Разглядзім дашборд з віджэтамі ўнутры яго:

    <section class="dashboard">
      <article class="widget">
        <div class="widget-content">
          ...
        </div>
      </article>
    </section>
    

    Разумны выбор — зробіць дашборд іменаваным контэйнерам:

    .dashboard {
      container: dashboard / inline-size;
    }
    

    і дазволіць кожнаму віджэту реагаваць на яго. Правілам не ёсь "выкорыстоўваць контэйнерныя запиты па всім месцы", а "выкорыстоўваць іх там, дзе поведэнне залежыць ад доступнага прастору".

    Замена точак перерыву на точкі перерыву, заснованыя на контэнце

    Багато шаблонаў стылю маюць іерархію точак перерыву відворачання екрана падобнае да гэтаго:

    @media (max-width: 1200px) {
      ...
    }
    
    @media (max-width: 1024px) {
      ...
    }@media (max-width: 900px) {
      ...
    }@media (max-width: 768px) {
      ...
    }@media (max-width: 640px) {
      ...
    }@media (max-width: 480px) {
      ...
    }
    

    Іноды такая структура є правильной. Частае явісць таго, што компаненты былі спроектаваны з урахованнем шырыны прыстроя, а не ўсередзіні самога компанента. Запыткі контейнера прыводзяць нас да іншага пытання. Уместо таго, каб спытацца «Калькольку пунктав прызначэння зазвычай викорыстоўвае команда?», трэба спытацца «Пры якой шырыне этот компанент перестае выглядаць правільна?» Адказ даўа нам пунктав прызначэння, які базуецца на усередзіні:

    @container (max-width: 420px) {
      .card {
        flex-direction: column;
      }
    }
    

    Няма нічага, што бы 420 пкс адпавядала конкрэтнаму тэлефону; гэта проста шырына, праз якую карточка перестае маты месца. Пунктав прызначэння, выбраныя такім спосабам, застаюцца актуальнымі праз змены лейауту і новыя прыстроі.

    Проектаванне компанентаў, якія не залежыць ад розташоўвання

    Запыткі контейнера таксама падказываюць командам ствараць сапраўдна незалежныя компаненты, чыяя дзеяння є прагнозаванымі незалежна ад таго, дзе яны відображаюцца. Уявіце сабе групу кнопак у системе дизайна. Яна можа знаходзіцца ўнутрь формы на сторанцы:

    Page
     └── Form
          └── Button Group
    

    Усередзіне карткі на панелі керування:

    Dashboard
     └── Card
          └── Button Group
    

    Або усередзіне карткі ў бокавай панелі:

    Sidebar
     └── Card
          └── Button Group
    

    Вікнава область аднойчыная ў всіх трох прыкладах; прастор жа ня такі. За дапамогою запиту контейнера група прыстосоўваецца без паведамленняя пра структуру над яю.

    Патэрн респансівных картак, які можна викорыстоўваць знову

    Ёсць цэлы патэрн, які можна без перашкод застосаваць. Маркап укладае картку ў элемент-контейнер; знову ж такі, HTML паказаны ў двух суседзяючых частках.

    <div class="card-container">
      <article class="card">
        <img src="image.jpg" alt="">
    
        <div class="card-content">
          <h2>Performance Dashboard</h2>
          <p>
            Monitor application performance and infrastructure metrics.
          </p>
          <a href="#">View dashboard</a>
        </div>
      </article>
    </div>
    

    Обгорак прызначаецца як контейнер:

    .card-container {
      container-type: inline-size;
    }
    

    Карточка спачатку мае формат адностолбцовай сеткі з зображэнням спараваным па прасцене 16:9. Калі ўсероўні з яе контейнерам досягае 600 пкс, ёна пераходзіць на формат з фіксаваным столбцам зображэння па боку ад контента і робіць зображэнне квадратным. Правіла напісаны без перерываў между ямі, што є правямым CSS, але карэткаваеся пераканструляваць іх, калі ўводзіць іх у базу кода.

    .card {
      display: grid;
      gap: 1rem;
    }.card img {
      width: 100%;
      aspect-ratio: 16 / 9;
      object-fit: cover;
    }@container (min-width: 600px) {
      .card {
        grid-template-columns: 200px 1fr;
        align-items: center;
      }  .card img {
        aspect-ratio: 1;
      }
    }
    

    Зверніце ўвагу, чаго не мае гэты шаблон стылю:

    @media (max-width: 768px)
    

    Карточка ніколі не бере пад заўважэнне відобразны прастор. Усе, што яна адлучае, базуецца на ўсероўні з яе контейнерам.

    Спаўнасць запытанняя контейнера з сеткай, якая сама падбірае колькасць столбцоў

    Запытанняя контейнера особліва добра спаўнаюцца з сеткай, якая сама выбірае колькасць своіх столбцоў:

    .dashboard {
      display: grid;
      grid-template-columns:
        repeat(auto-fit, minmax(280px, 1fr));
      gap: 1rem;
    }
    

    За дапамою repeat(auto-fit, minmax(280px, 1fr)) браузер стварае як магчыма больш за лічбу столбцоў павелічэння 280px, сколькі дозволяе рядок, і растягвае іх, каб запаўніць залишковы прастор. Кожны віджэт тады атрымле свой сабстоячы контейнер:

    .widget-container {
      container-type: inline-size;
    }
    

    і пераходзіць на внутршняе двухстолбчатая распаўненне, калі його месца будзе дастаткова шырока:

    @container (min-width: 500px) {
      .widget {
        grid-template-columns: 1fr 1fr;
      }
    }
    

    Панель керування прыстосоўваецца да шчырокага спектру шыроў без пунктавых меж віджэтаў: сетка адлучае, сколькі прастору атрымае кожны віджэт, а кожны віджэт сам адлучае, як ім гэты прастор выкарыстоўваць.

    Рэспансівнае распаўненне таксама ёсць пытаннем яго прыдатнасці

    Тое, што ўсё паседзі на экране, не значыць, што ўсё лягкава для викорыстання. Рядок кнапак, які тэхнічна паседзі на вузкай картцы, можа заставацца тыснучым і спрыяць падчас натискання. Запит контейнера можа складваць дзеяння і растягваць іх да павной шыроўкі, калі картка вузкая (правіла розмешчаны ў двух фрагментах):

    @container (max-width: 350px) {
      .actions {
        flex-direction: column;
      }
    
      .actions button {
        width: 100%;
      }
    }
    

    Кнопкі з абсалютным шырыненням ствараюць большэе прастор для спраўкі пальцам і зменшаюць рызык випадковых натысканняў. Той самы прынцып можа быць застосаваны і да тексту: яго размер мяняецца ў межах шырыні компонента.

    .card-title {
      font-size: clamp(1rem, 4cqi, 1.75rem);
    }
    

    Конкрэтныя значэння маюць меншое значэнне, чым прынцып, які за іх стоіць: рэспансіўнае паведанне должна адпраўляцца да умов, пад якімі фактычна викорыстоўваецца компонент, а не на падставе спадзявання, выведзенага з размеру вікна.

    Калі медыя-запиты застаюцца правым выборам

    Контэйнерныя запиты не є автаматычна лепшай альтэратывой. Глобальная навігацыя є яскравым прыкладам, калі патрэбны медыя-запиты, адколі закрыць весь меню і паказаць кнопку меню — це рашэнне, якое стосуецца структуры сторонічкі (гэта правіло таксама дзеліцца на два часткі):

    @media (max-width: 900px) {
      .navigation {
        display: none;
      }
    
      .menu-button {
        display: block;
      }
    }
    

    Няхібацкія настаўленні пользователя ёсць абошто іншая катэгорыя. Зменшэнне анімацый для тых, хто прагтаў у сваёй операцыйной системе менш руху, не мае нічынага з жадным контейнерам:

    @media (prefers-reduced-motion: reduce) {
      * {
        animation-duration: 0.01ms;
        animation-iteration-count: 1;
      }
    }
    

    Это ёсць настаўленні средавышча, якое можа чытаць толькі запиты медыя. Мета не ў знішчэнні запитоў медыя, а толькі ў тым, каб не выкарыстоўваць іх для прынятнага рашэння ў складовых.

    Трыслойны падход да адпаведнага CSS

    Для прыкладнай програмы, заснованай на складовых, карыстоўваць трыслойны падход да стайлізацыі, якая адпаведнае разным умовам, ёсць карыстным.

    Слой 1: глобальная адпаведнасць з запитамі медыя

    Запиты медыя адпавядаюць за праблемы, якія стосуюцца всей сторанкі:

    Page layout
    Navigation
    Global typography
    Major structural changes
    Application shell
    

    Слой 2: адпаведнасць складовых з запитамі контэйнера

    Запиты контэйнера адпавядаюць за внутршняе распалоžэнне самастоятельных частак:

    Cards
    Widgets
    Panels
    Reusable components
    Design-system components
    Dashboard modules
    

    Слой 3: плавна працэўнасць за дапамою функцый і еўранаў

    Калі не патрэбны жорсткія точкі перерыву, нехай значэнні паступова зменяюцца за дапамою сучасных функцый і еўранаў:

    clamp()
    min()
    max()
    minmax()
    cqi
    cqw
    

    Напрыклад, загалоўка можа растаць разам з свайным контейнерам у межах двух фіксаваных значэнняў:

    .heading {
      font-size: clamp(1.5rem, 3cqi, 3rem);
    }
    

    Разам этыя слоі ствараюць систему, а не проста скупчэнне патчаў для точак перерыву.

    Праўя змена — хто прыймае рашэнні

    Існуе спадчынае прагненне апісваць запиты контейнераў як "запиты медыа для элементаў". Гэта тэхнічна правядома, але не выказвае сутнасці прыбылей. Зменяецца модэль адпаведнасці. У традыцыйным рэспансівным CSS стораніца фактычна керуе тым, як кожны компонент працюе:

    Viewport
       ↓
    Media Query
       ↓
    Component
    

    За дапамою запитаў контейнера кожны компонент атрымвае інструкцыі зі свайго сабеўскага контейнера:

    Component Container
            ↓
    Container Query
            ↓
    Component
    

    Компаненты, які маюць своія правіла адаптавання, лёгкія да падвойнага выкарыстання, перамешчання, тэставання ізольавана і падтрымкі. Гэта змена праваў на ўладу являецца дыявальным прынтам.

    Адна запытанне для рашэння кожнага случая

    Калі вы не вядзеце, які інструмент выкарыстоўваць, запытайцеся, чы рашэнне па макету стосуецца сторанкі чы компанента. Якщо ён стосуецца сторанкі, выкарыстаўваюце запытанні медыя. Якщо ён стосуецца прастора, які быў даны компаненту, выкарыстаўваюце запытанні контейнера. Прыклады для частаўпадаючых случаяў:

    Should the sidebar disappear?
            ↓
        Media Query
    
    Should this card switch from horizontal
    to vertical?
            ↓
      Container Query
    
    Should the navigation collapse?
            ↓
        Media Query
    
    Should this reusable widget change
    its internal layout?
            ↓
      Container Query
    

    Галоўныя выводы

    • Запытанні медыя описваюць вікна перагляду і аблака пользователя, таму яны падходяць для структуры сторанкі, навігацыі, глобальнай типаграфіі і прывярк, такіх як зменшаны рух.
    • Запытанні контейнера описваюць прастор, які отрымае компанент, таму яны падходяць для карточак, віджэтов, панелей і компанентаў дизайн-сістэмы.
  • Запиты к контейнерам стылязуюць ўсі элементы, якія знаходзяцца пад імі; трэба залічваць контейнер і компонент як адзінаковыя елементы, а таксама старанна следзіць за тыми контейнерамі, якім патрэбна шырока, залежная ад контэнту.
  • Тыпавыя пункты перерыву, якія залежнаць ад контэнту і встановлены там, дзе компонент насправды перестае працаваць, маюць большую стабільнасць чым тыя, якія залежнаць ад прыстрою.
  • Елементы вимеры для контейнераў, такія як cqi і cqw, якія выкарыстоўваюцца ў функцыі clamp() з межамі, заданымі за дапамою rem, дазваляюць ствараць гнеккія размеры без паслаблення налаштаванняў розмеру тексту для корыстніка.
  • Называйце контейнеры тады, калі яны ўтвараюць вялікія структуры, і стварайце іх толькі на значных межах компонентаў.
  • Найболей надзеяны ўстановкі спалучаюць запиты да медыя, запиты к контейнерам і гнеккі CSS замест таго, каб выбраць толькі адны з іх.