Нові властивості CSS, що трансформують веб-розробку

incss

Короткий підсумок

Дізнайтеся про інноваційні властивості CSS, які з'явились нещодавно і допомагають створювати більш сучасні та адаптивні інтерфейси.

Container Queries

Container queries - це революційна функція, яка дозволяє стилізувати елементи на основі розміру їхнього батьківського контейнера, а не розміру вікна перегляду. Це дає нам можливість створювати справді модульні компоненти.

/* Визначаємо контейнер */
.card-container {
  container-type: inline-size;
  container-name: card;
}
 
/* Застосовуємо різні стилі залежно від розміру контейнера */
@container card (min-width: 400px) {
  .card-title {
    font-size: 1.5rem;
  }
 
  .card-content {
    display: grid;
    grid-template-columns: 2fr 1fr;
  }
}

Це особливо корисно для компонентів, що використовуються в різних контекстах, наприклад, картка, яка може з'являтися як в основному вмісті, так і в бічній панелі.

Container queries надають більш детальний контроль над адаптивним дизайном. Наприклад, ви можете мати компонент картки, який налаштовує свій макет відповідно до ширини контейнера, роблячи його більш пристосованим до різних розмірів екрану та макетів.

Ось більш детальний приклад адаптивного компонента картки з використанням container queries:

<div class="card-container">
  <div class="card">
    <h2 class="card-title">Заголовок картки</h2>
    <p class="card-content">Це деякий вміст всередині картки.</p>
  </div>
</div>
.card-container {
  container-type: inline-size;
  container-name: card;
  padding: 1rem;
  border: 1px solid #ccc;
}
 
.card {
  padding: 1rem;
  background-color: #f9f9f9;
}
 
@container card (min-width: 600px) {
  .card {
    display: flex;
    flex-direction: row;
  }
 
  .card-title {
    font-size: 2rem;
  }
 
  .card-content {
    font-size: 1.25rem;
  }
}
 
@container card (max-width: 599px) {
  .card {
    display: block;
  }
 
  .card-title {
    font-size: 1.5rem;
  }
 
  .card-content {
    font-size: 1rem;
  }
}

У цьому прикладі компонент картки змінює свій макет та розміри шрифту залежно від ширини свого контейнера. Коли контейнер ширший за 600px, картка відображає свій вміст у макеті рядка з більшим текстом. Коли контейнер вужчий, картка повертається до блокового макету з меншим текстом.

Container queries - це потужний інструмент для створення гнучких, адаптивних дизайнів, які пристосовуються до свого контексту, роблячи ваші компоненти більш придатними для повторного використання та простішими у обслуговуванні.


Container Style Queries

Container Style Queries розвивають концепцію container queries далі, дозволяючи запитувати не лише розмір контейнера, а й його обчислені стильові властивості. Це забезпечує ще більш динамічну та контекстуальну стилізацію.

/* Визначаємо контейнер */
.theme-container {
  container-name: theme;
  container-type: style;
  background-color: white;
}
 
/* Застосовуємо стилі на основі кольору фону контейнера */
@container theme(background-color: white) {
  .text {
    color: black;
  }
}
 
@container theme(background-color: black) {
  .text {
    color: white;
  }
}

Ця потужна функція дозволяє компонентам адаптуватися не тільки до обмежень розміру, але й до їх візуального контексту. Наприклад, текст може автоматично перемикатися на світлий або темний режим залежно від кольору фону свого контейнера.

Практичні випадки використання

Style queries забезпечують складну тематизацію та контекстну стилізацію:

/* Автоматичне регулювання контрасту */
.card {
  container: card / style;
}
 
@container card(--theme: 'dark') {
  .card-text {
    color: white;
  }
}
 
@container card(--theme: 'light') {
  .card-text {
    color: black;
  }
}
 
/* Комбіновані запити розміру та стилю */
@container card(min-width: 400px) and (--importance: 'high') {
  .card-title {
    font-size: 1.8rem;
    font-weight: bold;
  }
}

З Container Style Queries компоненти можуть стати дійсно самоадаптивними як до своїх розмірних, так і стилістичних контекстів, наближаючи нас до ідеалу компонентів інтерфейсу "напиши один раз, використовуй скрізь".


Subgrid

Subgrid дозволяє вкладеним елементам брати участь у сітці їхнього батьківського елемента. Це вирішує одну з найбільших проблем з CSS Grid — вирівнювання елементів у вкладених сітках.

.parent-grid {
  display: grid;
  grid-template-columns: repeat(9, 1fr);
  grid-template-rows: auto auto;
}
 
.child-grid {
  grid-column: 2 / 7;
  display: grid;
  grid-template-columns: subgrid;
}

З цим вкладені елементи в .child-grid будуть вирівнюватися з тими самими стовпцями, визначеними в .parent-grid.


Селектор :has()

Селектор :has() - це свого роду "батьківський селектор", на який розробники давно чекали. Він дозволяє вибирати елемент на основі його дочірніх або суміжних елементів.

