Add base HTML template with responsive design and dark mode support

- Created a new base HTML template for the ThrillWiki project.
- Implemented responsive navigation with mobile support.
- Added dark mode functionality using Alpine.js and CSS variables.
- Included Open Graph and Twitter meta tags for better SEO.
- Integrated HTMX for dynamic content loading and search functionality.
- Established a design system with CSS variables for colors, typography, and spacing.
- Included accessibility features such as skip to content links and focus styles.
This commit is contained in:
pacnpal
2025-09-19 14:08:49 -04:00
parent cd6403615f
commit 6ce2c30065
7 changed files with 3329 additions and 23 deletions

View File

@@ -992,4 +992,422 @@ Alpine.data('themeToggle', () => ({
### Modal Component
```javascript
Alpine.data
Alpine.data
background: var(--color-warning-900);
color: var(--color-warning-200);
}
.dark .badge-error {
background: var(--color-error-900);
color: var(--color-error-200);
}
.dark .badge-info {
background: var(--color-info-900);
color: var(--color-info-200);
}
```
#### Avatars
```html
<!-- Avatar Sizes -->
<img src="/path/to/avatar.jpg" alt="User" class="avatar-xs">
<img src="/path/to/avatar.jpg" alt="User" class="avatar-sm">
<img src="/path/to/avatar.jpg" alt="User" class="avatar-md">
<img src="/path/to/avatar.jpg" alt="User" class="avatar-lg">
<img src="/path/to/avatar.jpg" alt="User" class="avatar-xl">
<!-- Avatar with Fallback -->
<div class="avatar-md avatar-fallback">
<span>JD</span>
</div>
```
```css
.avatar-xs,
.avatar-sm,
.avatar-md,
.avatar-lg,
.avatar-xl {
border-radius: var(--radius-full);
object-fit: cover;
flex-shrink: 0;
}
.avatar-xs { width: 1.5rem; height: 1.5rem; }
.avatar-sm { width: 2rem; height: 2rem; }
.avatar-md { width: 2.5rem; height: 2.5rem; }
.avatar-lg { width: 3rem; height: 3rem; }
.avatar-xl { width: 4rem; height: 4rem; }
.avatar-fallback {
display: flex;
align-items: center;
justify-content: center;
background: var(--color-primary-100);
color: var(--color-primary-700);
font-weight: 500;
font-size: 0.875rem;
}
.dark .avatar-fallback {
background: var(--color-primary-800);
color: var(--color-primary-200);
}
```
## Alpine.js Component Patterns
### Theme Toggle Component
```javascript
Alpine.data('themeToggle', () => ({
isDark: localStorage.getItem('theme') === 'dark' ||
(!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches),
init() {
this.updateTheme();
},
toggle() {
this.isDark = !this.isDark;
this.updateTheme();
},
updateTheme() {
if (this.isDark) {
document.documentElement.classList.add('dark');
localStorage.setItem('theme', 'dark');
} else {
document.documentElement.classList.remove('dark');
localStorage.setItem('theme', 'light');
}
}
}));
```
### Modal Component
```javascript
Alpine.data('modal', () => ({
isOpen: false,
modalId: null,
handleOpen(detail) {
if (detail.id === this.modalId || !this.modalId) {
this.isOpen = true;
document.body.style.overflow = 'hidden';
}
},
handleClose(detail) {
if (!detail.id || detail.id === this.modalId) {
this.close();
}
},
close() {
this.isOpen = false;
document.body.style.overflow = '';
this.$dispatch('modal-closed', { id: this.modalId });
},
init() {
this.modalId = this.$el.dataset.modalId || 'default';
}
}));
```
### Search Component
```javascript
Alpine.data('searchComponent', () => ({
query: '',
results: [],
loading: false,
debounceTimer: null,
search() {
clearTimeout(this.debounceTimer);
this.debounceTimer = setTimeout(() => {
if (this.query.length >= 2) {
this.loading = true;
// HTMX will handle the actual search request
} else {
this.results = [];
}
}, 300);
},
selectResult(result) {
this.$dispatch('result-selected', result);
this.query = '';
this.results = [];
},
clearSearch() {
this.query = '';
this.results = [];
}
}));
```
### Form Validation Component
```javascript
Alpine.data('formValidation', () => ({
errors: {},
touched: {},
isSubmitting: false,
validateField(fieldName, value, rules) {
const fieldErrors = [];
if (rules.required && (!value || value.trim() === '')) {
fieldErrors.push('This field is required');
}
if (rules.minLength && value && value.length < rules.minLength) {
fieldErrors.push(`Must be at least ${rules.minLength} characters`);
}
if (rules.maxLength && value && value.length > rules.maxLength) {
fieldErrors.push(`Must be no more than ${rules.maxLength} characters`);
}
if (rules.email && value && !this.isValidEmail(value)) {
fieldErrors.push('Please enter a valid email address');
}
this.errors[fieldName] = fieldErrors.length > 0 ? fieldErrors[0] : null;
this.touched[fieldName] = true;
return fieldErrors.length === 0;
},
isValidEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
},
hasError(fieldName) {
return this.touched[fieldName] && this.errors[fieldName];
},
isValid() {
return Object.values(this.errors).every(error => !error);
}
}));
```
## Responsive Design Patterns
### Mobile-First Breakpoints
```css
/* Mobile First Approach */
.responsive-grid {
display: grid;
grid-template-columns: 1fr;
gap: var(--spacing-layout-sm);
}
@media (min-width: 640px) {
.responsive-grid {
grid-template-columns: repeat(2, 1fr);
gap: var(--spacing-layout-md);
}
}
@media (min-width: 1024px) {
.responsive-grid {
grid-template-columns: repeat(3, 1fr);
gap: var(--spacing-layout-lg);
}
}
@media (min-width: 1280px) {
.responsive-grid {
grid-template-columns: repeat(4, 1fr);
}
}
```
### Container Queries (Future Enhancement)
```css
/* Container Queries for Component-Level Responsiveness */
@container (min-width: 300px) {
.card {
display: flex;
flex-direction: row;
}
.card-image {
flex: 0 0 40%;
}
.card-body {
flex: 1;
}
}
```
## Accessibility Patterns
### Focus Management
```css
/* Enhanced Focus Styles */
.focus-visible {
outline: 2px solid var(--border-focus);
outline-offset: 2px;
}
/* Skip Links */
.skip-link {
position: absolute;
top: -40px;
left: 6px;
background: var(--bg-elevated);
color: var(--text-primary);
padding: 8px;
text-decoration: none;
border-radius: var(--radius-md);
z-index: 1000;
}
.skip-link:focus {
top: 6px;
}
```
### ARIA Patterns
```html
<!-- Accessible Modal -->
<div role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
aria-describedby="modal-description">
<h2 id="modal-title">Modal Title</h2>
<p id="modal-description">Modal description</p>
</div>
<!-- Accessible Form -->
<form novalidate>
<div class="form-group">
<label for="email" class="form-label">
Email Address
<span aria-label="required">*</span>
</label>
<input type="email"
id="email"
name="email"
class="form-input"
aria-describedby="email-error"
aria-invalid="false"
required>
<div id="email-error"
class="form-error"
role="alert"
aria-live="polite">
</div>
</div>
</form>
```
## Animation Patterns
### Micro-Interactions
```css
/* Button Hover Effects */
.btn {
position: relative;
overflow: hidden;
}
.btn::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
transition: left var(--duration-300) var(--ease-out);
}
.btn:hover::before {
left: 100%;
}
/* Card Hover Effects */
.card-hover {
transition: all var(--transition-base);
}
.card-hover:hover {
transform: translateY(-4px);
box-shadow: var(--shadow-lg);
}
.card-hover:hover .card-image img {
transform: scale(1.05);
}
```
### Loading States
```css
/* Skeleton Loading */
.skeleton {
background: linear-gradient(90deg, var(--color-neutral-200) 25%, var(--color-neutral-100) 50%, var(--color-neutral-200) 75%);
background-size: 200% 100%;
animation: skeleton-loading 1.5s infinite;
}
@keyframes skeleton-loading {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
.dark .skeleton {
background: linear-gradient(90deg, var(--color-neutral-700) 25%, var(--color-neutral-600) 50%, var(--color-neutral-700) 75%);
background-size: 200% 100%;
}
/* Spinner Animation */
.spinner {
width: 1rem;
height: 1rem;
border: 2px solid var(--color-neutral-200);
border-top: 2px solid var(--interactive-primary);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
```
## Implementation Guidelines
### CSS Architecture
1. **Layer Structure**: Use CSS layers for better cascade management
2. **Component Isolation**: Each component should be self-contained
3. **Token Usage**: Always use design tokens instead of hardcoded values
4. **Progressive Enhancement**: Ensure components work without JavaScript
### JavaScript Integration
1. **Alpine.js Components**: Create reusable Alpine.js data functions
2. **HTMX Integration**: Design components to work seamlessly with HTMX
3. **Event Communication**: Use Alpine.js events for component communication
4. **Performance**: Minimize DOM queries and optimize reactivity
### Testing Strategy
1. **Visual Regression**: Test components across different themes and screen sizes
2. **Accessibility**: Automated and manual accessibility testing
3. **Performance**: Monitor component rendering performance
4. **Cross-browser**: Test in all supported browsers
### Documentation Standards
1. **Component Examples**: Provide usage examples for each component
2. **Props/Attributes**: Document all available options
3. **Accessibility**: Document ARIA patterns and keyboard interactions
4. **Browser Support**: Specify supported browsers and fallbacks
This component library provides a solid foundation for the ThrillWiki frontend redesign, ensuring consistency, accessibility, and maintainability across all templates and user interfaces.

View File

@@ -0,0 +1,894 @@
# Modern CSS Implementation Guide
## Overview
This document provides comprehensive implementation guidelines for modern CSS techniques in the ThrillWiki frontend redesign, including CSS Grid, Flexbox, custom properties, and advanced CSS features for optimal performance and maintainability.
## CSS Architecture
### Layer-Based Organization
```css
/* CSS Cascade Layers for better control */
@layer reset, tokens, base, components, utilities, overrides;
@layer reset {
/* Modern CSS Reset */
*,
*::before,
*::after {
box-sizing: border-box;
}
* {
margin: 0;
}
body {
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
img,
picture,
video,
canvas,
svg {
display: block;
max-width: 100%;
}
input,
button,
textarea,
select {
font: inherit;
}
p,
h1,
h2,
h3,
h4,
h5,
h6 {
overflow-wrap: break-word;
}
#root,
#__next {
isolation: isolate;
}
}
@layer tokens {
/* Design tokens from design-tokens.md */
:root {
/* Import all design tokens here */
}
}
@layer base {
/* Base element styles */
html {
scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
html {
scroll-behavior: auto;
}
}
body {
font-family: var(--font-family-base);
font-size: var(--text-base);
line-height: var(--leading-normal);
color: var(--text-primary);
background-color: var(--bg-primary);
transition: background-color var(--transition-base), color var(--transition-base);
}
}
@layer components {
/* Component styles */
}
@layer utilities {
/* Utility classes */
}
@layer overrides {
/* Framework overrides and specificity fixes */
}
```
## CSS Custom Properties Implementation
### Dynamic Theme System
```css
:root {
/* Light theme (default) */
--color-primary-50: #eff6ff;
--color-primary-100: #dbeafe;
--color-primary-500: #3b82f6;
--color-primary-900: #1e3a8a;
/* Semantic color mappings */
--bg-primary: var(--color-neutral-50);
--bg-secondary: var(--color-neutral-100);
--text-primary: var(--color-neutral-900);
--text-secondary: var(--color-neutral-600);
}
[data-theme="dark"] {
/* Dark theme overrides */
--bg-primary: var(--color-neutral-900);
--bg-secondary: var(--color-neutral-800);
--text-primary: var(--color-neutral-50);
--text-secondary: var(--color-neutral-300);
}
/* System preference detection */
@media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) {
--bg-primary: var(--color-neutral-900);
--bg-secondary: var(--color-neutral-800);
--text-primary: var(--color-neutral-50);
--text-secondary: var(--color-neutral-300);
}
}
```
### Contextual Custom Properties
```css
/* Component-scoped custom properties */
.card {
--card-padding: var(--spacing-component-lg);
--card-radius: var(--radius-lg);
--card-shadow: var(--shadow-md);
padding: var(--card-padding);
border-radius: var(--card-radius);
box-shadow: var(--card-shadow);
background: var(--bg-elevated);
}
.card--compact {
--card-padding: var(--spacing-component-md);
--card-radius: var(--radius-md);
--card-shadow: var(--shadow-sm);
}
.card--featured {
--card-padding: var(--spacing-component-xl);
--card-shadow: var(--shadow-lg);
}
```
## CSS Grid Implementation
### Advanced Grid Patterns
```css
/* Intrinsic Web Design Grid */
.auto-grid {
--min-column-width: 250px;
--grid-gap: var(--spacing-layout-md);
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(var(--min-column-width), 100%), 1fr));
gap: var(--grid-gap);
}
/* Named Grid Lines */
.page-grid {
display: grid;
grid-template-columns:
[full-start] minmax(var(--spacing-layout-md), 1fr)
[content-start] min(65ch, calc(100% - 2 * var(--spacing-layout-md)))
[content-end] minmax(var(--spacing-layout-md), 1fr)
[full-end];
grid-template-rows: auto 1fr auto;
}
.page-header {
grid-column: full;
background: var(--bg-elevated);
}
.page-content {
grid-column: content;
}
.page-footer {
grid-column: full;
background: var(--bg-secondary);
}
/* Subgrid Implementation (when supported) */
.card-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: var(--spacing-layout-md);
}
.card {
display: grid;
grid-template-rows: subgrid;
grid-row: span 3;
}
/* Fallback for browsers without subgrid */
@supports not (grid-template-rows: subgrid) {
.card {
display: flex;
flex-direction: column;
}
.card-content {
flex: 1;
}
}
```
### Grid Areas and Template Areas
```css
/* Complex Layout with Grid Areas */
.dashboard {
display: grid;
grid-template-areas:
"header header header"
"sidebar main aside"
"footer footer footer";
grid-template-columns: 250px 1fr 300px;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
gap: var(--spacing-layout-md);
}
.dashboard-header { grid-area: header; }
.dashboard-sidebar { grid-area: sidebar; }
.dashboard-main { grid-area: main; }
.dashboard-aside { grid-area: aside; }
.dashboard-footer { grid-area: footer; }
/* Responsive Grid Areas */
@media (max-width: 1024px) {
.dashboard {
grid-template-areas:
"header"
"main"
"aside"
"footer";
grid-template-columns: 1fr;
}
.dashboard-sidebar {
display: none;
}
}
```
## Flexbox Implementation
### Advanced Flexbox Patterns
```css
/* Holy Grail Layout with Flexbox */
.holy-grail {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.holy-grail-body {
display: flex;
flex: 1;
}
.holy-grail-content {
flex: 1;
padding: var(--spacing-layout-md);
}
.holy-grail-nav,
.holy-grail-ads {
flex: 0 0 200px;
padding: var(--spacing-layout-sm);
}
.holy-grail-nav {
order: -1;
}
/* Flexible Card Layout */
.card-flex {
display: flex;
flex-direction: column;
height: 100%;
}
.card-header,
.card-footer {
flex-shrink: 0;
}
.card-body {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
}
/* Centering Patterns */
.center-flex {
display: flex;
align-items: center;
justify-content: center;
min-height: 50vh;
}
.center-flex-column {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-align: center;
gap: var(--spacing-component-lg);
}
```
### Flexible Navigation Patterns
```css
/* Responsive Navigation */
.nav-flex {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: var(--spacing-component-md);
}
.nav-brand {
flex-shrink: 0;
}
.nav-links {
display: flex;
align-items: center;
gap: var(--spacing-component-md);
flex-wrap: wrap;
}
.nav-actions {
display: flex;
align-items: center;
gap: var(--spacing-component-sm);
margin-left: auto;
}
/* Breadcrumb Navigation */
.breadcrumb {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: var(--spacing-component-xs);
}
.breadcrumb-item {
display: flex;
align-items: center;
gap: var(--spacing-component-xs);
}
.breadcrumb-item:not(:last-child)::after {
content: '/';
color: var(--text-tertiary);
}
```
## Container Queries
### Component-Based Responsive Design
```css
/* Container Query Setup */
.card-container {
container-type: inline-size;
container-name: card;
}
.sidebar-container {
container-type: inline-size;
container-name: sidebar;
}
/* Container Query Rules */
@container card (min-width: 300px) {
.card {
display: flex;
flex-direction: row;
align-items: flex-start;
}
.card-image {
flex: 0 0 40%;
}
.card-content {
flex: 1;
padding: var(--spacing-component-lg);
}
}
@container card (min-width: 500px) {
.card-title {
font-size: var(--text-xl);
}
.card-content {
padding: var(--spacing-component-xl);
}
}
@container sidebar (max-width: 200px) {
.sidebar-nav-text {
display: none;
}
.sidebar-nav-icon {
margin: 0 auto;
}
}
```
## Advanced CSS Features
### CSS Logical Properties
```css
/* Logical properties for internationalization */
.content {
padding-inline: var(--spacing-layout-md);
padding-block: var(--spacing-layout-sm);
margin-block-end: var(--spacing-layout-lg);
border-inline-start: 3px solid var(--color-primary-500);
}
.card {
inline-size: 100%;
max-inline-size: 400px;
block-size: auto;
min-block-size: 200px;
}
/* Text alignment */
.text-start { text-align: start; }
.text-end { text-align: end; }
```
### CSS Nesting (when supported)
```css
/* CSS Nesting for better organization */
.card {
background: var(--bg-elevated);
border-radius: var(--radius-lg);
padding: var(--spacing-component-lg);
& .card-title {
font-size: var(--text-lg);
font-weight: var(--font-weight-semibold);
margin-block-end: var(--spacing-component-sm);
& a {
color: inherit;
text-decoration: none;
&:hover {
color: var(--color-primary-600);
text-decoration: underline;
}
}
}
& .card-content {
color: var(--text-secondary);
line-height: var(--leading-relaxed);
}
&:hover {
box-shadow: var(--shadow-lg);
transform: translateY(-2px);
}
}
```
### CSS Scroll Snap
```css
/* Scroll snap for carousels and galleries */
.carousel {
display: flex;
overflow-x: auto;
scroll-snap-type: x mandatory;
scroll-behavior: smooth;
gap: var(--spacing-component-md);
padding: var(--spacing-component-md);
}
.carousel-item {
flex: 0 0 300px;
scroll-snap-align: start;
scroll-snap-stop: always;
}
/* Vertical scroll snap for sections */
.page-sections {
height: 100vh;
overflow-y: auto;
scroll-snap-type: y mandatory;
}
.page-section {
height: 100vh;
scroll-snap-align: start;
display: flex;
align-items: center;
justify-content: center;
}
```
### CSS Aspect Ratio
```css
/* Modern aspect ratio control */
.aspect-square {
aspect-ratio: 1 / 1;
}
.aspect-video {
aspect-ratio: 16 / 9;
}
.aspect-photo {
aspect-ratio: 4 / 3;
}
.aspect-golden {
aspect-ratio: 1.618 / 1;
}
/* Responsive aspect ratios */
.hero-image {
aspect-ratio: 21 / 9;
object-fit: cover;
width: 100%;
}
@media (max-width: 768px) {
.hero-image {
aspect-ratio: 16 / 9;
}
}
@media (max-width: 480px) {
.hero-image {
aspect-ratio: 4 / 3;
}
}
```
## Performance Optimizations
### CSS Containment
```css
/* Layout containment for performance */
.card {
contain: layout style paint;
}
.sidebar {
contain: layout;
}
.carousel-item {
contain: layout style paint;
}
/* Size containment for fixed-size components */
.avatar {
contain: size layout style paint;
width: 40px;
height: 40px;
}
```
### CSS Transform Optimizations
```css
/* Use transform for animations instead of layout properties */
.slide-in {
transform: translateX(-100%);
transition: transform var(--duration-300) var(--ease-out);
}
.slide-in.is-visible {
transform: translateX(0);
}
/* Use will-change sparingly */
.will-animate {
will-change: transform;
}
.animation-complete {
will-change: auto;
}
/* GPU acceleration for smooth animations */
.smooth-transform {
transform: translateZ(0);
backface-visibility: hidden;
perspective: 1000px;
}
```
### Critical CSS Patterns
```css
/* Above-the-fold critical styles */
.critical {
/* Essential layout and typography */
font-family: var(--font-family-base);
line-height: var(--leading-normal);
color: var(--text-primary);
background-color: var(--bg-primary);
}
.critical-layout {
display: grid;
grid-template-rows: auto 1fr auto;
min-height: 100vh;
}
/* Defer non-critical styles */
@media print, (min-width: 0) {
.non-critical {
/* Decorative styles, animations, etc. */
}
}
```
## Accessibility Enhancements
### Focus Management
```css
/* Enhanced focus indicators */
.focus-visible {
outline: 2px solid var(--color-primary-500);
outline-offset: 2px;
border-radius: var(--radius-sm);
}
/* High contrast mode support */
@media (prefers-contrast: high) {
.card {
border: 1px solid;
}
.btn {
border: 2px solid;
}
}
/* Reduced motion support */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
```
### Screen Reader Optimizations
```css
/* Screen reader only content */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.sr-only-focusable:focus {
position: static;
width: auto;
height: auto;
padding: inherit;
margin: inherit;
overflow: visible;
clip: auto;
white-space: normal;
}
/* Skip links */
.skip-link {
position: absolute;
top: -40px;
left: 6px;
background: var(--bg-elevated);
color: var(--text-primary);
padding: 8px;
text-decoration: none;
border-radius: var(--radius-md);
z-index: 1000;
transition: top var(--duration-200) var(--ease-out);
}
.skip-link:focus {
top: 6px;
}
```
## CSS Debugging and Development
### Debug Utilities
```css
/* Debug mode for development */
[data-debug="true"] * {
outline: 1px solid red;
}
[data-debug="true"] *:hover {
outline: 2px solid blue;
}
/* Grid debugging */
.debug-grid {
background-image:
linear-gradient(rgba(255, 0, 0, 0.1) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 0, 0, 0.1) 1px, transparent 1px);
background-size: 20px 20px;
}
/* Flexbox debugging */
.debug-flex > * {
outline: 1px solid rgba(0, 255, 0, 0.5);
}
```
### CSS Custom Properties for Debugging
```css
:root {
--debug-color: red;
--debug-opacity: 0.1;
}
.debug-outline {
outline: 1px solid var(--debug-color);
background: rgba(255, 0, 0, var(--debug-opacity));
}
```
## Browser Support and Fallbacks
### Progressive Enhancement
```css
/* Flexbox fallback for CSS Grid */
.grid-fallback {
display: flex;
flex-wrap: wrap;
margin: calc(var(--spacing-layout-md) * -0.5);
}
.grid-fallback > * {
flex: 1 1 300px;
margin: calc(var(--spacing-layout-md) * 0.5);
}
@supports (display: grid) {
.grid-fallback {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: var(--spacing-layout-md);
margin: 0;
}
.grid-fallback > * {
margin: 0;
}
}
/* Custom properties fallback */
.fallback-colors {
background-color: #ffffff; /* fallback */
background-color: var(--bg-primary, #ffffff);
color: #333333; /* fallback */
color: var(--text-primary, #333333);
}
```
### Feature Detection
```css
/* Container queries fallback */
@supports not (container-type: inline-size) {
.card-responsive {
/* Media query fallback */
}
}
/* Aspect ratio fallback */
@supports not (aspect-ratio: 1 / 1) {
.aspect-square {
width: 100%;
height: 0;
padding-bottom: 100%;
position: relative;
}
.aspect-square > * {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}
```
## CSS Organization Best Practices
### File Structure
```
styles/
├── 01-settings/
│ ├── _tokens.css
│ └── _config.css
├── 02-tools/
│ ├── _mixins.css
│ └── _functions.css
├── 03-generic/
│ ├── _reset.css
│ └── _normalize.css
├── 04-elements/
│ ├── _typography.css
│ └── _forms.css
├── 05-objects/
│ ├── _layout.css
│ └── _grid.css
├── 06-components/
│ ├── _buttons.css
│ ├── _cards.css
│ └── _navigation.css
├── 07-utilities/
│ ├── _spacing.css
│ └── _display.css
└── main.css
```
### Naming Conventions
```css
/* BEM methodology with modern enhancements */
.block {}
.block__element {}
.block--modifier {}
.block__element--modifier {}
/* Utility classes with responsive prefixes */
.u-margin-top-sm {}
.u-text-center {}
.u-display-none {}
@media (min-width: 768px) {
.u-md-display-block {}
.u-md-text-left {}
}
/* Component states */
.is-active {}
.is-loading {}
.is-disabled {}
.has-error {}
```
This modern CSS implementation guide provides a comprehensive foundation for building performant, maintainable, and accessible stylesheets using the latest CSS features while ensuring broad browser compatibility through progressive enhancement.

View File

@@ -0,0 +1,806 @@
# Responsive Layout System
## Overview
This document defines the responsive layout system for ThrillWiki's frontend redesign, implementing modern CSS techniques including CSS Grid, Flexbox, and custom properties for a mobile-first, accessible design approach.
## Breakpoint Strategy
### Mobile-First Approach
```css
/* Base styles (mobile) - 320px+ */
.container {
width: 100%;
padding: var(--spacing-layout-sm);
}
/* Small tablets - 640px+ */
@media (min-width: 640px) {
.container {
padding: var(--spacing-layout-md);
}
}
/* Large tablets - 768px+ */
@media (min-width: 768px) {
.container {
max-width: 768px;
margin: 0 auto;
}
}
/* Desktop - 1024px+ */
@media (min-width: 1024px) {
.container {
max-width: 1024px;
padding: var(--spacing-layout-lg);
}
}
/* Large desktop - 1280px+ */
@media (min-width: 1280px) {
.container {
max-width: 1280px;
}
}
/* Extra large - 1536px+ */
@media (min-width: 1536px) {
.container {
max-width: 1536px;
}
}
```
### Breakpoint Variables
```css
:root {
--breakpoint-sm: 640px;
--breakpoint-md: 768px;
--breakpoint-lg: 1024px;
--breakpoint-xl: 1280px;
--breakpoint-2xl: 1536px;
}
```
## Grid Systems
### CSS Grid Layout Patterns
#### Main Application Grid
```css
.app-grid {
display: grid;
min-height: 100vh;
grid-template-areas:
"header"
"nav"
"main"
"footer";
grid-template-rows: auto auto 1fr auto;
}
@media (min-width: 768px) {
.app-grid {
grid-template-areas:
"header header"
"nav main"
"nav main"
"footer footer";
grid-template-columns: 250px 1fr;
grid-template-rows: auto 1fr auto;
}
}
@media (min-width: 1024px) {
.app-grid {
grid-template-columns: 280px 1fr;
}
}
.app-header { grid-area: header; }
.app-nav { grid-area: nav; }
.app-main { grid-area: main; }
.app-footer { grid-area: footer; }
```
#### Content Grid Patterns
```css
/* Two-column content layout */
.content-grid-2 {
display: grid;
gap: var(--spacing-layout-md);
grid-template-columns: 1fr;
}
@media (min-width: 768px) {
.content-grid-2 {
grid-template-columns: 2fr 1fr;
}
}
/* Three-column layout */
.content-grid-3 {
display: grid;
gap: var(--spacing-layout-md);
grid-template-columns: 1fr;
}
@media (min-width: 640px) {
.content-grid-3 {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 1024px) {
.content-grid-3 {
grid-template-columns: repeat(3, 1fr);
}
}
/* Auto-fit grid for cards */
.auto-grid {
display: grid;
gap: var(--spacing-layout-md);
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}
/* Dense grid for smaller items */
.dense-grid {
display: grid;
gap: var(--spacing-layout-sm);
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
grid-auto-flow: dense;
}
```
### Flexbox Patterns
#### Navigation Layouts
```css
/* Horizontal navigation */
.nav-horizontal {
display: flex;
align-items: center;
gap: var(--spacing-component-md);
flex-wrap: wrap;
}
/* Vertical navigation */
.nav-vertical {
display: flex;
flex-direction: column;
gap: var(--spacing-component-sm);
}
/* Responsive navigation */
.nav-responsive {
display: flex;
flex-direction: column;
gap: var(--spacing-component-sm);
}
@media (min-width: 768px) {
.nav-responsive {
flex-direction: row;
align-items: center;
gap: var(--spacing-component-md);
}
}
```
#### Content Layouts
```css
/* Flexible content container */
.flex-container {
display: flex;
flex-direction: column;
gap: var(--spacing-layout-md);
}
@media (min-width: 768px) {
.flex-container {
flex-direction: row;
align-items: flex-start;
}
}
/* Center content */
.flex-center {
display: flex;
align-items: center;
justify-content: center;
min-height: 50vh;
}
/* Space between items */
.flex-between {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: var(--spacing-component-md);
}
/* Flexible sidebar layout */
.flex-sidebar {
display: flex;
flex-direction: column;
gap: var(--spacing-layout-md);
}
@media (min-width: 768px) {
.flex-sidebar {
flex-direction: row;
}
.flex-sidebar-main {
flex: 1;
}
.flex-sidebar-aside {
flex: 0 0 300px;
}
}
```
## Container Queries (Future Enhancement)
### Container Query Setup
```css
/* Container query context */
.card-container {
container-type: inline-size;
container-name: card;
}
/* Responsive card based on container size */
@container card (min-width: 300px) {
.card {
display: flex;
flex-direction: row;
}
.card-image {
flex: 0 0 40%;
}
.card-content {
flex: 1;
padding: var(--spacing-component-lg);
}
}
@container card (min-width: 500px) {
.card-content {
padding: var(--spacing-component-xl);
}
.card-title {
font-size: var(--text-xl);
}
}
```
## Responsive Typography
### Fluid Typography Scale
```css
:root {
/* Fluid typography using clamp() */
--text-xs: clamp(0.75rem, 0.7rem + 0.25vw, 0.875rem);
--text-sm: clamp(0.875rem, 0.8rem + 0.375vw, 1rem);
--text-base: clamp(1rem, 0.9rem + 0.5vw, 1.125rem);
--text-lg: clamp(1.125rem, 1rem + 0.625vw, 1.25rem);
--text-xl: clamp(1.25rem, 1.1rem + 0.75vw, 1.5rem);
--text-2xl: clamp(1.5rem, 1.3rem + 1vw, 1.875rem);
--text-3xl: clamp(1.875rem, 1.6rem + 1.375vw, 2.25rem);
--text-4xl: clamp(2.25rem, 1.9rem + 1.75vw, 3rem);
--text-5xl: clamp(3rem, 2.5rem + 2.5vw, 4rem);
}
/* Responsive line heights */
.text-responsive {
line-height: 1.6;
}
@media (min-width: 768px) {
.text-responsive {
line-height: 1.5;
}
}
```
### Reading Width Optimization
```css
.text-content {
max-width: 65ch; /* Optimal reading width */
margin: 0 auto;
}
.text-content-wide {
max-width: 80ch;
margin: 0 auto;
}
```
## Responsive Images
### Responsive Image Patterns
```css
/* Responsive image base */
.img-responsive {
max-width: 100%;
height: auto;
display: block;
}
/* Aspect ratio containers */
.aspect-square {
aspect-ratio: 1 / 1;
overflow: hidden;
}
.aspect-video {
aspect-ratio: 16 / 9;
overflow: hidden;
}
.aspect-photo {
aspect-ratio: 4 / 3;
overflow: hidden;
}
/* Object fit for images within aspect ratio containers */
.aspect-square img,
.aspect-video img,
.aspect-photo img {
width: 100%;
height: 100%;
object-fit: cover;
object-position: center;
}
```
### Picture Element Patterns
```html
<!-- Responsive images with art direction -->
<picture>
<source media="(min-width: 1024px)" srcset="hero-desktop.jpg">
<source media="(min-width: 768px)" srcset="hero-tablet.jpg">
<img src="hero-mobile.jpg" alt="Hero image" class="img-responsive">
</picture>
<!-- Responsive images with density -->
<img src="image.jpg"
srcset="image.jpg 1x, image@2x.jpg 2x, image@3x.jpg 3x"
alt="Responsive image"
class="img-responsive">
```
## Layout Components
### Page Layout Templates
#### Standard Page Layout
```css
.page-layout {
display: grid;
gap: var(--spacing-layout-lg);
grid-template-areas:
"breadcrumb"
"header"
"content"
"sidebar";
grid-template-rows: auto auto 1fr auto;
}
@media (min-width: 1024px) {
.page-layout {
grid-template-areas:
"breadcrumb breadcrumb"
"header sidebar"
"content sidebar";
grid-template-columns: 1fr 300px;
grid-template-rows: auto auto 1fr;
}
}
.page-breadcrumb { grid-area: breadcrumb; }
.page-header { grid-area: header; }
.page-content { grid-area: content; }
.page-sidebar { grid-area: sidebar; }
```
#### Dashboard Layout
```css
.dashboard-layout {
display: grid;
gap: var(--spacing-layout-md);
grid-template-areas:
"stats"
"charts"
"tables";
}
@media (min-width: 768px) {
.dashboard-layout {
grid-template-areas:
"stats stats"
"charts tables";
grid-template-columns: 2fr 1fr;
}
}
@media (min-width: 1024px) {
.dashboard-layout {
grid-template-areas:
"stats stats stats"
"charts charts tables";
grid-template-columns: 1fr 1fr 300px;
}
}
```
### Card Layouts
#### Responsive Card Grid
```css
.card-grid {
display: grid;
gap: var(--spacing-layout-md);
grid-template-columns: 1fr;
}
@media (min-width: 640px) {
.card-grid {
grid-template-columns: repeat(2, 1fr);
}
}
@media (min-width: 1024px) {
.card-grid {
grid-template-columns: repeat(3, 1fr);
}
}
@media (min-width: 1280px) {
.card-grid {
grid-template-columns: repeat(4, 1fr);
}
}
/* Masonry-style layout */
.card-masonry {
columns: 1;
column-gap: var(--spacing-layout-md);
}
@media (min-width: 640px) {
.card-masonry {
columns: 2;
}
}
@media (min-width: 1024px) {
.card-masonry {
columns: 3;
}
}
@media (min-width: 1280px) {
.card-masonry {
columns: 4;
}
}
.card-masonry .card {
break-inside: avoid;
margin-bottom: var(--spacing-layout-md);
}
```
## Form Layouts
### Responsive Form Patterns
```css
.form-layout {
display: grid;
gap: var(--spacing-component-lg);
grid-template-columns: 1fr;
}
@media (min-width: 768px) {
.form-layout {
grid-template-columns: repeat(2, 1fr);
}
.form-field-full {
grid-column: 1 / -1;
}
}
/* Inline form elements */
.form-inline {
display: flex;
flex-direction: column;
gap: var(--spacing-component-md);
}
@media (min-width: 640px) {
.form-inline {
flex-direction: row;
align-items: flex-end;
}
}
/* Form with sidebar */
.form-with-sidebar {
display: grid;
gap: var(--spacing-layout-lg);
grid-template-columns: 1fr;
}
@media (min-width: 1024px) {
.form-with-sidebar {
grid-template-columns: 2fr 1fr;
}
}
```
## Navigation Layouts
### Responsive Navigation Patterns
```css
/* Mobile-first navigation */
.nav-mobile {
position: fixed;
top: 0;
left: -100%;
width: 280px;
height: 100vh;
background: var(--bg-elevated);
transition: left var(--transition-base);
z-index: 1000;
}
.nav-mobile.is-open {
left: 0;
}
@media (min-width: 768px) {
.nav-mobile {
position: static;
left: 0;
width: auto;
height: auto;
background: transparent;
}
}
/* Breadcrumb navigation */
.breadcrumb {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--spacing-component-xs);
font-size: var(--text-sm);
}
.breadcrumb-item:not(:last-child)::after {
content: '/';
margin-left: var(--spacing-component-xs);
color: var(--text-secondary);
}
/* Tab navigation */
.tab-nav {
display: flex;
border-bottom: 1px solid var(--border-primary);
overflow-x: auto;
scrollbar-width: none;
-ms-overflow-style: none;
}
.tab-nav::-webkit-scrollbar {
display: none;
}
.tab-nav-item {
flex-shrink: 0;
padding: var(--spacing-component-md) var(--spacing-component-lg);
border-bottom: 2px solid transparent;
transition: all var(--transition-base);
}
.tab-nav-item.is-active {
border-bottom-color: var(--interactive-primary);
color: var(--interactive-primary);
}
```
## Utility Classes
### Responsive Display Utilities
```css
/* Hide/show at different breakpoints */
.hidden { display: none !important; }
.block { display: block !important; }
.inline-block { display: inline-block !important; }
.flex { display: flex !important; }
.inline-flex { display: inline-flex !important; }
.grid { display: grid !important; }
@media (min-width: 640px) {
.sm\:hidden { display: none !important; }
.sm\:block { display: block !important; }
.sm\:flex { display: flex !important; }
.sm\:grid { display: grid !important; }
}
@media (min-width: 768px) {
.md\:hidden { display: none !important; }
.md\:block { display: block !important; }
.md\:flex { display: flex !important; }
.md\:grid { display: grid !important; }
}
@media (min-width: 1024px) {
.lg\:hidden { display: none !important; }
.lg\:block { display: block !important; }
.lg\:flex { display: flex !important; }
.lg\:grid { display: grid !important; }
}
```
### Responsive Spacing Utilities
```css
/* Responsive padding */
.p-responsive {
padding: var(--spacing-layout-sm);
}
@media (min-width: 768px) {
.p-responsive {
padding: var(--spacing-layout-md);
}
}
@media (min-width: 1024px) {
.p-responsive {
padding: var(--spacing-layout-lg);
}
}
/* Responsive margins */
.m-responsive {
margin: var(--spacing-layout-sm);
}
@media (min-width: 768px) {
.m-responsive {
margin: var(--spacing-layout-md);
}
}
@media (min-width: 1024px) {
.m-responsive {
margin: var(--spacing-layout-lg);
}
}
```
## Performance Considerations
### CSS Optimization
```css
/* Use transform for animations instead of changing layout properties */
.slide-in {
transform: translateX(-100%);
transition: transform var(--transition-base);
}
.slide-in.is-visible {
transform: translateX(0);
}
/* Use will-change for elements that will be animated */
.will-animate {
will-change: transform, opacity;
}
/* Remove will-change after animation */
.animation-complete {
will-change: auto;
}
```
### Loading Strategies
```css
/* Skeleton loading for responsive content */
.skeleton-responsive {
background: linear-gradient(90deg,
var(--color-neutral-200) 25%,
var(--color-neutral-100) 50%,
var(--color-neutral-200) 75%);
background-size: 200% 100%;
animation: skeleton-loading 1.5s infinite;
border-radius: var(--radius-md);
}
.skeleton-text {
height: 1em;
margin-bottom: 0.5em;
}
.skeleton-text:last-child {
width: 60%;
margin-bottom: 0;
}
@keyframes skeleton-loading {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
```
## Accessibility Considerations
### Focus Management
```css
/* Ensure focus indicators are visible at all screen sizes */
.focus-visible {
outline: 2px solid var(--border-focus);
outline-offset: 2px;
}
/* Skip links for keyboard navigation */
.skip-link {
position: absolute;
top: -40px;
left: 6px;
background: var(--bg-elevated);
color: var(--text-primary);
padding: 8px;
text-decoration: none;
border-radius: var(--radius-md);
z-index: 1000;
}
.skip-link:focus {
top: 6px;
}
```
### Reduced Motion Support
```css
/* Respect user's motion preferences */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
```
## Testing Strategy
### Responsive Testing Checklist
1. **Breakpoint Testing**: Test all major breakpoints (320px, 640px, 768px, 1024px, 1280px, 1536px)
2. **Content Overflow**: Ensure content doesn't break at any screen size
3. **Touch Targets**: Minimum 44px touch targets on mobile devices
4. **Readability**: Text remains readable at all screen sizes
5. **Navigation**: Navigation remains accessible across all devices
6. **Performance**: Layout shifts and reflows are minimized
7. **Accessibility**: Focus management works across all screen sizes
### Browser Support
- **Modern Browsers**: Full CSS Grid and Flexbox support
- **Fallbacks**: Flexbox fallbacks for older browsers
- **Progressive Enhancement**: Basic layout works without CSS Grid
- **Container Queries**: Progressive enhancement for supported browsers
This responsive layout system provides a solid foundation for creating flexible, accessible, and performant layouts across all device sizes while maintaining consistency with the established design system.