docs refactor
All checks were successful
All checks were successful
This commit is contained in:
770
docs/content/styles/index.md
Normal file
770
docs/content/styles/index.md
Normal file
@ -0,0 +1,770 @@
|
||||
---
|
||||
version: "1.0"
|
||||
date: "2025-01-15"
|
||||
author: "DWS Foldsite Team"
|
||||
title: "Styles Guide"
|
||||
description: "Understanding Foldsite's CSS cascade system"
|
||||
summary: "Learn how CSS styles cascade through your Foldsite project - from base styles to page-specific customizations."
|
||||
quick_tips:
|
||||
- "base.css is required and loaded on every page"
|
||||
- "All matching styles are loaded (unlike templates where first match wins)"
|
||||
- "Styles cascade down through directory structure like templates"
|
||||
---
|
||||
|
||||
# Styles Guide
|
||||
|
||||
Foldsite's style system follows the same hierarchical logic as templates, allowing you to organize CSS in a maintainable, scalable way.
|
||||
|
||||
## The Style System
|
||||
|
||||
### Key Differences from Templates
|
||||
|
||||
| Templates | Styles |
|
||||
|-----------|--------|
|
||||
| **First match wins** | **All matches load** |
|
||||
| One template per page | Multiple stylesheets per page |
|
||||
| Must have at least one | base.css required |
|
||||
|
||||
**Why the difference?**
|
||||
|
||||
CSS is designed to cascade and layer. Loading multiple stylesheets allows you to:
|
||||
- Share base styles
|
||||
- Add section-specific styles
|
||||
- Override with page-specific styles
|
||||
|
||||
## Required Style: base.css
|
||||
|
||||
Every Foldsite project **must have** `styles/base.css`.
|
||||
|
||||
This file is **loaded on every page**, providing:
|
||||
- Typography
|
||||
- Layout basics
|
||||
- Color scheme
|
||||
- Resets/normalizes
|
||||
|
||||
### Minimal base.css
|
||||
|
||||
```css
|
||||
/* styles/base.css */
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin-top: 1.5em;
|
||||
margin-bottom: 0.5em;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0066cc;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
```
|
||||
|
||||
## Style Discovery
|
||||
|
||||
Styles follow a **hierarchical discovery pattern** similar to templates.
|
||||
|
||||
### For File: `blog/my-post.md`
|
||||
|
||||
**All matching styles load (in order):**
|
||||
|
||||
1. **Base style** (always)
|
||||
```
|
||||
/styles/base.css
|
||||
```
|
||||
|
||||
2. **Type + extension** styles (from root to specific)
|
||||
```
|
||||
/styles/__file.md.css
|
||||
/styles/blog/__file.md.css
|
||||
```
|
||||
|
||||
3. **Type + category** styles
|
||||
```
|
||||
/styles/__file.document.css
|
||||
/styles/blog/__file.document.css
|
||||
```
|
||||
|
||||
4. **Specific file** style
|
||||
```
|
||||
/styles/blog/my-post.md.css
|
||||
```
|
||||
|
||||
**All found styles are included!**
|
||||
|
||||
### Rendered HTML
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="/styles/base.css">
|
||||
<link rel="stylesheet" href="/styles/__file.md.css">
|
||||
<link rel="stylesheet" href="/styles/blog/__file.md.css">
|
||||
```
|
||||
|
||||
## Style Naming Patterns
|
||||
|
||||
### File Styles
|
||||
|
||||
Pattern: `__file.{extension}.css` or `__file.{category}.css`
|
||||
|
||||
```
|
||||
styles/
|
||||
├── __file.md.css # All markdown files
|
||||
├── __file.document.css # All document files
|
||||
├── __file.image.css # Individual images (rare)
|
||||
└── __file.other.css # Other file types
|
||||
```
|
||||
|
||||
### Folder Styles
|
||||
|
||||
Pattern: `__folder.{category}.css`
|
||||
|
||||
```
|
||||
styles/
|
||||
├── __folder.md.css # Folders with markdown
|
||||
├── __folder.image.css # Photo galleries
|
||||
└── __folder.html # Any folder view
|
||||
```
|
||||
|
||||
### Specific Page Styles
|
||||
|
||||
Pattern: `{path/to/file}.css`
|
||||
|
||||
```
|
||||
styles/
|
||||
├── index.md.css # Only homepage
|
||||
├── about.md.css # Only about page
|
||||
└── blog/
|
||||
└── special-post.md.css # One specific post
|
||||
```
|
||||
|
||||
## Directory Structure
|
||||
|
||||
### Basic Structure
|
||||
|
||||
```
|
||||
styles/
|
||||
├── base.css # Required: Base styles
|
||||
├── __file.md.css # Markdown file styles
|
||||
└── __folder.image.css # Gallery styles
|
||||
```
|
||||
|
||||
### Advanced Structure
|
||||
|
||||
```
|
||||
styles/
|
||||
├── base.css # Base
|
||||
├── __file.md.css # General markdown
|
||||
├── __folder.image.css # General galleries
|
||||
├── blog/
|
||||
│ ├── __file.md.css # Blog posts
|
||||
│ └── __folder.md.css # Blog index
|
||||
├── docs/
|
||||
│ └── __file.md.css # Documentation
|
||||
├── layouts/
|
||||
│ ├── document.css # Document layout
|
||||
│ ├── gallery.css # Gallery layout
|
||||
│ └── landing.css # Landing pages
|
||||
└── components/
|
||||
├── navigation.css # Navigation
|
||||
├── footer.css # Footer
|
||||
└── breadcrumbs.css # Breadcrumbs
|
||||
```
|
||||
|
||||
## Cascade & Specificity
|
||||
|
||||
### CSS Cascade Order
|
||||
|
||||
**Load order matters:**
|
||||
|
||||
1. `base.css` - Loaded first
|
||||
2. General styles (`__file.md.css`)
|
||||
3. Section styles (`blog/__file.md.css`)
|
||||
4. Specific styles (`blog/my-post.md.css`)
|
||||
|
||||
**Later styles override earlier ones** (standard CSS behavior).
|
||||
|
||||
### Example Cascade
|
||||
|
||||
**Given page:** `blog/tutorial.md`
|
||||
|
||||
**Loaded styles:**
|
||||
```html
|
||||
<link rel="stylesheet" href="/styles/base.css">
|
||||
<link rel="stylesheet" href="/styles/__file.md.css">
|
||||
<link rel="stylesheet" href="/styles/blog/__file.md.css">
|
||||
```
|
||||
|
||||
**base.css:**
|
||||
```css
|
||||
h1 {
|
||||
color: black; /* Default */
|
||||
}
|
||||
```
|
||||
|
||||
**__file.md.css:**
|
||||
```css
|
||||
h1 {
|
||||
color: #333; /* Slightly lighter */
|
||||
}
|
||||
```
|
||||
|
||||
**blog/__file.md.css:**
|
||||
```css
|
||||
h1 {
|
||||
color: #0066cc; /* Blue - wins! */
|
||||
}
|
||||
```
|
||||
|
||||
**Result:** Blog headings are blue.
|
||||
|
||||
## Common Patterns
|
||||
|
||||
### Pattern 1: Base + Overrides
|
||||
|
||||
Start with comprehensive base, override as needed:
|
||||
|
||||
**base.css** - Everything
|
||||
```css
|
||||
/* Typography */
|
||||
body { font-family: sans-serif; }
|
||||
h1 { font-size: 2.5rem; }
|
||||
h2 { font-size: 2rem; }
|
||||
|
||||
/* Layout */
|
||||
.container { max-width: 1200px; }
|
||||
|
||||
/* Components */
|
||||
nav { /* navigation styles */ }
|
||||
footer { /* footer styles */ }
|
||||
```
|
||||
|
||||
**blog/__file.md.css** - Blog-specific
|
||||
```css
|
||||
/* Override heading colors for blog */
|
||||
h1 { color: #0066cc; }
|
||||
|
||||
/* Add blog-specific components */
|
||||
.post-meta { /* metadata styles */ }
|
||||
```
|
||||
|
||||
### Pattern 2: Modular Components
|
||||
|
||||
Split styles into reusable modules:
|
||||
|
||||
**base.css** - Minimal
|
||||
```css
|
||||
@import url('components/typography.css');
|
||||
@import url('components/layout.css');
|
||||
@import url('components/navigation.css');
|
||||
```
|
||||
|
||||
**components/typography.css**
|
||||
```css
|
||||
body {
|
||||
font-family: Georgia, serif;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
h1 { font-size: 2.5rem; }
|
||||
/* ... */
|
||||
```
|
||||
|
||||
**components/navigation.css**
|
||||
```css
|
||||
nav {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
/* ... */
|
||||
```
|
||||
|
||||
### Pattern 3: Layout Variants
|
||||
|
||||
Different layouts for different sections:
|
||||
|
||||
**layouts/document.css**
|
||||
```css
|
||||
.document-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 250px 1fr;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.docs-sidebar { /* sidebar styles */ }
|
||||
.docs-content { /* content styles */ }
|
||||
```
|
||||
|
||||
**layouts/gallery.css**
|
||||
```css
|
||||
.gallery {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.photo-item { /* photo card styles */ }
|
||||
```
|
||||
|
||||
**Include in templates:**
|
||||
```html
|
||||
<!-- __file.md.html for docs -->
|
||||
<link rel="stylesheet" href="/styles/layouts/document.css">
|
||||
<div class="document-layout">
|
||||
<!-- content -->
|
||||
</div>
|
||||
```
|
||||
|
||||
### Pattern 4: Responsive Design
|
||||
|
||||
Mobile-first approach:
|
||||
|
||||
```css
|
||||
/* base.css - Mobile first */
|
||||
body {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Tablet */
|
||||
@media (min-width: 768px) {
|
||||
body {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 300px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Desktop */
|
||||
@media (min-width: 1200px) {
|
||||
body {
|
||||
padding: 3rem;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Practical Examples
|
||||
|
||||
### Example 1: Blog Site
|
||||
|
||||
```
|
||||
styles/
|
||||
├── base.css # Site-wide styles
|
||||
├── __file.md.css # General markdown
|
||||
├── __folder.md.css # Folder listings
|
||||
└── blog/
|
||||
├── __file.md.css # Blog posts
|
||||
└── __folder.md.css # Blog index
|
||||
```
|
||||
|
||||
**base.css:**
|
||||
```css
|
||||
/* Basic layout and typography */
|
||||
body {
|
||||
font-family: Georgia, serif;
|
||||
line-height: 1.6;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
a { color: #0066cc; }
|
||||
```
|
||||
|
||||
**__file.md.css:**
|
||||
```css
|
||||
/* Default markdown styles */
|
||||
article {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
code {
|
||||
background: #f4f4f4;
|
||||
padding: 0.2em 0.4em;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #f4f4f4;
|
||||
padding: 1rem;
|
||||
overflow-x: auto;
|
||||
}
|
||||
```
|
||||
|
||||
**blog/__file.md.css:**
|
||||
```css
|
||||
/* Blog post specific */
|
||||
.post-header {
|
||||
border-bottom: 2px solid #eee;
|
||||
padding-bottom: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.post-meta {
|
||||
color: #666;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.post-tags {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.tag {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.75rem;
|
||||
background: #f0f0f0;
|
||||
border-radius: 3px;
|
||||
margin-right: 0.5rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
```
|
||||
|
||||
**blog/__folder.md.css:**
|
||||
```css
|
||||
/* Blog index */
|
||||
.post-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.post-item {
|
||||
margin: 2rem 0;
|
||||
padding: 1.5rem;
|
||||
border: 1px solid #eee;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.post-item:hover {
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2: Photo Gallery
|
||||
|
||||
```
|
||||
styles/
|
||||
├── base.css
|
||||
└── galleries/
|
||||
└── __folder.image.css
|
||||
```
|
||||
|
||||
**galleries/__folder.image.css:**
|
||||
```css
|
||||
.photo-gallery {
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.photo-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
||||
gap: 1.5rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.photo-item {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
||||
transition: transform 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.photo-item:hover {
|
||||
transform: translateY(-4px);
|
||||
box-shadow: 0 4px 16px rgba(0,0,0,0.15);
|
||||
}
|
||||
|
||||
.photo-item img {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.photo-caption {
|
||||
padding: 0.75rem;
|
||||
background: white;
|
||||
font-size: 0.85rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 768px) {
|
||||
.photo-grid {
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Example 3: Documentation Site
|
||||
|
||||
```
|
||||
styles/
|
||||
├── base.css
|
||||
├── layouts/
|
||||
│ └── document.css
|
||||
└── docs/
|
||||
└── __file.md.css
|
||||
```
|
||||
|
||||
**layouts/document.css:**
|
||||
```css
|
||||
.docs-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 250px 1fr;
|
||||
gap: 3rem;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.docs-sidebar {
|
||||
position: sticky;
|
||||
top: 2rem;
|
||||
height: calc(100vh - 4rem);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.docs-content {
|
||||
min-width: 0; /* Prevent grid blowout */
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.docs-layout {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.docs-sidebar {
|
||||
position: static;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**docs/__file.md.css:**
|
||||
```css
|
||||
.documentation {
|
||||
max-width: 800px;
|
||||
}
|
||||
|
||||
/* Table of contents */
|
||||
.doc-toc {
|
||||
background: #f8f8f8;
|
||||
padding: 1rem;
|
||||
border-radius: 4px;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
/* Code blocks */
|
||||
.documentation pre {
|
||||
background: #282c34;
|
||||
color: #abb2bf;
|
||||
padding: 1.5rem;
|
||||
border-radius: 6px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.documentation code {
|
||||
font-family: 'Monaco', 'Courier New', monospace;
|
||||
}
|
||||
|
||||
/* Callouts */
|
||||
.note,
|
||||
.warning,
|
||||
.tip {
|
||||
padding: 1rem 1.5rem;
|
||||
margin: 1.5rem 0;
|
||||
border-left: 4px solid;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.note {
|
||||
background: #e3f2fd;
|
||||
border-color: #2196f3;
|
||||
}
|
||||
|
||||
.warning {
|
||||
background: #fff3e0;
|
||||
border-color: #ff9800;
|
||||
}
|
||||
|
||||
.tip {
|
||||
background: #e8f5e9;
|
||||
border-color: #4caf50;
|
||||
}
|
||||
```
|
||||
|
||||
## CSS Variables
|
||||
|
||||
Use CSS custom properties for theming:
|
||||
|
||||
### base.css with Variables
|
||||
|
||||
```css
|
||||
:root {
|
||||
/* Colors */
|
||||
--color-primary: #0066cc;
|
||||
--color-secondary: #6c757d;
|
||||
--color-text: #333;
|
||||
--color-background: #fff;
|
||||
--color-border: #dee2e6;
|
||||
|
||||
/* Typography */
|
||||
--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
|
||||
--font-serif: Georgia, serif;
|
||||
--font-mono: 'Monaco', 'Courier New', monospace;
|
||||
|
||||
/* Spacing */
|
||||
--space-xs: 0.5rem;
|
||||
--space-sm: 1rem;
|
||||
--space-md: 2rem;
|
||||
--space-lg: 3rem;
|
||||
|
||||
/* Breakpoints (for reference) */
|
||||
/* Use in @media queries */
|
||||
}
|
||||
|
||||
body {
|
||||
color: var(--color-text);
|
||||
background: var(--color-background);
|
||||
font-family: var(--font-sans);
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
/* ... */
|
||||
```
|
||||
|
||||
### Dark Mode
|
||||
|
||||
```css
|
||||
/* base.css */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-text: #e4e4e4;
|
||||
--color-background: #1a1a1a;
|
||||
--color-border: #333;
|
||||
}
|
||||
}
|
||||
|
||||
/* Or toggle with class */
|
||||
body.dark-mode {
|
||||
--color-text: #e4e4e4;
|
||||
--color-background: #1a1a1a;
|
||||
--color-border: #333;
|
||||
}
|
||||
```
|
||||
|
||||
## Performance Tips
|
||||
|
||||
### 1. Minimize File Size
|
||||
|
||||
```css
|
||||
/* Remove unnecessary spaces/newlines in production */
|
||||
/* Use a CSS minifier */
|
||||
```
|
||||
|
||||
### 2. Avoid @import
|
||||
|
||||
```css
|
||||
/* Slow - additional HTTP request */
|
||||
@import url('components/typography.css');
|
||||
|
||||
/* Better - combine files or use build tool */
|
||||
/* Or let browser load multiple <link> tags in parallel */
|
||||
```
|
||||
|
||||
### 3. Optimize Selectors
|
||||
|
||||
```css
|
||||
/* Fast */
|
||||
.class-name { }
|
||||
#id-name { }
|
||||
|
||||
/* Slower */
|
||||
div > ul > li > a { }
|
||||
[data-attribute="value"] { }
|
||||
|
||||
/* Use classes for styling */
|
||||
```
|
||||
|
||||
### 4. Use Will-Change Sparingly
|
||||
|
||||
```css
|
||||
/* Only for elements that will actually animate */
|
||||
.photo-item {
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.photo-item:hover {
|
||||
transform: translateY(-4px);
|
||||
will-change: transform; /* Hint to browser */
|
||||
}
|
||||
```
|
||||
|
||||
## Debugging Styles
|
||||
|
||||
### Browser DevTools
|
||||
|
||||
1. **Inspect element** - Right-click → Inspect
|
||||
2. **Check computed styles** - See which rules apply
|
||||
3. **See cascade** - Understand override order
|
||||
4. **Live edit** - Test changes instantly
|
||||
|
||||
### Debug Checklist
|
||||
|
||||
**Styles not loading:**
|
||||
- [ ] File exists in `styles/` directory
|
||||
- [ ] Filename matches expected pattern
|
||||
- [ ] No syntax errors in CSS
|
||||
- [ ] Browser cache cleared
|
||||
|
||||
**Styles not applying:**
|
||||
- [ ] Check CSS specificity
|
||||
- [ ] Check cascade order
|
||||
- [ ] Look for typos in selectors
|
||||
- [ ] Verify HTML classes match CSS
|
||||
|
||||
**Wrong styles applying:**
|
||||
- [ ] Check for conflicting rules
|
||||
- [ ] Verify file loading order
|
||||
- [ ] Look for !important (avoid if possible)
|
||||
|
||||
## Next Steps
|
||||
|
||||
- **[Templates Guide](../templates/)** - Templates use these styles
|
||||
- **[Template Discovery](../templates/template-discovery.md)** - How styles are discovered
|
||||
- **[Recipes](../recipes/)** - Complete examples with CSS
|
||||
|
||||
Master the style system to create beautiful, maintainable Foldsites!
|
Reference in New Issue
Block a user