Files
cv-site/doc/12-CSS-ARCHITECTURE.md
T
juanatsap 95de841e14 feat: Add CSS bundling with Lightning CSS for production optimization
- Add Lightning CSS integration for CSS bundling and minification
- Create Makefile targets: css-dev, css-prod, css-watch, css-clean
- Implement conditional CSS loading based on GO_ENV (dev=modular, prod=bundled)
- Add IsProduction template variable for environment-aware rendering
- Keep print.css separate with media="print" for PDF export
- Add static/dist/ to .gitignore (generated bundles)
- Fix Go template syntax in _cv-header.css
- Remove redundant font @import in _typography.css

Performance gains:
- 27 HTTP requests → 1 (96% reduction)
- 188KB → 86KB CSS (54% reduction)
- ~15KB gzip network transfer

Documentation:
- Update 12-CSS-ARCHITECTURE.md with bundling section
- Add Phase 9 to 2-MODERN-WEB-TECHNIQUES.md
- Add css-bundling.test.mjs Playwright test (8/8 pass)
2025-11-30 12:32:46 +00:00

16 KiB

CSS Architecture Documentation

Overview

The CV site uses a modular CSS architecture based on ITCSS (Inverted Triangle CSS) principles, organized into layers from generic to specific styles. This approach ensures maintainability, scalability, and reduces specificity conflicts.

Directory Structure

static/css/
├── main.css                      # Entry point - imports all modules
├── print.css                     # Print styles (loaded separately with media="print")
├── 01-foundation/                # Base styles, variables, resets
│   ├── _reset.css               # CSS reset/normalize
│   ├── _variables.css           # CSS custom properties (colors, spacing)
│   ├── _typography.css          # Font definitions and text styles
│   └── _themes.css              # Theme variables (light/dark modes)
├── 02-layout/                    # Page structure and grids
│   ├── _container.css           # Container wrapper styles
│   ├── _page.css                # Page layout structure
│   ├── _grid.css                # Grid system
│   └── _paper.css               # CV paper/document styles
├── 03-components/                # UI components
│   ├── _action-bar.css          # Top action bar
│   ├── _sidebar.css             # Skills sidebar
│   ├── _cv-header.css           # CV header section
│   ├── _cv-section.css          # Generic CV sections
│   ├── _experience.css          # Work experience items
│   ├── _projects.css            # Projects section
│   ├── _courses.css             # Courses section
│   ├── _education.css           # Education section
│   └── _languages.css           # Languages section
├── 04-interactive/               # Interactive elements & HTMX patterns
│   ├── _toggles.css             # Toggle switches (theme, length, icons)
│   ├── _tooltips.css            # Tooltip styles
│   ├── _navigation.css          # Hamburger menu & navigation
│   ├── _scroll-behavior.css     # Scroll-based interactions
│   ├── _buttons.css             # Fixed action buttons
│   ├── _modals.css              # Modal dialogs
│   ├── _toasts.css              # Toast notifications
│   └── _zoom-control.css        # Zoom slider control
├── 05-responsive/                # Responsive breakpoints
│   └── _breakpoints.css         # Media queries for all screen sizes
└── 06-effects/                   # Visual effects
    └── _skeleton.css            # Loading skeleton screens

static/dist/                      # Generated by Lightning CSS (gitignored)
├── bundle.css                    # Development bundle
└── bundle.min.css                # Production bundle (minified)

Layer Descriptions

01-foundation/ - Base Styles (Most Generic)

Purpose: Fundamental styles that affect the entire application.

  • _reset.css: Normalizes browser defaults for consistency
  • _variables.css: CSS custom properties (colors, spacing, z-index)
  • _typography.css: Font families, sizes, line heights
  • _themes.css: Theme-specific variables (light/dark/clean modes)

When to edit: Changing global colors, fonts, or spacing values.

02-layout/ - Structure

Purpose: Page-level layout and positioning systems.

  • _container.css: Main wrapper containers
  • _page.css: Page layout structure (multi-page CV)
  • _grid.css: Grid system for content organization
  • _paper.css: CV paper/document styling (cv-short, cv-long classes)

When to edit: Adjusting page structure, paper sizes, or grid systems.

03-components/ - UI Components

Purpose: Reusable UI components specific to CV sections.

Each file contains styles for a specific CV section:

  • Visual appearance (colors, borders, spacing)
  • Component-specific layouts
  • Section-specific icons and imagery

When to edit: Styling individual CV sections or components.

04-interactive/ - Interactive Elements

Purpose: User interactions, HTMX patterns, and dynamic behaviors.

_toggles.css (5.9 KB)

  • Theme toggles (light/dark/clean)
  • Length toggles (short/long CV)
  • Icon visibility toggles
  • Toggle switch component styles

_navigation.css (8.2 KB)

  • Hamburger button styling
  • Slide-out navigation menu
  • Menu items and submenus
  • Smooth scrolling behavior
  • Pure CSS hover-triggered menus

_scroll-behavior.css (5.0 KB)

  • Header hide/show on scroll direction
  • Back-to-top button
  • Info button (bottom-left)
  • Scroll-based visual changes

