Правила компоновки
Этот раздел объясняет методы позиционирования визуальных компонентов и контейнеров в экранах.
Размеры компонентов
Компоненты, реализующие com.vaadin.flow.component.HasSize (например, button, textField, dataGrid, vbox, etc.) имеют следующие общие атрибуты: width, minWidth, maxWidth, height, minHeight, maxHeight. Эти атрибуты прямо соответствуют соответствующим по имени свойствам CSS.
| Атрибуты min/max размеров помогают в создании адаптивного дизайна, когда компоненты должны приспосабливаться к разным размерам экрана. Эти атрибуты также могут использоваться для предотвращения переполнения компонентов или их слишком большого размера. См. практический пример ниже. | 
Размеры компонентов могут быть следующих типов:
- 
Основанные на содержимом - AUTO
- 
Фиксированные, например, 25em
- 
Относительные (в процентах) к родительскому контейнеру, например, 100%
 
| Значение размера должно быть корректной для CSS строкой размера. | 
Размер, основанный на содержимом
Компонент займет достаточно места, чтобы вместить свое содержимое.
Примеры:
- 
Для buttonразмер определяется длиной значения атрибутаtext.
- 
Для контейнеров (layouts) размер определяется суммой всех размеров компонентов внутри контейнера. 
<button text="Button" width="AUTO"/>button.setWidth("AUTO");Компоненты с размером, основанным на содержимом, будут автоматически изменять свои размеры при инициализации экрана или при изменении размера содержимого.
 
Фиксированный размер
Фиксированный размер подразумевает, что размеры компонента не будут изменяться во время выполнения.
<vbox width="20em" height="15em"/>vBox.setWidth("20em");
vBox.setHeight("15em"); 
Размер можно установить, используя абсолютные (например, px) или относительные (например, em) единицы длины. Все экраны и компоненты платформы используют относительные единицы длины, такие как em и rem, поэтому можно изменить размер всего приложения.
| em- это единица измерения размера, относительная размера шрифта родителя. По умолчанию размер шрифта -16px. Для информации о единицах измерения см. CSS values and units. | 
| Вы можете столкнуться с ситуацией, когда вы устанавливаете фиксированный размер для компонента, например, ширины, но он становится меньше, если в родительском контейнере недостаточно места. Чтобы обойти это, можно либо установить значения minWidth/minHeightтакими же, как значенияwidth/height, либо установитьflex-shrink: 0, используя атрибут css.Это происходит потому, что когда компоненты размещены в контейнерах flexbox, таких как hbox, vbox или flexLayout, то даже если у них фиксированный размер вдоль главной оси контейнера, их размер не может превышать размер родительского контейнера. Согласно спецификации, начальное значение свойства flex-shrink равно 1, что означает, что по умолчанию flex-item уменьшает свой размер, если доступного места недостаточно. | 
Относительный размер
Относительный размер указывает процент доступного пространства, которое будет занимать компонент.
<button text="Button" width="50%"/>button.setWidth("50%");Компоненты с относительным размером будут реагировать на изменения доступного пространства и автоматически изменять свой фактический размер на экране.
 
Специфика контейнеров
- 
Корневой элемент 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> 
<vbox expand="btn" width="100%" minHeight="20em">
    <button text="Button"/>
    <button id="btn" text="Button"/>
    <button text="Button"/>
</vbox> 
| Расширение компонента фактически означает, что его CSS-свойство flex-grow установлено в 1. | 
Интервалы и отступы
С помощью атрибутов spacing, margin и padding можно определить пустое пространство вокруг компонентов и внутри них.
Spacing
Атрибут spacing переключает для компонента настройку spacing темы. Если тема поддерживает этот атрибут, то для компонента применятся или удалятся интервалы.
 
 
 
Интервал включен по умолчанию для компонентов 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> 
Padding
Атрибут padding позволяет задавать пространство между границами контейнера и вложенными компонентами.
 
По умолчанию padding включен для vbox. Его можно отключить, установив атрибут padding в false. Для hbox по умолчанию padding отключен и его можно включить, установив атрибут padding в true.
Выравнивание
Режим JustifyContent
Атрибут justifyContent соответствует CSS-свойству justify-content, которое определяет, как браузер распределяет пространство между и вокруг элементов контента вдоль главной оси flex-контейнера.
| Значение | Описание | 
|---|---|
| 
 | Элементы размещаются в начале контейнера. | 
| 
 | Элементы размещаются в центре контейнера. | 
| 
 | Элементы размещаются в конце контейнера. | 
| 
 | Элементы размещаются с пространством между строками; первый элемент на начальной линии, последний элемент на конечной линии. | 
