thedevtoolset
Mobile

SP to PX & PX to SP Converter for Android

Free Android sp to px converter (and px to sp): convert scale-independent pixels across every density bucket and font-scale setting, with a live per-scale text preview, Material 3 type scale, Figma letter-spacing panel, plus Kotlin, Java & Compose snippets. 100% in your browser.

Screen density
Font scale (accessibility text size)

16 × (160 / 160) × 1 = 16 px — Android renders 16px

16sp at every font scale
The quick fox0.85× · 13.6px
The quick fox1× · 16px
The quick fox1.3× · 20.8px · linear approx.
The quick fox2× · 32px · linear approx.
16sp across every density at 1× font scale
Densitydpipx
ldpi12012
mdpi16016
tvdpi21321.3 rounds to 21
hdpi24024
xhdpi32032
xxhdpi48048
xxxhdpi64064

Android rounds to whole pixels: floor(sp × density × fontScale + 0.5). Arrows mark values that won't land crisply.

Figma letter spacing → Android

Figma tracking is a percentage of the font size entered above — enter that percentage to get the equivalent em, sp and pixel values.

2% = 0.02em = 0.32sp ≈ 0.32px

Material 3 type scale at mdpi · 160 dpi · 1× font scale
Rolesppx
Display Large57sp57px
Display Medium45sp45px
Display Small36sp36px
Headline Large32sp32px
Headline Medium28sp28px
Headline Small24sp24px
Title Large22sp22px
Title Medium16sp16px
Title Small14sp14px
Body Large16sp16px
Body Medium14sp14px
Body Small12sp12px
Label Large14sp14px
Label Medium12sp12px
Label Small11sp11px
Use this value in code
<!-- res/values/dimens.xml -->
<dimen name="text_size">16sp</dimen>

// Compose
fontSize = 16.sp

// Views
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 16f, resources.displayMetrics)

What is sp, and why does Android need a separate unit for text?

sp (scale-independent pixels) is Android’s unit for text size. It starts from exactly the same density scaling as dp1sp renders larger on a denser screen, in the same proportions, so text looks the same physical size across devices. Where it differs is the second input: sp also multiplies by the user’s system font-scale preference, set under Settings > Display > Font size. Someone who finds default text too small can raise that setting once, system-wide, and every app that correctly used sp for text respects it immediately — no extra code required on your end.

That’s the entire reason the unit exists. If Android only had dp, there would be no way for a user to make text bigger without also inflating every margin, icon, and touch target in every app they use.

The sp to px formula (and the reverse)

Both directions extend the dp formula with one extra factor, the font scale:

  • sp → px: px = sp × (dpi / 160) × fontScale
  • px → sp: sp = px ÷ (dpi / 160) ÷ fontScale

dpi / 160 is the same density ratio the dp to px converter uses. fontScale defaults to 1.0 and is read live from Configuration.fontScale — it’s never something you set in code. At mdpi (160 dpi) with the default scale, 1sp = 1px, same as dp. At xxhdpi (480 dpi, a 3× density) with a 130% font scale, 16sp × 3 × 1.3 = 62.4px, which Android rounds to 62px. The converter above does both multiplications instantly — pick a density and font scale, type into either field, and read the result.

sp vs dp — choosing the right unit for text

Both units scale identically with screen density. The only difference is the font-scale factor, but that difference has a hard rule attached to it:

sp dp
Scales with screen density Yes Yes
Scales with user font-size setting Yes No
Use for Every fontSize value Margins, padding, icons, touch targets
16 at xxhdpi, 130% font scale ≈ 62px 48px (unaffected by font scale)

Get this backwards and you break accessibility in one of two directions. Text sized in dp ignores the user’s font-size preference entirely — someone who deliberately increased system text size for readability gets no benefit inside your app, which is exactly the failure sp was built to prevent. The opposite mistake — sizing layout dimensions in sp — makes padding, icon boxes, and touch targets balloon every time text grows, often producing cramped or overflowing screens instead of just bigger, more readable text. Text goes in sp. Everything around the text goes in dp.

What is fontScale, and where do users change it?

fontScale is a system-wide multiplier, exposed as Configuration.fontScale and, in Compose, as LocalDensity.current.fontScale. Users set it under Settings > Display > Font size (exact wording varies slightly by OEM). The typical steps are:

Preset Scale
Small 0.85×
Default 1.0×
Large 1.15×
Larger 1.30×
Extra large 1.50×
Largest (accessibility) 2.00×

