La mayoría de los conceptos de CSS se mapean a los conceptos de estilo de Roblox. Los siguientes ejemplos muestran cómo CSS y HTML se alinean con Luau y las clases/properties de Roblox.
Para probar cada uno de los siguientes ejemplos de script de Luau:
En el Explorer, crea lo siguiente:

- Instancia StyleSheet dentro de ReplicatedStorage.
- Contenedor ScreenGui en StarterGui.
- Instancia LocalScript dentro de ScreenGui.
En LocalScript, pega el siguiente código de soporte:
LocalScriptlocal CollectionService = game:GetService("CollectionService")local ReplicatedStorage = game:GetService("ReplicatedStorage")local coreSheet = ReplicatedStorage:FindFirstChildWhichIsA("StyleSheet")local screenGui = script.Parentlocal styleLink = screenGui:FindFirstChildWhichIsA("StyleLink")styleLink.StyleSheet = coreSheetPara cada ejemplo a continuación, pega las líneas de código Luau después de las líneas de soporte 1-7.
Selectores
La propiedad Selector de StyleRule especifica qué instancias debe afectar la regla. Los siguientes tipos de selectores se mapean de CSS a Luau y se pueden utilizar con combinadores.
Elemento
Equivalentes a los selectores de elementos CSS son los selectores de clase de Roblox que seleccionan todas las instancias de una clase dada GuiObject, por ejemplo Frame, ImageLabel, TextButton, etc.
botón {
background-color: #335FFF;
color: #E1E1E1;
width: 15%;
height: 40px;
border: none;
}<button>Menú Principal</button>local rule = Instance.new("StyleRule")
rule.Parent = coreSheet
rule.Selector = "TextButton" -- Selector de clase de Roblox
rule:SetProperties({
BackgroundColor3 = Color3.fromHex("335FFF"),
TextColor3 = Color3.fromHex("E1E1E1"),
Size = UDim2.new(0.15, 0, 0, 40),
BorderSizePixel = 0
})
local button = Instance.new("TextButton")
button.Text = "Menú Principal"
button.Parent = screenGuiClase
El equivalente de Roblox a los selectores de clase CSS son los selectores de etiqueta que utilizan etiquetas aplicadas a través de CollectionService.
.boton-primario {
background-color: #335FFF;
color: #E1E1E1;
}<button class="boton-primario">Menú Principal</button>local rule = Instance.new("StyleRule")
rule.Parent = coreSheet
rule.Selector = ".ButtonPrimary" -- Selector de etiqueta de Roblox
rule:SetProperties({
BackgroundColor3 = Color3.fromHex("335FFF"),
TextColor3 = Color3.fromHex("E1E1E1"),
AutomaticSize = Enum.AutomaticSize.XY
})
local button = Instance.new("TextButton")
button.Text = "Menú Principal"
button.Parent = screenGui
-- Aplicar etiqueta al botón
CollectionService:AddTag(button, "ButtonPrimary")Identificador
La comparación más cercana de Roblox al id de CSS es el selector #[nombre] que selecciona de acuerdo con el valor de Instance.Name. A diferencia de la especificación W3C del atributo id, no se espera que los nombres sean únicos.
#modal-frame {
background-color: #000022;
opacity: 0.5;
width: 50%;
min-height: 100px;
}<div id="modal-frame"></div>local rule = Instance.new("StyleRule")
rule.Parent = coreSheet
rule.Selector = "#ModalFrame" -- Selector de nombre de instancia
rule:SetProperties({
BackgroundColor3 = Color3.fromHex("000022"),
BackgroundTransparency = 0.5,
Size = UDim2.new(0.5, 0, 0, 100),
AutomaticSize = Enum.AutomaticSize.Y
})
local frame = Instance.new("Frame")
frame.Parent = screenGui
-- Renombrar marco para que coincida con el selector
frame.Name = "ModalFrame"Combinadores
Los combinadores te permiten mezclar selectores básicos para coincidir con relaciones jerárquicas más profundas.
Hijo
El selector de hijo > es idéntico entre CSS y Roblox.
.container-del-menu {
width: 25%;
}
.container-del-menu > button {
background-color: #335FFF;
color: #E1E1E1;
width: 80%;
height: 40px;
border: none;
}<div class="container-del-menu">
<button>Opciones</button>
</div>local rule = Instance.new("StyleRule")
rule.Parent = coreSheet
rule.Selector = ".MenuContainer > TextButton" -- Selector hijo
rule:SetProperties({
BackgroundColor3 = Color3.fromHex("335FFF"),
TextColor3 = Color3.fromHex("E1E1E1"),
Size = UDim2.new(0.8, 0, 0, 40),
BorderSizePixel = 0
})
-- Crear contenedor del menú
local menuContainer = Instance.new("Frame")
menuContainer.Size = UDim2.new(0.25, 0, 0, 0)
menuContainer.AutomaticSize = Enum.AutomaticSize.Y
menuContainer.Parent = screenGui
-- Aplicar etiqueta
CollectionService:AddTag(menuContainer, "MenuContainer")
-- Crear botón
local button = Instance.new("TextButton")
button.Text = "Opciones"
-- Establecer el contenedor del menú como padre del botón
button.Parent = menuContainerDescendiente
A diferencia de la sintaxis de espacio en blanco de CSS, por ejemplo .menu-container button que se observa aquí, Roblox utiliza el combinador >> para indicar una relación de descendencia.
.menu-container {
width: 25%;
}
.sub-container {
width: 75%;
}
.menu-container button {
background-color: #335FFF;
color: #E1E1E1;
width: 80%;
height: 40px;
border: none;
}<div class="menu-container">
<div class="sub-container">
<button>Opciones</button>
</div>
</div>local rule = Instance.new("StyleRule")
rule.Parent = coreSheet
rule.Selector = ".MenuContainer >> TextButton" -- Selector de descendiente
rule:SetProperties({
BackgroundColor3 = Color3.fromHex("335FFF"),
TextColor3 = Color3.fromHex("E1E1E1"),
Size = UDim2.new(0.8, 0, 0, 40),
BorderSizePixel = 0
})
-- Crear contenedor del menú
local menuContainer = Instance.new("Frame")
menuContainer.Size = UDim2.new(0.25, 0, 0, 0)
menuContainer.AutomaticSize = Enum.AutomaticSize.Y
menuContainer.Parent = screenGui
-- Aplicar etiqueta
CollectionService:AddTag(menuContainer, "MenuContainer")
-- Crear sub-contenedor
local subContainer = Instance.new("Frame")
subContainer.Size = UDim2.new(0.75, 0, 0, 0)
subContainer.AutomaticSize = Enum.AutomaticSize.Y
-- Establecer el contenedor del menú como padre del sub-contenedor
subContainer.Parent = menuContainer
-- Crear botón
local button = Instance.new("TextButton")
button.Text = "Opciones"
-- Establecer el sub-contenedor como padre del botón
button.Parent = subContainerLista de selectores
Múltiples selectores (incluyendo selectores con combinadores) se pueden declarar con el mismo bloque de propiedades, separados por comas, para reducir redundancia.
img, p {
background-color: #FF0033;
}<img src="gear.png" width="100" height="100">
<p>Menú Principal</p>local rule = Instance.new("StyleRule")
rule.Parent = coreSheet
rule.Selector = "ImageLabel, TextLabel" -- Selector para etiquetas de imagen Y etiquetas de texto
rule:SetProperty("BackgroundColor3", Color3.fromHex("ff0033"))
-- Crear etiqueta de imagen
local imageLabel = Instance.new("ImageLabel")
imageLabel.Image = "rbxassetid://104919049969988"
imageLabel.Size = UDim2.new(0, 100, 0, 100)
imageLabel.Parent = screenGui
-- Crear etiqueta de texto
local textLabel = Instance.new("TextLabel")
textLabel.Size = UDim2.new(1, 0, 0, 0)
textLabel.AutomaticSize = Enum.AutomaticSize.Y
textLabel.TextXAlignment = Enum.TextXAlignment.Left
textLabel.TextYAlignment = Enum.TextYAlignment.Top
textLabel.Text = "Menú Principal"
textLabel.Parent = screenGuiPseudo-clases
El equivalente de Roblox a los selectores pseudo-clase de CSS son los selectores de estado que corresponden a uno de los cuatro valores de Enum.GuiState, como Hover o Press.
img:hover {
opacity: 0.5;
}<img src="gear.png" width="100" height="100">local rule = Instance.new("StyleRule")
rule.Parent = coreSheet
rule.Selector = "ImageLabel:Hover" -- Selector de estado
rule:SetProperty("ImageTransparency", 0.5)
-- Crear etiqueta de imagen
local imageLabel = Instance.new("ImageLabel")
imageLabel.Image = "rbxassetid://104919049969988"
imageLabel.Size = UDim2.new(0, 100, 0, 100)
imageLabel.BackgroundTransparency = 1
imageLabel.Parent = screenGuiPseudo-instancias
De manera similar a cómo los pseudo-elementos de CSS pueden modificar partes específicas de un elemento, Roblox puede crear "fantasmas" UIComponents a través de la propiedad Selector de una regla de estilo. Por ejemplo, la siguiente regla crea efectivamente un modificador UICorner bajo cada Frame etiquetado con RoundedCorner20 y establece el CornerRadius de cada modificador a 20 píxeles.
local rule = Instance.new("StyleRule")
rule.Parent = coreSheet
rule.Selector = "Frame.RoundedCorner20::UICorner" -- Selector de componente de UI
rule:SetProperty("CornerRadius", UDim.new(0, 20))
-- Crear marco
local frame = Instance.new("Frame")
frame.Size = UDim2.new(0.4, 0, 0.2, 0)
frame.Parent = screenGui
-- Aplicar etiqueta al marco
CollectionService:AddTag(frame, "RoundedCorner20")Consultas
Las consultas de estilo de Roblox conectan la brecha entre las consultas de medios CSS y las consultas de contenedor. Usando el prefijo @, puedes alternar estilos basados en dimensiones de padre, tipos de dispositivos de entrada, o configuraciones de accesibilidad del usuario.
En CSS, @container aplica estilos basados en el tamaño de un elemento padre. En Roblox, defines una consulta pseudo‑instancia usando ::StyleQuery seguido de un identificador para la propiedad Selector de la condición, por ejemplo "::StyleQuery #WideContainer", junto con un nombre de condición de StyleQuery como "MinSize" para evaluar el GuiObject.AbsoluteSize del padre. Luego, para aplicar estilos a la instancia o a sus hijos cuando la consulta está activa, crea un StyleRule con el prefijo @[identifier] como su Selector, por ejemplo @WideContainer.
.container {
container-type: inline-size;
background-color: rgba(0, 0, 34, 0.5);
}
botón {
background-color: #335FFF;
color: #E1E1E1;
width: 75%;
height: 40px;
border: none;
}
@container (min-width: 400px) {
botón {
background-color: #cc0033;
}
}<div class="container" style="width: 80%; height: 200px;">
<button>Menú Principal</button>
</div>-- Regla de contenedor
local containerRule = Instance.new("StyleRule")
containerRule.Selector = "Frame" -- Selector de clase de Roblox
containerRule:SetProperties({
BackgroundColor3 = Color3.fromRGB(0, 0, 34),
BackgroundTransparency = 0.5,
BorderSizePixel = 0
})
containerRule.Parent = coreSheet
-- Regla de botón
local buttonRule = Instance.new("StyleRule")
buttonRule.Selector = "TextButton" -- Selector de clase de Roblox
buttonRule:SetProperties({
BackgroundColor3 = Color3.fromHex("335FFF"),
TextColor3 = Color3.fromHex("E1E1E1"),
Size = UDim2.new(0.75, 0, 0, 40),
BorderSizePixel = 0
})
buttonRule.Parent = containerRule -- Hijo de la regla del contenedor
-- Condición de consulta (#WideContainer)
local queryCondition = Instance.new("StyleRule")
queryCondition.Selector = "::StyleQuery #WideContainer"
queryCondition:SetProperty("MinSize", Vector2.new(400, 0))
queryCondition.Parent = containerRule -- Hijo de la regla del contenedor
-- Regla que se aplica cuando la condición está activa (@WideContainer)
local queryStyle = Instance.new("StyleRule")
queryStyle.Selector = "@WideContainer Frame > TextButton" -- Selector hijo
queryStyle:SetProperty("BackgroundColor3", Color3.fromHex("CC0033"))
queryStyle.Parent = containerRule -- Hijo de la regla del contenedor
-- Crear instancias
local container = Instance.new("Frame")
container.Size = UDim2.new(0.8, 0, 0, 200)
container.Parent = screenGui
local button = Instance.new("TextButton")
button.Text = "Menú Principal"
button.Parent = containerRoblox también proporciona consultas integradas que se mapean directamente a estados globales del entorno como ViewportDisplaySize o ReducedMotionEnabled. Estas no requieren una definición de ::StyleQuery y se pueden usar directamente con un prefijo @.
| Característica de Medios CSS | Selector de Consulta de Estilo Roblox |
|---|---|
| (max-width: 600px) | @ViewportDisplaySizeSmall |
| (min-width: 601px) and (max-width: 1200px) | @ViewportDisplaySizeMedium |
| (min-width: 1201px) | @ViewportDisplaySizeLarge |
| (pointer: fine) | @PreferredInputKeyboardAndMouse |
| (pointer: coarse) | @PreferredInputTouch |
| (any-pointer: coarse) | @PreferredInputGamepad |
| (prefers-reduced-motion: reduce) | @ReducedMotionEnabledTrue |
| (prefers-reduced-motion: no-preference) | @ReducedMotionEnabledFalse |
.container {
container-type: inline-size;
background-color: rgba(0, 0, 34, 0.5);
}
@media (prefers-reduced-motion: reduce) {
.container {
background-color: rgba(0, 0, 34, 1);
}
}<div class="container" style="width: 80%; height: 200px;">
</div>-- Regla de contenedor
local containerRule = Instance.new("StyleRule")
containerRule.Selector = "Frame" -- Selector de clase de Roblox
containerRule:SetProperties({
BackgroundColor3 = Color3.fromRGB(0, 0, 34),
BackgroundTransparency = 0.5,
BorderSizePixel = 0
})
containerRule.Parent = coreSheet
-- Consulta integrada
local motionRule = Instance.new("StyleRule")
motionRule.Selector = "@ReducedMotionEnabledTrue Frame"
motionRule:SetProperty("BackgroundTransparency", 0)
motionRule.Parent = containerRule -- Hijo de la regla del contenedor
-- Crear instancias
local container = Instance.new("Frame")
container.Size = UDim2.new(0.8, 0, 0, 200)
container.Parent = screenGuiVariables
CSS te permite declarar y hacer referencia a variables en todo un sistema de estilos. Roblox logra esto a través de tokens y el sistema de atributos de instancia. Usando $ como prefijo, puedes hacer referencia a atributos declarados en una cadena de herencia de StyleRule o StyleSheet al establecer propiedades de estilo.
:root {
--button-bg-color: #335FFF;
--button-text-color: #E1E1E1;
}
botón {
background-color: var(--button-bg-color);
color: var(--button-text-color);
}<button>Menú Principal</button>local rule = Instance.new("StyleRule")
rule.Parent = coreSheet
-- Establecer tokens de hoja de estilo utilizando atributos
coreSheet:SetAttribute("ButtonBgColor", Color3.fromHex("335FFF"))
coreSheet:SetAttribute("ButtonTextColor", Color3.fromHex("E1E1E1"))
rule.Selector = "TextButton" -- Selector de clase
rule:SetProperties({
BackgroundColor3 = "$ButtonBgColor",
TextColor3 = "$ButtonTextColor"
})
-- Crear botón
local button = Instance.new("TextButton")
button.AutomaticSize = Enum.AutomaticSize.XY
button.Text = "Menú Principal"
button.Parent = screenGuiTransiciones
Las transiciones de CSS te permiten interpolar valores de propiedad durante un tiempo determinado. Puedes lograr esto en Roblox estableciendo transiciones de propiedad en una StyleRule a través de SetPropertyTransition() (único) o SetPropertyTransitions() (múltiples).
botón {
background-color: #335FFF;
color: #E1E1E1;
width: 15%;
height: 40px;
border: none;
transition:
background-color 1s ease-out,
transform 1.25s ease-out
}
botón:hover {
background-color: #33AAFF;
transform: rotate(-5deg);
}<button>Menú Principal</button>-- Regla del botón
local buttonRule = Instance.new("StyleRule")
buttonRule.Selector = "TextButton" -- Selector de clase de Roblox
buttonRule:SetProperties({
BackgroundColor3 = Color3.fromHex("335FFF"),
TextColor3 = Color3.fromHex("E1E1E1"),
Size = UDim2.new(0.15, 0, 0, 40),
BorderSizePixel = 0
})
-- Establecer comportamientos de transición de propiedades
buttonRule:SetPropertyTransitions({
BackgroundColor3 = TweenInfo.new(1, Enum.EasingStyle.Cubic, Enum.EasingDirection.Out),
Rotation = TweenInfo.new(1.25, Enum.EasingStyle.Cubic, Enum.EasingDirection.Out)
})
buttonRule.Parent = coreSheet
-- Regla para el hover del botón
local hoverRule = Instance.new("StyleRule")
hoverRule.Selector = "TextButton:Hover" -- Selector de estado
hoverRule:SetProperties({
AutoButtonColor = false,
BackgroundColor3 = Color3.fromHex("33AAFF"),
Rotation = -5
})
hoverRule.Parent = coreSheet
-- Crear botón de texto
local button = Instance.new("TextButton")
button.Text = "Menú Principal"
button.Parent = screenGuiAnidación y fusión
Tomando un concepto de SCSS, StyleRules se pueden anidar y sus selectores se fusionarán.
#menu-frame {
background-color: #000022;
width: 25%;
min-height: 200px;
display: flex;
flex-direction: column;
justify-content: space-evenly;
align-items: center;
> botón {
background-color: #335FFF;
color: #E1E1E1;
width: 80%;
height: 40px;
border: none;
&:hover {
opacity: 0.5;
}
}
}<div id="menu-frame">
<button>Encantos</button>
<button>Maná</button>
<button>Rollos</button>
</div>-- Regla del marco de menú
local menuFrameRule = Instance.new("StyleRule")
menuFrameRule.Selector = "#MenuFrame"
menuFrameRule:SetProperties({
BackgroundColor3 = Color3.fromHex("000022"),
Size = UDim2.new(0.25, 0, 0, 200),
AutomaticSize = Enum.AutomaticSize.Y
})
menuFrameRule.Parent = coreSheet
-- Regla del diseño del menú
local menuLayoutRule = Instance.new("StyleRule")
menuLayoutRule.Selector = "::UIListLayout"
menuLayoutRule:SetProperties({
FillDirection = Enum.FillDirection.Vertical,
VerticalFlex = Enum.UIFlexAlignment.SpaceEvenly,
HorizontalAlignment = Enum.HorizontalAlignment.Center
})
menuLayoutRule.Parent = menuFrameRule -- Establecer la regla del marco de menú como padre
-- Regla del botón
local buttonRule = Instance.new("StyleRule")
buttonRule.Selector = "> TextButton"
buttonRule:SetProperties({
BackgroundColor3 = Color3.fromHex("335FFF"),
TextColor3 = Color3.fromHex("E1E1E1"),
Size = UDim2.new(0.8, 0, 0, 40),
BorderSizePixel = 0
})
buttonRule.Parent = menuFrameRule -- Establecer la regla del marco de menú como padre
-- Regla de hover del botón
local buttonHoverRule = Instance.new("StyleRule")
buttonHoverRule.Selector = ":Hover"
buttonHoverRule:SetProperties({
AutoButtonColor = false,
BackgroundTransparency = 0.5,
TextTransparency = 0.5
})
buttonHoverRule.Parent = buttonRule -- Establecer la regla del botón como padre
-- Crear marco padre
local menuFrame = Instance.new("Frame")
menuFrame.Name = "MenuFrame"
menuFrame.Parent = screenGui
-- Crear botones dentro del marco
local button1 = Instance.new("TextButton")
button1.Text = "Encantos"
button1.Parent = menuFrame
local button2 = Instance.new("TextButton")
button2.Text = "Maná"
button2.Parent = menuFrame
local button3 = Instance.new("TextButton")
button3.Text = "Rollos"
button3.Parent = menuFrame