# Posicionamento da UI

Para todos os tipos de conteúdo de UI, use o `uiTransform` component para definir o tamanho, a posição e outras propriedades relacionadas ao alinhamento da entity.

O `uiTransform` component funciona no espaço 2D da tela, de forma muito parecida com o `Transform` component funciona no espaço 3D da scene.

***arquivo ui.tsx:***

```ts
import { UiEntity, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

export const uiMenu = () => (
	<UiEntity
		uiTransform={{
			width: '200px',
			height: '100px',
			justifyContent: 'center',
			alignItems: 'center',
		}}
		uiBackground={{ color: Color4.Green() }}
	/>
)
```

***arquivo index.ts:***

```ts
import { ReactEcsRenderer } from '@dcl/sdk/react-ecs'
import { uiMenu } from './ui'

export function main() {
    ReactEcsRenderer.setUiRenderer(uiMenu, { virtualWidth: 1920, virtualHeight: 1080 })
}
```

{% hint style="warning" %}
**📔 Nota**: Todos os snippets a seguir nesta página assumem que você tem um `.ts` semelhante ao acima, executando a função `ReactEcsRenderer.setUiRenderer()` .
{% endhint %}

## Propriedades de posicionamento

O alinhamento das entities de UI é baseado no modelo de alinhamento Flexbox. Este é um modelo muito poderoso para organizar dinamicamente entities aninhadas dentro de modals que podem variar de tamanho.

