Skip to content

fix(PanelHeader): Replace FixedLayout with sticky position#6609

Closed
mendrew wants to merge 3 commits intomasterfrom
mendrew/6588/PanelHeader/remove-fixed-layout-usage
Closed

fix(PanelHeader): Replace FixedLayout with sticky position#6609
mendrew wants to merge 3 commits intomasterfrom
mendrew/6588/PanelHeader/remove-fixed-layout-usage

Conversation

@mendrew
Copy link
Copy Markdown
Contributor

@mendrew mendrew commented Feb 20, 2024

related (по поводу использования position sticky): #2422 (comment) #2414 (comment)

Описание

Убираем использование FixedLayout из PanelHeader, так как это провоцирует ререндер и сдвиг контента из-за того, что FixedLayout адаптирует свою ширину под ширину SplitCol .

Только сейчас по браузерной поддержке мы можем использовать position: sticky.

Изменения

  • заменили FixedLayout на position: sticky.

@github-actions github-actions bot added the ci:cherry-pick:patch Автоматизация: PR продублируется в ветку последнего минорного релиза для выпуска патча label Feb 20, 2024
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 20, 2024

size-limit report 📦

Path Size
JS 351.99 KB (-0.06% 🔽)
JS (gzip) 107.63 KB (-0.05% 🔽)
JS (brotli) 89.09 KB (+0.07% 🔺)
JS import Div (tree shaking) 1.43 KB (0%)
CSS 257.9 KB (-0.03% 🔽)
CSS (gzip) 33.81 KB (-0.01% 🔽)
CSS (brotli) 27.46 KB (+0.04% 🔺)

@codesandbox-ci
Copy link
Copy Markdown

codesandbox-ci bot commented Feb 20, 2024

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 20, 2024

e2e tests

Playwright Report

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Feb 20, 2024

👀 Docs deployed

Commit 49b6f96

@codecov
Copy link
Copy Markdown

codecov bot commented Feb 20, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 82.20%. Comparing base (e140ea9) to head (49b6f96).
Report is 84 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6609      +/-   ##
==========================================
- Coverage   82.21%   82.20%   -0.01%     
==========================================
  Files         331      331              
  Lines       10250    10246       -4     
  Branches     3439     3436       -3     
==========================================
- Hits         8427     8423       -4     
  Misses       1823     1823              