/* Стилізуємо картки, що містять зображення */
.card:has(img) {
  padding-top: 0;
}
 
/* Стилізуємо абзаци, що містять посилання */
p:has(a) {
  padding-left: 1rem;
  border-left: 3px solid blue;
}
 
/* Змінюємо стиль форми, якщо поле вводу містить помилку */
form:has(input:invalid) {
  border-color: red;
}

Logical Properties

Logical Properties - це сучасний спосіб написання CSS, який працює з будь-яким напрямком письма та для будь-якої мови. Вони замінюють звичні терміни "зверху, знизу, ліворуч, праворуч" на напрямки, які залежать від режиму письма.

.card {
  /* Замість margin-left, margin-right, margin-top, margin-bottom */
  margin-inline: 1rem;
  margin-block: 2rem;
 
  /* Замість padding-left, padding-right */
  padding-inline: 1rem;
 
  /* Замість width та height */
  inline-size: 300px;
  block-size: 200px;
}

CSS Nesting

CSS Nesting дозволяє писати CSS-селектори всередині інших селекторів, створюючи ієрархію, яка відображає структуру вашого HTML. Це робить ваш CSS більш читабельним і зручним для обслуговування, зменшуючи повторення та чітко показуючи зв'язки між елементами.

.card {
  background: white;
  border-radius: 8px;
 
  /* Вкладене правило для заголовка у картці */
  & header {
    padding: 1rem;
    border-bottom: 1px solid #eee;
 
    /* Подальше вкладення для заголовка в header */
    & h2 {
      margin: 0;
      color: #333;
    }
  }
 
  /* Вкладене правило для вмісту в картці */
  & .content {
    padding: 1rem;
 
    /* Вкладені псевдокласи */
    &:hover {
      background-color: #f9f9f9;
    }
  }
 
  /* Комбінування з псевдокласами */
  &:hover {
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  }
}

Без вкладення ті ж стилі потребували б повторення батьківського селектора кілька разів:

.card {
  background: white;
  border-radius: 8px;
}
.card header {
  padding: 1rem;
  border-bottom: 1px solid #eee;
}
.card header h2 {
  margin: 0;
  color: #333;
}
.card .content {
  padding: 1rem;
}
.card .content:hover {
  background-color: #f9f9f9;
}
.card:hover {
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}

CSS Nesting робить ваші таблиці стилів більш інтуїтивними та тісно пов'язаними з компонентною архітектурою, яка використовується в сучасній веб-розробці.


CSS @scope

Правило @scope надає спосіб обмежити дію селекторів у певній частині DOM-дерева. Це допомагає уникнути конфліктів стилів і створює більш модульний CSS, що особливо корисно в архітектурах на основі компонентів.

/* Визначаємо межу сфери дії */
@scope (.card) {
  /* Ці стилі застосовуються лише в межах елементів .card */
  header {
    padding: 1rem;
  }
 
  img {
    border-radius: 4px;
  }
 
  /* Використання :scope для посилання на сам елемент обмеження */
  :scope {
    border: 1px solid #ddd;
    border-radius: 8px;
  }
}

Ви також можете визначити як корінь області видимості, так і її межу:

@scope (.tabs) to (.tab-panel) {
  /* Ці стилі застосовуються лише між елементами .tabs і .tab-panel */
  h2 {
    font-size: 1.2rem;
    margin-bottom: 0.5rem;
  }
}

Переваги @scope

  1. Уникнення конфліктів стилів: Стилі, визначені в межах області, не впливатимуть на елементи за межами цієї області, навіть якщо вони відповідають селектору.
  2. Ізоляція компонентів: Полегшує створення самодостатніх компонентів без занепокоєння про витік стилів.
  3. Чистіші селектори: Зменшує потребу в складних, специфічних селекторах для уникнення конфліктів.
  4. Краща організація: Допомагає структурувати CSS таким чином, що відображає ієрархію компонентів.
/* Без @scope */
.card .title {
  font-weight: bold;
}
.card .content .title {
  font-weight: normal;
}
 
/* З @scope */
@scope (.card) {
  .title {
    font-weight: bold;
  }
}
 
@scope (.card .content) {
  .title {
    font-weight: normal;
  }
}

CSS @scope допомагає створювати більш зручні для обслуговування таблиці стилів з чіткішими межами між різними частинами вашого інтерфейсу.


Властивості анімації та переходу

CSS тепер пропонує кращі способи створення плавних і живих анімацій. Ці нові інструменти дозволяють легко додавати рух до вашого сайту без використання JavaScript.

Анімації, керовані прокруткою

Тепер ви можете пов'язувати анімації з тим, як користувачі прокручують вашу сторінку. Це допомагає синхронізувати анімації точно з тим моментом, коли користувачі їх бачать.