Android 12 and later split out a separate “Larger accessibility sizes” toggle that unlocks the top end of that range (up to 200%) independently of the regular font-size slider. Whatever the user picks, it applies to your entire app the moment they change it — your code should never hardcode or cache a font scale value.

Live preview: your sp value across every font scale

Type a value into the sp field above and the preview row renders it as real text at four font scales — 0.85×, 1.0×, 1.3×, and 2.0× — side by side, each labeled with its computed pixel size. This is the fastest way to sanity-check a design decision: a caption that looks fine at 100% may become uncomfortably cramped against its container at 200%, and the only way to know is to look at it rendered, not just at the number.

Common sp values across densities

The sp sizes you’ll use most, at the default 100% font scale:

sp mdpi hdpi xhdpi xxhdpi xxxhdpi Typical use
11sp 11 16.5 22 33 44 Label Small (M3)
12sp 12 18 24 36 48 Caption / Body Small
14sp 14 21 28 42 56 Body Medium / Label Large
16sp 16 24 32 48 64 Body Large / default body text
18sp 18 27 36 54 72 Subtitle
20sp 20 30 40 60 80 Section header
24sp 24 36 48 72 96 Headline Small

Every value scales again once the font scale leaves 100% — the all-densities table above applies your chosen font scale to any sp value you enter, at every bucket simultaneously.

Material 3 type scale

Material 3 defines fifteen named text roles, from Display Large at 57sp down to Label Small at 11sp, each with its own recommended letter-spacing — the values below match Google’s own type-scale tokens reference:

Role sp Tracking
Display Large 57 -0.25
Display Medium 45 0
Display Small 36 0
Headline Large 32 0
Headline Medium 28 0
Headline Small 24 0
Title Large 22 0
Title Medium 16 0.15
Title Small 14 0.1
Body Large 16 0.5
Body Medium 14 0.25
Body Small 12 0.4
Label Large 14 0.1
Label Medium 12 0.5
Label Small 11 0.5

The type-scale table above converts every role at your chosen density and font scale, so you can see exactly how many pixels a Body Large string renders as on a 480 dpi screen at 150% font scale — not just what it looks like on the design spec.

Designing for 200% font scale

The largest accessibility setting, 200%, is where layouts most often break, and it’s worth testing deliberately rather than eyeballing 100% and hoping — exactly what Android’s own guide on supporting user-scalable content recommends. A few concrete rules that hold up:

  • Never fix the height of a container that wraps text. Let it grow with wrap_content / Compose’s default sizing, or the text will clip.
  • Reserve maxLines + ellipsis only where truncation is genuinely acceptable — a list-item subtitle, not a button label a user needs to read in full.
  • Keep icons and touch targets in dp, never sp. If they scaled with text, a 200% font setting would also balloon every icon, compounding the space problem instead of just making text legible.
  • Check line-height, not just font-size. A tight lineHeight that looked fine at 16sp can cause overlapping lines once the same text renders at 32sp-equivalent size.

sp to px in Kotlin & Java

The canonical on-device conversion, using the same TypedValue API dp uses, just with a different unit constant:

// Kotlin — the canonical sp → px conversion
val px = TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_SP, 16f, resources.displayMetrics
)
// Java — sp → px
float px = TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_SP, 16f, getResources().getDisplayMetrics());

TypedValue.COMPLEX_UNIT_SP already factors in both density and scaledDensity — you don’t need to multiply by fontScale yourself if you use this API. Most of the time you won’t touch this at all: put the value in res/values/dimens.xml as <dimen name="text_size">16sp</dimen> and set it via android:textSize, and the framework converts it for you at inflation time.

sp to px in Jetpack Compose

Compose reads both density and font scale from the same composition local:

// Compose — sp → px (already includes fontScale)
val px = with(LocalDensity.current) { 16.sp.toPx() }

This is one place Compose text differs from Compose dp: Dp.toPx() ignores font scale entirely, while TextUnit.toPx() (used for .sp values) multiplies by LocalDensity.current.fontScale automatically, because text is the one thing meant to respond to it. As with dp, you rarely need this directly — Text(fontSize = 16.sp) and TextStyle(fontSize = 16.sp) already handle the conversion internally. Reach for raw pixels only inside Canvas, a custom Layout, or a graphics API that requires floats.

Figma letter spacing to Android

Figma expresses letter spacing (tracking) as a percentage of the font size, not an absolute unit — which is exactly why the panel above reuses the sp value you’ve already entered instead of asking for a separate font size. The conversion is:

em = figma_percent / 100
sp_tracking = em × font_size_sp