_buttons.css (4.7 KB)

  • Fixed action buttons:
    • Download button (PDF export)
    • Print-friendly button
    • Keyboard shortcuts button
    • Zoom toggle button
  • Mobile horizontal layout
  • At-bottom state changes

_modals.css (16 KB)

  • Info Modal: Project details dialog
  • Keyboard Shortcuts Modal: Shortcut reference
  • PDF Download Modal: Interactive thumbnail selection
  • Native <dialog> element styling
  • Glassmorphism effects
  • Accessibility features

_zoom-control.css (6.3 KB)

  • Zoom slider (50%-150%)
  • Reset button
  • Draggable positioning
  • Mobile auto-disable
  • localStorage persistence

When to edit: Adding new interactive features or HTMX swap patterns.

05-responsive/ - Responsive Design

Purpose: Media queries for different screen sizes.

_breakpoints.css (14 KB)

  • Desktop (>1280px): Full layout with sidebars
  • Medium (1024-1280px): Compact fonts, collapsible sidebars
  • Medium (901-1023px): EN/ES labels, icon-only buttons
  • Tablet (≤768px): Centered photo, larger touch targets
  • Mobile (≤540px): Single-column, hamburger menu only
  • Small Mobile (≤480px): Ultra-compact zoom control

When to edit: Adjusting responsive behavior at specific breakpoints.

06-effects/ - Visual Effects

Purpose: Animations, transitions, and loading states.

  • _skeleton.css: Loading skeleton screens for language transitions

When to edit: Adding new animations or loading states.

print.css - Print Styles (Separate File)

Purpose: Print-optimized styles loaded via <link rel="stylesheet" href="print.css" media="print">.

Location: static/css/print.css (at root level, NOT bundled)

Why separate:

  1. Only loaded when printing (no bundle bloat)
  2. Uses media="print" for automatic browser handling
  3. Special PDF export requirements
  4. Independent of theme system

When to edit: Adjusting print output or PDF export appearance.

Import Order (main.css)

The import order follows the ITCSS inverted triangle - from generic to specific:

/* 01 - Foundation (most generic) */
@import './01-foundation/_reset.css';
@import './01-foundation/_variables.css';
@import './01-foundation/_typography.css';
@import './01-foundation/_themes.css';

/* 02 - Layout */
@import './02-layout/_container.css';
@import './02-layout/_page.css';
@import './02-layout/_grid.css';
@import './02-layout/_paper.css';

/* 03 - Components */
@import './03-components/_action-bar.css';
@import './03-components/_sidebar.css';
@import './03-components/_cv-header.css';
@import './03-components/_cv-section.css';
@import './03-components/_experience.css';
@import './03-components/_projects.css';
@import './03-components/_courses.css';
@import './03-components/_education.css';
@import './03-components/_languages.css';

/* 04 - Interactive */
@import './04-interactive/_toggles.css';
@import './04-interactive/_navigation.css';
@import './04-interactive/_scroll-behavior.css';
@import './04-interactive/_buttons.css';
@import './04-interactive/_modals.css';
@import './04-interactive/_zoom-control.css';

/* 05 - Responsive */
@import './05-responsive/_breakpoints.css';

/* 06 - Effects */
@import './06-effects/_skeleton.css';

/* NOTE: print.css is loaded separately in HTML with media="print" */

⚠️ IMPORTANT: Do not change the import order. Later imports can override earlier ones based on specificity.

CSS Bundling (Lightning CSS)

For production, CSS files are bundled and minified using Lightning CSS for better performance.

Bundle Strategy

Mode CSS Loading HTTP Requests
Development Individual files via @import ~27 requests (waterfall)
Production Single bundled file 1 request

Size Comparison

Metric Individual Files Bundle (dev) Bundle (minified) Gzip
Size 188 KB 110 KB 86 KB ~15 KB
Reduction - 43% 54% 92%

Makefile Targets

# Development: Bundle CSS (readable)
make css-dev

# Production: Bundle + minify CSS
make css-prod

# Watch mode (auto-rebuild on changes)
make css-watch

# Clean generated bundles
make css-clean

Environment-Based Loading

The template conditionally loads CSS based on GO_ENV:

<!-- In templates/index.html -->
{{if .IsProduction}}
<link rel="stylesheet" href="/static/dist/bundle.min.css">
{{else}}
<link rel="stylesheet" href="/static/css/main.css">
{{end}}
<!-- Print always separate -->
<link rel="stylesheet" href="/static/css/print.css" media="print">

Build Requirements

# Install Lightning CSS CLI globally
npm install -g lightningcss-cli

# Verify installation
lightningcss --version

CI/CD Integration

Production builds should run make css-prod before deployment:

# Example GitHub Actions
- name: Build CSS
  run: make css-prod

File Naming Conventions

  • Prefix with underscore: _filename.css indicates a partial file (imported by main.css)
  • Lowercase with hyphens: _action-bar.css (not _ActionBar.css or _action_bar.css)
  • Descriptive names: File name should clearly indicate its purpose

HTMX Integration

Interactive Elements Design

