398 lines
8.1 KiB
Markdown
398 lines
8.1 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
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:
|
|
|
|
```css
|
|
: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
|
|
|
|
```css
|
|
--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
|
|
|
|
```css
|
|
--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
|
|
|
|
```css
|
|
--spacing-unit: 1.5rem; /* Base spacing (24px) */
|
|
--spacing-small: 0.75rem; /* 12px */
|
|
--spacing-large: 3rem; /* 48px */
|
|
```
|
|
|
|
### Layout
|
|
|
|
```css
|
|
--max-width: 70rem; /* Content max-width */
|
|
--border-radius: 4px; /* Corner rounding */
|
|
```
|
|
|
|
## Adding Custom Fonts
|
|
|
|
### Step 1: Add Font Files
|
|
|
|
```bash
|
|
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`:
|
|
|
|
```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:
|
|
|
|
```html
|
|
<body class="section-blog page-2025-11-02-my-post">
|
|
```
|
|
|
|
Use these for targeted styling:
|
|
|
|
```css
|
|
/* 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:
|
|
|
|
```css
|
|
: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:
|
|
|
|
```css
|
|
.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:
|
|
|
|
```css
|
|
: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
|
|
|
|
```css
|
|
.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
|
|
|
|
```css
|
|
.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
|
|
|
|
```css
|
|
.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
|
|
|
|
```css
|
|
.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:
|
|
|
|
```css
|
|
/* 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
|
|
|
|
```css
|
|
: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:
|
|
|
|
```css
|
|
/* 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:
|
|
|
|
```html
|
|
<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:
|
|
|
|
```bash
|
|
cp app/default/styles/base.css custom/styles/base.css
|
|
```
|
|
|
|
Then edit freely. Remember: you're responsible for all styles when you do this.
|
|
|
|
## Related
|
|
|
|
- [Custom Templates](custom-templates.md)
|
|
- [CSS Reference](../reference/css-variables.md)
|
|
- [File Structure Reference](../reference/file-structure.md)
|