A 2% tracking spec on 16sp text is 0.02 × 16 = 0.32sp. But neither Android XML nor Compose take that sp value directly for letter spacing — both actually want the em figure:

<!-- res/values/styles.xml — letterSpacing is unitless em, not sp -->
<item name="android:letterSpacing">0.02</item>
// Compose — matches a Figma percentage exactly
letterSpacing = 0.02.em

The reason it’s em and not sp: tracking needs to compound with whatever size the text renders at, the same way em works in CSS. A fixed sp offset would look proportionally tight on a large headline and proportionally loose on a small caption — the opposite of what a percentage-based design spec intends. Compose’s TextUnit supports both .sp (absolute, rarely what you want for tracking) and .em (relative, matches Figma) — for any handoff coming from a percentage-based tool, reach for .em.

When you actually need this conversion

  • Accessibility QA. Confirming your text actually grows at 130% and 200% font-scale settings, and that nothing clips or overlaps when it does.
  • Design handoff. A Figma spec in px needs converting to sp for implementation, and a QA report measuring pixels on a screenshot needs converting back to the sp value that produced it.
  • Cross-checking Material 3 roles. Verifying that a Body Large string actually renders at the pixel size the spec implies on a specific density and font-scale combination.
  • Letter-spacing handoff. Turning a Figma tracking percentage into the em value Android’s letterSpacing attribute and Compose’s TextStyle both expect.

Shipping the launcher icons for the same app? The App Icon Generator produces the full native size set for Android, iOS and more from one source image. And since accessible type needs accessible color too, check your palette against WCAG with the color contrast checker. Building the iOS side of a cross-platform app? The iOS points to pixels converter covers the equivalent @1x/@2x/@3x scaling for Apple’s platform.

Everything runs 100% client-side — nothing you type ever leaves your device.

