Electron utiliza por defecto la interfaz nativa del sistema operativo y ofrece opciones limitadas para personalizar su apariencia. Para lograr un diseño completamente a medida, la estrategia consiste en construir la interfaz mediante tecnologías web y utilizar la comunicación entre procesos para invocar las funciones del sistema como minimizar, maximizar, cerrar y arrastrar ventanas.
1. Eliminación del marco nativo de la ventana
La creación de ventanas en Electron se realiza instanciando BrowserWindow. Para prescindir de los elementos visuales del sistema, se deben configurar las siguiantes opciones:
transparencyEnabled: true,
bgColor: 'rgba(0,0,0,0)',
showFrame: false,
Estos parámetros eliminan el borde y vuelven transparente el fondo, dejando únicamente el contenido renderizado por la capa frontend. Esto permite aplicar cualquier estilo personalizado mediante CSS.
Al remover los controles nativos, se pierden funcionalidades como los botones de gestión de ventana. Estas deben reimplementarse mediante comunicación entre procesos (IPC). El proceso de renderización emite eventos que el proceso principal intercepta para ejecutar las acciones correspondientes.
Ejemplo de implementación para la funcionalidad de maximizar:
Componente Vue:
<img class="window-btn" src="@/assets/icons/expand.png" @click="toggleMaximize" />
function toggleMaximize() {
window.windowAPI.toggleMaximize()
}
Script de precarga (preload):
const channelMap = {
minimize: 'win-minimize',
toggleMax: 'win-toggle-maximize',
restore: 'win-restore',
close: 'win-close',
relayPage: 'page-changed'
}
const emit = (key, ...args) => ipcRenderer.send(channelMap[key], ...args)
contextBridge.exposeInMainWorld('windowAPI', {
minimize: () => emit('minimize'),
toggleMaximize: () => emit('toggleMax'),
restore: () => emit('restore'),
close: () => emit('close'),
notifyPage: (pageId) => emit('relayPage', pageId)
})
Proceso principal:
ipcMain.on('win-toggle-maximize', () => {
if (mainWindow.isMaximized()) {
mainWindow.unmaximize()
} else {
mainWindow.maximize()
}
})
2. Habilitación del arrastre de ventana
Para permitir que el usuario mueva la ventana arrastrando un área específica, no basta con la configuración inicial. Es necesario aplicar una propiedad CSS especial de Electron al elemento deseado:
<div class="drag-zone"></div>
.drag-zone {
-webkit-app-region: drag;
}
La directiva -webkit-app-region: drag convierte cualquier elemento HTML en un área arrastrable de la ventana. Los elementos interactivos dentro de esta zona deben declararse con -webkit-app-region: no-drag para mantener su funcionalidad.
3. Redimensionamiento dinámico según la vista activa
El dimensionamiento de la ventana debe gestionarse desde el proceso principal. Si se controla únciamente desde el frontend volviendo transparentes las áreas no utilizadas, el resultado es engañoso: las zonas invisibles siguen interceptando eventos del mouce, afectando la experiencia del usuario.
La solución consiste en que cada vista notifique al proceso principal su identificador al montarse. El proceso principal ajusta entonces las dimensiones de la ventana según corresponda.
Notificación desde el frontend:
function navigateTo(routeName) {
router.push({ name: routeName })
activeRoute.value = routeName
window.windowAPI.notifyPage(routeName)
}
Gestión de tamaños en el proceso principal:
const dimensions = {
auth: { w: 480, h: 600 },
dashboard: { w: 1024, h: 768 }
}
ipcMain.on('page-changed', (event, pageId) => {
const config = dimensions[pageId] || dimensions.dashboard
mainWindow.setSize(config.w, config.h)
mainWindow.center()
const showMenu = pageId !== 'auth'
mainWindow.setMenuBarVisibility(showMenu)
})
4. Menús contextuales personalizados
El menú contextual nativo de Electron (Menu) tiene un estilo fijo que no puede modificarse mediante CSS. Si se requiere un diseño a medida, la alternativa es prescindir de la API nativa y construir el menú como un componente HTML ordinario.
El enfoque consiste en capturar el evento contextmenu en el frontend, renderizar un menú personalizado posicionado según las coordenadas del cursor y comunicar la acción seleccionada al proceso principal mediante IPC cuando sea necesario ejecutar operaciones del sistema.