Skip to main content

Fixing Line-Height Inconsistencies in Outlook 2016-2021

Stop the Word engine recomputing leading from font metrics: absolute line-height, mso-line-height-rule exactly, and the elements that need it beyond paragraphs.

A paragraph set at line-height: 1.5 renders with visibly tighter leading in Outlook 2016 through 2021 on Windows than in every other client, and a heading set the same way sometimes renders looser. This guide covers the exact declarations that pin leading in the Word engine, and the elements people forget to apply them to.

Root Cause: The Word Engine Treats Leading as a Minimum

Browsers compute a unitless line-height by multiplying it against the element's font size and using the result as the line box height. The Word engine does something different: it derives its own leading from the font's internal ascent, descent and line-gap metrics, then treats your declared value as a minimum rather than as the answer.

Two consequences follow. Where the font's natural leading exceeds your declared value, the engine uses the font's — so a heading at line-height: 1.1 renders looser than designed. Where the font's natural leading is smaller, the engine may still apply its own rounding, producing a value close to but not equal to yours. Neither behaviour is a bug in the sense of being unintended; the engine is laying out a word-processing document, where the font's metrics are authoritative.

Unitless values make this worse because there is nothing absolute to anchor on, and the fallback font — which the Word engine has probably substituted anyway, since it ignores @font-face entirely — has different metrics from the one you designed against.

Declared line-height versus engine-derived leading A browser multiplies the declared multiplier by the font size, while the Word engine computes leading from font metrics and treats the declaration as a floor. Same Declaration, Two Computations Browser and WebKit clients 16px x 1.5 = 24px line box The declaration is the answer. Font metrics do not enter into it. predictable at any font size Word engine, Outlook 2016-2021 max(font metrics, declaration) The declaration is a floor, and the substituted font decides the rest. varies with the font actually used
Because the engine takes the larger of the two, a tight heading loosens and a loose paragraph stays as authored — which is why the inconsistency looks arbitrary.

The Exact Fix

Two declarations together, on every element that renders text.

<!-- line-height in ABSOLUTE units gives the engine a concrete value.
     mso-line-height-rule:exactly changes it from a floor to an exact value,
     so the font's own metrics stop contributing.
     Affects: Outlook 2016, 2019, 2021 on Windows. Ignored elsewhere. -->
<td style="font-family:Arial,sans-serif;
           font-size:16px;
           line-height:24px;
           mso-line-height-rule:exactly;
           padding:0;">
  Body copy that holds a 24px rhythm in every client.
</td>

mso-line-height-rule: exactly is the declaration that does the real work; the absolute unit is what gives it something unambiguous to apply. Using one without the other leaves the behaviour partially undefined: a pixel value alone is still treated as a minimum, and the MSO rule with a unitless value has no fixed number to enforce.

Because the rule is a mso- prefixed property, it is ignored by every non-Microsoft client, so it can be declared inline without a conditional wrapper. That is a considerable convenience — unlike most Word-engine fixes, this one needs no separate conditional block.

The Elements People Miss

The declaration inherits poorly in email, and several clients reset font properties on table elements, so it must be repeated rather than set once on a wrapper.

Element Needs the pair? Why
td containing text Yes The most common text container; inheritance is unreliable
p Yes Some clients apply a default margin and leading
h1h6 Yes Tight heading leading is where the floor behaviour is most visible
a styled as a button Yes Line height determines the button's rendered height
span inside a styled cell Usually not Inherits from the cell if the cell declares it
li Yes List items are frequently reset by the client
Empty spacer td Yes An empty cell with no leading rule collapses differently per engine

The spacer cell row is the one that produces mysterious vertical gaps. An empty <td height="24"> with no line-height picks up the engine's default leading, which can exceed the declared height and push the layout apart. Setting line-height: 24px; mso-line-height-rule: exactly; font-size: 1px; on spacers makes them behave identically everywhere.

Spacer cell height versus rendered height An empty spacer cell without a leading rule renders taller than its declared height in the Word engine, pushing the surrounding layout apart. An Empty Cell Still Has a Line Box height="24" only content above renders ~34px, not 24px content below with the exact rule content above exactly 24px content below font-size:1px prevents any residual glyph box
Spacer cells are the most common source of unexplained vertical drift, because an empty cell still reserves a line box.

