folderweb/docs/how-to/custom-styles.md
2025-11-02 13:46:47 +01:00

8.1 KiB

How to Customize Styles

This guide shows you how to override the default styles with your own CSS.

Overview

FolderWeb uses a fallback system for styles:

  1. Check /custom/styles/base.css
  2. Fall back to /app/default/styles/base.css

The framework automatically versions CSS files with MD5 hashes for cache busting.

Quick Start

Step 1: Create Custom Stylesheet

mkdir -p custom/styles
touch custom/styles/base.css

Step 2: Override CSS Variables

The easiest way to customize is to override CSS custom properties:

:root {
    --color-primary: oklch(0.65 0.20 30);      /* Orange */
    --color-secondary: oklch(0.50 0.18 30);    /* Dark orange */
    --color-light: oklch(0.98 0.01 30);        /* Warm white */
    --color-grey: oklch(0.40 0 0);             /* Grey */
    
    --font-body: "Helvetica Neue", Arial, sans-serif;
    --font-heading: "Georgia", serif;
    
    --spacing-unit: 1.5rem;
    --border-radius: 8px;
}

Step 3: Test Your Changes

Refresh your browser. If changes don't appear, do a hard refresh (Ctrl+Shift+R or Cmd+Shift+R).

Available CSS Variables

Colors

--color-primary: oklch(0.65 0.15 250);      /* Primary blue */
--color-secondary: oklch(0.50 0.12 250);    /* Dark blue */
--color-light: oklch(0.97 0.01 250);        /* Off-white */
--color-grey: oklch(0.37 0 0);              /* Dark grey */

Note: FolderWeb uses OKLCH colors for perceptually uniform color spaces. You can also use hex, rgb, or hsl if preferred.

Typography

--font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
--font-heading: Georgia, "Times New Roman", serif;

--font-size-base: 1.125rem;     /* 18px */
--font-size-small: 0.875rem;    /* 14px */
--line-height-base: 1.6;
--line-height-heading: 1.2;

Spacing

--spacing-unit: 1.5rem;         /* Base spacing (24px) */
--spacing-small: 0.75rem;       /* 12px */
--spacing-large: 3rem;          /* 48px */

Layout

--max-width: 70rem;             /* Content max-width */
--border-radius: 4px;           /* Corner rounding */

Adding Custom Fonts

Step 1: Add Font Files

mkdir -p custom/fonts
# Copy your .woff2 files here
cp ~/Downloads/MyFont-Regular.woff2 custom/fonts/
cp ~/Downloads/MyFont-Bold.woff2 custom/fonts/

Step 2: Declare Font Faces

In custom/styles/base.css:

@font-face {
    font-family: 'MyFont';
    src: url('/custom/fonts/MyFont-Regular.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}

@font-face {
    font-family: 'MyFont';
    src: url('/custom/fonts/MyFont-Bold.woff2') format('woff2');
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}

:root {
    --font-body: 'MyFont', sans-serif;
}

Note: Font files are automatically served by FolderWeb's static file handler.

Page-Specific Styling

FolderWeb adds dynamic CSS classes to the <body> element:

<body class="section-blog page-2025-11-02-my-post">

Use these for targeted styling:

/* Style all blog pages */
.section-blog {
    --color-primary: oklch(0.60 0.15 150);  /* Green for blog */
}

/* Style a specific page */
.page-about {
    font-size: 1.25rem;
}

/* Combine for precision */
.section-docs.page-installation {
    background: var(--color-light);
}

Responsive Design

FolderWeb uses modern CSS features for responsiveness. Use clamp() for fluid typography:

:root {
    --font-size-base: clamp(1rem, 0.9rem + 0.5vw, 1.25rem);
    --spacing-unit: clamp(1rem, 0.8rem + 1vw, 2rem);
}

h1 {
    font-size: clamp(2rem, 1.5rem + 2vw, 3.5rem);
}

Use container queries for component responsiveness:

.card-grid {
    container-type: inline-size;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
    gap: var(--spacing-unit);
}

@container (min-width: 600px) {
    .card {
        padding: var(--spacing-large);
    }
}

Dark Mode

Add a dark mode using CSS custom properties and media queries:

:root {
    --color-bg: oklch(0.97 0.01 250);
    --color-text: oklch(0.20 0 0);
}

@media (prefers-color-scheme: dark) {
    :root {
        --color-bg: oklch(0.20 0 0);
        --color-text: oklch(0.95 0 0);
        --color-light: oklch(0.25 0 0);
        --color-primary: oklch(0.70 0.15 250);
    }
}

body {
    background: var(--color-bg);
    color: var(--color-text);
}

List Template Styling

Style the different list templates:

Grid Layout

.list-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: var(--spacing-unit);
}

.list-grid article {
    border: 1px solid var(--color-light);
    border-radius: var(--border-radius);
    overflow: hidden;
}

.list-grid img {
    aspect-ratio: 16 / 9;
    object-fit: cover;
    width: 100%;
}

Card Grid

.card-grid .card {
    background: var(--color-light);
    padding: var(--spacing-unit);
    border-radius: var(--border-radius);
    transition: transform 0.2s ease;
}

.card-grid .card:hover {
    transform: translateY(-4px);
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
}

FAQ Layout

.faq details {
    border: 1px solid var(--color-light);
    border-radius: var(--border-radius);
    padding: var(--spacing-unit);
    margin-block-end: var(--spacing-small);
}

.faq summary {
    cursor: pointer;
    font-weight: 700;
    user-select: none;
}

.faq summary:hover {
    color: var(--color-primary);
}

Modern CSS Features

FolderWeb encourages use of modern CSS:

CSS Nesting

.article {
    padding: var(--spacing-unit);
    
    & h2 {
        color: var(--color-primary);
        margin-block-start: var(--spacing-large);
    }
    
    & a {
        color: var(--color-secondary);
        text-decoration: none;
        
        &:hover {
            text-decoration: underline;
        }
    }
}

Logical Properties

Use logical properties for internationalization:

/* Instead of: margin-left, margin-right */
article {
    margin-inline: auto;
    padding-inline: var(--spacing-unit);
    padding-block: var(--spacing-large);
}

/* Instead of: text-align: left */
.content {
    text-align: start;
}

Modern Color Functions

:root {
    /* OKLCH: lightness, chroma, hue */
    --primary: oklch(0.65 0.15 250);
    
    /* Adjust lightness for hover */
    --primary-hover: oklch(0.55 0.15 250);
    
    /* Or use color-mix */
    --primary-light: color-mix(in oklch, var(--primary), white 20%);
}

Performance Tips

Minimize Custom Styles

Override only what's necessary. The default stylesheet is already optimized.

Use CSS Variables

Variables reduce repetition and improve maintainability:

/* Good */
:root {
    --card-padding: var(--spacing-unit);
}

.card { padding: var(--card-padding); }
.box { padding: var(--card-padding); }

/* Less maintainable */
.card { padding: 1.5rem; }
.box { padding: 1.5rem; }

Avoid !important

FolderWeb uses low-specificity selectors, so you shouldn't need !important.

Debugging Styles

Check Which Stylesheet is Loaded

View source and look for:

<link rel="stylesheet" href="/app/styles/base.css?v=abc123...">

If you see /app/styles/, your custom stylesheet is being used.
If you see /app/default-styles/, the default is being used.

Browser DevTools

  1. Right-click element → Inspect
  2. Check "Computed" tab to see which properties are applied
  3. Check "Sources" tab to verify your CSS file is loaded
  4. Use "Network" tab to ensure CSS isn't cached with old version

Hard Refresh

Always do a hard refresh after CSS changes:

  • Chrome/Firefox: Ctrl+Shift+R (Windows/Linux) or Cmd+Shift+R (Mac)
  • Safari: Cmd+Option+R

Complete Override

If you want complete control, you can replace the entire stylesheet. Copy the default:

cp app/default/styles/base.css custom/styles/base.css

Then edit freely. Remember: you're responsible for all styles when you do this.