This document outlines our hybrid styling approach using Tailwind CSS and PostCSS, with custom functions and utilities ported from our previous SASS setup.
Our styling system combines the utility-first approach of Tailwind CSS with custom PostCSS functions and configuration to maintain pixel-perfect designs across different viewport sizes. The system is designed to be responsive, maintainable, and developer-friendly.
styles/
├── css/ # Base CSS files including root variables
├── scripts/ # Style generation and PostCSS function scripts
├── colors.ts # Color definitions and themes
├── config.ts # Central configuration export
├── easings.ts # Animation easing functions
├── fonts.ts # Typography configurations
├── layout.mjs # Layout and breakpoint definitions
└── typography.ts # Typography system settings
We provide custom PostCSS functions for converting pixel values to viewport units:
mobile-vw(pixels)
: Converts pixels to vw units for mobile viewportsmobile-vh(pixels)
: Converts pixels to vh units for mobile viewportsdesktop-vw(pixels)
: Converts pixels to vw units for desktop viewportsdesktop-vh(pixels)
: Converts pixels to vh units for desktop viewports
Example usage in CSS:
.element {
width: mobile-vw(375);
height: mobile-vh(100);
}
We implement a custom column-based grid system using CSS custom properties:
- Mobile: 4-column grid (depending on layout.mjs config)
- Desktop: 12-column grid (depending on layout.mjs config)
The columns()
function helps calculate widths based on the number of columns:
.element {
width: columns(3); /* Spans 3 columns + gaps */
}
We use custom media queries for responsive design:
@custom-media --mobile (width <= 799.98px);
@custom-media --desktop (width >= 800px);
Usage:
.element {
@media (--mobile) {
/* Mobile styles */
}
@media (--desktop) {
/* Desktop styles */
}
}
We use the tailwind v4.0 introduced @utility directive to create our own custom tailwind utilities. This basic gist of it is that you can prefix classic tailwind classes with an "s" to make it a scaling utility based on the current viewport. The number after the dash is the value in pixels for the current viewport. There are custom utilities for all tailwind classes that are related to sizing, spacing, etc.
Example:
<div className="sw-150">
<!-- This will be 150px relative to the current viewport off mobile or desktop -->
</div>
Special utilites for column based sizes ending in -col-* are available. They will set a value based on the number of columns and the current viewport.
Example:
<div className="w-col-4">
<!-- This will be 4 columns wide relative to the current viewport off mobile or desktop -->
</div>
Our root.css defines various CSS custom properties for:
- Viewport dimensions
- Grid configuration
- Spacing
- Header heights
- Easing functions
These variables automatically adjust based on viewport size.
We use several PostCSS plugins to enhance our CSS capabilities:
@tailwindcss/postcss
: Tailwind CSS processing@csstools/postcss-global-data
: Global CSS contextpostcss-extend-rule
: CSS extension capabilities- Custom PostCSS functions
postcss-preset-env
: Modern CSS featurescssnano
: CSS optimization (production only)
-
Use Tailwind First: Start with Tailwind utilities for common styles. Only create custom CSS when needed for specific designs or components.
-
Responsive Design:
- Use our custom viewport functions for pixel-perfect conversions
- Leverage the built-in breakpoint system
- Test designs at both mobile and desktop breakpoints
-
Custom Properties:
- Access theme values through CSS custom properties
- Use the columns() function for grid-based layouts
- Leverage predefined easing functions for animations
-
Performance:
- Minimize custom CSS where possible
- Use @apply for frequently repeated utility combinations
- Leverage CSS composition over inheritance
The CSS directory contains the core stylesheets of the system:
global.css
: Global styles and base layer customizationsindex.css
: Main entry point that imports and orders all CSS filesreset.css
: CSS reset and normalizationroot.css
: Generated CSS custom properties (DO NOT EDIT DIRECTLY)tailwind.css
: Generated Tailwind utilities (DO NOT EDIT DIRECTLY)
Note: Files marked with "DO NOT EDIT DIRECTLY" are automatically generated by the setup scripts. Make changes to the source configuration files instead.
The scripts directory contains the build and generation tools:
-
generate-root.ts
: Generates CSS custom properties from your configuration files- Creates CSS variables for colors, typography, spacing, etc.
- Outputs to
root.css
-
generate-scale.ts
: Creates consistent scaling utilities- Generates size scales for spacing, typography, etc.
- Used in combination with Tailwind's configuration
-
generate-tailwind.ts
: Configures Tailwind CSS- Merges your custom configuration with Tailwind's defaults
- Sets up custom utilities, variants, and themes
-
postcss-functions.mjs
: Custom PostCSS functions for responsive units- Implements
mobile-vw()
,desktop-vw()
, etc. - Handles viewport-based calculations
- Implements
-
setup-styles.ts
: Main orchestration script- Runs all generation scripts in the correct order
- Creates the final CSS output files
- Updates necessary configurations
When customizing the styling system:
- Modify the source configuration files (
colors.ts
,typography.ts
, etc.) - Run
bun setup:styles
to regenerate the CSS files - Never edit the generated files directly as changes will be lost
.component {
width: mobile-vw(335);
margin: 0 auto;
@media (--desktop) {
width: desktop-vw(1200);
}
}
.grid-element {
width: columns(2);
margin-right: var(--gap);
@media (--desktop) {
width: columns(4);
}
}
The styles/scripts/
directory contains various utilities:
generate-root.ts
: Generates CSS custom propertiesgenerate-scale.ts
: Creates consistent scaling utilitiesgenerate-tailwind.ts
: Configures Tailwind settingspostcss-functions.mjs
: Custom PostCSS functionssetup-styles.ts
: Style system initialization
When adding new styles:
- Check if Tailwind utilities can achieve the desired effect
- Use custom PostCSS functions for viewport-specific measurements
- Add new variables to the appropriate configuration file
- Update this documentation for significant changes
For questions or clarification, consult the team lead or reference this documentation.
Since this is a template repository, you'll likely need to adjust various aspects of the styling system to match your project's design requirements. Here's how to customize key components:
The typography system is defined in typography.ts
. To customize:
- Define your font families in the
fonts
object:
const fonts = {
sans: '--font-sans',
mono: '--font-mono',
display: '--font-display',
// Add your custom font variables
} as const
- Define typography styles in the
typography
object:
const typography = {
'heading-1': {
'font-family': fonts.sans,
'font-style': 'normal',
'font-weight': 700,
'line-height': '120%',
'letter-spacing': -0.5,
'font-size': 48,
},
// Add more typography styles
} as const
The layout system controls breakpoints, grid settings, and spacing. Customize in layout.mjs
:
- Adjust breakpoints:
const breakpoints = {
dt: 800, // Desktop breakpoint
// Add more breakpoints if needed
}
- Modify viewport sizes:
const screens = {
mobile: { width: 375, height: 650 }, // Default mobile viewport
desktop: { width: 1440, height: 816 }, // Default desktop viewport
}
- Customize grid settings:
const layout = {
columns: {
mobile: 4, // Number of columns for mobile
desktop: 12, // Number of columns for desktop
},
gap: {
mobile: 16, // Gap between columns (mobile)
desktop: 16, // Gap between columns (desktop)
},
space: {
mobile: 16, // Page margin (mobile)
desktop: 16, // Page margin (desktop)
},
}
To customize the color system:
- Define your color palette
- Set up themes for light/dark mode
- Add any additional color variants
Example:
const colors = {
primary: '#000000',
secondary: '#FFFFFF',
// Add your color palette
} as const
const themes = {
light: {
background: colors.white,
text: colors.black,
// Define light theme colors
},
dark: {
background: colors.black,
text: colors.white,
// Define dark theme colors
},
} as const
Customize animation timing functions in easings.ts
:
const easings = {
'ease-in-out': 'cubic-bezier(0.4, 0, 0.2, 1)',
'bounce': 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
// Add custom easing functions
} as const
After customizing these configurations:
- Run the style generation script:
bun setup:styles
# or
npm run setup:styles
This will:
- Update root CSS variables
- Regenerate Tailwind configuration
- Update type definitions
Note: This project uses Bun as the JavaScript runtime. Make sure you have Bun installed on your system. If you don't have Bun installed, you can install it by following the instructions at bun.sh.
After customization:
- Check responsive layouts at different breakpoints
- Verify typography scales across viewports
- Test color themes and transitions
- Validate grid system with example components
Remember to update any existing components that might be affected by your customizations.