Fluid CSS methodologies have completely transformed my approach to web integration by improving the responsive aspect and simplifying maintenance. I find this topic deceptively simple yet incredibly powerful and still relevant today.

When I work with a new team, I'm always curious to discover their layout integration methodologies, as this will partly determine the project's complexity. Especially for content websites, the number of design system components to integrate doesn't allow me to spend too much time on each one. So, when I'm not using my own tools and frameworks, I spend a day or two setting up the grid system and this crucial integration methodology to ensure efficiency in my work.
That's why I decided to compile the best practices from all the team methodologies I've had the chance to work with and create my own. Here we go.
Pixel unit everywhere
Writing about this CSS subject, definitely makes me want to reflet on my beginning in web development. I discovered CSS through Le zen des CSS, a Book written by Dave Shea, the creator of csszengarden.com. Any of the layouts described on this book were built using the px
unit on each elements. The web was more static back then, and devices mostly had the same screen size. The main centered column was often 960px
width. (Ho! and who remember 960 grid system?). Mobile integration wasn't a priority at that time. Because smartphones didn't exist.
With the arrival of new devices with portrait screens, CSS specifications have adapted by including media queries. Big revolution for webmasters! We could then integrate designs based on min or max breakpoint sizes. Today, breakpoints are still relevant; however, it's about adapting to a multitude of device sizes. We can't set a breakpoint every 10px, as that would be unmanageable.
Then came the notion of fluid design. The content of our web pages must adapt to the screen size, rather than waiting to exceed a specific breakpoint to modify the layout. We started using units like em
, rem
, and vw
.
With the web becoming powerful enough to accommodate apps and games of all kinds, web design has taken liberties. The needs in UI development have completely changed.
A modern approach
Let's start with an example to describe the need. On this game interface, there is no scrolling possible; the design is centered, regardless of the screen size. The goal is to ensure that all elements on the screen are always visible, whether resizing the width or the height.
Height adjustment really depends on the project. We don't always need it. I am deliberately presenting the most comprehensive example. So, how does it work?
Fluid calculation basis
We need a function that converts an absolute value to a relative value based on the viewing context, specifically the viewport size. To achieve this, we first need the width of our viewport, the width of our design mockup, and the value to be transformed.
We calculate a ratio of viewport-width / design-width
, then multiply the value to be rationalized by this ratio: ratio * value
. In CSS, it could look like this.
Arbitrarily, the design width is set to 600
, but this can vary depending on your needs. (I use the same size in the module example below). If we apply this calculation to the font-size of an HTML page, here is the result.
The behavior is as expected. The font size increases as the width of our viewport grows. Note that the font-size reaches 16px when the viewport width equals the design mockup value.
Adding a limiting ratio
The problem is that the calculation changes the font-size too quickly. So I added a vw-ratio
to limit how fast the calculated value grows. This brings us to a more practical and real world use case.
The vw-ratio
determines the percentage of viewport width used in the fluid integration. If it is set to 1, 100% of the value is based on the viewport width. If it is set to 0.5, 50% of the value is based on the viewport width, and 50% is based on the browser's native font-size.
And here is what it looks like in use. Note that the vw-ratio
does not affect the font-size when the viewport size matches the design size. This is the expected behavior.
Adding height to the calculation
In the INCA video screen presented previously, we observe the elements centered in the viewport regardless of its width, but also its height. To achieve this, I had to improve the calculation seen previously. This time, the added part refers to the viewport height
or vh
.
Dividing the sum of the width contribution and the height contribution by two gives a "weight" equal to the scaling factor of these two parts of the calculation. At this point, no limiting ratio is involved. Here is the result when resizing the height.
My font-size is now mapped to a value that scales based on the viewport size, including its height!
Width, height & ratios
Finally, just like with the width calculation, I apply a ratio to both parts. This allows me to control the scaling on each axis. I introduce a vh-ratio
, and with that, we will be done with this complex calculation.
This sandbox performs the same calculations as the module above. You can update the CSS variable values and observe how the font-size changes when resizing the sandbox. The updates will be applied dynamically.
Real world usage
Of course, the idea isn't just to use this for font-size. If we want the entire interface to be fluid, we should apply this calculation to any CSS property as needed. And this is where it gets interesting.
Dividing the calculation by 16 gives us a pseudo-pixel value for use. "Pseudo" because it's now a relative value. Let's say --fluid
represents "1px in a relative viewport ratio". This is very convenient for my front-end tasks, as I can simply integrate Figma values into my CSS to achieve a "relative pixel-perfect" design.
And since these are just CSS variables, we can even test different vw
and vh
ratios directly in the inspector. I took a screenshot of my last project where I modified these values.
I often notice that I am asked not to apply size variation on viewport height resize. This is a specific use case that generally works on interfaces without scroll, a bit like a poster, where the design is closed by screen borders.
To conclude, the method described above remains quite basic. Like most front-end developers, I usually use CSS preprocessors, such as Sass, which no longer need to be introduced. In this specific case, it allows me to put this calculation in a function and reset --fluid
on demand, within a restricted scope.
A future approach
A more modern approach might be worth considering. Miriam Suzanne explains this in her post Reimagining Fluid Typography.
At first glance, this calculation is based on a property related to width rather than height. This doesn't cover all the cases explored in this article, so I'll probably need some time to think about it. Perhaps this will be an opportunity to revisit the topic.
If you've read this far, thank you to Pierre and Manu, with whom I've often discussed and tested these concepts. They'll recognize themselves. 👋