home ~ socials ~ projects ~ rss

CSS Linear Interpolation Map Range Function Math

November 2025

Starting Square

Let's say you have a square and a slider that changes its size. It's trivial to make happen by using slider's value to set both the width and height of the square. Here's one that's 50 pixels per side at its smallest and 200 when it's fully grown.

Output

HTML

<bitty-5-1 data-connect="SquareExample">
  <div class="square"></div> 
  <div>
    <label>Square Size: 
      <span data-receive="updateSquare">-</span>
      <br />
      <input data-send="updateSquare" type="range" min="50" max="200" value="50">
    </label>
  </div>
</bitty-5-1>

CSS

:root {
  --square-width: 50px;
  --square-height: 50px;
}

.square {
  display: inline-block;
  background-color: blue;
  width: var(--square-width);
  height: var(--square-height);
}
JavaScript
window.SquareExample = class {
  updateSquare(event, el) {
    const value = `${event.target.value}px`;
    this.api.setProp("--square-width", value);
    this.api.setProp("--square-height", value);
    el.innerHTML = value;
  }
}

Changing Shape

Works great. But, what if you wanted to start with a square and end up with a rectangle? That's where Linear Interpolation (LERP)1 comes. It lets you create a map between two ranges. Feed it the position in one range and it gives you the corresponding value for the other.

For example, if we want to start with the same 50x50 pixel square, but end up with a 400x100 pixel rectangle we know that:

  • When our slider is all the way down (i.e. at 0%), both values should be 50.
  • When our slider is all the way up (i.e. at 100%), the width should be 400 and the height should be 100.

The Linear Interpolation gives us all the values in between. Here's what the CSS looks like:

CSS

:root {
  /* inputs */
  --x-base: 1px;
  --x-min: 50;
  --x-max: 400; 
  --y-base: 1px;
  --y-min: 50;
  --y-max: 100;
  --current-value: 50;

  /* outputs */
  --current-x: calc(var(--x-base) * var(--current-value));
  --current-y: calc(var(--y-base) * calc(calc(calc(calc(var(--x-max) - var(--current-value)) * var(--y-min)) + calc(calc(var(--current-value) - var(--x-min)) * var(--y-max))) / calc(var(--x-max) - var(--x-min))));
}

It's pretty gnarly, but that's what copy/paste is for. Just fill in the input values and update the --current-value with the raw number for your x value. Then, use the --current-x and --current-y output values wherever you need them. As long as the values work with the CSS calc() function you're all set.

Here's what it looks like in action:

Output

HTML

<bitty-5-1 data-connect="LerpCSS">
  <div class="box"></div> 
  <div>
    <label>
      Current Width:
      <span data-receive="updateLerp">-</span>
      <br />
      <input data-send="updateLerp" type="range" min="50" max="400" value="50">
    </label>
  </div>
</bitty-5-1>
JavaScript
window.LerpCSS = class {
  updateLerp(event, el) {
    const value = parseInt(event.target.value);
    this.api.setProp("--current-value", value);
    el.innerHTML = `${value}px`;
  }
}

CSS

.box {
  display: inline-block;
  background-color: red;
  width: var(--current-x);
  height: var(--current-y);
}

Happy Sizing

It took me a while to find the LERP math when I was first looking for it. I was doing a JavaScript project at the time. I figured I might as well make a CSS version since I already had the math.

I expect I'll use JavaScript most of the time. But, it's nice to know doing it directly in CSS is an option.

Enjoy,

-a

end of line

Endnotes

The JavaScript on this page uses bitty to wire things up. It's a little single file web component that adds interactive to pages. Check it out if you're into that kind of thing:

bitty.alanwsmith.com

This is the CSS version of the Linear Interpolation (LERP) Math function I set up in JavaScript in A JavaScript Linear Interpolation Map Range Function Thing

Footnotes

The math that I'm glad someone else figured out.

Share link:
https://www.alanwsmith.com/en/35/or/mx/h8/?css-linear-interpolation-map-range-function-math