Правила компоновки

Этот раздел объясняет методы позиционирования визуальных компонентов и контейнеров в экранах.

Размеры компонентов

Компоненты, реализующие com.vaadin.flow.component.HasSize (например, button, textField, dataGrid, vbox, etc.) имеют следующие общие атрибуты: width, minWidth, maxWidth, height, minHeight, maxHeight. Эти атрибуты прямо соответствуют соответствующим по имени свойствам CSS.

Атрибуты min/max размеров помогают в создании адаптивного дизайна, когда компоненты должны приспосабливаться к разным размерам экрана. Эти атрибуты также могут использоваться для предотвращения переполнения компонентов или их слишком большого размера. См. практический пример ниже.

Размеры компонентов могут быть следующих типов:

  • Основанные на содержимом - AUTO

  • Фиксированные, например, 25em

  • Относительные (в процентах) к родительскому контейнеру, например, 100%

size types
Значение размера должно быть корректной для CSS строкой размера.

Размер, основанный на содержимом

Компонент займет достаточно места, чтобы вместить свое содержимое.

Примеры:

  • Для button размер определяется длиной значения атрибута text.

  • Для контейнеров (layouts) размер определяется суммой всех размеров компонентов внутри контейнера.

XML
<button text="Button" width="AUTO"/>
Java
button.setWidth("AUTO");

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

content based size

Фиксированный размер

Фиксированный размер подразумевает, что размеры компонента не будут изменяться во время выполнения.

XML
<vbox width="20em" height="15em"/>
Java
vBox.setWidth("20em");
vBox.setHeight("15em");
fixed size

Размер можно установить, используя абсолютные (например, px) или относительные (например, em) единицы длины. Все экраны и компоненты платформы используют относительные единицы длины, такие как em и rem, поэтому можно изменить размер всего приложения.

em - это единица измерения размера, относительная размера шрифта родителя. По умолчанию размер шрифта - 16px. Для информации о единицах измерения см. CSS values and units.

Относительный размер

Относительный размер указывает процент доступного пространства, которое будет занимать компонент.

XML
<button text="Button" width="50%"/>
Java
button.setWidth("50%");

Компоненты с относительным размером будут реагировать на изменения доступного пространства и автоматически изменять свой фактический размер на экране.

relative size

Специфика контейнеров

  • Корневой элемент layout - это вертикальный контейнер (vbox), который по умолчанию имеет ширину и высоту 100%.

  • scroller должен иметь фиксированную или относительную (но не AUTO) ширину и высоту. Компоненты внутри scroller, расположенные в направлении прокрутки, не должны иметь относительного размера.

Специфика компонентов

  • Для dataGrid не требуется явно присваивать height="100%" или расширять его внутри vbox или корневого элемента layout, потому что его CSS-свойство flex-grow установлено в 1, что означает, что по умолчанию компонент уже расширен в родительском контейнере. Тем не менее, для dataGrid рекомендуется установить атрибут minHeight, чтобы предотвратить коллапс компонента, если вертикального пространства недостаточно.

Расширение компонентов

Компоненты могут быть настроены на расширение и занятие всего дополнительного пространства, которое есть у контейнера.

<hbox expand="btn" padding="true" width="100%">
    <button text="Button"/>
    <button id="btn" text="Button"/>
    <button text="Button"/>
</hbox>
hbox expand
Figure 1. Горизонтальный контейнер с расширением
<vbox expand="btn" width="100%" minHeight="20em">
    <button text="Button"/>
    <button id="btn" text="Button"/>
    <button text="Button"/>
</vbox>
vbox expand
Figure 2. Вертикальный контейнер с расширением
Расширение компонента фактически означает, что его CSS-свойство flex-grow установлено в 1.

Интервалы и отступы

С помощью атрибутов spacing, margin и padding можно определить пустое пространство вокруг компонентов и внутри них.

Spacing

Атрибут spacing переключает для компонента настройку spacing темы. Если тема поддерживает этот атрибут, то для компонента применятся или удалятся интервалы.

hbox no spacing
Figure 3. Горизонтальный контейнер без интервалов
hbox spacing
Figure 4. Горизонтальный контейнер с интервалом по умолчанию
vbox spacing
Figure 5. Вертикальный контейнер с интервалом по умолчанию

Интервал включен по умолчанию для компонентов vbox и hbox.

Варианты интервалов

Атрибут spacing неявно добавляет средний интервал к теме компонента, что эквивалентно определению themeNames="spacing". Для установки других вариантов используйте атрибут themeNames явно. Доступно пять различных вариантов интервалов:

Вариант темы Рекомендации по использованию

spacing-xs

Очень маленький интервал между элементами

spacing-s

Небольшой интервал между элементами

spacing

