# Posicionamiento de UI

Para todo tipo de contenido UI, usa el `uiTransform` component para establecer el tamaño, la posición y otras propiedades relacionadas con la alineación de la entity.

El `uiTransform` component funciona en el espacio 2D de la pantalla de forma muy similar a como el `Transform` component funciona en el espacio 3D de la scene.

***archivo 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() }}
	/>
)
```

***archivo 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 los siguientes fragmentos de esta página asumen que tienes un `.ts` similar al anterior, ejecutando la función `ReactEcsRenderer.setUiRenderer()` .
{% endhint %}

## Propiedades de posicionamiento

La alineación de las entities de UI se basa en el modelo de alineación Flexbox. Este es un modelo muy poderoso para organizar dinámicamente entities anidadas dentro de modals que pueden variar de tamaño.

{% hint style="info" %}
**💡 Consejo**: La implementación de la UI de Decentraland se basa en la de [Yoga](https://yogalayout.com/docs/). Lee [este artículo](https://www.joshwcomeau.com/css/interactive-guide-to-flexbox/) para una cobertura muy accesible y detallada de las propiedades disponibles en Flexbox.
{% endhint %}

### Tamaño de la entity

Usa `width` y `height` para establecer el tamaño de la entity. Se admiten los siguientes tipos de valores:

* `auto`: El tamaño se adapta para ajustarse al contenido interior. Esto es muy conveniente para texto que puede variar en longitud. Escribe el valor como "auto".
* **Porcentaje**: Como porcentaje de las medidas del parent. Escribe el valor como una string que termine en "%", por ejemplo `10 %`.
* **Pixeles**: Escribe el valor como un número.
* **Ancho o alto de la pantalla**: Se pueden usar vw (view width) y vh (view height) para indicar una fracción del tamaño completo de la ventana que ejecuta Decentraland. Por ejemplo `10vw` se refiere al 10% del ancho de la ventana, `25vh` al 25% de la altura de la ventana.

Ten en cuenta que estas propiedades afectan al **default** tamaño de ese elemento, el tamaño del elemento antes de que se realicen los cálculos de flex grow y flex shrink. El tamaño final puede interpretarse de forma distinta según el tamaño de la entity parent y las propiedades Flexbox que se establezcan.

{% hint style="warning" %}
**📔 Nota**: En las propiedades que admiten tanto números como strings, para establecer el valor en pixeles, escribe un número. Para establecer estos campos como un porcentaje de las medidas del parent, escribe el valor como una string que termine en "%", por ejemplo `10 %`. También puedes establecer un valor en pixeles como string terminando la string en `px`, por ejemplo `200px`.

* Cuando los valores se expresan como porcentaje, siempre se relacionan con el contenedor del parent. Si la entity no tiene parents, entonces el valor es un porcentaje de toda la pantalla.
* Si los valores se expresan en pixeles, son absolutos y no se ven afectados por la escala del parent.
* Si los valores se expresan en `vh` o `vw`, son un porcentaje de la ventana completa y no se ven afectados por la escala del parent.

Para que `auto` width/height funcione, se aplican las siguientes reglas:

* El UiTransform que use width/height como “auto” debe tener `alignSelf`: `“center”`/`“flex-start”`/`“flex-end”` O `positionType: “absolute”`
* Si el UiTransform de un child usa `positionType: “absolute”`, el parent no se adaptará a su tamaño/posición
* Si el UiTransform de un child usa cualquier sobrescritura de posición, el parent no se adaptará a su tamaño/posición
  {% endhint %}

También están disponibles estas otras propiedades para ajustar el tamaño de una forma más avanzada:

* `maxWidth` y `maxHeight`: *number* o string (como height y width). El tamaño máximo que puede tener la entity.
* `minWidth` y `minHeight`: *number* o string (como height y width). El tamaño mínimo que puede tener la entity. Si el parent es demasiado pequeño para ajustarse al tamaño mínimo de las entities, estas sobresaldrán de su parent.
* `flexBasis`: Esta es una forma independiente del eje de proporcionar el tamaño predeterminado de un elemento a lo largo del eje principal. Establecer el flex basis de un child es similar a establecer el width de ese child si su parent es un contenedor con flex direction: row, o establecer el height de un child si su parent es un contenedor con 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() }}
	/>
)
```

### Organizar entities child

Por defecto, las entities child se posicionan en relación con la esquina superior izquierda de su parent. Puedes usar propiedades como `justifyContent` y `alignItems` para cambiar este comportamiento.