/* Спочатку створюємо часову шкалу на основі прокрутки */
@scroll-timeline move-in {
  source: auto; /* Використовує вікно перегляду для прокрутки */
  orientation: vertical; /* Відстежує вертикальну прокрутку */
  start: 0%; /* Починається зверху області прокрутки */
  end: 100%; /* Закінчується внизу області прокрутки */
}
 
/* Тепер пов'язуємо анімацію з часовою шкалою */
.fade-in-box {
  animation: fade 1s linear;
  animation-timeline: move-in; /* Пов'язуємо з нашою часовою шкалою прокрутки */
  animation-range: entry 25% cover 50%; /* Коли відтворюється анімація */
}
 
@keyframes fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

Це робить так, щоб елементи з'являлися саме тоді, коли користувачі прокручують до них, не раніше і не пізніше.

View Transitions API

API переходів між переглядами допомагає створювати плавні зміни між різними станами вашої сторінки:

/* Додайте це у свій CSS */
::view-transition-old(root) {
  animation: fade-out 0.5s ease;
}
 
::view-transition-new(root) {
  animation: fade-in 0.5s ease;
}
 
/* Потім у вашому JS */
document.startViewTransition(() => {
  // Тут оновлюйте свій DOM
  document.body.innerHTML = newHTML;
});

Це допомагає користувачам відстежувати, що відбувається, коли змінюється вміст сторінки, роблячи ваш сайт більш досконалим.

Композиція анімацій

Тепер ви можете поєднувати анімації разом новими способами:

.box {
  /* Перша анімація */
  animation: slide-right 2s ease forwards;
 
  /* Друга анімація - зверніть увагу на 'add', щоб поєднати їх */
  animation-composition: add;
  animation-name: slide-right, fade-in;
}

Це дозволяє будувати складні рухи, змішуючи прості, без написання спеціальних ключових кадрів для кожного випадку.


Cascade Layers

Cascade layers допомагають контролювати порядок застосування стилів, забезпечуючи більш передбачуваний результат.

/* Визначаємо шари в порядку пріоритету, від найнижчого до найвищого */
@layer base, components, utilities;
 
/* Додаємо стилі до відповідних шарів */
@layer base {
  h1 {
    font-size: 2rem;
    font-weight: bold;
  }
}
 
@layer components {
  .card h1 {
    font-size: 1.5rem;
    color: navy;
  }
}
 
@layer utilities {
  .text-center {
    text-align: center;
  }
}

Адаптивні значення з clamp()

Функція clamp() дозволяє визначити мінімальне, бажане та максимальне значення для властивості:

h1 {
  /* Мінімум 1.5rem, бажане 5vw, максимум 3rem */
  font-size: clamp(1.5rem, 5vw, 3rem);
 
  /* Адаптивні відступи */
  padding: clamp(1rem, 3vw + 0.5rem, 3rem);
}

CSS @property

Правило @property дозволяє визначати власні властивості CSS з перевіркою типів, значеннями за замовчуванням і контролем успадкування. Це робить власні властивості більш надійними та відкриває нові можливості для анімацій і переходів.

/* Визначаємо власну властивість з перевіркою типів */
@property --gradient-angle {
  syntax: "<angle>";
  initial-value: 0deg;
  inherits: false;
}
 
/* Використовуємо власну властивість */
.card {
  --gradient-angle: 45deg;
  background: linear-gradient(var(--gradient-angle), blue, purple);
 
  /* Тепер ми можемо анімувати цю властивість! */
  transition: --gradient-angle 0.3s;
}
 
.card:hover {
  --gradient-angle: 135deg;
}

Основні переваги

Тепер ви можете:

  1. Додавати типи до CSS-змінних: Встановлювати та перевіряти типи, такі як колір, довжина чи число
  2. Контролювати успадкування: Зупиняти або дозволяти значенням переходити до дочірніх елементів
  3. Встановлювати розумні значення за замовчуванням: Визначати, що відбувається, коли значення не встановлено
  4. Анімувати власні властивості: Анімувати значення, які раніше не можна було анімувати

Простий приклад:

@property --my-color {
  syntax: "<color>"; /* Тип: дозволені лише значення кольору */
  initial-value: #0066cc; /* Значення за замовчуванням, якщо не встановлено */
  inherits: true; /* Це значення передається дочірнім елементам */
}
 
button {
  background-color: var(--my-color);
  transition: background-color 0.3s;
}
 
button:hover {
  --my-color: #0099ff; /* Змінюється плавно завдяки визначенню типу */
}

Функція @property наближає CSS до типізованих систем. Вона допомагає виявляти помилки та робить власні властивості більш корисними для реальних завдань.


Висновок

Сучасний CSS стає все більш потужним і виразним, дозволяючи розробникам створювати складні інтерфейси з мінімальним використанням JavaScript. Використання цих нових властивостей не тільки спрощує розробку, але часто покращує продуктивність, доступність і інтернаціоналізацію ваших проектів.

Пам'ятайте, що не всі браузери підтримують всі ці функції однаково, тому завжди перевіряйте сумісність на Can I Use перед використанням їх у виробничих проектах.


Подальше навчання