| 
 | Элементы равномерно размещаются в линии с равным пространством вокруг них. Обратите внимание, что промежутки в начале и конце равны половине размера пространства между каждым элементом. | 
| 
 | Элементы размещаются так, чтобы пространство между любыми двумя элементами (и пространство до краев) было равным. | 
Для vbox и flexLayout с flexDirection="COLUMN" (то есть при flex-direction: column) атрибут justifyContent работает следующим образом:
<vbox justifyContent="START" minHeight="20em">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</vbox> 
justifyContent="START"<vbox justifyContent="CENTER" minHeight="20em">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</vbox> 
justifyContent="CENTER"<vbox justifyContent="END" minHeight="20em">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</vbox> 
justifyContent="END"<vbox justifyContent="BETWEEN" minHeight="20em">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</vbox> 
justifyContent="BETWEEN"<vbox justifyContent="AROUND" minHeight="20em">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</vbox> 
justifyContent="AROUND"<vbox justifyContent="EVENLY" minHeight="20em">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</vbox> 
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> 
justifyContent="START"<hbox justifyContent="CENTER" padding="true" width="100%">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</hbox> 
justifyContent="CENTER"<hbox justifyContent="END" padding="true" width="100%">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</hbox> 
justifyContent="END"<hbox justifyContent="BETWEEN" padding="true" width="100%">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</hbox> 
justifyContent="BETWEEN"<hbox justifyContent="AROUND" padding="true" width="100%">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</hbox> 
justifyContent="AROUND"<hbox justifyContent="EVENLY" padding="true" width="100%">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</hbox> 
justifyContent="EVENLY"AlignItems
Атрибут alignItems соответствует CSS-свойству align-items, которое определяет поведение по умолчанию для размещения элементов flex-контейнера вдоль поперечной оси на текущей линии. Можно рассматривать его как версию justify-content для поперечной оси (перпендикулярной главной оси).
| Значение | Описание | 
|---|---|
| 
 | Элементы размещаются в начале поперечной оси. | 
| 
 | Элементы центрируются в поперечной оси. | 
| 
 | Элементы размещаются в конце поперечной оси. | 
| 
 | Элементы с неопределенным размером вдоль поперечной оси растягиваются, чтобы соответствовать контейнеру. | 
| 
 | Элементы размещаются на базовой линии контейнера. Работает только для  | 
| 
 | Элемент наследует свойство 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> 
alignItems="START"<vbox alignItems="CENTER">
    <button text="Button" width="6em"/>
    <button text="Button" width="7em"/>
    <button text="Button" width="5em"/>
</vbox> 
alignItems="CENTER"<vbox alignItems="END">
    <button text="Button" width="6em"/>
    <button text="Button" width="7em"/>
    <button text="Button" width="5em"/>
</vbox> 
alignItems="END"<vbox alignItems="STRETCH">
    <button text="Button" width="AUTO"/>
    <button text="Button" width="AUTO"/>
    <button text="Button" width="AUTO"/>
</vbox> 
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> 
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> 
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> 
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> 
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> 
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> 
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> 
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 коллапсирует.
 
Ошибка 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 не выравниваются с компонентами снаружи.
 
Ошибка 3. Выравнивание компонентов с относительным размером
<hbox alignItems="CENTER" padding="true" width="100%" minHeight="10em">
    <span text="Span" height="100%"/>
</hbox>В этом примере span имеет высоту 100% в контейнере hbox, который определяет alignItems="CENTER". В результате текст размещается в верхнем левом углу.
 
Ошибка 4. Растягивание компонентов с фиксированным размером
<hbox alignItems="STRETCH" padding="true" width="100%" minHeight="10em">
    <button text="Button"/>
    <button text="Button"/>
    <button text="Button"/>
</hbox>В этом примере кнопки имеют высоту, заданную в стилях по умолчанию. В результате кнопки не растягиваются по вертикали.
 
Ошибка 5. Установка размера без единиц измерения
<textField width="400"/>В этом примере у textField не указаны единицы измерения размера. В результате значение размера игнорируется.
Советы и хитрости
Адаптация к экранам разного размера
Пример определения адаптивного текстового поля с фиксированным размером на больших экранах и шириной 100% на маленьких:
<hbox width="100%">
    <textField width="100%" maxWidth="40em"/>
    <button text="Button"/>
</hbox> 
Пример определения 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 | Установка максимальной ширины. | 
 
Использование утилитных классов 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) | 
 
Пример выравнивания компонента в конец горизонтального контейнера:
<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), т. е. определяет отступ в логическом конце элемента. | 
 
