PX to VW Converter

Pixels to vw, then the same vw across eight viewport widths so you can see it collapse on a phone, plus the clamp() that stops it.

Live output

Enable JavaScript to customise; default output below.

What you measured in the design.

The canvas width the pixel size came from. 1440 and 1920 are the usual ones.

Live preview px-to-vw.txt
Pixels                         48px
At design width                1920px
In vw                          2.5vw
In rem                         3rem

2.5vw resolves to
  360×800, small phone         9px
  390×844, phone               9.75px
  768×1024, tablet, portrait   19.2px
  1024×768, tablet, landscape  25.6px
  1280×800, small laptop       32px
  1440×900, laptop             36px
  1920×1080, desktop           48px   <- your design width
  2560×1440, large desktop     64px

Floor at 360px wide            24px
Fluid, with both ends held     clamp(1.5rem, 1.1538rem + 1.5385vw, 3rem)

48px at a 1920px design width is 2.5vw. On a 360px phone that same value
renders at 9px, which is 19 percent of what you designed.

vw is a hundredth of the viewport width, and it keeps going in both
directions: there is no floor and no ceiling. That is the whole problem
with it as a type unit, and the reason the table above is longer than
the conversion.

The clamp() holds the size between 24px and 48px and interpolates in
between. The middle term is written as rem plus vw rather than vw alone
so that the value still responds to a reader who has changed their
browser font size; a bare vw ignores that setting completely, which is
an accessibility failure and not only a taste one.

vw includes the scrollbar width on desktop browsers, so 100vw is wider
than the space you can actually use and produces a horizontal scrollbar
on a full-width element. 100% does not have that problem, and neither
does 100dvw in the browsers that support it.

Output is valid and updates as you type.

Dividing a pixel size by the design width gives you a vw value. That takes one line and it is not the useful part.

The useful part is what that vw becomes everywhere else. 48px at a 1920px design width is 2.5vw, and 2.5vw on a 360px phone is 9px. Type set in vw does not shrink politely, it collapses, and the figure most people check is the one from the design file where it looked fine.

So this converts, shows the value at eight viewport widths, and writes the clamp() that holds both ends.

How to use

  1. Put in the pixel size and the design width you measured it at.
  2. Read the table: that is the same declaration on eight screens.
  3. Put in a floor for 360px wide, and copy the clamp().

Example

48px at a 1920px design width, with a 24px floor:

Pixels                         48px
At design width                1920px
In vw                          2.5vw
In rem                         3rem

2.5vw resolves to
  360×800, small phone         9px
  390×844, phone               9.75px
  768×1024, tablet, portrait   19.2px
  1024×768, tablet, landscape  25.6px
  1280×800, small laptop       32px
  1440×900, laptop             36px
  1920×1080, desktop           48px   <- your design width
  2560×1440, large desktop     64px

Floor at 360px wide            24px
Fluid, with both ends held     clamp(1.5rem, 1.1538rem + 1.5385vw, 3rem)

9px on a phone is 19 percent of what you designed. Nobody would specify a 9px heading, and shipping font-size: 2.5vw specifies it by accident.

Pitfalls

A bare vw has no floor and no ceiling. It keeps scaling in both directions, so the same declaration that looks right on your laptop is unreadable on a phone and enormous on a 4K monitor. Clamp it or use rem.

A vw-only value ignores the reader’s font size setting. Someone who has set their browser to a 24px default gets nothing from font-size: 2.5vw, which is a genuine accessibility failure rather than a preference. The clamp() this tool writes puts a rem term in the middle expression, so the value still responds to that setting.

100vw is wider than the space you have. On desktop browsers it includes the classic scrollbar, so a full-width element in 100vw produces a horizontal scrollbar. Use 100%, or 100dvw where it is available.

vw is the viewport, not the container. A component inside a 400px sidebar still sizes its vw against the whole window. If you want the container, that is container query units: cqw and friends, which have been in every current browser since 2023.

Check the narrow end, not the wide one. Most vw bugs are on small screens, and most previews are taken on large ones. The table here starts at 360px for that reason.

Beware very small vw values on very large screens. At 2560px wide, 1vw is 25.6px, so a 0.5vw gap you fine-tuned on a laptop becomes 13px on a large monitor.

Compatibility

Arithmetic in the browser: nothing is uploaded and nothing is stored. The share link carries the figures and the clamp.

clamp() has been in every current browser since 2020. The pattern written here is the standard one: a rem minimum, a rem + vw preferred value and a rem maximum. The middle term is a linear equation through your two points, which means the size moves in a straight line between the two viewports rather than stepping at a breakpoint.

The interpolation is linear in viewport width, so a clamp() between 360px and 1920px is a little steeper in the middle than a designer’s eye usually wants. If the midpoint feels large, set the floor a touch higher rather than reaching for a media query.

The viewport list is a spread rather than a device list. If a value is wrong somewhere, it is wrong somewhere in this range.

Frequently asked questions

Should I use vw for font sizes at all?
Inside a clamp(), yes: it is the cleanest way to get type that scales smoothly between two sizes without breakpoints. On its own, no.
What design width should I put in?
Whatever the canvas was in the design file. 1440 and 1920 are the usual desktop widths. If you are converting a value from a mobile mockup, put 390 in and expect a much larger vw number.
Why does the clamp have rem in the middle term?
So the value still responds to a reader’s browser font size. A middle term of pure vw makes the text immune to that setting, and a clamp() with a rem minimum but a vw-only preferred value is only accessible at the very bottom of its range.
What about vmin and vmax?
vmin is a hundredth of the shorter viewport side and vmax the longer. vmin is useful for something that must fit on screen in either orientation, such as a square hero image. The general CSS unit converter on this site handles both.
Can I use container query units instead?
Yes, and often you should: cqw is a hundredth of the container’s width, which is what you usually meant. The arithmetic is identical, with the container width in place of the design width.
Weekly drops

New tools, when there are new tools

One email when something worth using ships. No schedule to fill, so no filler.

Your address goes nowhere else, and one click unsubscribes.