A PostCSS plugin for creating fluid and responsive CSS values with granular breakpoint control
Features • Installation • Usage • Examples • Contributing
PostCSS Flow is a powerful plugin that simplifies responsive design by transforming a simple flow() function into fluid CSS values with automatic media queries. Write responsive styles in a single line instead of managing multiple breakpoints manually.
.heading {
font-size: clamp(20px, calc(20px + (30 - 20) * ((100vw - 834px) / 606)), 30px);
}
@media (width <= 834px) {
.heading {
font-size: clamp(10px, calc(10px + (20 - 10) * ((100vw - 360px) / 474)), 20px);
}
}.heading {
font-size: flow(10-360, 20-834, 30-1440);
}- Fluid Values: Automatically generates
clamp()functions with linear interpolation - Fixed Values: Define fixed breakpoints with the
-0suffix - Desktop First: Exclusive desktop-first approach with automatic breakpoint sorting
- Auto-Sorting: Breakpoints are automatically ordered from largest to smallest viewport
- Auto Media Queries: Generates necessary media queries using
width <= - Simple Syntax: One line instead of multiple declarations and media queries
- Zero Dependencies: Lightweight and efficient
Install via npm:
npm install @soyleninjs/postcss-flow --save-devOr using yarn:
yarn add @soyleninjs/postcss-flow --devOr using pnpm:
pnpm add @soyleninjs/postcss-flow --save-devAdd the plugin to your PostCSS configuration:
postcss.config.js (Array syntax)
module.exports = {
plugins: [
require('@soyleninjs/postcss-flow'),
// other plugins...
]
}postcss.config.js (Object syntax)
module.exports = {
plugins: {
'@soyleninjs/postcss-flow': {},
// other plugins...
}
}.element {
property: flow(value1-viewport1, value2-viewport2, value3-viewport3);
}For optimal results, we recommend using PostCSS Flow together with postcss-sort-media-queries. This plugin will organize and merge all generated media queries, resulting in cleaner and more optimized CSS output.
Installation:
npm install postcss-sort-media-queries --save-devConfiguration:
module.exports = {
plugins: [
require('@soyleninjs/postcss-flow'),
require('postcss-sort-media-queries')({
sort: 'desktop-first' // Matches PostCSS Flow's approach
}),
// other plugins...
]
}Note: While not required, this combination significantly improves your final CSS structure by consolidating media queries and reducing duplication.
flow(value-viewport[, value-viewport-isFluid]*)
Each breakpoint is defined with the format:
| Format | Description |
|---|---|
value-viewport |
Creates a fluid value between breakpoints |
value-viewport-0 |
Creates a fixed (non-fluid) value at that breakpoint |
Parameter details:
- value: Numeric value (unitless, automatically converted to px)
- viewport: Viewport width in pixels
- isFluid (optional): Omit or use any value except
0for fluid. Use0for fixed.
The plugin works exclusively with a Desktop First approach, starting from the largest viewport and going down to smaller ones. Breakpoints are automatically sorted to ensure this behavior.
Important: The order you write breakpoints doesn't matter - they're automatically sorted from largest to smallest viewport!
Transform a single line into fluid typography:
Input:
.heading {
font-size: flow(10-360, 20-834, 30-1440);
}Output:
.heading {
font-size: clamp(20px, calc(20px + (30 - 20) * ((100vw - 834px) / 606)), 30px);
}
@media (width <= 834px) {
.heading {
font-size: clamp(10px, calc(10px + (20 - 10) * ((100vw - 360px) / 474)), 20px);
}
}What happens:
- From 1440px and up: Fluid scaling from 20px to 30px
- At 834px and below: Fluid scaling from 10px to 20px
Mix fluid and fixed breakpoints for precise control. Using -0 makes a breakpoint fixed (non-fluid) from that viewport down to the next breakpoint:
Input:
.container {
padding: flow(10-360, 20-834-0, 30-1440);
}Output:
.container {
padding: clamp(20px, calc(20px + (30 - 20) * ((100vw - 834px) / 606)), 30px);
}
@media (width <= 360px) {
.container {
padding: 10px;
}
}What happens:
- From 1440px down to 834px: Fluid scaling from 30px to 20px
- At 834px (marked with
-0): The value becomes fixed at 20px - From 834px down to 360px: Stays fixed at 20px (no fluid interpolation)
- At 360px and below: Fixed 10px
The -0 suffix prevents fluid interpolation from that breakpoint downwards, creating a fixed value zone.
Don't worry about the order - write breakpoints in any order you want:
Input:
.text {
font-size: flow(20-834, 10-360, 30-1440);
}Output:
.text {
font-size: clamp(20px, calc(20px + (30 - 20) * ((100vw - 834px) / 606)), 30px);
}
@media (width <= 834px) {
.text {
font-size: clamp(10px, calc(10px + (20 - 10) * ((100vw - 360px) / 474)), 20px);
}
}The plugin automatically sorts: 30-1440 → 20-834 → 10-360
Input:
.section {
margin-bottom: flow(20-375, 40-768, 80-1920);
}Output:
.section {
margin-bottom: clamp(40px, calc(40px + (80 - 40) * ((100vw - 768px) / 1152)), 80px);
}
@media (width <= 768px) {
.section {
margin-bottom: clamp(20px, calc(20px + (40 - 20) * ((100vw - 375px) / 393)), 40px);
}
}Use flow() on any CSS property that accepts pixel values:
Input:
.card {
padding: flow(16-360, 24-768, 32-1440);
gap: flow(8-360, 16-768, 24-1440);
border-radius: flow(4-360, 8-768, 12-1440);
}Each property gets its own fluid calculations and media queries!
Perfect for:
- Fluid Typography: Scale font sizes smoothly across devices
- Responsive Spacing: Padding, margins, and gaps that adapt naturally
- Adaptive Layouts: Grid gaps, container widths, and more
- Design Systems: Maintain consistent scaling across breakpoints
- Performance: Uses native CSS
clamp()for optimal rendering
- PostCSS: 8.0.0 or higher
- Browsers: All modern browsers with
clamp()support- Chrome 79+
- Firefox 75+
- Safari 13.1+
- Edge 79+
For older browser support, consider using a CSS clamp() polyfill.
- Parse: The plugin detects
flow()functions in your CSS - Sort: Breakpoints are automatically sorted from largest to smallest viewport
- Calculate: Linear interpolation formulas are generated for fluid values
- Generate: CSS
clamp()functions and media queries are created - Output: Clean, production-ready CSS
Contributions are welcome! Here's how you can help:
Found a bug or have a feature request?
- Check existing issues
- Create a new issue with:
- Clear description
- Steps to reproduce (for bugs)
- Expected vs actual behavior
- Code examples
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes
- Test thoroughly
- Commit:
git commit -m 'Add amazing feature' - Push:
git push origin feature/amazing-feature - Open a Pull Request
Q: Can I use rem or em units? A: Currently, the plugin works with px values only. Unit conversion may be added in future versions.
Q: Does it work with CSS variables?
A: The flow() function requires numeric values. CSS variables are not supported within the function.
Q: Can I use negative values? A: Yes! Negative values work perfectly for margins and transforms.
Q: Is there a maximum number of breakpoints? A: No hard limit, but 3-4 breakpoints is recommended for maintainability.
MIT License - see LICENSE file for details.
Lenin
- GitHub: @soyleninjs
Inspired by the need for simpler responsive design workflows and the power of modern CSS functions.
If this plugin helps you, consider giving it a star on GitHub!
Made with by @soyleninjs