{% hint style="info" %}
**💡 Consejo**: Cualquier propiedad que se refiera a *content* se refiere a entities a lo largo del eje principal (determinado por `flexDirection`). Cualquier propiedad que se refiera
{% endhint %}

* `flexDirection`: La flex direction controla la dirección en la que se distribuyen los children de un nodo. Esto también se denomina eje principal. El eje principal es la dirección en la que se distribuyen los children. El eje transversal es el eje perpendicular al eje principal, o el eje en el que se distribuyen las líneas envueltas. Toma su valor del tipo `FlexDirectionType` . Las siguientes opciones están disponibles:
  * `row` (DEFAULT)
  * `row-reverse`
  * `column`
  * `column-reverse`
* `justifyContent`: Esta propiedad describe cómo alinear los children dentro del eje principal de su contenedor. Por ejemplo, puedes usar esta propiedad para centrar horizontalmente un child dentro de un contenedor con `flexDirection` establecido en row o verticalmente dentro de un contenedor con `flexDirection` establecido en column. El valor de esta propiedad debe provenir del tipo `AlignType` . Los valores posibles son:
  * `flex-start` (DEFAULT): Alinea los children de un contenedor al inicio del eje principal del contenedor.
  * `flex-end`: Alinea los children de un contenedor al final del eje principal del contenedor.
  * `center`: Alinea los children de un contenedor en el centro del eje principal del contenedor.
  * `space-between`: Distribuye uniformemente los children a lo largo del eje principal del contenedor, distribuyendo el espacio restante entre los children.
  * `space-around`: Distribuye uniformemente los children a lo largo del eje principal del contenedor, distribuyendo el espacio restante alrededor de los children. En comparación con space between, usar space around hará que el espacio se distribuya al inicio del primer child y al final del último child.
* `alignItems`: Describe cómo alinear los children a lo largo del eje transversal de su contenedor. Align items es muy similar a justify content, pero en lugar de aplicarse al eje principal, align items se aplica al eje transversal. Esta propiedad requiere un valor del `AlignType` . Las siguientes opciones están disponibles:
  * `stretch`: (DEFAULT) Estira los children de un contenedor para que coincidan con la altura del eje transversal del contenedor.
  * `flex-start`: Alinea los children de un contenedor al inicio del eje transversal del contenedor.
  * `flex-end`: Alinea los children de un contenedor al final del eje transversal del contenedor.
  * `center`: Alinea los children de un contenedor en el centro del eje transversal del contenedor.
  * `baseline`: Alinea los children de un contenedor a lo largo de una línea base común. Los children individuales pueden configurarse para ser la línea base de referencia de sus parents.
* `alignSelf`: Align self tiene las mismas opciones y el mismo efecto que `alignItems` pero, en lugar de afectar a los children dentro de un contenedor, puedes aplicar esta propiedad a un solo child para cambiar su alineación dentro de su parent. align self anula cualquier opción establecida por el parent con align items. Toma su valor de `AlignType`, consulta `alignItems` arriba para obtener detalles sobre estas opciones.
* `alignContent`: Align content define la distribución de las líneas a lo largo del eje transversal. Esto solo tiene efecto cuando los elementos se envuelven en múltiples líneas usando `flexWrap`. Toma su valor del `AlignType` . Las siguientes opciones están disponibles:
  * `flex-start`: (DEFAULT) Alinea las líneas envueltas al inicio del eje transversal del contenedor.
  * `flex-end`: Alinea las líneas envueltas al final del eje transversal del contenedor.
  * `stretch`: Estira las líneas envueltas para que coincidan con la altura del eje transversal del contenedor.
  * `center`: Alinea las líneas envueltas en el centro del eje transversal del contenedor.
  * `space-between`: Distribuye uniformemente las líneas envueltas a lo largo del eje principal del contenedor, distribuyendo el espacio restante entre las líneas.
  * `space-around`: Distribuye uniformemente las líneas envueltas a lo largo del eje principal del contenedor, distribuyendo el espacio restante alrededor de las líneas. En comparación con space between, usar space around hará que el espacio se distribuya al principio de las primeras líneas y al final de la última línea.