Flag Coverage Δ
unittests 82.20% <ø> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@github-actions github-actions bot added the pr-needs-work Автоматизация: PR автоматически закроется через 14 дней при отсутствии активности label Feb 28, 2024
Because it's the default value, so we don't need set it again.
Also it breaks fixed prop as it doesn't allow to override
position due to cascade.
@mendrew mendrew force-pushed the mendrew/6588/PanelHeader/remove-fixed-layout-usage branch from 221ba5c to c6d079d Compare February 29, 2024 11:01
* VKCOM
*/
.PanelHeader--vkcom {
position: relative;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Убрал, потому что иначе проп fixed не работает с платформой vkcom.
А не работает из-за того, что веса PanelHeader--fixedsticky и .PanelHeader--vkcom теперь одинаковы.

@mendrew mendrew marked this pull request as ready for review February 29, 2024 12:07
@mendrew mendrew requested a review from a team as a code owner February 29, 2024 12:07
@mendrew mendrew modified the milestone: v6.0.1 Feb 29, 2024
Copy link
Copy Markdown
Contributor

@inomdzhon inomdzhon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

display: block;
content: '';
.PanelHeader--fixed {
position: sticky;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Возможно стоит добавить backface-visibility: hidden, сталкивался с багом то ли в сафари, то ли в хроме, когда стики то пропадает, то появляется. Мб сейчас уже ок, не смог найти инфы в инете поправлено ли.

Ссылки

@github-actions github-actions bot removed the pr-needs-work Автоматизация: PR автоматически закроется через 14 дней при отсутствии активности label Mar 1, 2024
@mendrew
Copy link
Copy Markdown
Contributor Author

mendrew commented Mar 1, 2024

Заметил, что если использовать PanelHeader в многоколоночном интерфейсе на широком экране на Android или iOS, передавая PanelHeader в свойство header у SplitLayout, чтобы это работало как заглушка, заполняя пробелы между колонками, то c position: sticky эта заглушка прилипнет к концу SplitCol если контент панели больше высоты вьюпорта.
https://vkui-screenshot.hb.bizmrg.com/pull/6609/49b6f9609c6529755717a602ac36f8ce18b5446f/styleguide/index.html#/SplitLayout

Screen.Recording.2024-03-01.at.16.33.26.mov

Перевожу пока в draft. Надо подумать.

@mendrew mendrew marked this pull request as draft March 1, 2024 13:34
@mendrew
Copy link
Copy Markdown
Contributor Author

mendrew commented Mar 5, 2024

Другая причина не переходить полностью на position: sticky, это то, что PanelHeader начинает скакать вместе с контентом панели при scroll overflow.
На видео сначала показываю что PanelHeader скачет с position: sticky, а при position: fixed - нет.

Screen.Recording.2024-03-05.at.18.23.17.mov

@vkcom-publisher vkcom-publisher added pr-needs-work Автоматизация: PR автоматически закроется через 14 дней при отсутствии активности and removed pr-needs-work Автоматизация: PR автоматически закроется через 14 дней при отсутствии активности labels Mar 13, 2024
@vkcom-publisher vkcom-publisher added pr-needs-work Автоматизация: PR автоматически закроется через 14 дней при отсутствии активности and removed pr-needs-work Автоматизация: PR автоматически закроется через 14 дней при отсутствии активности labels Mar 22, 2024
@vkcom-publisher vkcom-publisher added the pr-needs-work Автоматизация: PR автоматически закроется через 14 дней при отсутствии активности label Mar 30, 2024
@vkcom-publisher
Copy link
Copy Markdown
Contributor

PR закрыт из-за отсутствия активности в течение последних 14 дней. Если это произошло по ошибке или изменения все ещё актуальны, откройте PR повторно.

inomdzhon added a commit that referenced this pull request Dec 1, 2025
h2. `PanelHeader`

1. Заменил `FixedLayout` на `position: sticky` прямо в компоненте.
2. Перенёс `z-index` перманентно в корень, т.к. `position: sticky`
  теперь применяется на `.host`. Это исправляет также  перекрытие
  `PanelHeaderContext` при `<PanelHeader fixed={false} />`.
3. Заменил компонент `Spacing` на `delimiter="spacing"` на отступ в CSS,
  т.к. из-за него высота `PanelHeader` становится больше, появляется
  невидимая область и из-за п.2 это теперь блокирует взаимодействие
  с другими элементами в ситуации, когда частично зализает на них
  (`<Spacing />` добавили в #3135).

h2. `SplitCol`

Для `<SplitCol fixed />` также заменяем `position: fixed` на `position: sticky`.

Также добавляем растягивание на `100vh` с вычетом `safe-area`
и с Graceful Degradation на [dvh](https://caniuse.com/?search=dvh).

h2. `SplitLayout`

Чтобы решить проблему когда стики шапка при `<SplitLayout header={<PanelHeader delimiter="none" />} />`
остается в рамках `100vh` (см. #6609 (comment)),
избавляемся от `height: 100%` у `<html>`, `<body>`, `.vkui__root`.
Вместо этого используем магию с Flexbox.

- на `<html>` `display: flex` + `min-height: 100%`, чтобы страница
  растягивалась с учётом контента, а не области видимости;
- для `<body>` используем `flex: 1`, чтобы растягивался также как
  и `<html>`, а также `display: flex` + `flex-direction: column`,
  чтобы также растягивать потомков (об этом далее);
- для `.vkui__root` повторяем тоже самое, что и для `<body>`.

`height: 100%` у `AppRoot`, `SplitLayout` и так далее по каскаду
не трогаем, т.к. они растягиваются от `flex: 1`.

Ориентировался на статью https://stackoverflow.com/questions/30962863/holy-grail-layout-with-flex-and-always-visible-header.
inomdzhon added a commit that referenced this pull request Dec 2, 2025
h2. `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
>
> Обновил их.

h2. `SplitCol`

Для `<SplitCol fixed />` также заменяем `position: fixed` на `position: sticky`.

Также добавляем растягивание на `100vh` с вычетом `safe-area`
и с Graceful Degradation на [dvh](https://caniuse.com/?search=dvh).

h2. `SplitLayout`

Чтобы решить проблему когда стики шапка при `<SplitLayout header={<PanelHeader delimiter="none" />} />`
остается в рамках `100vh` (см. #6609 (comment)),
избавляемся от `height: 100%` у `<html>`, `<body>`, `.vkui__root`.
Вместо этого используем магию с Flexbox.

- на `<html>` `display: flex` + `min-height: 100%`, чтобы страница
  растягивалась с учётом контента, а не области видимости;
- для `<body>` удаляем `block-size: 100%` и задаём `display: flex`,
  чтобы растягивался также потомки растягивались на всю высоту.

`height: 100%` у `.vkui__root`, `AppRoot`, `SplitLayout` и так далее
по каскаду – не трогаем, их логика остаётся прежней. Элементы должны
продолжать наследовать `height: 100%`.

Ориентировался на статью https://stackoverflow.com/questions/30962863/holy-grail-layout-with-flex-and-always-visible-header.

Добавил скриншотных тестов для проверки стики элементов. Заодно удалил
`dark` старых скриншотов, т.к. она не нужна в этих проверках.

h3. Ожидаемый эффект

Теперь высота всей страницы зависит от контента. На это можно повлиять
через указание какому-либо элементу высоту через единицы `vh` или `dvh`.

В частности, из-за этого для скриншотов `FixedLayout` делаем теперь
`expectScreenshotClippedToContent({ fullPage: false })`, т.к. внутри
функции `getBoundingClientRect()` отдаёт абсолютную высоту элемента.

h3. Что может сломаться?

- Получение области видимости через `document.body.clientHeight` или его
  потомков с `height: 100%`. Необходимо заменить либо на
  `document.documentElement.clientHeight`, либо на `window.innerHeight`.

  ```diff
  - document.body.clientHeight
  + document.documentElement.clientHeight
  // или
  + window.innerHeight
  ```

- Применение `position: absolute` на элементе на уровне `<body>`. Вместо
  этого использовать `position: fixed`.

h2. Окружение

- **Storybook**: потребовалось перебить стиль `display: block`, который
  они навешивают на `<body>`, потому что нам нужен `display: flex`.
- **Playwright**:
  - добавил новых параметров для `AppDefaultWrapper` и
    `screenshotWithClipToContent`, чтобы была возможность скриншотить
    только область видимости.
  - `index.ts` подключил `import '../src/styles/layout.css';`, чтобы
    собирались новые CSS утилиты для раскладки.
inomdzhon added a commit that referenced this pull request Dec 2, 2025
h2. `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
>
> Обновил их.

h2. `SplitCol`

Для `<SplitCol fixed />` также заменяем `position: fixed` на `position: sticky`.

Также добавляем растягивание на `100vh` с вычетом `safe-area`
и с Graceful Degradation на [dvh](https://caniuse.com/?search=dvh).

h2. `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`,
  чтобы растягивался также потомки растягивались на всю высоту.

`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` добавил эту пометку.

h3. Ожидаемый эффект

Теперь высота всей страницы зависит от контента. На это можно повлиять
через указание какому-либо элементу высоту через единицы `vh` или `dvh`.

В частности, из-за этого для скриншотов `FixedLayout` делаем теперь
`expectScreenshotClippedToContent({ fullPage: false })`, т.к. внутри
функции `getBoundingClientRect()` отдаёт абсолютную высоту элемента.

h3. Что может сломаться?

- Получение области видимости через `document.body.clientHeight` или его
  потомков с `height: 100%`. Необходимо заменить либо на
  `document.documentElement.clientHeight`, либо на `window.innerHeight`.

  ```diff
  - document.body.clientHeight
  + document.documentElement.clientHeight
  // или
  + window.innerHeight
  ```

- Применение `position: absolute` на элементе на уровне `<body>`. Необходимо
  заменить на `position: fixed`.

h2. Окружение

- **Storybook**: потребовалось перебить стиль `display: block`, который
  они навешивают на `<body>`, потому что нам нужен `display: flex`.
- **Playwright**:
  - добавил новых параметров для `AppDefaultWrapper` и
    `screenshotWithClipToContent`, чтобы была возможность скриншотить
    только область видимости.
  - `index.ts` подключил `import '../src/styles/layout.css';`, чтобы
    собирались новые CSS утилиты для раскладки.
inomdzhon added a commit that referenced this pull request Dec 8, 2025
- 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` на этом потомке.
@inomdzhon inomdzhon deleted the mendrew/6588/PanelHeader/remove-fixed-layout-usage branch December 12, 2025 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:cherry-pick:patch Автоматизация: PR продублируется в ветку последнего минорного релиза для выпуска патча pr-needs-work Автоматизация: PR автоматически закроется через 14 дней при отсутствии активности

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug][PanelHeader]: Некорректная позиция after на первом рендере

3 participants