{% hint style="info" %}
**💡 Dica**: A implementação de UI da Decentraland é baseada na de [Yoga](https://yogalayout.com/docs/). Leia [este artigo](https://www.joshwcomeau.com/css/interactive-guide-to-flexbox/) para uma cobertura muito acessível e detalhada das propriedades disponíveis no Flexbox.
{% endhint %}

### Tamanho da entity

Use `width` e `height` para definir o tamanho da entity. Os seguintes tipos de valores são suportados:

* `auto`: O tamanho se adapta para caber no conteúdo interno. Isso é muito conveniente para texto que pode variar de tamanho. Escreva o valor como "auto".
* **Porcentagem**: Como porcentagem das medidas do parent. Escreva o valor como uma string que termina em "%", por exemplo `10 %`.
* **Pixels**: Escreva o valor como um número.
* **Largura ou altura da tela**: Use vw (view width) e vh (view height) podem ser usados para indicar uma fração do tamanho total da janela que executa a Decentraland. Por exemplo `10vw` refere-se a 10% da largura da janela, `25vh` a 25% da altura da janela.

Observe que essas propriedades afetam o tamanho **default** desse item, o tamanho do item antes que quaisquer cálculos de flex grow e flex shrink sejam realizados. O tamanho final pode ser interpretado de forma diferente com base no tamanho da entity parent e nas propriedades Flexbox definidas.

{% hint style="warning" %}
**📔 Nota**: Em propriedades que suportam tanto números quanto strings, para definir o valor em pixels, escreva um número. Para definir esses campos como uma porcentagem das medidas do parent, escreva o valor como uma string que termina em "%", por exemplo `10 %`. Você também pode definir um valor em pixels como uma string, terminando a string em `px`, por exemplo `200px`.

* Quando os valores são expressos como porcentagem, eles sempre se referem ao container do parent. Se a entity não tiver parents, então o valor é uma porcentagem de toda a tela.
* Se os valores são expressos em pixels, eles são absolutos e não são afetados pela escala do parent.
* Se os valores são expressos em `vh` ou `vw`, eles representam uma porcentagem da janela completa e não são afetados pela escala do parent.

Para que `auto` width/height funcione, aplicam-se as seguintes regras:

* O UiTransform que usa width/height como “auto” deve ter `alignSelf`: `“center”`/`“flex-start”`/`“flex-end”` OU `positionType: “absolute”`
* Se o UiTransform de um child usar `positionType: “absolute”`, o parent não se adaptará ao seu tamanho/posição
* Se o UiTransform de um child usar qualquer substituição de posição, o parent não se adaptará ao seu tamanho/posição
  {% endhint %}

Estas outras propriedades também estão disponíveis para ajustar o tamanho de forma mais avançada:

* `maxWidth` e `maxHeight`: *number* ou string (como height e width). O tamanho máximo que a entity pode ter.
* `minWidth` e `minHeight`: *number* ou string (como height e width). O tamanho mínimo que a entity pode ter. Se o parent for pequeno demais para caber no tamanho mínimo das entities, elas vão transbordar do parent.
* `flexBasis`: Esta é uma forma independente de eixo de fornecer o tamanho padrão de um item ao longo do eixo principal. Definir o flex basis de um child é semelhante a definir a largura desse child se o seu parent for um container com flex direction: row ou definir a altura de um child se o seu parent for um container com flex direction: column.

```ts
import { UiEntity, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

export const uiMenu = () => (
	<UiEntity
		uiTransform={{
			alignSelf: 'center',
			alignContent: 'center',
			width: '80%',
			height: '30%',
			minWidth: 300,
			maxWidth: 2500,
			margin: { left: '10%', right: '10%' },
		}}
		uiBackground={{ color: Color4.Green() }}
	/>
)
```

### Organizando entities filhas

Por padrão, as entities filhas são posicionadas em relação ao canto superior esquerdo do seu parent. Você pode usar propriedades como `justifyContent` e `alignItems` para alterar esse comportamento.

{% hint style="info" %}
**💡 Dica**: Quaisquer propriedades que se refiram a *content* se referem a entities ao longo do eixo principal (determinado por `flexDirection`). Quaisquer propriedades que se refiram
{% endhint %}

* `flexDirection`: A flex direction controla a direção em que os children de um node são dispostos. Isso também é chamado de eixo principal. O eixo principal é a direção em que os children são dispostos. O eixo cruzado é o eixo perpendicular ao eixo principal, ou o eixo em que as linhas de quebra são dispostas. Ele obtém seu valor do tipo `FlexDirectionType` . As seguintes opções estão disponíveis:
  * `row` (PADRÃO)
  * `row-reverse`
  * `column`
  * `column-reverse`
* `justifyContent`: Esta propriedade descreve como alinhar os children dentro do eixo principal do seu container. Por exemplo, você pode usar esta propriedade para centralizar um child horizontalmente dentro de um container com `flexDirection` definido como row ou verticalmente dentro de um container com `flexDirection` definido como column. O valor desta propriedade deve ser do tipo `AlignType` . Os valores possíveis são:
  * `flex-start` (PADRÃO): Alinha os children de um container ao início do eixo principal do container.
  * `flex-end`: Alinha os children de um container ao final do eixo principal do container.
  * `center`: Alinha os children de um container no centro do eixo principal do container.
  * `space-between`: Distribui uniformemente o espaço entre os children ao longo do eixo principal do container, distribuindo o espaço restante entre os children.
  * `space-around`: Distribui uniformemente o espaço entre os children ao longo do eixo principal do container, distribuindo o espaço restante ao redor dos children. Em comparação com space between, usar space around fará com que o espaço seja distribuído no início do primeiro child e no final do último child.
* `alignItems`: Descreve como alinhar os children ao longo do eixo cruzado do seu container. Align items é muito semelhante a justify content, mas em vez de se aplicar ao eixo principal, align items se aplica ao eixo cruzado. Esta propriedade requer um valor do `AlignType` . As seguintes opções estão disponíveis:
  * `stretch`: (PADRÃO) Estica os children de um container para corresponder à altura do eixo cruzado do container.
  * `flex-start`: Alinha os children de um container ao início do eixo cruzado do container.
  * `flex-end`: Alinha os children de um container ao final do eixo cruzado do container.
  * `center`: Alinha os children de um container no centro do eixo cruzado do container.
  * `baseline`: Alinha os children de um container ao longo de uma baseline comum. Children individuais podem ser definidos como a baseline de referência dos seus parents.
* `alignSelf`: Align self tem as mesmas opções e o mesmo efeito que `alignItems` mas, em vez de afetar os children dentro de um container, você pode aplicar esta propriedade a um único child para alterar seu alinhamento dentro do parent. align self substitui qualquer opção definida pelo parent com align items. Ela obtém seu valor de `AlignType`, veja `alignItems` acima para detalhes sobre estas opções.
* `alignContent`: Align content define a distribuição de linhas ao longo do eixo cruzado. Isso só tem efeito quando os items são quebrados em várias linhas usando `flexWrap`. Ele obtém seu valor do `AlignType` . As seguintes opções estão disponíveis:
  * `flex-start`: (PADRÃO) Alinha as linhas quebradas ao início do eixo cruzado do container.
  * `flex-end`: Alinha as linhas quebradas ao final do eixo cruzado do container.
  * `stretch`: Estica as linhas quebradas para corresponder à altura do eixo cruzado do container.
  * `center`: Alinha as linhas quebradas no centro do eixo cruzado do container.
  * `space-between`: Distribui uniformemente as linhas quebradas ao longo do eixo principal do container, distribuindo o espaço restante entre as linhas.
  * `space-around`: Distribui uniformemente as linhas quebradas ao longo do eixo principal do container, distribuindo o espaço restante ao redor das linhas. Em comparação com space between, usar space around fará com que o espaço seja distribuído no início da primeira linha e no final da última linha.
* `flexGrow`: Isso descreve como qualquer espaço dentro de um container deve ser distribuído entre seus children ao longo do eixo principal. Depois de organizar seus children, um container distribuirá qualquer espaço restante de acordo com os valores de flex grow especificados pelos seus children. Flex grow aceita qualquer valor de ponto flutuante >= 0, sendo 0 o valor padrão. Um container distribuirá qualquer espaço restante entre seus children ponderado pelo valor de flex grow do child.
* `flexShrink`: Descreve como reduzir os children ao longo do eixo principal no caso de o tamanho total dos children exceder o tamanho do container no eixo principal. flex shrink é muito semelhante a flex grow e pode ser pensado da mesma forma se qualquer tamanho excedente for considerado espaço restante negativo. Essas duas propriedades também funcionam bem juntas, permitindo que os children cresçam e encolham conforme necessário. Flex shrink aceita qualquer valor de ponto flutuante >= 0, sendo 1 o valor padrão. Um container reduzirá seus children ponderado pelo valor de flex shrink do child.
* `overflow`: Determina o que acontece se o tamanho dos children de uma entity exceder o seu parent. Usa valores do tipo `OverflowType` .
  * `hidden`: As entities que transbordam tornam-se invisíveis.
  * `visible`: As entities que transbordam ultrapassam as margens do parent.
  * `scroll`: A área torna-se rolável, permitindo que o player role pelo conteúdo excedente. Veja [Containers roláveis](#scrollable-containers) para detalhes.
* `flexWrap`: A propriedade flex wrap é definida em containers e controla o que acontece quando os children excedem o tamanho do container ao longo do eixo principal. Por padrão, os children são forçados para uma única linha (o que pode reduzir entities). Se a quebra for permitida, os items são distribuídos em várias linhas ao longo do eixo principal, se necessário. wrap reverse funciona da mesma forma, mas a ordem das linhas é invertida. Esta propriedade obtém seu valor do `FlexWrapType` .
  * `wrap`
  * `no-wrap`
  * `wrap-reverse`

### Margens e preenchimento

* `margin`: Esta propriedade afeta o espaçamento ao redor do lado de fora de um node. Um node com margin se deslocará em relação aos limites do seu parent, mas também deslocará a localização de quaisquer siblings. A margin de um node contribui para o tamanho total do seu parent se o parent tiver tamanho automático. Defina o espaço entre a entity e as margens do seu parent. O valor esperado é um objeto que contém as propriedades `top`, `left`, `bottom`e `right`.
* `padding`: Esta propriedade afeta o tamanho do node ao qual é aplicada. O padding no Yoga age como se box-sizing: border-box; estivesse definido. Ou seja, o padding não será adicionado ao tamanho total de uma entity se ela tiver um tamanho explícito definido. Para nodes com tamanho automático, o padding aumentará o tamanho do node e também deslocará a localização de quaisquer children. O valor esperado é um objeto que contém as propriedades `top`, `left`, `bottom`e `right`.

### Ajuste fino da posição

No Flexbox, as posições das entities são determinadas principalmente por como elas estão parented e quais propriedades de arranjo estão definidas no parent e no child. Muitas vezes você não precisa definir a `position` property de forma alguma. Mas, se quiser ajustar isso ou substituir completamente o fluxo normal do Flexbox e definir uma posição absoluta, aqui estão as propriedades relevantes:

* `positionType`: Define como as entities são posicionadas. Usa um valor do `PositionType` enum.
  * `relative`: (PADRÃO) Por padrão, uma entity é posicionada relativamente. Isso significa que a entity é posicionada de acordo com o fluxo normal do layout e, em seguida, deslocada em relação a essa posição com base nos valores de `top`, `right`, `bottom`e `left`. O deslocamento não afeta a posição de quaisquer sibling ou parent entities.
  * `absolute`: Quando posicionada absolutamente, uma entity não participa do fluxo normal do layout. Em vez disso, ela é organizada de forma independente de seus siblings. A posição é determinada com base nos `top`, `right`, `bottom`e `left` valores.
* `position`: Os valores de posição `top`, `right`, `bottom`e `left` se comportam de maneira diferente dependendo do `positionType`. Para uma entity relativa, eles deslocam a posição da entity na direção especificada. Para uma entity absoluta, porém, estas propriedades especificam o deslocamento do lado da entity em relação ao mesmo lado no parent. O valor esperado é um objeto que contém as propriedades `top`, `left`, `bottom`e `right`.

{% hint style="warning" %}
**📔 Nota** : Quando se mede a partir do topo, os números para `position` devem ser negativos. Exemplo: para posicionar um component deixando uma margem de 20 pixels em relação ao parent nas laterais superior e esquerda, defina `position` como 20, -20.
{% endhint %}

### Visibilidade

* `display`: Determina se uma entity está visível ou não. Para tornar uma entity invisível, defina `display` para `none`.

### Índice Z

O `zIndex` propriedade de um `UiEntity` determina a ordem em que as entities são renderizadas. Entities com um `zIndex` mais alto são renderizadas acima das entities com um `zIndex`mais baixo. O `zIndex` padrão é 0.

```ts
import { UiEntity, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

export const uiMenu = () => (
	<UiEntity
		uiTransform={{
			zIndex: 4
		}}
		uiBackground={{ color: Color4.Green() }}
	/>
)
```

{% hint style="warning" %}
**📔 Nota** : A propriedade `zIndex` só ordenará os elementos em relação a siblings diretos; ela não pode ser usada para renderizar uma entity acima de outras partes da árvore de layout. Em termos de html/CSS, cada elemento de UI DCL cria um novo [stacking context](https://web.dev/learn/css/z-index#stacking_context).

A UI padrão da Decentraland, incluindo o mapa, chat etc., é sempre renderizada acima de todos os outros elementos de UI.
{% endhint %}

## Containers roláveis

Quando uma UI entity tem mais conteúdo do que cabe no tamanho atribuído, você pode tornar a área rolável definindo `overflow` para `scroll` na `uiTransform`propriedade da entity. O player pode então rolar pelo conteúdo arrastando ou usando a roda do mouse.

Para criar um container rolável, a entity parent deve ter um tamanho fixo (usando `width` e `height`), e os children devem exceder esse tamanho.

```ts
import { UiEntity, Label, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

export const scrollableMenu = () => (
	<UiEntity
		uiTransform={{
			width: 300,
			height: 400,
			overflow: 'scroll',
			flexDirection: 'column',
		}}
		uiBackground={{ color: Color4.fromHexString('#1a1a1a') }}
	>
		{/* Estes children excedem a altura de 400px do parent, tornando a área rolável */}
		<Label value="Item 1" fontSize={18} uiTransform={{ width: '100%', height: 80 }} />
		<Label value="Item 2" fontSize={18} uiTransform={{ width: '100%', height: 80 }} />
		<Label value="Item 3" fontSize={18} uiTransform={{ width: '100%', height: 80 }} />
		<Label value="Item 4" fontSize={18} uiTransform={{ width: '100%', height: 80 }} />
		<Label value="Item 5" fontSize={18} uiTransform={{ width: '100%', height: 80 }} />
		<Label value="Item 6" fontSize={18} uiTransform={{ width: '100%', height: 80 }} />
		<Label value="Item 7" fontSize={18} uiTransform={{ width: '100%', height: 80 }} />
	</UiEntity>
)
```

Isso é útil para criar listas longas, inventários, registros de chat, rankings ou qualquer panel em que o conteúdo possa crescer além do que cabe na tela.

Você também pode aninhar containers roláveis dentro de outros layouts de UI. Por exemplo, um modal de diálogo com um cabeçalho fixo e um corpo rolável:

```ts
import { UiEntity, Label, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

export const dialogWithScroll = () => (
	<UiEntity
		uiTransform={{
			width: 400,
			height: 500,
			flexDirection: 'column',
		}}
		uiBackground={{ color: Color4.fromHexString('#2a2a2a') }}
	>
		{/* Cabeçalho fixo */}
		<Label
			value="Leaderboard"
			fontSize={22}
			uiTransform={{ width: '100%', height: 60 }}
		/>

		{/* Corpo rolável */}
		<UiEntity
			uiTransform={{
				width: '100%',
				flexGrow: 1,
				overflow: 'scroll',
				flexDirection: 'column',
			}}
		>
			<Label value="1. Alice - 9500" fontSize={16} uiTransform={{ width: '100%', height: 50 }} />
			<Label value="2. Bob - 8200" fontSize={16} uiTransform={{ width: '100%', height: 50 }} />
			<Label value="3. Charlie - 7800" fontSize={16} uiTransform={{ width: '100%', height: 50 }} />
			<Label value="4. Diana - 6100" fontSize={16} uiTransform={{ width: '100%', height: 50 }} />
			<Label value="5. Eve - 5500" fontSize={16} uiTransform={{ width: '100%', height: 50 }} />
			<Label value="6. Frank - 4900" fontSize={16} uiTransform={{ width: '100%', height: 50 }} />
			<Label value="7. Grace - 4200" fontSize={16} uiTransform={{ width: '100%', height: 50 }} />
			<Label value="8. Hank - 3800" fontSize={16} uiTransform={{ width: '100%', height: 50 }} />
			<Label value="9. Ivy - 3100" fontSize={16} uiTransform={{ width: '100%', height: 50 }} />
			<Label value="10. Jack - 2700" fontSize={16} uiTransform={{ width: '100%', height: 50 }} />
		</UiEntity>
	</UiEntity>
)
```

{% hint style="info" %}
**💡 Dica**: Use `flexGrow: 1` na entity rolável para fazê-la preencher o espaço restante no parent, para que ela se adapte se outros siblings (como um header ou footer) mudarem de tamanho.
{% endhint %}

## Tamanho responsivo da UI

Players com tamanhos de tela diferentes podem ver o layout da sua UI de maneira diferente. Se você definir o tamanho de qualquer elemento de UI para um número fixo de pixels, essa UI pode parecer pequena demais para ser lida em telas retina, que têm uma densidade de pixels muito maior.

Em vez de posicionar e dimensionar elementos de UI em termos de porcentagens da tela, você também pode obter as dimensões do canvas e então calcular as posições e tamanhos absolutos seguindo sua própria lógica personalizada. Por exemplo, você poderia escolher arranjos de diálogo diferentes dependendo do tamanho da tela.

Para obter informações sobre a dimensão da tela, você pode verificar o `UiCanvasInformation`, que é adicionado por padrão à root entity da scene.

O `UiCanvasInformation` component contém as seguintes informações:

* `height`: Altura do canvas em pixels
* `width`: Largura do canvas em pixels
* `devicePixelRatio`: A relação entre a resolução em pixels físicos no dispositivo e os pixels no canvas
* `interactableArea`: Um objeto `BorderRect` , detalhando a área designada para os elementos de UI da scene. Este objeto contém valores para `top`, `bottom`, `left` e `right`, cada um deles é o número de pixels dessa margem da tela que é ocupado pela UI do explorer.

{% hint style="warning" %}
**📔 Nota** : Diferentes explorers da Decentraland terão valores diferentes para estes, pois as UIs globais da plataforma podem diferir, e os valores podem mudar dinamicamente conforme o usuário expande ou oculta diferentes menus globais de UI.
{% endhint %}

```ts
export function Main(){
  let canvas = UiCanvasInformation.get(engine.RootEntity)
	console.log("DIMENSÕES DO CANVAS: ", canvas.width, canvas.height)
})
```

O snippet a seguir calcula continuamente um valor multiplicador com base no tamanho da tela:

```ts
import { engine, UiCanvasInformation } from "@dcl/sdk/ecs"

let timer = 0
let canvasInfoTimer = 0.5
export let scaleFactor = 1

export function UIScaleUpdate() {

  engine.addSystem((dt) => {
    timer += dt

    if (timer <= canvasInfoTimer) return
    timer = 0

    const uiCanvasInfo = UiCanvasInformation.getOrNull(engine.RootEntity)

    if (!uiCanvasInfo) return

    const newScaleFactor = Math.min(uiCanvasInfo.width / 1920, uiCanvasInfo.height / 1080)

    if (newScaleFactor !== scaleFactor) {
      scaleFactor = newScaleFactor
      console.log('NOVO scaleFactor da UI: ', scaleFactor)
    }
  })
}
```

O valor da `scaleFactor` variável, que esta função atualiza, pode então ser usado como multiplicador em qualquer elemento de UI da scene, incluindo `heigh`, `width` e `fontSize` valores.

```ts
import { UiEntity, Label, ReactEcs } from '@dcl/sdk/react-ecs'
import { scaleFactor } from './calculate-scale-factor'
import { Color4 } from '@dcl/sdk/math'

export const uiMenu = () => (
	<UiEntity
		uiTransform={{
			width: 200 * scaleFactor,
			height: 100 * scaleFactor,
			justifyContent: 'center',
			alignItems: 'center',
			padding: 4 * scaleFactor
		}}
		uiBackground={{ color: Color4.Green() }}
	>
	  	<Label
		        value={description}
		        fontSize={18 * scaleFactor}
		        textAlign="middle-center"
		        uiTransform={{
		          width: "auto",
		          height: "auto",
		          alignSelf: "center",
		          margin: { top: 10 * scaleFactor, bottom: 10 * scaleFactor },
		        }}
	      />
	</UiEntity>
)
```

Algumas outras boas práticas em relação aos tamanhos de UI:

* Se a largura ou altura de qualquer elemento de UI for dinâmica, é bom também usar os parâmetros `maxWidth`, `minWidth`, `maxHeight`e `minHeight` para garantir que permaneçam dentro de valores razoáveis.
* O tamanho da fonte do texto é relativo a um número fixo de pixels; você deve torná-lo dinâmico para que permaneça legível em telas retina. Veja [Tamanho de texto responsivo](/creator/content-creator-pt/scenes-sdk7/ui-2d/ui_text.md#responsive-text-size)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.decentraland.org/creator/content-creator-pt/scenes-sdk7/ui-2d/ui-positioning.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