Средний интервал между элементами

spacing-l

Большой интервал между элементами

spacing-xl

Очень большой интервал между элементами

Пример добавления интервала spacing-xl:

<vbox themeNames="spacing-xl" alignItems="STRETCH">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</vbox>
vbox spacing xl
Figure 6. Вертикальный контейнер с интервалом spacing-xl

Padding

Атрибут padding позволяет задавать пространство между границами контейнера и вложенными компонентами.

vbox padding
Figure 7. Вертикальный контейнер с padding

По умолчанию padding включен для vbox. Его можно отключить, установив атрибут padding в false. Для hbox по умолчанию padding отключен и его можно включить, установив атрибут padding в true.

Margin

Margin - это пространство вокруг границ контейнера.

vbox margin
Figure 8. Вертикальный контейнер с margin

По умолчанию margin отключен. Его можно включить, используя атрибут margin.

Выравнивание

Режим JustifyContent

Атрибут justifyContent соответствует CSS-свойству justify-content, которое определяет, как браузер распределяет пространство между и вокруг элементов контента вдоль главной оси flex-контейнера.

Значение Описание

START (по умолчанию)

Элементы размещаются в начале контейнера.

CENTER

Элементы размещаются в центре контейнера.

END

Элементы размещаются в конце контейнера.

BETWEEN

Элементы размещаются с пространством между строками; первый элемент на начальной линии, последний элемент на конечной линии.

AROUND

Элементы равномерно размещаются в линии с равным пространством вокруг них. Обратите внимание, что промежутки в начале и конце равны половине размера пространства между каждым элементом.

EVENLY

Элементы размещаются так, чтобы пространство между любыми двумя элементами (и пространство до краев) было равным.

Для vbox и flexLayout с flexDirection="COLUMN" (то есть при flex-direction: column) атрибут justifyContent работает следующим образом:

<vbox justifyContent="START" minHeight="20em">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</vbox>
vbox justifyContent start
Figure 9. Вертикальный контейнер с justifyContent="START"
<vbox justifyContent="CENTER" minHeight="20em">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</vbox>
vbox justifyContent center
Figure 10. Вертикальный контейнер с justifyContent="CENTER"
<vbox justifyContent="END" minHeight="20em">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</vbox>
vbox justifyContent end
Figure 11. Вертикальный контейнер с justifyContent="END"
<vbox justifyContent="BETWEEN" minHeight="20em">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</vbox>
vbox justifyContent between
Figure 12. Вертикальный контейнер с justifyContent="BETWEEN"
<vbox justifyContent="AROUND" minHeight="20em">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</vbox>
vbox justifyContent around
Figure 13. Вертикальный контейнер с justifyContent="AROUND"
<vbox justifyContent="EVENLY" minHeight="20em">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</vbox>
vbox justifyContent evenly
Figure 14. Вертикальный контейнер с justifyContent="EVENLY"

Для hbox и flexLayout с flexDirection="ROW" (то есть при flex-direction: row) атрибут justifyContent работает следующим образом:

<hbox justifyContent="START" padding="true" width="100%">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</hbox>
hbox justifyContent start
Figure 15. Горизонтальный контейнер с justifyContent="START"
<hbox justifyContent="CENTER" padding="true" width="100%">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</hbox>
hbox justifyContent center
Figure 16. Горизонтальный контейнер с justifyContent="CENTER"
<hbox justifyContent="END" padding="true" width="100%">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</hbox>
hbox justifyContent end
Figure 17. Горизонтальный контейнер с justifyContent="END"
<hbox justifyContent="BETWEEN" padding="true" width="100%">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</hbox>
hbox justifyContent between
Figure 18. Горизонтальный контейнер с justifyContent="BETWEEN"
<hbox justifyContent="AROUND" padding="true" width="100%">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</hbox>
hbox justifyContent around
Figure 19. Горизонтальный контейнер с justifyContent="AROUND"
<hbox justifyContent="EVENLY" padding="true" width="100%">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</hbox>
hbox justifyContent evenly
Figure 20. Горизонтальный контейнер с justifyContent="EVENLY"

AlignItems

Атрибут alignItems соответствует CSS-свойству align-items, которое определяет поведение по умолчанию для размещения элементов flex-контейнера вдоль поперечной оси на текущей линии. Можно рассматривать его как версию justify-content для поперечной оси (перпендикулярной главной оси).

Значение Описание

START

Элементы размещаются в начале поперечной оси.

CENTER

Элементы центрируются в поперечной оси.

END

Элементы размещаются в конце поперечной оси.

STRETCH

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

BASELINE

Элементы размещаются на базовой линии контейнера. Работает только для flex-direction: row.

AUTO

