Responsify
#Prevent abrupt layout shifts when user resizes the browser
What is responsify?
#window.on("resize", preventAbruptLayoutShift)At my past job at a digital agency I transformed Photoshop, Sketch, and InVision designs into functioning websites. But the designs gave no instructions on how to handle the in-between resolutions. So, to minimize the abrupt layout jumps I employed a technique I call responsify, which uses CSS calc() function to fluidly change width, margin, left, etc. at breakpoints.
Many told me they didn't understand what responsify is/does until they saw it in action. So, below's a screen recording of an example.
responsify verb to make an HTML element fluidly adapt to changes in viewport size
Read on to learn how to use it in your project.
- Update:
- Today I learned that responsify is a rediscovery of CSS locks. Read the comparison between CSS locks and responsify.
Table of contents
#How to responsify
#Examples assume smallest viewport width of 320px, a tablet breakpoint at 768px, and a desktop breakpoint at 1024px.
Example 1 featuring two media queries
#Suppose a <div> needs to be 90% wide below desktop breakpoint and 40% above that. Because you practice mobile-first approach, you start with:
div {
width: 90%;
}and for desktop you add:
@media (min-width: 1024px) {
div {
width: 40%;
}
}You want to gradually transition between these two values so you reserve, let's say, the 900px - 1024px range to smooth this out. You add another media query with the calc() value that you generate using the responsify formbelow and you're done! ð
@media (min-width: 900px) and (max-width: 1023px) {
div {
width: calc(3716.129px - 322.903%); /* https://responsify.dev - parent lower bound: 900px; parent upper bound: 1024px; element lower bound: 90%; element upper bound: 40%; */
}
}Note the comment that accompanies calc() value. Preserving input values makes it easier to maintain the code.
The comment also includes https://responsify.dev both as a reference for future maintainers and as a unique string you can match against when tracking down responsified values.
Without responsify:
With responsify:
You want the <body>'s padding to increase from 10px to 50px, and have it stay at 50px once it hits the desktop breakpoint. For desktop and above you start off with:
body {
padding: 50px;
}and for below desktop you add:
@media (max-width: 1023px) {
body {
padding: calc(-8.182px + 5.682vw); /* https://responsify.dev - viewport lower bound: 320px; viewport upper bound: 1024px; element lower bound: 10px; element upper bound: 50px; */
}
}I'm not a fan of using a max-widthmedia query because it smells of a desktop-first approach ð, but I've included it here for completeness' sake.
You want the <header>'s height to increase from 40px to 90px, and have it stay at 90px once it hits the desktop breakpoint.
header {
height: calc(17.273px + 7.102vw); /* https://responsify.dev - viewport lower bound: 320px; viewport upper bound: 1024px; element lower bound: 40px; element upper bound: 90px; */
max-height: 90px;
}Without the max-height the <header> would continue to grow in height with increase in viewport width. This approach removes the need for a media query ð, but is limited to width and height as no other property has a corresponding max-width and max-height. ð
You want the <button>'s border-widthto increase from 1ch to 2ch, and have it stay at 2ch once it hits the desktop breakpoint. In this example let's say that the average character width is 13.65px.
button {
border-width: min(calc(0.545ch + 1.939vw), 2ch); /* https://responsify.dev - viewport lower bound: 320px; viewport upper bound: 1024px; element lower bound: 1ch; element upper bound: 2ch; "ch" width in pixels: 13.65; */
}By using min() you can do away with media query and you're not limited to width and height like in Example 3. ðŊ
You want the <footer>'s margin-top to be 20px below tablet breakpoint, 200px above desktop breakpoint, and increase from 2.6vw at tablet breakpoint (0.026 * 768px â
20px) to 19.5vw at desktop breakpoint (0.195 * 1024px â
200px).
footer {
margin-top: clamp(20px, calc(-515.482px + 69.87vw), 200px); /* https://responsify.dev - viewport lower bound: 768px; viewport upper bound: 1024px; element lower bound: 2.75vw; element upper bound: 19.53vw; */
}Responsify + clamp()is a powerful combination ðŠ that also allows you to do away with media queries and also allows you to mix and match units, something you can't do with responsify alone.
JavaScript failed to execute. ðĩ You won't be able to generate a calc() value.
You might be able to resolve the issue by reloading the page. If that doesn't work, update your browser to the latest version and try again. If that doesn't work please email me at petar@responsify.dev.
Error stack is logged to the console.
Generate responsified calc() value using the form below.
Bookmark the link next to the form heading above for direct access to this form.
You can use responsify as a Sass @function. Download _responsify.scss, unzip it, and import it to your root Sass file. Usage examples are included in the file.
The advantage of using the Sass @functionis that you don't need comments documenting input values. ð
Note that at the moment, Sass @function doesn't support ch and rem units. ð
Browser support
#Browser support for calc() is very good practically universal.
In spite of IE having known issues with calc() I haven't encountered any. Two of my examples above use clamp() and min(), which IE doesn't support. As far as the "exotic" ð CSS values that I used in my examples go: vw is supported by all browsers and ch is narrower on IE compared to other browsers, so just look out for that.
IE should really be irrelevant in 2026. ðŠĶ
Comparison with CSS locks
#CSS locks originated as Molten leading. In the article that introduced the concept and in almost every example I came across CSS locks are used for controlling line-height and font-size, even though it works with many CSS properties.
CSS locks and responsify are based on fundamentally the same logic/math and as such share many similarities. They both:
- work with CSS properties that accept a
pxvalue, - don't work with properties that accept keyword value like
visibility, - don't work with properties that accept a unitless value like
z-index.
There are also a few differences, most notable are listed in the following table.
| Criterion | CSS locks | Responsify |
|---|---|---|
| Sass | CSS locks Sass function | Responsify Sass function |
| PostCSS | postcss-scale | No |
| Web interface | No | Yes |
| Since | 2016 | 2019 |
Related resources
#There's a similar tool that can generate non-linear calc() value.
For more awesomeness, James Gilyead and Trys Mudford created "Utopia" design systemwhere elements scale proportionally and fluidly. It's an awesome and somewhat unconventional approach that uses a whole lot of calc(), CSS variables, rem and vw relative units, all tied together with what seems to me as undecipherable math. Fascinating stuff. ð§