A powerful SCSS mixin system for creating perfectly responsive designs that maintain Figma proportions across all screen sizes.
Pure CSS implementations are affected by this breaking change.
- CSS Variables: Variable names changed from
--computed-scale-factor-px
/--computed-scale-factor-rem
to generic--computed-scale-factor
- Calc Expressions: Units are now appended to multipliers (e.g.,
* 2rem
instead of* 2
) - SCSS Usage: Unchanged - existing SCSS mixin calls continue to work
SCSS implementations are NOT affected - existing @include responsive-scale()
calls work unchanged.
Update your CSS variable definitions:
/* OLD (v1.x) */
:root {
--computed-scale-factor-px: calc(100vw / 1440);
--computed-scale-factor-rem: calc(100vw / 1440 / 16);
--computed-tablet-scale-factor-px: calc(100vw / 768);
--computed-tablet-scale-factor-rem: calc(100vw / 768 / 16);
--computed-mobile-scale-factor-px: calc(100vw / 375);
--computed-mobile-scale-factor-rem: calc(100vw / 375 / 16);
--tablet-proportion-scale-factor: calc((100vw - 375px) / (1440px - 375px));
}
/* NEW (v2.0) */
:root {
--computed-scale-factor: calc(100vw / 1440);
--computed-tablet-scale-factor: calc(100vw / 768);
--computed-mobile-scale-factor: calc(100vw / 375);
--tablet-proportion-scale-factor: calc((100vw - 375px) / (1440px - 375px));
}
Update your calc expressions to include units:
/* OLD (v1.x) */
font-size: calc(var(--computed-scale-factor-px) * 40);
/* NEW (v2.0) */
font-size: calc(var(--computed-scale-factor) * 40px);
- Figma Proportions: Maintains exact proportions from your Figma designs
- Automatic Scaling: No manual breakpoint calculations needed
- Tablet Interpolation: Smart interpolation between mobile and desktop values
- CSS Custom Properties: Uses modern CSS variables for optimal performance
- Framework Agnostic: Works with any CSS framework or vanilla CSS
- TypeScript Ready: Compatible with CSS Modules and CSS-in-JS solutions
- Universal Unit Support: Handles all CSS units including absolute (px, pt, cm, mm, in, pc) and relative (%, em, rem, vw, vh, vmin, vmax) units
npm install responsive-scale-mixins
yarn add responsive-scale-mixins
pnpm add responsive-scale-mixins
// app/globals.css or app/styles/globals.scss
@import "~responsive-scale-mixins";
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
// Define CSS variables globally (required)
@include responsive-scale-variables(1440px, 768px, 375px);
// Or use defaults: @include responsive-scale-variables();
}
// Import in app/layout.tsx: import './globals.css'
// styles/globals.scss
@import "~responsive-scale-mixins";
:root {
// Define CSS variables globally (required)
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
@include responsive-scale-variables(1440px, 768px, 375px);
// Or use defaults: @include responsive-scale-variables();
}
// Import in pages/_app.js: import '../styles/globals.scss'
Next.js Setup:
- App Router: Put
:root
inapp/globals.css
(imported inlayout.tsx
) - Pages Router: Put
:root
instyles/globals.scss
(imported inpages/_app.js
) - The
:root
selector defines global CSS custom properties accessible everywhere
// src/index.scss or src/styles/main.scss
@import "~responsive-scale-mixins";
:root {
// Define CSS variables globally (required)
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
@include responsive-scale-variables(1440px, 768px, 375px);
// Or use defaults: @include responsive-scale-variables();
}
// Import in src/index.js: import './index.scss'
Create React App Setup:
- Put
:root
in your main SCSS file (e.g.,src/index.scss
) - Import the SCSS file in
src/index.js
- The
:root
selector makes CSS variables available app-wide
// src/assets/styles/main.scss
@import "~responsive-scale-mixins";
:root {
// Define CSS variables globally (required)
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
@include responsive-scale-variables(1440px, 768px, 375px);
// Or use defaults: @include responsive-scale-variables();
}
// Import in src/main.js: import './assets/styles/main.scss'
Vue.js Setup:
- Put
:root
in your global SCSS file - Import in
src/main.js
or use in a global style resource - The
:root
selector defines app-wide CSS variables
// src/styles.scss (global styles)
@import "~responsive-scale-mixins";
:root {
// Define CSS variables globally (required)
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
@include responsive-scale-variables(1440px, 768px, 375px);
// Or use defaults: @include responsive-scale-variables();
}
// This file is automatically included by Angular CLI
Angular Setup:
- Put
:root
insrc/styles.scss
(automatically included by Angular CLI) - No manual import needed - Angular handles it
- The
:root
selector defines global CSS variables
// src/styles/main.scss
@import "responsive-scale-mixins";
:root {
// Customize for your design system (optional)
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
@include responsive-scale-variables(1440px, 768px, 375px);
// Or use defaults: @include responsive-scale-variables();
}
// src/styles/global.scss
@import "~responsive-scale-mixins";
:root {
// Customize for your design system (optional)
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
@include responsive-scale-variables(1440px, 768px, 375px);
// Or use defaults: @include responsive-scale-variables();
}
// assets/styles/main.scss
@import "~responsive-scale-mixins";
:root {
// Customize for your design system (optional)
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
@include responsive-scale-variables(1440px, 768px, 375px);
// Or use defaults: @include responsive-scale-variables();
}
// src/app.scss
@import "responsive-scale-mixins";
:root {
// Customize for your design system (optional)
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
@include responsive-scale-variables(1440px, 768px, 375px);
// Or use defaults: @include responsive-scale-variables();
}
// src/styles/global.scss
@import "responsive-scale-mixins";
:root {
// Customize for your design system (optional)
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
@include responsive-scale-variables(1440px, 768px, 375px);
// Or use defaults: @include responsive-scale-variables();
}
// styles.module.scss
@import "~responsive-scale-mixins";
// Variables must be in global scope
// In your main CSS file:
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
--computed-scale-factor: calc(100vw / 1920);
--computed-tablet-scale-factor: calc(100vw / 768);
--computed-mobile-scale-factor: calc(100vw / 390);
--tablet-proportion-scale-factor: calc((100vw - 390px) / (1920px - 390px));
}
// Then in your module
.myClass {
@include responsive-scale(font-size, 24, 16);
}
// styles/main.scss
@import "~responsive-scale-mixins";
:root {
@include responsive-scale-variables();
}
// Use alongside Tailwind
.custom-element {
@include responsive-scale(padding, 20 40, 10 20);
@apply bg-blue-500 text-white; // Tailwind classes still work
}
// If using styled-components with SCSS preprocessing
import styled from 'styled-components';
import './styles/responsive-mixins.scss'; // Import in your main file
const StyledComponent = styled.div`
${props => props.theme.responsiveScale('font-size', 24, 16)}
`;
// In your main SCSS file
@import "~responsive-scale-mixins";
// Include variables in your root element (required)
:root {
@include responsive-scale-variables();
}
// Use the mixin anywhere
.my-element {
@include responsive-scale(font-size, 24, 16);
@include responsive-scale(padding, 20 40, 10 20);
}
Defines the CSS custom properties for scaling calculations.
Parameters:
$desktop-width
: Design width for desktop (default: 1920px)$tablet-width
: Design width for tablet (default: 768px)$mobile-width
: Design width for mobile (default: 390px)
responsive-scale($property, $desktop-value, $mobile-value, $unit, $is-percentage, $desktop-relative, $mobile-relative, $important)
The main responsive scaling mixin.
Parameters:
$property
: CSS property name (e.g.,font-size
,padding
)$desktop-value
: Value for desktop screens$mobile-value
: Value for mobile screens$unit
: Unit for scaling (px
orrem
, default:px
)$is-percentage
: Whether the value is a percentage (default:false
)$desktop-relative
: Base value for percentage calculations on desktop$mobile-relative
: Base value for percentage calculations on mobile$important
: String to append (e.g.," !important"
for override, default:null
)
.hero-title {
@include responsive-scale(font-size, 48, 32);
@include responsive-scale(line-height, 1.2, 1.3);
@include responsive-scale(letter-spacing, -1, -0.5);
}
.card {
@include responsive-scale(padding, 32 48, 16 24);
@include responsive-scale(margin-bottom, 24, 16);
}
.button {
@include responsive-scale(width, 200, 150);
@include responsive-scale(height, 56, 44);
@include responsive-scale(border-radius, 8, 6);
}
.text {
// Letter-spacing as 1% of font-size
@include responsive-scale(letter-spacing, 1, 1, px, true, 48, 32);
}
.override-bootstrap {
@include responsive-scale(
font-size,
24,
16,
px,
false,
null,
null,
" !important"
);
@include responsive-scale(
padding,
16 32,
8 16,
px,
false,
null,
null,
" !important"
);
}
Easily customize the design widths to match your project's breakpoints:
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
// Custom design widths (desktop, tablet, mobile)
@include responsive-scale-variables(1440px, 768px, 375px);
// Or use defaults: @include responsive-scale-variables();
}
Default values:
- Desktop: 1920px
- Tablet: 768px
- Mobile: 390px
.element {
@include responsive-scale(
font-size,
3,
2,
rem
); // 3rem / 2rem - uses rem scale factor
@include responsive-scale(
font-size,
2,
1.5,
em
); // 2em / 1.5em - uses rem scale factor
}
Universal Unit Support:
The mixin supports all CSS units with a single generic scale factor:
Absolute Units:
@include responsive-scale(property, value, mobile-value, px)
β* valuepx
@include responsive-scale(property, value, mobile-value, pt)
β* valuept
@include responsive-scale(property, value, mobile-value, cm)
β* valuecm
@include responsive-scale(property, value, mobile-value, mm)
β* valuemm
@include responsive-scale(property, value, mobile-value, in)
β* valuein
@include responsive-scale(property, value, mobile-value, pc)
β* valuepc
Relative Units:
@include responsive-scale(property, value, mobile-value, em)
β* valueem
@include responsive-scale(property, value, mobile-value, rem)
β* valuerem
@include responsive-scale(property, value, mobile-value, %)
β* value%
@include responsive-scale(property, value, mobile-value, vw)
β* valuevw
@include responsive-scale(property, value, mobile-value, vh)
β* valuevh
@include responsive-scale(property, value, mobile-value, vmin)
β* valuevmin
@include responsive-scale(property, value, mobile-value, vmax)
β* valuevmax
Example Usage:
.element {
@include responsive-scale(margin, 2, 1, cm); // centimeters
@include responsive-scale(width, 50, 30, vw); // viewport width
@include responsive-scale(height, 80, 60, vh); // viewport height
@include responsive-scale(font-size, 1.5, 1, em); // em units
}
If you prefer manual control, you can set the CSS variables directly:
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
--computed-scale-factor: calc(100vw / 1440); // Your desktop width
--computed-tablet-scale-factor: calc(100vw / 768); // Your tablet width
--computed-mobile-scale-factor: calc(100vw / 375); // Your mobile width
--tablet-proportion-scale-factor: calc((100vw - 375px) / (1440px - 375px));
}
If the @include responsive-scale-variables()
mixin doesn't work in your setup (e.g., due to SCSS compilation issues), use the manual CSS variables approach. Below are manual setups for each framework:
The @include responsive-scale-variables()
mixin may fail in certain SCSS compilation environments (like some Next.js setups) because the imported mixins aren't processed correctly. The manual CSS variables approach bypasses this by directly defining the required --computed-scale-factor-*
variables in :root
.
// app/globals.css or app/styles/globals.scss
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
--computed-scale-factor: calc(100vw / 1440); // Your design desktop width
--computed-tablet-scale-factor: calc(100vw / 768);
--computed-mobile-scale-factor: calc(100vw / 375);
--tablet-proportion-scale-factor: calc((100vw - 375px) / (1440px - 375px));
}
// In component files
@import "responsive-scale-mixins";
.my-element {
@include responsive-scale(font-size, 24, 16);
}
// styles/globals.scss
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
--computed-scale-factor: calc(100vw / 1440);
--computed-tablet-scale-factor: calc(100vw / 768);
--computed-mobile-scale-factor: calc(100vw / 375);
--tablet-proportion-scale-factor: calc((100vw - 375px) / (1440px - 375px));
}
// In component files
@import "responsive-scale-mixins";
// src/index.scss
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
--computed-scale-factor: calc(100vw / 1440);
--computed-tablet-scale-factor: calc(100vw / 768);
--computed-mobile-scale-factor: calc(100vw / 375);
--tablet-proportion-scale-factor: calc((100vw - 375px) / (1440px - 375px));
}
// In component files
@import "responsive-scale-mixins";
// src/assets/styles/main.scss
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
--computed-scale-factor: calc(100vw / 1440);
--computed-tablet-scale-factor: calc(100vw / 768);
--computed-mobile-scale-factor: calc(100vw / 375);
--tablet-proportion-scale-factor: calc((100vw - 375px) / (1440px - 375px));
}
// In component styles
@import "responsive-scale-mixins";
// src/styles.scss
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
--computed-scale-factor: calc(100vw / 1440);
--computed-tablet-scale-factor: calc(100vw / 768);
--computed-mobile-scale-factor: calc(100vw / 375);
--tablet-proportion-scale-factor: calc((100vw - 375px) / (1440px - 375px));
}
// In component styles
@import "responsive-scale-mixins";
// src/styles/main.scss
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
--computed-scale-factor: calc(100vw / 1440);
--computed-tablet-scale-factor: calc(100vw / 768);
--computed-mobile-scale-factor: calc(100vw / 375);
--tablet-proportion-scale-factor: calc((100vw - 375px) / (1440px - 375px));
}
// In components
@import "responsive-scale-mixins";
// src/styles/global.scss
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
--computed-scale-factor: calc(100vw / 1440);
--computed-tablet-scale-factor: calc(100vw / 768);
--computed-mobile-scale-factor: calc(100vw / 375);
--tablet-proportion-scale-factor: calc((100vw - 375px) / (1440px - 375px));
}
// In components
@import "responsive-scale-mixins";
// assets/styles/main.scss
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
--computed-scale-factor: calc(100vw / 1440);
--computed-tablet-scale-factor: calc(100vw / 768);
--computed-mobile-scale-factor: calc(100vw / 375);
--tablet-proportion-scale-factor: calc((100vw - 375px) / (1440px - 375px));
}
// In components
@import "responsive-scale-mixins";
// src/app.scss
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
--computed-scale-factor: calc(100vw / 1440);
--computed-tablet-scale-factor: calc(100vw / 768);
--computed-mobile-scale-factor: calc(100vw / 375);
--tablet-proportion-scale-factor: calc((100vw - 375px) / (1440px - 375px));
}
// In components
@import "responsive-scale-mixins";
// src/styles/global.scss
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
--computed-scale-factor: calc(100vw / 1440);
--computed-tablet-scale-factor: calc(100vw / 768);
--computed-mobile-scale-factor: calc(100vw / 375);
--tablet-proportion-scale-factor: calc((100vw - 375px) / (1440px - 375px));
}
// In components
@import "responsive-scale-mixins";
// In your global CSS file (e.g., globals.scss)
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
--computed-scale-factor: calc(100vw / 1920);
--computed-tablet-scale-factor: calc(100vw / 768);
--computed-mobile-scale-factor: calc(100vw / 390);
--tablet-proportion-scale-factor: calc((100vw - 390px) / (1920px - 390px));
}
// In your module files
@import "responsive-scale-mixins";
.myClass {
@include responsive-scale(font-size, 24, 16);
}
// styles/main.scss
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
--computed-scale-factor: calc(100vw / 1440);
--computed-tablet-scale-factor: calc(100vw / 768);
--computed-mobile-scale-factor: calc(100vw / 375);
--tablet-proportion-scale-factor: calc((100vw - 375px) / (1440px - 375px));
}
// In components
@import "responsive-scale-mixins";
.custom-element {
@include responsive-scale(padding, 20 40, 10 20);
@apply bg-blue-500 text-white;
}
// In your global styles
:root {
// Replace 1440 with your design width or leave default (desktop)
// Replace 768 with your design width or leave default (tablet)
// Replace 375 with your design width or leave default (mobile)
--computed-scale-factor: calc(100vw / 1440);
--computed-tablet-scale-factor: calc(100vw / 768);
--computed-mobile-scale-factor: calc(100vw / 375);
--tablet-proportion-scale-factor: calc((100vw - 375px) / (1440px - 375px));
}
// In styled components with SCSS preprocessing
import styled from 'styled-components';
import './styles/responsive-mixins.scss';
const StyledComponent = styled.div`
${props => props.theme.responsiveScale('font-size', 24, 16)}
`;
Note: Replace 1440
, 768
, 375
with your actual design widths. The manual approach ensures compatibility across all build tools and frameworks.
- Desktop: β₯992px (scales from desktop design width)
- Tablet: 768px - 991px (interpolated values)
- Mobile: β€767px (scales from mobile design width)
npm install
# No build step required - pure SCSS
npm test
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Inspired by Figma's responsive design principles
- Built for modern web development workflows
- Compatible with CSS Modules, Styled Components, and traditional CSS
The library includes a comprehensive test suite located in the test/
directory:
# Run the test suite
cd test && ./test.sh # Unix/Linux/macOS
cd test && test.bat # Windows
See test/TEST_README.md
for detailed testing instructions.
- π§ Email: [email protected]
- π Issues: GitHub Issues
- π Docs: Full Documentation
- π¦ NPM: https://www.npmjs.com/package/responsive-scale-mixins
- π€ NPM Profile: https://www.npmjs.com/~sidodus
Made with β€οΈ by Saheed Odulaja