From 266717df51df3cba3284789aca56e4b015076902 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sat, 4 Oct 2025 06:00:10 +0000 Subject: [PATCH 1/2] feat: Implement OKLCH color space architecture with semantic aliases and theme system MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Major architectural improvements: - OKLCH color foundation with separate lightness/chroma/hue variables - Semantic alias layer (success, danger, warning, info) alongside priority names - Theme system supporting multiple named themes (enchanted-forest, ocean-breeze, etc.) - Automatic dark mode support via prefers-color-scheme - Layer-based CSS architecture for organized customization - Comprehensive README documentation Breaking changes: - Removed legacy token.css from default imports (still available in dual layer) - Converted color_token.css to user customization layer All existing functionality maintained: - Priority-based naming (Primaryβ†’Denary) - 5-color and 10-color modes - All color variations (tints, shades, highlights) - Component color system - Visual harmony over logical order philosophy Co-Authored-By: jesco@rpdevstudios.com --- README.md | 238 ++++++++++++++++++++++++++++++++++----- css/color_token.css | 75 +++++------- css/semantic_aliases.css | 118 +++++++++++++++++++ css/site.css | 37 ++++-- css/themes.css | 237 ++++++++++++++++++++++++++++++++++++++ css/token_oklch.css | 109 ++++++++++++++++++ 6 files changed, 727 insertions(+), 87 deletions(-) create mode 100644 css/semantic_aliases.css create mode 100644 css/themes.css create mode 100644 css/token_oklch.css diff --git a/README.md b/README.md index 66a54cc..92b6fc9 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,36 @@ A comprehensive, semantic color system that scales from 1 essential color to 10 extended colors, providing everything you need for modern web interfaces. +## ✨ What's New in v2.0 + +### OKLCH Color Foundation +ZephyrCSS now uses the modern OKLCH color space as its foundation, providing: +- **Perceptually uniform colors** - More natural color transitions +- **Better dark mode support** - Automatic lightness inversion +- **Enhanced color manipulation** - Precise control over hue, chroma, and lightness +- **Future-proof architecture** - Built on cutting-edge CSS standards + +### Semantic Aliases +Use intent-based names alongside priority-based names: +```css +/* Both work! */ +--success: var(--quinary); /* Semantic name */ +--quinary: /* ... */; /* Priority name */ +``` + +### Multi-Theme Support +Switch between multiple pre-built themes at runtime: +```html + + + + + +``` + +### Automatic Dark Mode +Respects system preferences with `prefers-color-scheme: dark` - no configuration needed! + ## 🎨 Philosophy: Visual Harmony Over Logical Order One of the key insights in developing this framework was discovering that **visual harmony doesn't always follow logical color order**. When building color palettes, the temptation is to arrange colors in a sequential, logical progression. However, we found that creating truly harmonious palettes requires a more thoughtful approach to color relationships. @@ -30,6 +60,27 @@ Instead of following a strict chromatic progression, these colors were selected ## πŸ—οΈ Architecture +### Modern OKLCH Foundation + +ZephyrCSS v2.0 is built on OKLCH (Oklab Lightness Chroma Hue), providing superior color manipulation: + +```css +/* Instead of hex values: */ +--primary: #264653; + +/* We now define components: */ +--primary-l: 35%; /* Lightness */ +--primary-c: 0.05; /* Chroma (saturation) */ +--primary-h: 196; /* Hue (0-360) */ +--primary: oklch(var(--primary-l) var(--primary-c) var(--primary-h)); +``` + +**Benefits:** +- **Dark mode**: Simply invert lightness values automatically +- **Consistency**: Perceptually uniform color space +- **Control**: Adjust saturation globally by tweaking chroma +- **Predictability**: More intuitive color relationships + ### Dual-Mode System The framework operates in two modes: @@ -47,21 +98,69 @@ Toggle between modes using the `data-palette` attribute: ``` +### Theme System + +Switch between pre-built themes or create your own: + +```html + + + + + +``` + +**Available Themes:** +- `enchanted-forest` (default) - Earthy teal and warm accents +- `ocean-breeze` - Cool blues with aqua accents +- `sunset-warmth` - Warm sunset purples and oranges +- `lively-spring` - Fresh spring greens +- `monochrome-pro` - Professional grayscale with subtle blue undertones + ### Color Hierarchy & Semantic Roles +ZephyrCSS uses **priority-based naming** (Primary β†’ Denary) where colors are ordered by visual prominence, not chromatic sequence. This represents "most visible β†’ least visible" in typical UI layouts. + #### Core Colors (1-5) -1. **Primary** (`#264653`) - Main background layer, foundational UI elements -2. **Secondary** (`#E9C46A`) - Foreground/surface accent, elevated content -3. **Tertiary** (`#287271`) - Borders/structure, form elements, dividers -4. **Quaternary** (`#EFB366`) - Calm accent, secondary actions, info states -5. **Quinary** (`#2A9D8F`) - Emphasis/positive tone, CTAs, success states +1. **Primary** - Main background layer, foundational UI elements +2. **Secondary** - Foreground/surface accent, elevated content +3. **Tertiary** - Borders/structure, form elements, dividers +4. **Quaternary** - Calm accent, secondary actions, info states +5. **Quinary** - Emphasis/positive tone, CTAs, success states #### Extended Colors (6-10) -6. **Senary** (`#F4A261`) - Utility overlay, tooltips, helper content -7. **Septenary** (`#8AB17D`) - Danger/warning states, destructive actions -8. **Octonary** (`#EE8959`) - Info states, notifications, guidance -9. **Nonary** (`#BABB74`) - Neutral accent, pending states, subtle emphasis -10. **Denary** (`#E76F51`) - Text anchor, readable text on light backgrounds +6. **Senary** - Utility overlay, tooltips, helper content +7. **Septenary** - Danger/warning states, destructive actions +8. **Octonary** - Info states, notifications, guidance +9. **Nonary** - Neutral accent, pending states, subtle emphasis +10. **Denary** - Text anchor, readable text on light backgrounds + +### Semantic Aliases (New in v2.0!) + +Use intent-based names for better code readability: + +```css +/* Priority-based (original) */ +--quinary: oklch(60% 0.10 175); +--septenary: oklch(65% 0.09 130); +--octonary: oklch(68% 0.16 40); +--nonary: oklch(70% 0.08 95); + +/* Semantic aliases (new) */ +--success: var(--quinary); +--danger: var(--septenary); +--info: var(--octonary); +--warning: var(--nonary); +--neutral: var(--tertiary); +--accent: var(--quaternary); +``` + +**Use whichever naming makes sense for your context:** +```css +/* Both are valid! */ +.alert-success { background: var(--bg-success-base); } +.alert-success { background: var(--bg-quinary-base); } +``` #### Using a 1 to 3 color palette @@ -141,41 +240,73 @@ Example usage: ``` ZephyrCSS/ -β”œβ”€β”€ token.css # Core color definitions -β”œβ”€β”€ color_token.css # Override Core color definitions & mode switching -β”œβ”€β”€ color_tints_shades.css # Automatic color variations -β”œβ”€β”€ colors.css # Complete component color system -β”œβ”€β”€ layout.css # Layout utilities & grid system -β”œβ”€β”€ site.css # Main import file +β”œβ”€β”€ css/ +β”‚ β”œβ”€β”€ token_oklch.css # OKLCH color foundation (NEW) +β”‚ β”œβ”€β”€ themes.css # Pre-built theme system (NEW) +β”‚ β”œβ”€β”€ semantic_aliases.css # Intent-based color names (NEW) +β”‚ β”œβ”€β”€ token.css # Legacy hex color definitions (maintained) +β”‚ β”œβ”€β”€ color_token.css # Color overrides & mode switching +β”‚ β”œβ”€β”€ color_tints_shades.css # Automatic color variations +β”‚ β”œβ”€β”€ colors.css # Complete component color system +β”‚ β”œβ”€β”€ layout.css # Layout utilities & grid system +β”‚ └── site.css # Main import file with layer architecture └── index.html # Complete showcase & documentation ``` +### Import Order & Layers + +The framework uses CSS `@layer` for organized customization: + +```css +@layer themes, semantic-aliases, override, dual; + +1. token_oklch.css β†’ OKLCH foundation +2. themes.css β†’ Named theme variants +3. semantic_aliases.css β†’ Intent-based names +4. token.css β†’ Legacy compatibility (layer: dual) +5. color_token.css β†’ Color overrides +6. color_tints_shades.css β†’ Variations +7. colors.css β†’ Component tokens +8. layout.css β†’ Layout system +``` + ## πŸš€ Quick Start 1. **Include the framework:** ```html - + ``` -2. **Set your preferred mode:** +2. **Set your preferred mode and theme:** ```html - + + + ``` -3. **Use semantic color classes:** +3. **Use semantic color classes (now with aliases!):** ```html - +