Элемент наследует свойство align-items своего родительского контейнера или "stretch", если у него нет родительского контейнера.

Для vbox и flexLayout с flexDirection="COLUMN" (когда flex-direction: column), атрибут alignItems работает следующим образом:

<vbox alignItems="START">
    <button text="Button" width="6em"/>
    <button text="Button" width="7em"/>
    <button text="Button" width="5em"/>
</vbox>
vbox alignItems start
Figure 21. Вертикальный контейнер с alignItems="START"
<vbox alignItems="CENTER">
    <button text="Button" width="6em"/>
    <button text="Button" width="7em"/>
    <button text="Button" width="5em"/>
</vbox>
vbox alignItems center
Figure 22. Вертикальный контейнер с alignItems="CENTER"
<vbox alignItems="END">
    <button text="Button" width="6em"/>
    <button text="Button" width="7em"/>
    <button text="Button" width="5em"/>
</vbox>
vbox alignItems end
Figure 23. Вертикальный контейнер с alignItems="END"
<vbox alignItems="STRETCH">
    <button text="Button" width="AUTO"/>
    <button text="Button" width="AUTO"/>
    <button text="Button" width="AUTO"/>
</vbox>
vbox alignItems stretch
Figure 24. Вертикальный контейнер с alignItems="STRETCH"

Для hbox и flexLayout с flexDirection="ROW" (когда flex-direction: row), атрибут alignItems работает следующим образом:

<hbox alignItems="START" padding="true" width="100%" minHeight="10em">
    <button text="Button" height="2em"/>
    <button text="Button" height="3em"/>
    <button text="Button" height="1.5em"/>
</hbox>
hbox alignItems start
Figure 25. Горизонтальный контейнер с alignItems="START"
<hbox alignItems="CENTER" padding="true" width="100%" minHeight="10em">
    <button text="Button" height="2em"/>
    <button text="Button" height="3em"/>
    <button text="Button" height="1.5em"/>
</hbox>
hbox alignItems center
Figure 26. Горизонтальный контейнер с alignItems="CENTER"
<hbox alignItems="END" padding="true" width="100%" minHeight="10em">
    <button text="Button" height="2em"/>
    <button text="Button" height="3em"/>
    <button text="Button" height="1.5em"/>
</hbox>
hbox alignItems end
Figure 27. Горизонтальный контейнер с alignItems="END"
<hbox alignItems="STRETCH" padding="true" width="100%" minHeight="10em">
    <button text="Button" height="AUTO"/>
    <button text="Button" height="AUTO"/>
    <button text="Button" height="AUTO"/>
</hbox>
hbox alignItems stretch
Figure 28. Горизонтальный контейнер с alignItems="STRETCH"
<hbox alignItems="BASELINE" padding="true" width="100%" minHeight="10em">
    <button text="Button" height="2em"/>
    <button text="Button" height="3em"/>
    <button text="Button" height="1.5em"/>
</hbox>
hbox alignItems baseline
Figure 29. Горизонтальный контейнер с alignItems="BASELINE"

AlignSelf

Атрибут alignSelf соответствует CSS-свойству align-self, которое определяет выравнивание отдельных компонентов внутри контейнера. Это индивидуальное выравнивание компонента переопределяет любое выравнивание, установленное с помощью alignItems.

<vbox alignItems="START">
    <button text="alignSelf=END" alignSelf="END"/>
    <button text="alignSelf=CENTER" alignSelf="CENTER"/>
    <button text="alignSelf=AUTO" alignSelf="AUTO"/>
</vbox>
vbox alignSelf
Figure 30. Вертикальный контейнер с alignItems="START" и разным alignSelf для вложенных компонентов
<hbox alignItems="START" justifyContent="BETWEEN" padding="true" width="100%" minHeight="10em">
    <button text="alignSelf=END" alignSelf="END"/>
    <button text="alignSelf=CENTER" alignSelf="CENTER"/>
    <button text="alignSelf=AUTO" alignSelf="AUTO"/>
</hbox>
hbox alignSelf
Figure 31. Горизонтальный контейнер с alignItems="START" и разным alignSelf для вложенных компонентов

Распространенные ошибки компоновки

Ошибка 1. Установка относительного размера для компонента в контейнере с размером, основанным на содержимом

Пример неправильного контейнера:
<vbox>
    <dataGrid id="usersDataGrid" dataContainer="usersDc"
              width="100%" height="100%">
        <actions/>
        <columns>
            <column property="firstName"/>
            <column property="lastName"/>
            <column property="username"/>
        </columns>
    </dataGrid>
</vbox>

В этом примере dataGrid имеет высоту 100%, в то время как высота по умолчанию для vbox - AUTO, т.е. основана на содержимом. В результате dataGrid коллапсирует.

