Responsiveness should be a core feature of any website. Screen-sizes are both growing and shrinking. This makes that responsiveness now goes beyond composition and layout. We need to adjust the sizes of text and elements and the surrounding spacing. Most achieve this by adding media-queries. But with various pages, elements, and breakpoints, adding media-queries become unmaintainable.

When refactoring vycke.dev I wanted to remove the dependency on media-queries. But, I wanted sizing and spacing adjust based on the screen size. I needed *fluidity* on my website. By utilizing CSS variables and the CSS `calc`

function, I could achieve this. Check out how!

## Fluid sizing and spacing

I was using media-queries for spacing values (e.g. `padding`

and `margin`

) and font-sizes. On big screens I want larger font-sizes and spacing compared to mobile. The goal is to improve usability and reduce wasted space. But with media-queries, I had to go over all different breakpoints and determine how I wanted to change the spacing and font-sizes. Introducing, fluid interfaces.

With fluid interfaces, you scale up attributes linear when your website increases in size automatically (e.g. between `16px`

and `20px`

). To achieve this, we need to determine a *ratio* (a value between 0 and 1) which we can use to scale values based on the website size.

To determine the ratio, you first need to determine the min. and max. width your site has. Some sites take up all the available horizontal space, but many have a max. width. With a min. and max. determined, we can calculate the ratio with the equation below. With this ratio, we can scale a size between two values linearly.

```
min(space, max-sw) - min-sw
ratio = -----------------------------
max-sw - min-sw
```

With this ratio, we can scale any size (e.g. font-sizes or spacing) based on how big the horizontal size of our website is.

```
size = min-size + (max-size - min-size) Ã— ratio
```

##
Calculating the ratio with `calc`

To implement this concept, you need CSS variables and the `calc`

function. Although it seems easy enough, the implementation comes with some quirks. But first, let's determine our base values. In this implementation all sizes are unitless or in `rem`

(based on `--unit`

). Every website has a default font-size in `px`

that corresponds to `1rem`

. Although this base value can be set by you, it can also be set by the user in the browser settings. This is a simple implementation of fluidity. Based on this value, we can set our initial variables.

```
/* base values */
:root {
--unit: 1rem;
--min-width: 20; /* based on 16px */
--max-width: 75; /* based on 16px */
}
```

With the base values known, we can start calculating the ratio. Here we find the quirks we need to handle. We need to use the `min`

CSS function to calculate the `--area`

value we can determine the ratio with. But, this function always needs values with units for comparison. Thus we multiply our `--max-width`

with the `--unit`

.

INFO: when multiplying using`calc`

, at least one value needs to be unitless. At least the right-hand side of a division needs to be unitless. Adding and subtracting need all values to be unitless, or have (varying) units.

The `--area`

variable is the left-hand side of the described *ratio* equation. Now we can calculate the `--ratio`

. Because `--area`

already has a unit of `rem`

, `--ratio`

will be a value between `0rem`

and `1rem`

.

```
/* ratio calculation */
:root {
--screen: calc(min(100vw, var(--max-width) * var(--unit)));
--area: calc(var(--screen) - var(--min-width) * var(--unit));
--ratio: calc(var(--area) / (var(--max-width) - var(--min-width)));
}
```

## Creating size-related design tokens

With a ratio based on the actual screen size between `0rem`

and `1rem`

, we can start scaling elements on our website. For this, we used the described *scale* equation. Let's look at the example below. This example calculates a build font-size for an article.

```
/* example for a fluid article font-size */
:root {
--min-size: 1.125rem;
--max-size: 1.375rem;
--scale: calc(var(--max-size) - var(--min-size));
--size: calc(var(--min-size) + var(--scale) * var(--ratio));
}
```

On small screens, the font-size will be `1.125rem`

and on big screens `1.375rem`

. With a base font-size of `16px`

, we can now calculate the exact font-sizes for different screen-sizes. A screen-size of `784px`

will have an article font-size of `20.109px`

. But font-sizes is one of many places where we can apply fluidity.

- Font-sizes for paragraphs and headers.
- Various spacing values used between and around element s.
- Sizing of the site's logo and icons.

All can have their own set of calculations for fluidity. These can be separate design tokens, or you can scale from the parent element (e.g. using `em`

instead of `rem`

).

## Conclusion

When refactoring vycke.dev I wanted to reduce the number of media-queries, but maintain responsiveness. I wanted to reduce the CSS footprint of the website. But above all, I wanted to make my CSS more maintainable. Adding fluidity for font-sizes, element sizes, and spacing contributed to achieving this goal. Want to see this fluidity in action? Just open this article on your laptop or PC, and slowly resize the browser window.

Posted on by:

### Kevin Pennekamp

ðŸ‘‹ Hey, I'm Kevin. I'm a Dutch software engineer. I love CSS, front-end architecture, engineering and writing about it!

## Discussion

Great stuff man!

But you still need media queries to adjust grid and other container sizes on different screen sizes so in the end its not really replacing media queries nor really reducing the amount of media queries much.

Good stuff though!

With minmax and auto-fit you don't always have to! Did not use media-query myself to size my grids. But that's for a next article

Youre right well ill wait for that article then, but I get the idea !

You should try something like this:

This snippet fills the available space automatically with a suitable number of "tiles". These tiles are a minimum of

`20rem`

. If there is room for 3.5 tiles, it will show 3 tiles, but it will stretch all tiles. When the screen decreases in size, it will hit a point where only 2 tiles fit on a row, and eventually only 1 tile.Cool thanks for that!

If you want to see the pattern in action, you can view 2 implementations on my own website vycke.dev. First I implemented it on the homepage for the overview of articles (max-width of 1200px and a max of 3 columns). Secondly, all articles have a section to cycle to the next or previous article at the bottom. These are two links next to each other (page wide), that are below each other on smaller screens. No media queries required!