Personalización de temas
lh-ui-plus ofrece un sistema completo de temas basado en variables CSS, que admite la estética china (国风, estilo chino), el modo oscuro, los fondos con patrón y el cambio en tiempo de ejecución, entre otras amplias posibilidades de personalización.
¿Quieres ajustar los colores de forma visual y exportar directamente un archivo scss? Consulta el Estudio de temas.
Sistema de colores chinos
La biblioteca, inspirada en la tradición de la pintura a tinta 水墨丹青 (pintura a tinta china), define 8 colores de tema chinos:
| Color | Significado | Color principal | Hover | Aplicación |
|---|---|---|---|---|
| 靛蓝 (azul índigo) | El azul de la porcelana azul y blanco | #2B4C7C | #3D649E | Botones principales, enlaces, estado de foco |
| 松花绿 (verde pino) | El verde fresco de las sombras del bambú | #5B8C5A | #6FA36E | Estado de éxito |
| 藤黄 (amarillo herbáceo) | El dorado de las hojas otoñales | #C4A35A | #D4B76F | Estado de advertencia |
| 朱砂 (cinabrio, peligro) | El rojo de la pasta de los sellos | #B23A3A | #C45050 | Estado de peligro/error (--lh-danger-*) |
| 黛色 (gris tinta) | El toque tenue de la tinta china | #7A7A7A | #8F8F8F | Estado de información |
| 金色 (dorado) | El encanto antiguo de la suntuosidad | #B8860B | #D4A843 | Adornos decorativos (--lh-gold-*) |
| 朱砂红 (cinabrio rojizo, énfasis) | Variante de énfasis del cinabrio | #C43A31 | #E85D4A | Color de énfasis (--lh-vermilion-*) |
| 玉色 (verde jade) | El encanto fresco del bambú esmeralda | #5B8C5A | #7AAE7A | Éxito/decoración (mismo valor que 松花绿) |
Cada color suele incluir 4 niveles (color principal, hover, active, fondo light); el color principal y el dorado añaden además un color de borde lighter (*-color-border), de modo que siempre exista un contraste adecuado para cada escenario.
Sistema de temas con variables CSS
Todos los colores de tema se implementan mediante propiedades personalizadas CSS (--lh-*), en total más de 88 variables, que cubren las siguientes categorías:
Variables de color
| Prefijo de variable | Descripción | Ejemplo |
|---|---|---|
--lh-primary-color | Valor base del color principal | #2B4C7C |
--lh-primary-color-hover | Estado hover del color principal | #3D649E |
--lh-primary-color-active | Estado active del color principal | #1F3A5F |
--lh-primary-color-bg | Fondo claro del color principal | #E8EDF3 |
--lh-success-color | Color de éxito | #5B8C5A |
--lh-warning-color | Color de advertencia | #C4A35A |
--lh-danger-color | Color de peligro | #B23A3A |
--lh-info-color | Color de información | #7A7A7A |
Variables de texto
| Variable | Descripción | Predeterminado |
|---|---|---|
--lh-text-primary | Texto principal | #2C2C2C |
--lh-text-regular | Texto regular | #5A5A5A |
--lh-text-secondary | Texto secundario | #8A8A8A |
--lh-text-placeholder | Marcador de posición | #B0B0B0 |
--lh-text-disabled | Texto deshabilitado | #C8C8C8 |
Variables de borde
| Variable | Descripción | Predeterminado |
|---|---|---|
--lh-border-color-base | Borde predeterminado | #D8D3CC |
--lh-border-color-light | Borde ligero | #E5E0D8 |
--lh-border-radius-base | Redondeo base | 2px |
--lh-border-radius-round | Redondeo de cápsula | 20px |
Variables de fondo
| Variable | Descripción | Predeterminado |
|---|---|---|
--lh-bg-color | Fondo de los componentes | #FAF6F0 (color 宣纸, papel de arroz) |
--lh-bg-color-page | Fondo de la página | #F5F0EB |
--lh-bg-color-overlay | Fondo de la capa de cobertura | rgba(26, 26, 26, 0.4) |
Variables de sombra
| Variable | Descripción |
|---|---|
--lh-box-shadow-base | Sombra predeterminada |
--lh-box-shadow-light | Sombra ligera |
--lh-box-shadow-lighter | Sombra muy ligera |
Variables de tipografía
| Variable | Descripción | Predeterminado |
|---|---|---|
--lh-font-family | Familia tipográfica | Noto Serif SC, STSong, SimSun... |
--lh-font-size-base | Tamaño de fuente base | 14px |
--lh-font-size-small | Tamaño de fuente pequeño | 13px |
--lh-font-weight-primary | Grosor de fuente regular | 400 |
--lh-font-line-height-primary | Altura de línea | 1.8 |
Variables de espaciado
| Variable | Valor | Uso |
|---|---|---|
--lh-spacing-xs | 4px | Espaciado mínimo |
--lh-spacing-sm | 8px | Espaciado pequeño |
--lh-spacing-md | 12px | Espaciado medio |
--lh-spacing-base | 16px | Espaciado base |
--lh-spacing-lg | 20px | Espaciado grande |
--lh-spacing-xl | 24px | Espaciado muy grande |
Variables de Z-Index
| Variable | Valor | Uso |
|---|---|---|
--lh-z-index-dropdown | 1000 | Menú desplegable |
--lh-z-index-modal | 1050 | Cuadro modal |
--lh-z-index-tooltip | 2000 | Información sobre herramientas |
Variables de transición
| Variable | Valor | Descripción |
|---|---|---|
--lh-transition-duration-fast | 0.25s | Transición rápida |
--lh-transition-duration-base | 0.3s | Transición predeterminada |
--lh-transition-duration-slow | 0.4s | Transición lenta |
Tema oscuro
La biblioteca incorpora los estilos del tema oscuro; todas las variables CSS cambian automáticamente a sus valores adaptados en el modo oscuro.
Opción 1: usar el composable useLhTheme
Composition API
<script setup lang="ts">
import { useLhTheme } from '@lh-ui/vue3'
const { theme, toggleTheme, setTheme } = useLhTheme()
</script>
<template>
<div>
<LhButton @click="toggleTheme">
{{ theme === 'dark' ? 'Cambiar a claro' : 'Cambiar a oscuro' }}
</LhButton>
<LhButton @click="() => setTheme('light')">Claro</LhButton>
<LhButton @click="() => setTheme('dark')">Oscuro</LhButton>
</div>
</template>Options API
<script>
import { useLhTheme } from '@lh-ui/vue3'
export default {
setup() {
const { theme, toggleTheme, setTheme } = useLhTheme()
return { theme, toggleTheme, setTheme }
},
}
</script>
<template>
<div>
<LhButton @click="toggleTheme">
{{ theme === 'dark' ? 'Cambiar a claro' : 'Cambiar a oscuro' }}
</LhButton>
</div>
</template>
useLhThemepersiste automáticamente el estado del tema enlocalStorage(clave:lh-ui-theme); tras actualizar la página, el tema no se pierde.
Opción 2: conmutación mediante atributo HTML
Establece data-theme="dark" en el elemento raíz para activar globalmente el modo oscuro:
<!DOCTYPE html>
<html lang="es" data-theme="dark">
<!-- ... -->
</html>Colores de tema personalizados (porcelana azul y blanco / verde pino / cinabrio)
Además de los temas claro y oscuro integrados, la biblioteca permite personalizar cualquier combinación de colores a través de themeVars para crear temas propios.
El ejemplo siguiente es una demostración de variables personalizadas escritas a mano, con valores ajustados para la explicación, y no coincide exactamente con los presets integrados del mismo nombre (
cerblue/songhua/zhusha) de Temas predefinidos. Para usar directamente un preset integrado, empleauseLhPresetThemeogetThemeVars(name).
Tema 青花瓷 (porcelana azul y blanco)
Con un azul índigo profundo como color principal, inspirado en la porcelana azul y blanco tradicional.
Composition API
<script setup lang="ts">
const cerblueTheme = {
'primary-color': '#2B4C7C',
'primary-color-hover': '#3D649E',
'primary-color-active': '#1F3A5F',
'primary-color-bg': '#E8EDF3',
'bg-color': '#F0F4F8',
'border-color-base': '#C8D6E5',
}
</script>
<template>
<LhConfigProvider :theme-vars="cerblueTheme">
<LhButton type="primary">Botón de porcelana azul</LhButton>
<LhInput placeholder="Campo de porcelana azul" />
</LhConfigProvider>
</template>Options API
<script>
import { LhConfigProvider, LhButton, LhInput } from '@lh-ui/vue3'
export default {
components: { LhConfigProvider, LhButton, LhInput },
data() {
return {
cerblueTheme: {
'primary-color': '#2B4C7C',
'primary-color-hover': '#3D649E',
'primary-color-bg': '#E8EDF3',
'bg-color': '#F0F4F8',
},
}
},
}
</script>
<template>
<LhConfigProvider :theme-vars="cerblueTheme">
<LhButton type="primary">Botón de porcelana azul</LhButton>
</LhConfigProvider>
</template>Tema 松花绿 (verde pino)
Con el verde del bambú como adorno, crea un estilo fresco y natural.
<script setup lang="ts">
const bambooTheme = {
'primary-color': '#5B8C5A',
'primary-color-hover': '#6FA36E',
'primary-color-bg': '#EDF5EC',
'success-color': '#5B8C5A',
'bg-color': '#F6FAF5',
}
</script>
<template>
<LhConfigProvider :theme-vars="bambooTheme">
<LhButton type="primary">Sendero del bosque de bambú</LhButton>
<LhTag type="success">Nuevas hojas</LhTag>
</LhConfigProvider>
</template>Tema 朱砂红 (cinabrio rojizo)
Con el rojo de la pasta de los sellos como tono principal, destaca una atmósfera de elegancia y suntuosidad.
<script setup lang="ts">
const vermilionTheme = {
'primary-color': '#C43A31',
'primary-color-hover': '#E85D4A',
'primary-color-bg': '#FDF0EE',
'bg-color': '#FFFBF9',
'border-color-base': '#F0D5CF',
}
</script>
<template>
<LhConfigProvider :theme-vars="vermilionTheme">
<LhButton type="primary">Sello de cinabrio</LhButton>
</LhConfigProvider>
</template>Sistema de fondos con patrón
La biblioteca ofrece un sistema de fondos con patrón de poética china, con 6 presets, que se puede combinar con la lista blanca patternComponents para controlar con precisión el alcance de la aplicación.
Presets de patrón
| Patrón | Variable CSS | Descripción |
|---|---|---|
| 柳叶 (hoja de sauce) | var(--lh-pattern-willow) | Hojas de sauce alargadas, con densidad bien compuesta |
| 祥云 (nube propicia) | var(--lh-pattern-cloud) | Nubes propicias que se despliegan, serpenteando |
| 水波 (ondas de agua) | var(--lh-pattern-water) | Ondulaciones tenues, en capas superpuestas |
| 雪花 (copo de nieve) | var(--lh-pattern-snow) | Copos hexagonales, con ramificaciones finas |
| 梅花 (flor de ciruelo) | var(--lh-pattern-plum) | Cinco pétalos desplegados, con el centro bien definido |
| 竹叶 (hoja de bambú) | var(--lh-pattern-bamboo) | Hojas de bambú lanceoladas, dispuestas con armonía |
Configuración global de patrón
Composition API
<script setup lang="ts">
const config = {
themeVars: {
'bg-pattern': 'var(--lh-pattern-cloud)',
'bg-pattern-opacity': '0.15',
},
patternComponents: ['button', 'input'] as const,
}
</script>
<template>
<LhConfigProvider
:theme-vars="config.themeVars"
:pattern-components="config.patternComponents"
>
<!-- Los botones y los campos aplican la textura; Dialog no -->
<LhButton>Botón con patrón</LhButton>
<LhInput placeholder="Campo con patrón" />
</LhConfigProvider>
</template>Options API
<script>
export default {
data() {
return {
config: {
themeVars: {
'bg-pattern': 'var(--lh-pattern-cloud)',
'bg-pattern-opacity': '0.15',
},
patternComponents: ['button', 'input'],
},
}
},
}
</script>
<template>
<LhConfigProvider
:theme-vars="config.themeVars"
:pattern-components="config.patternComponents"
>
<LhButton>Botón con patrón</LhButton>
</LhConfigProvider>
</template>Referencia de variables de patrón
| Variable | Descripción | Predeterminado |
|---|---|---|
--lh-bg-pattern | URL del patrón de fondo | none |
--lh-bg-pattern-repeat | Modo de repetición en mosaico | repeat |
--lh-bg-pattern-size | Tamaño del patrón | 40px |
--lh-bg-pattern-opacity | Opacidad del patrón | 0.15 |
--lh-bg-pattern-color | Color del patrón | var(--lh-decoration-color, rgba(184, 134, 11, 0.12)) |
--lh-bg-pattern-blend | Modo de mezcla | soft-light |
Ejemplo de configuración completa
A continuación se muestra el uso completo de la configuración de ConfigProvider, integrando todas las capacidades de tema, idioma, tamaño y patrón.
Composition API
<script setup lang="ts">
import { zhCN } from '@lh-ui/vue3'
const configProvider = {
size: 'medium' as const,
locale: zhCN,
themeVars: {
'primary-color': '#2B4C7C',
'bg-pattern': 'var(--lh-pattern-cloud)',
'bg-pattern-opacity': '0.15',
},
patternComponents: ['button', 'input', 'dialog'],
}
</script>
<template>
<LhConfigProvider
:size="configProvider.size"
:locale="configProvider.locale"
:theme-vars="configProvider.themeVars"
:pattern-components="configProvider.patternComponents"
>
<slot />
</LhConfigProvider>
</template>Options API
<script>
import { zhCN } from '@lh-ui/vue3'
export default {
data() {
return {
configProvider: {
size: 'medium',
locale: zhCN,
themeVars: {
'primary-color': '#2B4C7C',
'bg-pattern': 'var(--lh-pattern-cloud)',
},
patternComponents: ['button', 'input', 'dialog'],
},
}
},
}
</script>
<template>
<LhConfigProvider
:size="configProvider.size"
:locale="configProvider.locale"
:theme-vars="configProvider.themeVars"
:pattern-components="configProvider.patternComponents"
>
<slot />
</LhConfigProvider>
</template>Prioridad de las variables de tema
Las variables CSS finales de un componente se fusionan según la siguiente prioridad (cada nivel sobrescribe al anterior):
themeVarsglobal de ConfigProvider (prioridad más baja)componentTheme[nombre del componente]de ConfigProvider- La prop
themeVarsdel propio componente - La prop
bgPatterndel propio componente (prioridad más alta)
Para la variable bg-pattern existe además el control de la lista blanca patternComponents: solo los componentes de la lista blanca aplican el bg-pattern de la configuración global.
Diseño rápido con sx
La propiedad sx ofrece una forma declarativa de diseño en línea, que permite establecer los márgenes y el tamaño de los componentes sin escribir CSS. Actualmente está soportado en los siguientes componentes: Button, Input, Dialog, Tooltip, Alert, Card, Empty, Breadcrumb, Pagination, Steps, Tabs y Skeleton.
Principio
sx se basa en una retícula de referencia de 8px: el número se multiplica por 8 para obtener el valor en píxeles. Por ejemplo, mt: 2 equivale a marginTop: 16px.
Propiedades admitidas
Márgenes y rellenos
| Propiedad | Descripción | Ejemplo | CSS equivalente |
|---|---|---|---|
m | Margen exterior en los cuatro lados | m: 2 | margin: 16px |
mx | Margen exterior horizontal | mx: 1 | marginLeft: 8px; marginRight: 8px |
my | Margen exterior vertical | my: 1 | marginTop: 8px; marginBottom: 8px |
mt, mr, mb, ml | Margen exterior de un solo lado | mt: 2 | marginTop: 16px |
p | Relleno interior en los cuatro lados | p: 3 | padding: 24px |
px | Relleno interior horizontal | px: 2 | paddingLeft: 16px; paddingRight: 16px |
py | Relleno interior vertical | py: 1 | paddingTop: 8px; paddingBottom: 8px |
pt, pr, pb, pl | Relleno interior de un solo lado | pt: 2 | paddingTop: 16px |
Tamaño
| Propiedad | Descripción | Ejemplo |
|---|---|---|
w | Ancho (un número es px; una cadena es el valor en bruto) | w: 200 o w: '100%' |
h | Alto | h: 100 o h: 'auto' |
Diseño Flex
| Propiedad | Descripción | Ejemplo |
|---|---|---|
display | Tipo de visualización | display: 'flex' |
flex | Abreviatura de flex | flex: '1 1 0%' |
flexDirection | Dirección del eje principal | flexDirection: 'column' |
alignItems | Alineación del eje transversal | alignItems: 'center' |
justifyContent | Alineación del eje principal | justifyContent: 'flex-end' |
Ejemplos de uso
<script setup lang="ts">
import { ref } from 'vue'
const visible = ref(false)
</script>
<template>
<!-- Márgenes del botón -->
<LhButton type="primary" :sx="{ mt: 2, mx: 1 }">Botón con márgenes</LhButton>
<!-- Margen exterior del campo -->
<LhInput placeholder="Márgenes verticales del campo" :sx="{ my: 1 }" />
<!-- Ancho del Dialog: sx solo admite w/h y propiedades de tipo layout -->
<LhDialog v-model="visible" title="Ejemplo" :sx="{ w: 480 }">
<p>Diálogo con ancho fijo</p>
</LhDialog>
</template><script>
export default {
data() {
return { visible: false }
},
}
</script>
<template>
<LhButton type="primary" :sx="{ mt: 2, mx: 1 }">Botón con márgenes</LhButton>
</template>