The 04-interactive layer is designed to work seamlessly with HTMX patterns:

  1. Atomic Swaps: Each component can be swapped independently
  2. Out-of-Band Updates: Modals and toggles support hx-swap-oob
  3. Loading States: Skeleton screens for async content transitions
  4. Progressive Enhancement: CSS-first approach with JavaScript fallbacks

Common HTMX Patterns

<!-- Toggle with out-of-band swap -->
<div hx-post="/toggle/theme"
     hx-target=".cv-container"
     hx-swap="outerHTML">
  <!-- Content updated by server -->
</div>

<!-- Modal trigger -->
<button onclick="document.getElementById('pdf-modal').showModal()">
  Download PDF
</button>

<!-- Navigation with smooth scroll -->
<a href="#experience" class="menu-item">
  Experience
</a>

Best Practices

1. Single Responsibility Principle

Each CSS file should have one clear purpose. Don't mix concerns.

Good: _buttons.css contains only button styles Bad: _buttons.css contains buttons + modals + forms

2. Component Isolation

Components should be self-contained and not depend on parent context.

Good:

.modal-close {
  position: absolute;
  top: 1rem;
  right: 1rem;
}

Bad:

.modal .close {  /* Requires .modal parent */
  position: absolute;
}

3. Mobile-First Responsive Design

Write mobile styles first, then add desktop enhancements.

Good:

.button { padding: 0.5rem; }

@media (min-width: 768px) {
  .button { padding: 1rem; }
}

4. CSS Custom Properties for Theming

Use variables for theme-specific values.

Good:

.button { background: var(--primary-color); }

Bad:

.button { background: #27ae60; }

5. Avoid Deep Nesting

Keep specificity low for easier overrides.

Good: .menu-item { } Bad: .navigation .menu .item { }

Adding New Styles

Adding a New Component

  1. Create new file in 03-components/:

    touch static/css/03-components/_my-component.css
    
  2. Add import to main.css in the components section:

    @import './03-components/_my-component.css';
    
  3. Write component styles:

    /* My Component - Description */
    .my-component {
      /* Styles here */
    }
    

Adding a New Interactive Pattern

  1. Determine if it fits an existing file or needs a new one

  2. If new file needed, create in 04-interactive/:

    touch static/css/04-interactive/_my-feature.css
    
  3. Add import to main.css after other interactive files

  4. Document HTMX integration patterns if applicable

Adding Responsive Styles

  1. Add media queries to 05-responsive/_breakpoints.css
  2. Group by breakpoint, not by component
  3. Use min-width for mobile-first approach

Performance Considerations

File Sizes (Production Bundle)

  • Production CSS: 86 KB minified (~15 KB gzip)
  • Print CSS: 18 KB (loaded only when printing)
  • Development CSS: ~188 KB across 27 files

Production Optimizations

  1. Lightning CSS bundling: Combines all CSS into single file
  2. Minification: Removes whitespace, comments, shortens values
  3. Single HTTP request: Eliminates waterfall from @import
  4. Gzip compression: 92% network transfer reduction

Development Workflow

  1. Hot reload friendly: Individual files for debugging
  2. Browser DevTools: Can trace styles to source files
  3. Faster iteration: No build step required
  4. Modular organization: Easy to find and edit specific styles

Troubleshooting

Styles Not Applying

  1. Check import order: Later imports override earlier ones
  2. Check specificity: Use browser DevTools to see which rule wins
  3. Check file path: Ensure @import path is correct
  4. Clear browser cache: Hard refresh (Cmd+Shift+R / Ctrl+Shift+F5)

Modal Not Showing

  1. Check if <dialog> element is in DOM
  2. Verify .showModal() is called (not .show())
  3. Check z-index conflicts
  4. Inspect ::backdrop styling

Responsive Issues

  1. Check viewport meta tag in HTML:
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
  2. Test at exact breakpoint values
  3. Use browser DevTools responsive mode
  4. Check for !important overrides

Migration History

v1.0 → v2.0 (Current)

Before (Monolithic):

  • Single _remaining.css file: 2,287 lines
  • Difficult to navigate and maintain
  • High merge conflict risk

After (Modular):

  • 6 focused files: 2,042 lines total
  • Clear separation of concerns
  • Better caching and collaboration
  • 245 lines saved through organization

Breaking Changes: None - CSS is backward compatible

Future Enhancements

Planned Improvements

  • CSS Modules for component scoping
  • CSS Container Queries for responsive components
  • View Transitions API for smooth page changes
  • CSS Nesting (when browser support improves)
  • Tailwind CSS integration (optional)

Considerations

  • Keep HTMX-friendly patterns
  • Maintain progressive enhancement
  • Preserve print stylesheet functionality
  • Ensure accessibility standards (WCAG AA)

References

Contributing

When adding new styles:

  1. Follow the established file structure
  2. Use CSS custom properties for theme values
  3. Write mobile-first responsive styles
  4. Test in multiple browsers
  5. Document complex interactions
  6. Update this documentation for structural changes

Last Updated: November 30, 2025 Version: 2.1 (Lightning CSS bundling) Maintainer: Development Team