Frequently asked questions

  • What is sp in Android?

    sp (scale-independent pixels) is Android's unit for text size. It behaves exactly like dp — it scales with screen density so text stays the same physical size across devices — but it adds one more factor: the user's font-size preference in Settings &gt; Display &gt; Font size. If someone sets their font scale to 130%, every sp value in your app grows by that amount, while dp values (margins, icons, touch targets) stay exactly the same size. That's the entire reason the unit exists — so raising system font size doesn't also blow up your layout spacing.

  • How do I convert sp to px?

    The formula is px = sp × (dpi / 160) × fontScale. The first part, dpi / 160, is the same density ratio dp uses; fontScale is the user's font-size setting (1.0 by default). At mdpi (160 dpi) with the default font scale, 16sp = 16px. At xxhdpi (480 dpi, a 3× density) with a 130% font scale, 16sp × 3 × 1.3 = 62.4px, which Android rounds to 62px. Pick a density and font scale above and type into the sp field — the converter does both multiplications and shows the exact and rounded pixel values.

  • How do I convert px to sp?

    Divide by both factors instead of multiplying: sp = px ÷ (dpi / 160) ÷ fontScale. On an xhdpi screen (320 dpi, a 2× density) at the default font scale, 28px ÷ 2 = 14sp. Type into the px field above and the sp value updates instantly — useful when a design spec gives you a pixel measurement and you need the sp value that will actually produce it on-device.

  • What is 16sp in px?

    It depends on both density and font scale, which is the whole point of the unit. At the default 100% font scale, 16sp is 16px at mdpi, 24px at hdpi, 32px at xhdpi, 48px at xxhdpi, and 64px at xxxhdpi. Bump the font scale to 130% and every one of those numbers grows by another 1.3× — 16sp becomes roughly 62px at xxhdpi. The all-densities table above shows every combination at once for whatever value you enter.

  • What is 14sp in px?

    At 100% font scale: 14px at mdpi, 21px at hdpi, 28px at xhdpi, 42px at xxhdpi, 56px at xxxhdpi. 14sp is Material 3's Body Medium and Label Large size — common for secondary text and buttons — so it's worth checking against the type-scale table above, which shows it alongside every other Material role at your chosen density and font scale.

  • What is the difference between sp and dp for text?

    Both scale with screen density in the same way, but only sp additionally responds to the user's font-size preference. In practice this means: use sp for every fontSize value, and dp for everything else that surrounds text — line height containers, padding, icon sizes, touch targets. Sizing text in dp silently breaks accessibility, because a user who increases their system font size to read more comfortably gets no benefit inside your app. Sizing padding in sp is the opposite mistake — a button's internal padding growing every time text grows can produce cramped or overflowing layouts. Keep the two units in their separate lanes.

  • What is fontScale and where do users change it?

    fontScale is a system-wide multiplier read from Configuration.fontScale, set by the user under Settings &gt; Display &gt; Font size (exact wording varies by OEM — some show it as "Font size and style"). The typical presets are Small (0.85×), Default (1.0×), Large (1.15×), Largest (1.30×), and on Android 12+ a separate "Larger accessibility sizes" toggle unlocks additional steps up to 2.0× (200%). Every sp value in the app is multiplied by whatever the user has chosen — it isn't something you set from your own code.

  • How do I convert sp to px in Jetpack Compose?

    Compose exposes both density and font scale as a composition local, so the conversion happens inside a with block: with(LocalDensity.current) { 16.sp.toPx() }. Note this already factors in the user's font scale — unlike Dp.toPx(), which ignores it, TextUnit.toPx() multiplies by LocalDensity.current.fontScale automatically. As with dp, you rarely need this: Text(fontSize = 16.sp) handles the conversion internally, and dropping to raw pixels is only necessary inside Canvas or custom text-layout code.

  • How do I read the current font scale in Compose or Kotlin?

    In Compose, LocalDensity.current.fontScale gives you the live multiplier as a Float. Outside Compose, the same value is available as resources.configuration.fontScale. Both update automatically when the user changes their system font size while your app is backgrounded, since a configuration change is triggered on resume — you should never hardcode or cache this value.

  • Does Android scale sp non-linearly at large font sizes?

    Yes, starting with Android 14. Below roughly a 1.3× font scale, the system multiplies sp linearly — the exact formula this converter uses. Above that, Android 14+ applies a non-linear curve (via FontScaleConverter) that scales small text proportionally more than large text, so a 12sp caption grows faster than a 57sp display heading at the same accessibility setting. This keeps huge headlines from becoming physically unusable while still making small text meaningfully bigger. This converter's numbers above ~1.3× font scale are a linear approximation — treat them as a reasonable upper bound, not the exact figure Android 14+ will render, since the real curve isn't part of any public, stable API to reproduce precisely.

  • Should text ever be sized in dp instead of sp?

    Almost never, and Android's accessibility guidance explicitly recommends against it. The one narrow exception is text that must stay a fixed physical size regardless of user preference — a pixel-perfect logo lockup or a canvas-drawn watermark, for instance — and even then, consider whether a min/max sp clamp would serve the same goal without opting the text out of scaling entirely.

  • What text sizes does Material Design 3 recommend?

    M3's type scale runs from Display Large at 57sp down to Label Small at 11sp, with body text typically at 14–16sp and buttons/labels around 11–14sp. The type-scale table above lists all 15 roles with their sp value and Material's specified letter-spacing, converted at whatever density and font scale you've selected — useful for checking what a design-system role actually renders as in pixels on a real device.

  • How do I convert Figma letter spacing to Android?

    Figma expresses tracking as a percentage of the font size, not an absolute unit, so 2% tracking on 16sp text is 0.02 × 16 = 0.32sp. Divide the Figma percentage by 100 to get em (a unitless multiplier of the font size), which is the form both Android and Compose actually accept. The letter-spacing panel above takes the Figma percentage and the font size already in the sp field and computes the em, sp and pixel equivalents together.

  • Why is android:letterSpacing unitless when text size is in sp?

    Because tracking needs to compound with whatever font size it's applied to, the same way em works in CSS: android:letterSpacing="0.02" means 2% of the current text size, at any size. If letterSpacing were expressed in sp directly, a fixed value would look proportionally tighter on large headlines and proportionally looser on small captions — the opposite of what a percentage-based spec (like Figma's) intends. Compose mirrors this with a TextUnit that accepts either .sp (absolute) or .em (relative) — for a Figma percentage handoff, always reach for .em.

  • Does letter spacing behave the same in Compose as in XML?

    The em-based math is identical, but the types differ. XML's android:letterSpacing is a bare float always interpreted as em. Compose's TextStyle.letterSpacing is a TextUnit that can be either Sp or Em0.02.em matches a Figma percentage exactly, while 0.5.sp is a fixed absolute offset that won't scale with font size the way a percentage-based design spec expects.

  • How do I keep my layout intact at 200% font scale?

    Test at the largest setting deliberately, since most layouts are only ever eyeballed at 100%. Use the preview above to see your actual sp values rendered at 0.85×, 1.0×, 1.3× and 2.0× side by side. Practical fixes: avoid fixed-height containers around text (let them wrap), use maxLines with an ellipsis only where truncation is acceptable, and never size icons or touch targets in sp — keep those in dp so they don't compound with text growth and crowd the layout.

Related tools