Primary Content

- -
Success message
-
Warning message
+ +
Success message
+
Error message
+
Warning message
+
Info message
+ + + + +``` - - +4. **Dark mode works automatically:** +```css +/* No configuration needed! */ +/* Framework respects prefers-color-scheme: dark */ ``` ## 🎨 Real-World Usage Examples @@ -257,23 +388,72 @@ This approach led to the much more cohesive "Enchanted Forest Hues" palette we u ## πŸ”§ Customization -### Creating Your Own Palette +### Creating Your Own Theme + +With the new theme system, creating custom themes is easier: + +```css +/* In themes.css or your own override file */ +@layer themes { + :root[data-theme="my-brand"] { + /* Define OKLCH components */ + --primary-l: 40%; + --primary-c: 0.12; + --primary-h: 280; + + --secondary-l: 75%; + --secondary-c: 0.15; + --secondary-h: 50; + + /* ... define all 10 colors */ + } +} +``` + +Then use your theme: +```html + +``` + +### Creating Your Own Palette (Legacy Method) -To adapt this framework with your own colors: +To adapt this framework with your own colors using the legacy system: 1. **Replace the color values** in `color_token.css` 2. **Maintain the semantic structure** (don't change the variable names) 3. **Test all variations** using the included showcase page 4. **Validate accessibility** with tools like WebAIM Color Contrast Checker +### Advanced Customization with OKLCH + +Fine-tune colors by adjusting individual components: + +```css +/* Increase saturation across all colors */ +:root { + --primary-c: calc(var(--primary-c) * 1.2); + --secondary-c: calc(var(--secondary-c) * 1.2); +} + +/* Create custom dark mode lightness values */ +@media (prefers-color-scheme: dark) { + :root { + --primary-l: 70%; /* Lighter in dark mode */ + --secondary-l: 40%; /* Darker in dark mode */ + } +} +``` + ### Extended Customization The framework is designed to be modular. You can: +- Create new themes in `themes.css` +- Add semantic aliases in `semantic_aliases.css` - Modify tint/shade percentages in `color_tints_shades.css` - Add new component variations in `colors.css` - Extend the layout system in `layout.css` -- Create new semantic mappings for your specific use case +- Override at specific layers using `@layer override` ## 🎭 Examples & Showcase diff --git a/css/color_token.css b/css/color_token.css index 00ca0f7..d43e54a 100644 --- a/css/color_token.css +++ b/css/color_token.css @@ -1,54 +1,31 @@ /** - This is the root color token that should be modified as it uses CSS3 layer system. + * User Customization Override Layer + * + * This file is designed for users to override the default theme colors. + * You can either: + * 1. Define your own OKLCH components and let the system generate variations + * 2. Override specific color values directly + * + * NOTE: The previous color palettes have been moved to the themes system. + * Use data-theme="lively-spring" to access the Lively Spring Spectrum palette. + * + * Example customization: + * + * @layer override { + * :root { + * --primary-l: 40%; + * --primary-c: 0.12; + * --primary-h: 280; + * } + * } */ -@layer dual { - :root, - :root[data-palette="5"] { - /* Core palette */ - --primary: #42047e; /* Background layer */ - --secondary: #07f49e; /* Foreground/surface layer */ - --tertiary: transparent; /* Borders/structure layer */ - --quaternary: transparent; /* Accent layer */ - --quinary: transparent; /* Emphasis layer */ - } - - /* ========================================================================== - 10‑TOKEN MODE (Primary–Denary) β€” EXTENDED - Adds: Senary (utility), Septenary (danger), Octonary (info), - Nonary (neutral/warning), Denary (explicit text anchor) - ========================================================================== */ - :root[data-palette="10"] { - /* Enhancers / semantics */ - --senary: transparent; /* utility overlay */ - --septenary: transparent; /* danger */ - --octonary: transparent; /* info (blue) */ - --nonary: transparent; /* warning / neutral accent */ - --denary: transparent; /* text anchor on light surfaces */ - } -} @layer override { - :root, - :root[data-palette="5"] { - /* Core palette https://coolors.co/palette/e8f9c8-def7e1-bcf0c2-8be595-56da65-99d770-ffb775-ff9f77-ff8477-ff6478 Lively Spring Spectrum*/ - --primary: #E8F9C8; /* Background layer */ - --secondary: #99D770; /* Foreground/surface layer */ - --tertiary: #DEF7E1; /* Borders/structure layer */ - --quaternary: #FFB775; /* Accent layer */ - --quinary: #BCF0C2; /* Emphasis layer */ + /* Add your custom color overrides here */ + /* Example: + :root { + --primary: oklch(50% 0.15 200); + --secondary: oklch(70% 0.12 150); } - - /* ========================================================================== - 10‑TOKEN MODE (Primary–Denary) β€” EXTENDED - Adds: Senary (utility), Septenary (danger), Octonary (info), - Nonary (neutral/warning), Denary (explicit text anchor) - ========================================================================== */ - :root[data-palette="10"] { - /* Enhancers / semantics */ - --senary: #FF9F77; /* utility overlay */ - --septenary: #8BE595; /* danger */ - --octonary: #FF8477; /* info (blue) */ - --nonary: #56DA65; /* warning / neutral accent */ - --denary: #FF6478; /* text anchor on light surfaces */ - } -} \ No newline at end of file + */ +} diff --git a/css/semantic_aliases.css b/css/semantic_aliases.css new file mode 100644 index 0000000..9348e16 --- /dev/null +++ b/css/semantic_aliases.css @@ -0,0 +1,118 @@ +/* ========================================================================== + Semantic Aliases Layer + Provides intent-based names alongside priority-based names + Best of both worlds: developers can use either naming convention + ========================================================================== */ + +@layer semantic-aliases { + :root { + /* State aliases - map to priority-based colors */ + --success: var(--quinary); + --success-l: var(--quinary-l); + --success-c: var(--quinary-c); + --success-h: var(--quinary-h); + + --danger: var(--septenary); + --danger-l: var(--septenary-l); + --danger-c: var(--septenary-c); + --danger-h: var(--septenary-h); + + --warning: var(--nonary); + --warning-l: var(--nonary-l); + --warning-c: var(--nonary-c); + --warning-h: var(--nonary-h); + + --info: var(--octonary); + --info-l: var(--octonary-l); + --info-c: var(--octonary-c); + --info-h: var(--octonary-h); + + --neutral: var(--tertiary); + --neutral-l: var(--tertiary-l); + --neutral-c: var(--tertiary-c); + --neutral-h: var(--tertiary-h); + + --accent: var(--quaternary); + --accent-l: var(--quaternary-l); + --accent-c: var(--quaternary-c); + --accent-h: var(--quaternary-h); + + --emphasis: var(--quinary); + --emphasis-l: var(--quinary-l); + --emphasis-c: var(--quinary-c); + --emphasis-h: var(--quinary-h); + + /* Tints and shades for semantic colors */ + --success-tint: color-mix(in oklab, var(--success), white 12%); + --success-tint-light: color-mix(in oklab, var(--success), white 25%); + --success-highlight: color-mix(in oklab, var(--success), white 44%); + --success-subtle: color-mix(in oklab, var(--success), white 60%); + --success-shade: color-mix(in oklab, var(--success), black 20%); + --success-shade-deep: color-mix(in oklab, var(--success), black 35%); + + --danger-tint: color-mix(in oklab, var(--danger), white 12%); + --danger-tint-light: color-mix(in oklab, var(--danger), white 25%); + --danger-highlight: color-mix(in oklab, var(--danger), white 44%); + --danger-subtle: color-mix(in oklab, var(--danger), white 60%); + --danger-shade: color-mix(in oklab, var(--danger), black 20%); + --danger-shade-deep: color-mix(in oklab, var(--danger), black 35%); + + --warning-tint: color-mix(in oklab, var(--warning), white 12%); + --warning-tint-light: color-mix(in oklab, var(--warning), white 25%); + --warning-highlight: color-mix(in oklab, var(--warning), white 44%); + --warning-subtle: color-mix(in oklab, var(--warning), white 60%); + --warning-shade: color-mix(in oklab, var(--warning), black 20%); + --warning-shade-deep: color-mix(in oklab, var(--warning), black 35%); + + --info-tint: color-mix(in oklab, var(--info), white 12%); + --info-tint-light: color-mix(in oklab, var(--info), white 25%); + --info-highlight: color-mix(in oklab, var(--info), white 44%); + --info-subtle: color-mix(in oklab, var(--info), white 60%); + --info-shade: color-mix(in oklab, var(--info), black 20%); + --info-shade-deep: color-mix(in oklab, var(--info), black 35%); + + /* Background system for semantic colors */ + --bg-success-base: var(--success); + --bg-success-hover: var(--success-tint); + --bg-success-active: var(--success-shade); + --bg-success-subtle: var(--success-highlight); + + --bg-danger-base: var(--danger); + --bg-danger-hover: var(--danger-tint); + --bg-danger-active: var(--danger-shade); + --bg-danger-subtle: var(--danger-highlight); + + --bg-warning-base: var(--warning); + --bg-warning-hover: var(--warning-tint); + --bg-warning-active: var(--warning-shade); + --bg-warning-subtle: var(--warning-highlight); + + --bg-info-base: var(--info); + --bg-info-hover: var(--info-tint); + --bg-info-active: var(--info-shade); + --bg-info-subtle: var(--info-highlight); + + /* Border system for semantic colors */ + --border-success-base: var(--success); + --border-success-light: var(--success-tint); + --border-success-subtle: var(--success-highlight); + + --border-danger-base: var(--danger); + --border-danger-light: var(--danger-tint); + --border-danger-subtle: var(--danger-highlight); + + --border-warning-base: var(--warning); + --border-warning-light: var(--warning-tint); + --border-warning-subtle: var(--warning-highlight); + + --border-info-base: var(--info); + --border-info-light: var(--info-tint); + --border-info-subtle: var(--info-highlight); + + /* Text on semantic backgrounds */ + --text-on-success: var(--white); + --text-on-danger: var(--white); + --text-on-warning: var(--white); + --text-on-info: var(--white); + } +} diff --git a/css/site.css b/css/site.css index f497f27..25104d7 100644 --- a/css/site.css +++ b/css/site.css @@ -1,9 +1,28 @@ -/* remove layers or re-order to see them all in action */ -@layer override; -@layer dual; - -@import url('token.css') /* layer(dual)*/; /* uncomment the layer to see them in action. Core color palette tokens */ -@import url('color_token.css'); /* Core color palette tokens */ -@import url('color_tints_shades.css'); /* Color shades, tints and highlights */ -@import url('colors.css'); /* Extended color system with variations */ -@import url('layout.css'); /* Layout utilities and grid systems */ +/* ========================================================================== + ZephyrCSS - Semantic Theming Framework + Layer-based architecture for flexible theme customization + ========================================================================== */ + +/* Define layer order (first = lowest priority, last = highest priority) */ +@layer base, themes, semantic-aliases, override, dual; + +/* OKLCH Foundation - Modern color space for better manipulation */ +@import url('token_oklch.css') layer(base); + +/* Theme System - Named themes for runtime switching */ +@import url('themes.css'); + +/* Semantic Aliases - Intent-based names alongside priority names */ +@import url('semantic_aliases.css'); + +/* User Customization Layer - Override colors here if needed */ +@import url('color_token.css'); + +/* Color Variations - Tints, shades, and highlights */ +@import url('color_tints_shades.css'); + +/* Component Color System - Extended system with variations */ +@import url('colors.css'); + +/* Layout Utilities - Grid and spacing systems */ +@import url('layout.css'); diff --git a/css/themes.css b/css/themes.css new file mode 100644 index 0000000..d0d9864 --- /dev/null +++ b/css/themes.css @@ -0,0 +1,237 @@ +/* ========================================================================== + Theme System + Multiple named themes that can be switched at runtime + Each theme uses the same priority-based structure (Primary β†’ Denary) + ========================================================================== */ + +@layer themes { + /* ========================================================================== + Theme: Enchanted Forest (Original Default) + ========================================================================== */ + :root[data-theme="enchanted-forest"], + :root:not([data-theme]) { + --primary-l: 35%; + --primary-c: 0.05; + --primary-h: 196; + + --secondary-l: 80%; + --secondary-c: 0.12; + --secondary-h: 85; + + --tertiary-l: 45%; + --tertiary-c: 0.08; + --tertiary-h: 180; + + --quaternary-l: 75%; + --quaternary-c: 0.15; + --quaternary-h: 70; + + --quinary-l: 60%; + --quinary-c: 0.10; + --quinary-h: 175; + + --senary-l: 72%; + --senary-c: 0.14; + --senary-h: 50; + + --septenary-l: 65%; + --septenary-c: 0.09; + --septenary-h: 130; + + --octonary-l: 68%; + --octonary-c: 0.16; + --octonary-h: 40; + + --nonary-l: 70%; + --nonary-c: 0.08; + --nonary-h: 95; + + --denary-l: 65%; + --denary-c: 0.18; + --denary-h: 25; + } + + /* ========================================================================== + Theme: Ocean Breeze + Cool blue tones with aqua accents + ========================================================================== */ + :root[data-theme="ocean-breeze"] { + --primary-l: 40%; + --primary-c: 0.08; + --primary-h: 210; + + --secondary-l: 70%; + --secondary-c: 0.12; + --secondary-h: 200; + + --tertiary-l: 50%; + --tertiary-c: 0.06; + --tertiary-h: 220; + + --quaternary-l: 65%; + --quaternary-c: 0.10; + --quaternary-h: 190; + + --quinary-l: 55%; + --quinary-c: 0.12; + --quinary-h: 180; + + --senary-l: 72%; + --senary-c: 0.14; + --senary-h: 200; + + --septenary-l: 65%; + --septenary-c: 0.09; + --septenary-h: 10; + + --octonary-l: 68%; + --octonary-c: 0.14; + --octonary-h: 220; + + --nonary-l: 70%; + --nonary-c: 0.08; + --nonary-h: 50; + + --denary-l: 45%; + --denary-c: 0.10; + --denary-h: 230; + } + + /* ========================================================================== + Theme: Sunset Warmth + Warm sunset colors with purple accents + ========================================================================== */ + :root[data-theme="sunset-warmth"] { + --primary-l: 45%; + --primary-c: 0.12; + --primary-h: 280; + + --secondary-l: 75%; + --secondary-c: 0.18; + --secondary-h: 40; + + --tertiary-l: 55%; + --tertiary-c: 0.10; + --tertiary-h: 290; + + --quaternary-l: 70%; + --quaternary-c: 0.16; + --quaternary-h: 50; + + --quinary-l: 60%; + --quinary-c: 0.14; + --quinary-h: 30; + + --senary-l: 68%; + --senary-c: 0.16; + --senary-h: 60; + + --septenary-l: 55%; + --septenary-c: 0.14; + --septenary-h: 10; + + --octonary-l: 65%; + --octonary-c: 0.12; + --octonary-h: 270; + + --nonary-l: 72%; + --nonary-c: 0.10; + --nonary-h: 45; + + --denary-l: 50%; + --denary-c: 0.15; + --denary-h: 320; + } + + /* ========================================================================== + Theme: Lively Spring (From color_token.css) + Fresh spring greens with warm accents + ========================================================================== */ + :root[data-theme="lively-spring"] { + --primary-l: 92%; + --primary-c: 0.08; + --primary-h: 110; + + --secondary-l: 75%; + --secondary-c: 0.12; + --secondary-h: 100; + + --tertiary-l: 90%; + --tertiary-c: 0.06; + --tertiary-h: 125; + + --quaternary-l: 80%; + --quaternary-c: 0.14; + --quaternary-h: 60; + + --quinary-l: 88%; + --quinary-c: 0.10; + --quinary-h: 140; + + --senary-l: 78%; + --senary-c: 0.15; + --senary-h: 45; + + --septenary-l: 82%; + --septenary-c: 0.11; + --septenary-h: 130; + + --octonary-l: 76%; + --octonary-c: 0.16; + --octonary-h: 20; + + --nonary-l: 72%; + --nonary-c: 0.13; + --nonary-h: 135; + + --denary-l: 70%; + --denary-c: 0.18; + --denary-h: 10; + } + + /* ========================================================================== + Theme: Monochrome Pro + Professional grayscale with subtle blue undertones + ========================================================================== */ + :root[data-theme="monochrome-pro"] { + --primary-l: 25%; + --primary-c: 0.02; + --primary-h: 220; + + --secondary-l: 85%; + --secondary-c: 0.03; + --secondary-h: 220; + + --tertiary-l: 45%; + --tertiary-c: 0.02; + --tertiary-h: 220; + + --quaternary-l: 65%; + --quaternary-c: 0.03; + --quaternary-h: 220; + + --quinary-l: 55%; + --quinary-c: 0.08; + --quinary-h: 150; + + --senary-l: 75%; + --senary-c: 0.02; + --senary-h: 220; + + --septenary-l: 60%; + --septenary-c: 0.10; + --septenary-h: 10; + + --octonary-l: 65%; + --octonary-c: 0.08; + --octonary-h: 220; + + --nonary-l: 70%; + --nonary-c: 0.08; + --nonary-h: 50; + + --denary-l: 35%; + --denary-c: 0.04; + --denary-h: 220; + } +} diff --git a/css/token_oklch.css b/css/token_oklch.css new file mode 100644 index 0000000..b5a490e --- /dev/null +++ b/css/token_oklch.css @@ -0,0 +1,109 @@ +/* ========================================================================== + OKLCH Color Foundation + Modern color space foundation for better color manipulation and theming + Benefits: + - Perceptually uniform color space + - Easier dark mode (invert lightness) + - Better color manipulation + - More predictable results + ========================================================================== */ + +:root { + /* Neutrals */ + --white: oklch(100% 0 0); + --black: oklch(0% 0 0); + + /* OKLCH Components for each color */ + /* Primary - Deep teal - Background layer */ + --primary-l: 35%; + --primary-c: 0.05; + --primary-h: 196; + + /* Secondary - Warm yellow - Foreground/surface layer */ + --secondary-l: 80%; + --secondary-c: 0.12; + --secondary-h: 85; + + /* Tertiary - Teal green - Borders/structure layer */ + --tertiary-l: 45%; + --tertiary-c: 0.08; + --tertiary-h: 180; + + /* Quaternary - Soft orange - Accent layer */ + --quaternary-l: 75%; + --quaternary-c: 0.15; + --quaternary-h: 70; + + /* Quinary - Aqua green - Emphasis layer */ + --quinary-l: 60%; + --quinary-c: 0.10; + --quinary-h: 175; + + /* Senary - Coral orange - Utility overlay */ + --senary-l: 72%; + --senary-c: 0.14; + --senary-h: 50; + + /* Septenary - Sage green - Danger/warning */ + --septenary-l: 65%; + --septenary-c: 0.09; + --septenary-h: 130; + + /* Octonary - Burnt orange - Info states */ + --octonary-l: 68%; + --octonary-c: 0.16; + --octonary-h: 40; + + /* Nonary - Olive green - Neutral accent */ + --nonary-l: 70%; + --nonary-c: 0.08; + --nonary-h: 95; + + /* Denary - Terra cotta - Text anchor */ + --denary-l: 65%; + --denary-c: 0.18; + --denary-h: 25; +} + +/* ========================================================================== + Dark Mode Variants + Automatically adjusts lightness for dark mode while preserving hue/chroma + ========================================================================== */ +@media (prefers-color-scheme: dark) { + :root { + /* Invert lightness for dark mode */ + --primary-l: 65%; + --secondary-l: 45%; + --tertiary-l: 70%; + --quaternary-l: 50%; + --quinary-l: 55%; + --senary-l: 48%; + --septenary-l: 60%; + --octonary-l: 52%; + --nonary-l: 55%; + --denary-l: 58%; + } +} + +/* ========================================================================== + 5-TOKEN MODE (Primary–Quinary) β€” DEFAULT + ========================================================================== */ +:root, +:root[data-palette="5"] { + --primary: oklch(var(--primary-l) var(--primary-c) var(--primary-h)); + --secondary: oklch(var(--secondary-l) var(--secondary-c) var(--secondary-h)); + --tertiary: oklch(var(--tertiary-l) var(--tertiary-c) var(--tertiary-h)); + --quaternary: oklch(var(--quaternary-l) var(--quaternary-c) var(--quaternary-h)); + --quinary: oklch(var(--quinary-l) var(--quinary-c) var(--quinary-h)); +} + +/* ========================================================================== + 10-TOKEN MODE (Primary–Denary) β€” EXTENDED + ========================================================================== */ +:root[data-palette="10"] { + --senary: oklch(var(--senary-l) var(--senary-c) var(--senary-h)); + --septenary: oklch(var(--septenary-l) var(--septenary-c) var(--septenary-h)); + --octonary: oklch(var(--octonary-l) var(--octonary-c) var(--octonary-h)); + --nonary: oklch(var(--nonary-l) var(--nonary-c) var(--nonary-h)); + --denary: oklch(var(--denary-l) var(--denary-c) var(--denary-h)); +} From d28dc9690604c84da9f1449899e4613817681537 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sat, 4 Oct 2025 06:36:01 +0000 Subject: [PATCH 2/2] fix: Dark mode now works correctly by moving rules to unlayered CSS Root cause: CSS layer cascade prevented dark mode from working. The dark mode rules in the 'base' layer were being overridden by higher-priority layers (themes, semantic-aliases, override). Solution: Moved dark mode rules from token_oklch.css to unlayered CSS at the end of site.css, giving them the highest priority in the cascade. Changes: - Added unlayered dark mode rules to site.css for both automatic (OS preference) and manual (data-color-scheme attribute) dark mode - Removed non-functional layered dark mode rules from token_oklch.css - Updated README.md with comprehensive dark mode documentation including JavaScript toggle examples Dark mode now correctly: - Inverts OKLCH lightness values (e.g., 35% -> 65%) - Redefines color variables inside media query and attribute selector - Preserves hue and chroma for harmonious color relationships - Supports both automatic detection and manual override Tested and verified working in browser with visual confirmation. Co-Authored-By: jesco@rpdevstudios.com --- README.md | 64 +++++++++++++++++++++++++++++++++++--- css/site.css | 76 +++++++++++++++++++++++++++++++++++++++++++-- css/token_oklch.css | 20 ------------ 3 files changed, 133 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 92b6fc9..5452c38 100644 --- a/README.md +++ b/README.md @@ -303,12 +303,68 @@ The framework uses CSS `@layer` for organized customization: ``` -4. **Dark mode works automatically:** -```css -/* No configuration needed! */ -/* Framework respects prefers-color-scheme: dark */ +4. **Dark mode support (NEW!):** +```html + + + + + + ``` +```javascript +// Toggle dark mode with JavaScript (important-comment) +function toggleDarkMode() { + const root = document.documentElement; + const current = root.getAttribute('data-color-scheme') || 'light'; + root.setAttribute('data-color-scheme', current === 'dark' ? 'light' : 'dark'); +} +``` + +### Dark Mode + +ZephyrCSS v2.0 supports both automatic and manual dark mode: + +**Automatic Dark Mode (OS Preference)** +The framework automatically detects and respects your operating system's color scheme preference using `@media (prefers-color-scheme: dark)`. No configuration needed! + +**Manual Dark Mode Toggle** +Override the automatic detection using the `data-color-scheme` attribute: + +```html + + + + + +``` + +**JavaScript Toggle Example** +```javascript +function toggleDarkMode() { + const root = document.documentElement; + const currentScheme = root.getAttribute('data-color-scheme'); + const newScheme = currentScheme === 'dark' ? 'light' : 'dark'; + root.setAttribute('data-color-scheme', newScheme); + + localStorage.setItem('color-scheme', newScheme); +} + +window.addEventListener('DOMContentLoaded', () => { + const savedScheme = localStorage.getItem('color-scheme'); + if (savedScheme) { + document.documentElement.setAttribute('data-color-scheme', savedScheme); + } +}); +``` + +**How Dark Mode Works** +In dark mode, the OKLCH lightness values are inverted while preserving hue and chroma: +- Light backgrounds become darker (e.g., 80% β†’ 45%) +- Dark accents become lighter (e.g., 35% β†’ 65%) +- Colors remain harmonious and accessible + ## 🎨 Real-World Usage Examples ### Card Components diff --git a/css/site.css b/css/site.css index 25104d7..baa8a54 100644 --- a/css/site.css +++ b/css/site.css @@ -10,13 +10,13 @@ @import url('token_oklch.css') layer(base); /* Theme System - Named themes for runtime switching */ -@import url('themes.css'); +@import url('themes.css') layer(themes); /* Semantic Aliases - Intent-based names alongside priority names */ -@import url('semantic_aliases.css'); +@import url('semantic_aliases.css') layer(semantic-aliases); /* User Customization Layer - Override colors here if needed */ -@import url('color_token.css'); +@import url('color_token.css') layer(override); /* Color Variations - Tints, shades, and highlights */ @import url('color_tints_shades.css'); @@ -26,3 +26,73 @@ /* Layout Utilities - Grid and spacing systems */ @import url('layout.css'); + +/* ========================================================================== + Dark Mode Support (Unlayered - Highest Priority) + These rules are intentionally NOT in a layer so they override all layered + styles, ensuring dark mode works correctly regardless of theme or overrides + ========================================================================== */ + +/* Automatic Dark Mode (OS Preference) */ +@media (prefers-color-scheme: dark) { + :root { + --primary-l: 65%; + --secondary-l: 45%; + --tertiary-l: 70%; + --quaternary-l: 50%; + --quinary-l: 55%; + --senary-l: 48%; + --septenary-l: 60%; + --octonary-l: 52%; + --nonary-l: 55%; + --denary-l: 58%; + } + + :root, + :root[data-palette="5"] { + --primary: oklch(var(--primary-l) var(--primary-c) var(--primary-h)); + --secondary: oklch(var(--secondary-l) var(--secondary-c) var(--secondary-h)); + --tertiary: oklch(var(--tertiary-l) var(--tertiary-c) var(--tertiary-h)); + --quaternary: oklch(var(--quaternary-l) var(--quaternary-c) var(--quaternary-h)); + --quinary: oklch(var(--quinary-l) var(--quinary-c) var(--quinary-h)); + } + + :root[data-palette="10"] { + --senary: oklch(var(--senary-l) var(--senary-c) var(--senary-h)); + --septenary: oklch(var(--septenary-l) var(--septenary-c) var(--septenary-h)); + --octonary: oklch(var(--octonary-l) var(--octonary-c) var(--octonary-h)); + --nonary: oklch(var(--nonary-l) var(--nonary-c) var(--nonary-h)); + --denary: oklch(var(--denary-l) var(--denary-c) var(--denary-h)); + } +} + +/* Manual Dark Mode Toggle (data-color-scheme attribute) */ +:root[data-color-scheme="dark"] { + --primary-l: 65%; + --secondary-l: 45%; + --tertiary-l: 70%; + --quaternary-l: 50%; + --quinary-l: 55%; + --senary-l: 48%; + --septenary-l: 60%; + --octonary-l: 52%; + --nonary-l: 55%; + --denary-l: 58%; +} + +:root[data-color-scheme="dark"], +:root[data-color-scheme="dark"][data-palette="5"] { + --primary: oklch(var(--primary-l) var(--primary-c) var(--primary-h)); + --secondary: oklch(var(--secondary-l) var(--secondary-c) var(--secondary-h)); + --tertiary: oklch(var(--tertiary-l) var(--tertiary-c) var(--tertiary-h)); + --quaternary: oklch(var(--quaternary-l) var(--quaternary-c) var(--quaternary-h)); + --quinary: oklch(var(--quinary-l) var(--quinary-c) var(--quinary-h)); +} + +:root[data-color-scheme="dark"][data-palette="10"] { + --senary: oklch(var(--senary-l) var(--senary-c) var(--senary-h)); + --septenary: oklch(var(--septenary-l) var(--septenary-c) var(--septenary-h)); + --octonary: oklch(var(--octonary-l) var(--octonary-c) var(--octonary-h)); + --nonary: oklch(var(--nonary-l) var(--nonary-c) var(--nonary-h)); + --denary: oklch(var(--denary-l) var(--denary-c) var(--denary-h)); +} diff --git a/css/token_oklch.css b/css/token_oklch.css index b5a490e..08e362d 100644 --- a/css/token_oklch.css +++ b/css/token_oklch.css @@ -65,26 +65,6 @@ --denary-h: 25; } -/* ========================================================================== - Dark Mode Variants - Automatically adjusts lightness for dark mode while preserving hue/chroma - ========================================================================== */ -@media (prefers-color-scheme: dark) { - :root { - /* Invert lightness for dark mode */ - --primary-l: 65%; - --secondary-l: 45%; - --tertiary-l: 70%; - --quaternary-l: 50%; - --quinary-l: 55%; - --senary-l: 48%; - --septenary-l: 60%; - --octonary-l: 52%; - --nonary-l: 55%; - --denary-l: 58%; - } -} - /* ========================================================================== 5-TOKEN MODE (Primary–Quinary) β€” DEFAULT ========================================================================== */