Skip to content

Commit 5a0f0fc

Browse files
authored
feat(PanelHeader): use position sticky (#9252)
- resolve #9251 - fix #6588 - fix #3532 - close #8115 - resolve #3396 --- <!-- Чеклист. Лишние пункты можно удалить если изменения не подразумевают их наличие. Иначе, необходимо обоснование по каждому пункту. --> - ~[ ] Unit-тесты~ - [x] e2e-тесты - ~[ ] Дизайн-ревью~ - ~[ ] Документация фичи~ - [x] Release notes h3. `PanelHeader` 1. Заменил `FixedLayout` на `position: sticky` прямо в компоненте. 2. Перенёс `z-index` перманентно в корень, т.к. `position: sticky` теперь применяется на `.host`. Это исправляет также перекрытие `PanelHeaderContext` при `<PanelHeader fixed={false} />`. 3. Заменил компонент `Spacing` на `delimiter="spacing"` на отступ в CSS, т.к. из-за него высота `PanelHeader` становится больше, появляется невидимая область и из-за п.2 это теперь блокирует взаимодействие с другими элементами в ситуации, когда частично зализает на них (`<Spacing />` добавили в #3135). 4. Сделал `Separator` плавающим элементом, чтобы он не занимал лишние `0.3-0.5px` в потоке. 5. Удалил в стилях `FixedLayout` не существующий класс `.vkuiInternalPanelHeader__fixed`. > [!NOTE] > > Помимо скриншотов `PanelHeader`, задело: > > - `Epic` – из-за п.4 > - `Panel` – из-за п.4 > - `PanelHeaderContext` – из-за п.4 > - `FixedLayout` – из-за п.1 и п.4 > > Обновил их. h3. `SplitCol` Для `<SplitCol fixed />` также заменяем `position: fixed` на `position: sticky`. Также задаем минимальную высоту через [dvh](https://caniuse.com/?search=dvh) (с фолбеком на `100vh` с вычетом `safe-area`) и делаем его Flexbox'ом, чтобы потомки могли растягиваться на всю высоту через `flex: 1` вместо `block-size: 100%`. h3. `SplitLayout` Чтобы решить проблему когда стики шапка при `<SplitLayout header={<PanelHeader delimiter="none" />} />` остается в рамках `100vh` (см. #6609 (comment)), избавляемся от `height: 100%` у `<html>` и `<body>`. Вместо этого используем магию с Flexbox. - на `<html>` `display: flex` + `min-height: 100%`, чтобы страница растягивалась с учётом контента, а не области видимости; - для `<body>` удаляем `block-size: 100%` и задаём `display: flex`, чтобы высота зависела от содержимого, а потомки продолжали растягиваться через `block-size: 100%`. `height: 100%` у `.vkui__root`, `AppRoot`, `SplitLayout` и так далее по каскаду – не трогаем, их логика остаётся прежней. Элементы должны продолжать наследовать `height: 100%`. Ориентировался на статью https://stackoverflow.com/questions/30962863/holy-grail-layout-with-flex-and-always-visible-header. Добавил скриншотных тестов для проверки стики элементов. Заодно удалил `dark` старых скриншотов, т.к. она не нужна в этих проверках. Помимо этого, решил перенести удаление свойств `popout` и `modal` на VKUI v9. А для `getRef` добавил эту пометку. h4. Ожидаемый эффект Теперь высота всей страницы зависит от контента. На это можно повлиять через указание какому-либо элементу высоту через единицы `vh` или `dvh`. В частности, из-за этого для скриншотов `FixedLayout` делаем теперь `expectScreenshotClippedToContent({ fullPage: false })`, т.к. внутри функции `getBoundingClientRect()` отдаёт абсолютную высоту элемента. h4. Что может сломаться? - Получение области видимости через `document.body.clientHeight` или его потомков с `height: 100%`. Необходимо заменить либо на `document.documentElement.clientHeight`, либо на `window.innerHeight`. ```diff - document.body.clientHeight + document.documentElement.clientHeight // или + window.innerHeight ``` - Применение `position: absolute` на элементе на уровне `<body>`. Необходимо заменить на `position: fixed`. h3. Окружение - **Storybook**: потребовалось перебить стиль `display: block`, который они навешивают на `<body>`, потому что нам нужен `display: flex`. - **Playwright**: - добавил новых параметров для `AppDefaultWrapper` и `screenshotWithClipToContent`, чтобы была возможность скриншотить только область видимости. - `index.ts` подключил `import '../src/styles/layout.css';`, чтобы собирались новые CSS утилиты для раскладки. --- #h1. Release notes #h1. BREAKING CHANGE - PanelHeader: изменена реализация `fixed`, который закрепляет шапку в области видимости при скролле – вместо `position: fixed` используется `position: sticky`. Это потребовало изменение раскладки всей страницы – `height: 100%` на `<html>` и `<body>` удалён в пользу `display: flex` и теперь высота страницы зависит от содержимого. - Если вы получали высоту области видимости через `document.body.clientHeight` или на элементе с `height: 100%` по каскаду ниже, то замените такой код либо на [VIsualViewport](https://developer.mozilla.org/en-US/docs/Web/API/VisualViewport), либо на `document.documentElement.clientHeight`, либо на `window.innerHeight`. - Если вам нужно, чтобы какой-то из элементов растягивался на высоты области видимости, то используйте единицы измерения [`vh`](https://caniuse.com/?search=vh) или [`dvh`](https://caniuse.com/?search=dvh) вместо `%` (`height: 100%` → `height: 100dvh`) - SplitCol: - Изменена реализация `fixed`, который закрепляет колонку в области видимости при скролле – вместо `position: fixed` используется `position: sticky`. - Исправлена проблема когда переполненный контент при `fixed` обрезался – теперь высота `SplitCol` зависит от его содержимого. Чтобы растянуть потомок на всю колонку, используйте `flex-grow: 1` на этом потомке.
1 parent 0d5c3a8 commit 5a0f0fc

File tree

84 files changed

+551
-263
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+551
-263
lines changed

packages/vkui/.storybook/preview.css

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
@import '../src/styles/adaptivity.module.css';
66
@import '../src/styles/common.css';
77

8-
/* stylelint-disable-next-line selector-max-id */
9-
#root {
10-
block-size: 100%;
8+
/* Перебиваем стили Storybook под наши правила для `<body>` в `common.css` */
9+
.sb-show-main.sb-main-fullscreen {
10+
display: inherit;
1111
}

packages/vkui/playwright/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
import '../src/styles/layout.css';
12
import './index.css';
2-
33
// Как минимум, отключаем анимации
44
// eslint-disable-next-line no-restricted-globals
55
window.__isVkuiTesting = true;
Lines changed: 2 additions & 2 deletions
Lines changed: 2 additions & 2 deletions
Lines changed: 2 additions & 2 deletions
Lines changed: 2 additions & 2 deletions
Lines changed: 2 additions & 2 deletions
Lines changed: 2 additions & 2 deletions
Lines changed: 2 additions & 2 deletions

packages/vkui/src/components/FixedLayout/FixedLayout.e2e.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ test('FixedLayout with vertical=top', async ({
77
componentPlaygroundProps,
88
}) => {
99
await mount(<FixedLayoutPlayground {...componentPlaygroundProps} vertical="top" />);
10-
await expectScreenshotClippedToContent();
10+
await expectScreenshotClippedToContent({ fullPage: false });
1111
});
1212

1313
test('FixedLayout with vertical=bottom', async ({
@@ -16,7 +16,7 @@ test('FixedLayout with vertical=bottom', async ({
1616
componentPlaygroundProps,
1717
}) => {
1818
await mount(<FixedLayoutPlayground {...componentPlaygroundProps} vertical="bottom" />);
19-
await expectScreenshotClippedToContent();
19+
await expectScreenshotClippedToContent({ fullPage: false });
2020
});
2121

2222
test('FixedLayout with vertical=top filled=true', async ({
@@ -25,7 +25,7 @@ test('FixedLayout with vertical=top filled=true', async ({
2525
componentPlaygroundProps,
2626
}) => {
2727
await mount(<FixedLayoutPlayground {...componentPlaygroundProps} vertical="top" filled />);
28-
await expectScreenshotClippedToContent();
28+
await expectScreenshotClippedToContent({ fullPage: false });
2929
});
3030

3131
test('FixedLayout with vertical=bottom filled=true', async ({
@@ -34,5 +34,5 @@ test('FixedLayout with vertical=bottom filled=true', async ({
3434
componentPlaygroundProps,
3535
}) => {
3636
await mount(<FixedLayoutPlayground {...componentPlaygroundProps} vertical="bottom" filled />);
37-
await expectScreenshotClippedToContent();
37+
await expectScreenshotClippedToContent({ fullPage: false });
3838
});

0 commit comments

Comments
 (0)