dataGrid relative size
Figure 32. Пример относительного размера для компонента в контейнере с размером, основанным на содержимом

Ошибка 2. Не отключенный отступ для вложенных контейнеров vbox

Пример неправильного контейнера:
<layout>
    <genericFilter ...>
        ...
    </genericFilter>

    <vbox width="100%">
        <hbox id="buttonsPanel" classNames="buttons-panel">
            ...
        </hbox>
        <dataGrid id="usersDataGrid" ...>
            ...
        </dataGrid>
    </vbox>
    <hbox>
        ...
    </hbox>
</layout>

В этом примере dataGrid и hbox размещены внутри vbox, который по умолчанию имеет включенный отступ. В результате компоненты внутри vbox не выравниваются с компонентами снаружи.

vbox incorrect padding
Figure 33. Пример вложенного вертикального контейнера с включенным отступом

Ошибка 3. Выравнивание компонентов с относительным размером

Пример неправильного контейнера:
<hbox alignItems="CENTER" padding="true" width="100%" minHeight="10em">
    <span text="Span" height="100%"/>
</hbox>

В этом примере span имеет высоту 100% в контейнере hbox, который определяет alignItems="CENTER". В результате текст размещается в верхнем левом углу.

relative size alignment
Figure 34. Пример выравнивания компонентов с относительным размером

Ошибка 4. Растягивание компонентов с фиксированным размером

Пример неправильного контейнера:
<hbox alignItems="STRETCH" padding="true" width="100%" minHeight="10em">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</hbox>

В этом примере кнопки имеют высоту, заданную в стилях по умолчанию. В результате кнопки не растягиваются по вертикали.

fixed size stretching
Figure 35. Пример растягивания компонентов с фиксированным размером

Ошибка 5. Установка размера без единиц измерения

Пример неправильного указания размера:
<textField width="400"/>

В этом примере у textField не указаны единицы измерения размера. В результате значение размера игнорируется.

Советы и хитрости

Адаптация к экранам разного размера

Пример определения адаптивного текстового поля с фиксированным размером на больших экранах и шириной 100% на маленьких:

<hbox width="100%">
    <textField width="100%" maxWidth="40em"/>
    <button text="Button"/>
</hbox>
responsive text field

Пример определения formLayout с одной колонкой фиксированного размера на больших экранах и шириной 100% на маленьких:

<formLayout id="form"
            dataContainer="taskTypeDc"
            classNames="mx-m"
            maxWidth="40em"> (2)
    <responsiveSteps>
        <responsiveStep minWidth="0" columns="1"/> (1)
    </responsiveSteps>

    <textField id="nameField" property="name"/>
    <textArea id="descriptionField" property="description"
              height="9.5em"/>
</formLayout>
1 Определение того, что formLayout должен иметь одну колонку для любого размера экрана.
2 Установка максимальной ширины.
single column formLayout

Использование утилитных классов Lumo

Для простой стилизации можно использовать утилитные классы Lumo, предоставляемые Vaadin. Они представляют собой предопределенные классы CSS, решающие типовые задачи.

Каждый утилитный класс применяет определенный стиль к элементу, например, цвет фона, границы, шрифты, размеры или отступы. Доступны также классы для применения функций CSS flexbox и grid.

Java-класс LumoUtility содержит строковые константы для всех утилитных классов. Они разделены на вложенные классы категорий, например, LumoUtility.Margin.

Пример использования утилитных классов Lumo для добавления закругленной границы контейнеру:

<vbox id="imageWrapper"
      classNames="border                (1)
                  rounded-m             (2)
                  border-contrast-20"   (3)
      alignItems="CENTER"
      width="100%" maxWidth="30em">
1 Добавляет границу с цветом границы по умолчанию
2 Устанавливает радиус границы равный var(--lumo-border-radius-m)
3 Устанавливает цвет границы равный var(--lumo-contrast-20pct)
LumoUtility example

Пример выравнивания компонента в конец горизонтального контейнера:

<header id="header" classNames="jmix-main-view-header">
    <drawerToggle id="drawerToggle"
                  classNames="jmix-main-view-drawer-toggle"
                  themeNames="contrast"
                  ariaLabel="msg://drawerToggle.ariaLabel"/>
    <h1 id="viewTitle" classNames="jmix-main-view-title"/>

    <button id="logoutButton" icon="SIGN_OUT" classNames="ms-auto me-s"/> (1)
</header>
1 ms-auto эквивалентно margin-inline-start: auto, т.е. определяет отступ в логическом начале элемента, которое сопоставляется с физическим отступом в зависимости от flex-direction; me-s эквивалентно margin-inline-end: var(--lumo-space-s), т. е. определяет отступ в логическом конце элемента.
align to end