Overview
The BLACKICE Portal implements a comprehensive theming system using CSS custom properties (CSS variables) with automatic dark mode support based on system preferences. The theme adapts to user’s OS settings while maintaining consistent visual design.
CSS Custom Properties
The theme system is built on CSS variables defined in the :root scope:
:root {
--font-family-base : "Inter" , system-ui , -apple-system , BlinkMacSystemFont, "Segoe UI" , Roboto, sans-serif ;
--duration-fast : 150 ms ;
--duration-normal : 250 ms ;
--ease-standard : cubic-bezier ( 0.16 , 1 , 0.3 , 1 );
--radius-full : 9999 px ;
--space-15 : 15 px ;
--space-24 : 24 px ;
/* Light Mode Colors */
--color-background-light : #f8f9fa ;
--color-surface-light : rgba ( 255 , 255 , 255 , 0.2 );
--color-text-light : #212529 ;
--color-text-secondary-light : #6c757d ;
--color-primary-light : #007bff ;
--color-border-light : #dee2e6 ;
/* Dark Mode Colors */
--color-background-dark : #121212 ;
--color-surface-dark : #1e1e1e ;
--color-text-dark : #e8e6e3 ;
--color-text-secondary-dark : #8b949e ;
--color-primary-dark : #58a6ff ;
--color-border-dark : #30363d ;
/* Default Theme (Light) */
--color-background : var ( --color-background-light );
--color-surface : var ( --color-surface-light );
--color-text : var ( --color-text-light );
--color-text-secondary : var ( --color-text-secondary-light );
--color-primary : var ( --color-primary-light );
--color-border : var ( --color-border-light );
}
Dark Mode Implementation
The portal automatically switches to dark mode using the prefers-color-scheme media query:
@media (prefers-color-scheme: dark) {
:root {
--color-background : var ( --color-background-dark );
--color-surface : var ( --color-surface-dark );
--color-text : var ( --color-text-dark );
--color-text-secondary : var ( --color-text-secondary-dark );
--color-primary : var ( --color-primary-dark );
--color-border : var ( --color-border-dark );
}
}
The theme automatically adapts when users change their system preferences without requiring a page reload.
Color Palette
Background
Text
Interactive
--color-background-light: #f8f9fa;
--color-surface-light: rgba(255, 255, 255, 0 .2 );
Light mode features soft grays with high contrast text for optimal readability in bright environments. Background
Text
Interactive
--color-background-dark: #121212 ;
--color-surface-dark: #1e1e1e ;
Dark mode uses true black backgrounds (#121212) with carefully calibrated text colors to reduce eye strain.
Design Tokens
The theme system includes standardized design tokens:
Typography
--font-family-base: "Inter", system-ui , -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif ;
The font stack includes Inter as primary font with comprehensive system fallbacks for cross-platform consistency.
Animation & Transitions
--duration-fast: 150ms;
--duration-normal: 250ms;
--ease-standard: cubic-bezier(0 .16 , 1, 0 .3 , 1);
These tokens ensure consistent animation timing across all interactive elements.
Spacing & Dimensions
--space-15: 15px;
--space-24: 24px;
--radius-full: 9999px;
Applying Theme Variables
Use CSS custom properties throughout your components:
Background Colors
Interactive Elements
Typography
.container {
background : var ( --color-background );
color : var ( --color-text );
}
.card {
background : var ( --color-surface );
border : 1 px solid var ( --color-border );
}
Glass Morphism Effects
The portal extensively uses glassmorphism with backdrop filters:
.glass-card {
background : rgba ( 255 , 255 , 255 , 0.1 );
backdrop-filter : blur ( 24 px );
-webkit-backdrop-filter : blur ( 24 px );
border : 1 px solid rgba ( 255 , 255 , 255 , 0.2 );
border-radius : 20 px ;
}
/* Dark mode variant */
@media (prefers-color-scheme: dark) {
.glass-card {
background : rgba ( 0 , 0 , 0 , 0.3 );
border-color : rgba ( 255 , 255 , 255 , 0.1 );
}
}
Glass effects use backdrop-filter for blur and include -webkit- prefix for Safari support.
Component-Specific Theming
Navigation Bar
The navigation adapts to theme mode:
.logo {
font-size : 28 px ;
font-weight : 800 ;
color : var ( --color-text );
text-shadow : 0 2 px 4 px rgba ( 255 , 255 , 255 , 0.5 );
}
.nav-link {
color : var ( --color-text-secondary );
transition : color var ( --duration-fast );
}
.nav-link:hover {
color : var ( --color-text );
}
Cards & Boxes
Bento grid cards with theme-aware styling:
.box {
background : var ( --color-surface );
border-radius : 24 px ;
padding : 32 px ;
box-shadow : 0 4 px 20 px rgba ( 0 , 0 , 0 , .08 );
transition : transform .1 s ease-out , box-shadow .3 s ;
}
/* Dark mode specific cards */
.box.dark-variant {
background : #262626 ;
color : #f3f4f6 ;
border : 1 px solid #404040 ;
}
Widget Theme System
The BlackICE widget implements its own theming:
this . theme = {
font: "'Inter Tight', -apple-system, BlinkMacSystemFont, sans-serif" ,
glassBg: "rgba(9, 9, 11, 0.95)" ,
glassBorder: "rgba(255, 255, 255, 0.08)" ,
accent: "#3b82f6" ,
textMain: "#ffffff" ,
textMuted: "#a1a1aa"
};
These values are injected into widget styles dynamically:
const css = `
.bi-root {
font-family: ${ this . theme . font } ;
}
#bi-trigger {
background: #18181b !important;
border: 1px solid ${ this . theme . glassBorder } ;
color: ${ this . theme . textMain } ;
}
#bi-sidebar {
background: ${ this . theme . glassBg } ;
backdrop-filter: blur(24px);
border: 1px solid ${ this . theme . glassBorder } ;
}
` ;
Gradient Effects
The theme includes animated gradient buttons:
.btn-labs {
--c-color-1 : rgba ( 255 , 163 , 26 , .7 );
--c-color-2 : #1a23ff ;
--c-color-3 : #e21bda ;
--c-color-4 : rgba ( 255 , 232 , 26 , .7 );
--c-shadow : rgba ( 0 , 0 , 0 , .5 );
--c-radial-inner : #1a1a1a ;
--c-radial-outer : #2a2a2a ;
background : radial-gradient (
circle ,
var ( --c-radial-inner ),
var ( --c-radial-outer ) 80 %
);
box-shadow : 0 0 14 px var ( --c-shadow );
}
Gradient buttons use CSS custom properties for color animation and include multiple circle elements for parallax effects.
Best Practices
1. Always Use CSS Variables
/* ✅ Good */
.element {
background : var ( --color-background );
color : var ( --color-text );
}
/* ❌ Bad */
.element {
background : #f8f9fa ;
color : #212529 ;
}
2. Leverage Inheritance
/* Define once at root level */
.app-container {
font-family : var ( --font-family-base );
color : var ( --color-text );
}
/* Child elements inherit automatically */
.app-container p {
/* Inherits color from parent */
}
3. Use Semantic Color Names
/* ✅ Good - Semantic */
--color-primary: #007bff ;
--color-text: #212529 ;
/* ❌ Bad - Generic */
--color-blue: #007bff ;
--color-dark-gray: #212529 ;
Testing Theme Modes
To test dark mode without changing system settings:
// Force dark mode in DevTools Console
document . documentElement . style . colorScheme = 'dark' ;
// Force light mode
document . documentElement . style . colorScheme = 'light' ;
// Reset to system preference
document . documentElement . style . colorScheme = '' ;
You can also use browser DevTools to emulate prefers-color-scheme in the Rendering panel.
Accessibility Considerations
Contrast Ratios
The theme ensures WCAG AA compliance:
Light mode text : 4.5:1 contrast ratio minimum
Dark mode text : 7:1 contrast ratio for enhanced readability
Interactive elements : 3:1 minimum for borders and controls
Reduced Motion
Respect user preferences for reduced motion:
@media (prefers-reduced-motion: reduce) {
* {
animation-duration : 0.01 ms !important ;
animation-iteration-count : 1 !important ;
transition-duration : 0.01 ms !important ;
}
}
Extending the Theme
To add new theme variables:
:root {
/* Existing variables */
/* New custom variables */
--color-success-light : #28a745 ;
--color-success-dark : #4ade80 ;
--color-success : var ( --color-success-light );
--color-danger-light : #dc3545 ;
--color-danger-dark : #f87171 ;
--color-danger : var ( --color-danger-light );
}
@media (prefers-color-scheme: dark) {
:root {
--color-success : var ( --color-success-dark );
--color-danger : var ( --color-danger-dark );
}
}
Always define both light and dark variants for new color variables to maintain consistency across themes.