* `flexGrow`: Esto describe cómo debe distribuirse el espacio dentro de un contenedor entre sus children a lo largo del eje principal. Después de distribuir sus children, un contenedor repartirá cualquier espacio restante según los valores de flex grow especificados por sus children. Flex grow acepta cualquier valor de punto flotante >= 0, siendo 0 el valor predeterminado. Un contenedor distribuirá cualquier espacio restante entre sus children ponderado por el valor de flex grow del child.
* `flexShrink`: Describe cómo reducir los children a lo largo del eje principal en caso de que el tamaño total de los children supere el tamaño del contenedor en el eje principal. flex shrink es muy similar a flex grow y puede entenderse de la misma manera si cualquier tamaño que se desborda se considera espacio restante negativo. Estas dos propiedades también funcionan bien juntas al permitir que los children crezcan y se reduzcan según sea necesario. Flex shrink acepta cualquier valor de punto flotante >= 0, siendo 1 el valor predeterminado. Un contenedor reducirá sus children ponderado por el valor de flex shrink del child.
* `overflow`: Determina qué ocurre si el tamaño de los children de una entity supera el de su parent. Usa valores del `OverflowType` .
  * `hidden`: Las entities que se desbordan se vuelven invisibles.
  * `visible`: Las entities que se desbordan sobresalen de los márgenes del parent.
  * `scroll`: El área se vuelve desplazable, permitiendo al player desplazarse por el contenido que se desborda. Consulta [contenedores desplazables](#scrollable-containers) para más detalles.
* `flexWrap`: La propiedad flex wrap se establece en los contenedores y controla qué ocurre cuando los children sobrepasan el tamaño del contenedor a lo largo del eje principal. Por defecto, los children se fuerzan a una sola línea (lo que puede reducir entities). Si se permite el ajuste, los elementos se envuelven en varias líneas a lo largo del eje principal si es necesario. wrap reverse funciona igual, pero el orden de las líneas se invierte. Esta propiedad toma su valor del `FlexWrapType` .
  * `wrap`
  * `no-wrap`
  * `wrap-reverse`

### Márgenes y padding

* `margin`: Esta propiedad afecta al espacio alrededor del exterior de un nodo. Un nodo con margin se desplazará respecto a los límites de su parent, pero también desplazará la ubicación de cualquier sibling. El margin de un nodo contribuye al tamaño total de su parent si el parent tiene tamaño automático. Establece el espacio entre la entity y los márgenes de su parent. El valor esperado es un objeto que contiene las propiedades `top`, `left`, `bottom`, y `right`.
* `padding`: Esta propiedad afecta al tamaño del nodo al que se aplica. El padding en Yoga actúa como si box-sizing: border-box; estuviera establecido. Es decir, el padding no se sumará al tamaño total de una entity si tiene un tamaño explícito establecido. En nodos de tamaño automático, el padding aumentará el tamaño del nodo y también desplazará la ubicación de cualquier child. El valor esperado es un objeto que contiene las propiedades `top`, `left`, `bottom`, y `right`.

### Ajustar la posición

En Flexbox, las posiciones de las entities se determinan en su mayor parte por cómo están parented y qué propiedades de distribución están establecidas en el parent y el child. A menudo no tienes que establecer la propiedad `position` en absoluto. Pero si quieres ajustar eso, o anular por completo el flujo normal de Flexbox y establecer una posición absoluta, aquí están las propiedades relevantes:

* `positionType`: Define cómo se posicionan las entities. Usa un valor del `PositionType` enum.
  * `relative`: (DEFAULT) Por defecto, una entity se posiciona de forma relativa. Esto significa que una entity se posiciona según el flujo normal del layout y luego se desplaza en relación con esa posición según los valores de `top`, `right`, `bottom`, y `left`. El desplazamiento no afecta a la posición de ninguna entity sibling o parent.
  * `absolute`: Cuando se posiciona de forma absoluta, una entity no participa en el flujo normal del layout. En su lugar, se distribuye de forma independiente de sus siblings. La posición se determina en función de los valores de `top`, `right`, `bottom`, y `left` .
* `position`: Los valores de posición `top`, `right`, `bottom`, y `left` se comportan de manera diferente según el `positionType`. Para una entity relativa, desplazan la posición de la entity en la dirección especificada. Para una entity absoluta, en cambio, estas propiedades especifican el desplazamiento del lado de la entity respecto al mismo lado en el parent. El valor esperado es un objeto que contiene las propiedades `top`, `left`, `bottom`, y `right`.

{% hint style="warning" %}
**📔 Nota** : Al medir desde la parte superior, los números para `position` deben ser negativos. Ejemplo: para posicionar un component dejando un margen de 20 pixeles respecto al parent en los lados superior e izquierdo, establece `position` en 20, -20.
{% endhint %}

### Visibilidad

* `display`: Determina si una entity es visible o no. Para hacer que una entity sea invisible, establece `display` en `none`.

### Z Index

El `zIndex` propiedad de una `UiEntity` determina el orden en que se renderizan las entities. Las entities con un `zIndex` más alto se renderizan por encima de las entities con un `zIndex`más bajo. El `zIndex` predeterminado es 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** : La propiedad `zIndex` solo ordenará los elementos en relación con siblings directos; no puede usarse para renderizar una entity por encima de otras partes del árbol del layout. En términos de html/CSS, cada elemento de DCL UI crea un nuevo [stacking context](https://web.dev/learn/css/z-index#stacking_context).

La UI predeterminada de Decentraland, incluyendo el mapa, chat, etc., siempre se renderiza por encima de todos los demás elementos de UI.
{% endhint %}

## contenedores desplazables

Cuando una entity de UI tiene más contenido del que cabe en su tamaño asignado, puedes hacer que el área sea desplazable estableciendo `overflow` en `scroll` en la `uiTransform`de la entity. El player puede entonces desplazarse por el contenido arrastrando o usando la rueda del mouse.

Para crear un contenedor desplazable, la entity parent debe tener un tamaño fijo (usando `width` y `height`), y los children deben superar ese tamaño.

```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') }}
	>
		{/* Estos children superan la altura de 400px del parent, haciendo que el área sea desplazable */}
		<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>
)
```

Esto es útil para crear listas largas, inventarios, registros de chat, tablas de clasificación o cualquier panel en el que el contenido pueda crecer más allá de lo que cabe en pantalla.

También puedes anidar contenedores desplazables dentro de otros layouts de UI. Por ejemplo, un modal de diálogo con un encabezado fijo y un cuerpo desplazable:

```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') }}
	>
		{/* Encabezado fijo */}
		<Label
			value="Leaderboard"
			fontSize={22}
			uiTransform={{ width: '100%', height: 60 }}
		/>

		{/* Cuerpo desplazable */}
		<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" %}
**💡 Consejo**: Usa `flexGrow: 1` en la entity desplazable para hacer que llene el espacio restante en el parent, de modo que se adapte si otros siblings (como un encabezado o pie de página) cambian de tamaño.
{% endhint %}

## Tamaño de UI adaptable

Los players con diferentes tamaños de pantalla pueden ver el layout de tu UI de forma distinta. Si estableces el tamaño de cualquier elemento de UI con un número fijo de pixeles, esta UI puede verse demasiado pequeña para leer en pantallas retina, que tienen una densidad de pixeles mucho mayor.

En lugar de posicionar y escalar elementos de UI en términos de porcentajes de pantalla, también puedes obtener las dimensiones del canvas y luego calcular las posiciones y tamaños absolutos siguiendo tu propia lógica personalizada. Por ejemplo, podrías elegir distintas distribuciones de diálogo según el tamaño de la pantalla.

Para obtener información sobre la dimensión de la pantalla, puedes consultar `UiCanvasInformation`, que se añade por defecto a la root entity de la scene.

El `UiCanvasInformation` component contiene la siguiente información:

* `height`: Altura del canvas en pixeles
* `width`: Anchura del canvas en pixeles
* `devicePixelRatio`: La relación entre la resolución en pixeles físicos del dispositivo y los pixeles del canvas
* `interactableArea`: Un objeto `BorderRect` , que detalla el área designada para los elementos UI de la scene. Este objeto contiene valores para `top`, `bottom`, `left` y `right`, cada uno de estos es el número de pixeles en ese margen de la pantalla que ocupa la UI del Explorer.

{% hint style="warning" %}
**📔 Nota** : Los distintos explorers de Decentraland tendrán valores diferentes para estos, ya que las UIs globales de la plataforma pueden diferir y los valores podrían cambiar dinámicamente a medida que el usuario expande u oculta distintos menús globales de UI.
{% endhint %}

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

El siguiente fragmento calcula continuamente un valor multiplicador según el tamaño de la pantalla:

```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('NEW UI scaleFactor: ', scaleFactor)
    }
  })
}
```

El valor de la `scaleFactor` variable, que actualiza esta función, puede usarse luego como multiplicador en cualquier elemento de UI de la scene, incluyendo `heigh`, `width` y `fontSize` .

```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>
)
```

Algunas otras buenas prácticas con respecto a los tamaños de UI:

* Si el width o height de cualquier elemento de UI es dinámico, también conviene usar los `maxWidth`, `minWidth`, `maxHeight`, y `minHeight` parámetros para asegurarse de que se mantengan dentro de valores razonables.
* El tamaño de fuente del texto es relativo a un número fijo de pixeles; deberías hacerlo dinámico para que siga siendo legible en pantallas retina. Consulta [Tamaño de texto adaptable](/creator/content-creator-es/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-es/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.
