Скроллбары, флексбоксы и другие CSS-грабли

#css#webkit#react

Последние три бага в моей практике оказались связаны с тем, что где-то в глубине стеков технологий лежат специфичные правила рендеринга. Сегодня — подборка реальных кейсов, которые заставляют перепроверять, казалось бы, базовые вещи.

Когда скроллбар становится дизайн-системой

WebKit даёт кастомизировать скроллбары через префиксные псевдоэлементы, но составные части оказываются неожиданно сложными:

body::-webkit-scrollbar {
  width: 1em; /* толщина всей конструкции */
}

body::-webkit-scrollbar-track {
  box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); /* фон трека */
}

body::-webkit-scrollbar-thumb {
  background-color: darkgrey;
  outline: 1px solid slategrey; /* сам бегунок */
}

На практике:

Флексбокс vs. скролл: битва в Safari

Типичный сценарий: контейнер с display: flex и overflow: scroll вдруг перестаёт скроллиться в Safari. Причина — внутренняя оптимизация WebKit, которая считает, что флекс-дети не могут быть скроллящимися областями.

Решение нашлось на Stack Overflow:

  1. Переносим overflow: scroll на внутренний контейнер
  2. Убеждаемся, что этот контейнер — не флекс-элемент
  3. Если нужно сохранить структуру, добавляем промежуточный div-враппер
/* Так не сработает */
.flex-container {
  display: flex;
  overflow: scroll; /* Safari проигнорирует */
}

/* А так — да */
.scroll-host {
  overflow: scroll;
}

text-transform: магия и ограничения

Казалось бы, что может пойти не так с преобразованием регистра? Но и здесь есть нюансы:

.lowercase { text-transform: lowercase } /* ВСЁ в нижний */
.uppercase { text-transform: uppercase } /* ВСЁ в верхний */
.capitalize { text-transform: capitalize } /* Первая буква каждого слова */

Подвохи:

React.cloneElement: когда пропсы не доходят до детей

Вот типичный кейс из мира React: у вас есть компонент-контейнер, и нужно прокинуть пропсы всем детям, даже если они переданы как undefined. Нативный {children} не сработает — нужен клон:

// Вместо этого:
<Container>{children}</Container>

// Делаем так:
React.cloneElement(this.props.children, { 
  loggedIn: this.state.loggedIn 
})

Особенности:

Выводы для практики

  1. Safari — это отдельная вселенная: любые взаимодействия flexbox и overflow требуют тестирования
  2. Префиксные псевдоэлементы — не временное решение, а часть спецификации
  3. Кастомные скроллбары всё ещё остаются хаками, несмотря на десятилетия развития CSS
  4. React-паттерны вроде cloneElement постепенно уступают место контекстам и хукам

Что попробовать: если ещё не сталкивались с проблемой flex + scroll в Safari, создайте тестовый пример — это один из тех багов, который проще предупредить, чем искать в продакшне.


Источник: https://dev.to/ld8/daily-notes-4lde