Variant: Outlook 365 and the New Outlook

Builds running on WebView2 — the new Outlook for Windows, and Microsoft 365 desktop after the rollout — use a Chromium-derived engine and honour line-height exactly as a browser does. They also ignore mso-line-height-rule, harmlessly.

Leading behaviour by Outlook build Perpetual Outlook builds need the MSO exact rule, while WebView2 builds honour CSS line-height and ignore the rule harmlessly. One Template Covers Both Engines Word engine builds Outlook 2016, 2019, 2021 on Windows Reads the MSO rule and applies the pixel value exactly. WebView2 builds new Outlook, Outlook for Mac, mobile Honour CSS line-height and discard the MSO rule silently.
Because the MSO property is ignored rather than misapplied elsewhere, no conditional wrapper is required.

This means a single template with both declarations renders correctly across all Outlook builds without a conditional. It also means a bug reported by a colleague on the new Outlook and not reproducible on Outlook 2019 is genuinely a different engine, not a version difference in the same one.

Diagnosing It Without a Windows Machine

The fix is easy; confirming it worked usually is not, because the engine that misbehaves is the one most developers cannot open locally. Three approaches narrow the gap.

The cheapest is arithmetic. Measure the rendered block height in a client that behaves correctly, divide by the number of lines, and compare against the declared leading. If a five-line paragraph at 24px leading occupies 120px in Apple Mail, the same paragraph occupying 145px in a client render farm screenshot is being laid out at roughly 29px per line — which is the font's natural leading rather than yours. You do not need to inspect the DOM to establish that; the pixel height is sufficient evidence.

The second is a deliberate probe. Add a temporary block to a test template with a leading value far outside any font's natural range — say 60px on 16px text — and send it. If the rendered block is 60px per line, the exact rule is being applied; if it is closer to 19px, the declaration is not reaching the element at all, which points at the inliner or a stripped style block rather than at the engine.

The third is the client render farm, which gives you screenshots from real Outlook builds and is the only way to see the actual result. Its cost is latency rather than money — a render takes minutes, which is fine for a pre-release check and too slow for iterating on a fix. Use the arithmetic method while iterating and the farm to confirm.

What none of these give you is a computed-style inspector, because the Word engine does not expose one. That is the underlying reason this class of bug is diagnosed by measurement rather than by inspection, and why a probe with an absurd value is often the fastest route to an answer.

Pipeline Integration

Put the pair in a component rather than in each template. A cell component that always emits font-family, font-size, line-height and mso-line-height-rule together makes it impossible to declare one without the others — which is the actual failure mode, since a developer adding a font size to an existing cell rarely thinks to add a leading rule alongside it.

Add a lint step over compiled output that flags any line-height without an adjacent mso-line-height-rule, and any unitless line-height at all. Both are mechanical checks that run in a fraction of a second and catch the regression at the point it is introduced, in the same pass as the rest of your markup checks.

Validation and Deployment Checklist

Frequently Asked Questions

Does mso-line-height-rule need a conditional comment?

No. It is a Microsoft-prefixed property, so every other client's CSS parser discards it as unknown. Declaring it inline alongside the standard line-height is safe and is the simplest way to ship it.

Why does my heading render looser rather than tighter?

Because the engine takes the larger of the font's natural leading and your declaration. A heading with a tight declared leading — anything below about 1.2 — is usually below the font's natural value, so the engine uses the font's instead. The exact rule is what overrides that.

Is line-height in em acceptable instead of pixels?

It is better than unitless but still not reliable, because em resolves against a font size that the Word engine may itself have substituted. Pixels remove the dependency entirely, which is the point of the fix.

Does this change how the message looks in clients that were already correct?

No. line-height: 24px and line-height: 1.5 on 16px text resolve to the same value in every engine that computes it properly, so converting from a multiplier to an absolute value is visually neutral outside the Word engine. The MSO property is discarded by those clients entirely. The change is therefore safe to apply across an existing template set without a visual review of every client — only Outlook's rendering moves, and it moves toward what you designed.

Should the fix be applied to preheader text too?

Yes, and it matters there more than elsewhere. Preheader text is usually hidden with a zero or one pixel font size, and without an exact leading rule the engine can still reserve a full line box for it — producing a mysterious gap at the very top of the message, above the visible content.


← Back to Email Typography and Web Fonts