Markdown to PDF with CSS

Paste your own stylesheet next to the Markdown. Fonts, margins, @page headers, page numbers and printed backgrounds all apply. The preview shows the styled page before you download.

Pro · preview is free

Northwind — Q3 report

Q3 operations report

Prepared for the board meeting on 14 October. Figures are unaudited.

Headline numbers

MetricQ2Q3Change
Orders12,48014,905+19.4 %
Refund rate2.1 %1.6 %−0.5 pt

Next quarter

The warehouse migration starts on 3 November; see the runbook in the appendix.

1 / 3

Converted in your browser. Your file never leaves your device.
1

Add a <style> block or a .css file

Markdown allows raw HTML, so a <style> block at the top of the file is the simplest way. You can also drop a .css file next to the .md.

2

Check the preview

The preview renders with your rules applied on top of MDtoDOCX's own print stylesheet, including fonts and printed backgrounds. Your rules load last, so anything you set wins.

3

Download PDF

@page size, margins, running headers and page counters are honoured. Name a font that is bundled with MDtoDOCX or installed on your machine.

How your CSS is applied when Markdown becomes a PDF

Markdown has no styling of its own, which is exactly why people reach for CSS: it is the only widely understood way to say "11 pt serif body, 2 cm margins, a running header with the report title". MDtoDOCX converts Markdown to HTML, applies a cascade of stylesheets and then paginates that HTML into a PDF. Your CSS sits at the top of that cascade. This page describes what is in the cascade below it, which print-specific rules work, how fonts are handled and where the limits are, so you can write a stylesheet once and get the same document every time.

The cascade: MDtoDOCX's print stylesheet, then yours

Two stylesheets go into the document, in this order. First, MDtoDOCX's own print stylesheet, which is not a set of themes you choose between but a single sheet generated from the settings already in the converter: the font and size from the options bar become the body rules, the paper size and margins become the @page rule, and fixed rules handle table borders, code block padding, heading spacing, fragmentation and print-color-adjust. There is no theme picker in this version, so the way to change the starting point is to change those options or to override the properties yourself. Second, your CSS, emitted last in the document head. Nothing in the generated sheet uses !important, so any property you set wins on specificity ties simply by coming later, and you can reset the lot with a few blanket rules if you want a blank sheet. Because MDtoDOCX emits plain semantic HTML, h1 through h6, p, ul, table, pre code, blockquote, img, your selectors are the same ones you would write for a website. Fenced code blocks get a language-xxx class and syntax tokens get the standard .token.keyword classes, so a highlight.js or Prism theme pastes straight in and overrides the built-in token colours.

@page: size, margins, headers, footers and page numbers

The @page at-rule is where print CSS differs from screen CSS, and it is fully supported. size: A4, Letter, A4 landscape or explicit dimensions such as 210mm 297mm set the sheet. margin sets the printable area; anything you put in the sixteen margin boxes, @top-left, @top-center, @top-right, @bottom-center and so on, becomes a running header or footer on every page. Inside those boxes content: counter(page) gives the current page number and counter(pages) the total, so content: counter(page) " of " counter(pages) produces "3 of 12". The :first pseudo-class lets the title page drop its header, and named pages such as @page landscape { size: landscape } with .wide { page: landscape } rotate a single wide table. These rules only apply in the PDF; the HTML download ignores them.

Controlling page breaks

Use the modern fragmentation properties: break-before: page on an h1 starts each chapter on a new sheet; break-after: avoid on headings keeps them with the paragraph that follows; break-inside: avoid on pre, table, figure and blockquote stops them being cut. The older page-break-* spellings are accepted too. orphans and widows default to 2 and can be raised. A single Markdown line containing only ---pagebreak--- or the HTML comment <!-- pagebreak --> forces a break without any CSS.

Fonts: what a font-family actually resolves to

Any font-family you name is resolved in two steps. If it is one of the fonts bundled with MDtoDOCX (Inter, Source Serif 4, Source Sans 3, JetBrains Mono, Latin Modern, STIX Two), it is used directly. Otherwise the family is looked up on the machine doing the rendering, and if it is not installed there the next name in your font stack is tried, exactly as in a browser. Remote font files are not downloaded for you in this version: an @import url(https://fonts.googleapis.com/…) or an @font-face whose src points at a URL is not fetched, so a Google Fonts line in your stylesheet will silently fall through to the next family rather than producing the face you named. That is a limitation of the current release. The practical rule is to write a stack you can vouch for, ending in a generic family, for example font-family: "Source Serif 4", Georgia, serif. The glyphs actually used are embedded in the PDF when it is produced, so a recipient without the font still sees the document correctly. Prefer pt for font sizes and cm or mm for margins; px is converted at 96 per inch, which is what browsers assume, but point units make the intent clear on paper.

Printing backgrounds and colours

Browsers drop background colours when printing unless told otherwise, which is why a shaded table header vanishes in most Markdown-to-PDF tools. MDtoDOCX sets -webkit-print-color-adjust: exact and print-color-adjust: exact on every element, so th { background: #eee } prints as written. This is unconditional: there is no switch in the options bar to turn printed backgrounds off in the current version. If you want a toner-saving draft, say so in your own stylesheet, which is loaded after ours — @media print { *, *::before { background: none !important } } strips the shading while leaving the layout alone. Colours are written into the PDF as sRGB; if you need a CMYK-only workflow, export and convert in your print tool.

What is not supported

JavaScript in the Markdown is stripped. position: fixed is treated as static because the PDF engine paginates rather than scrolls; use margin boxes for running content instead. CSS Regions, string-set for chapter titles in headers and footnote floats are not implemented. Remote font files are not fetched, as described above, and there is no theme picker and no printed-background switch in this release. External images referenced from CSS background-image must be reachable over https. Everything else that renders in a current browser, including grid, flexbox, custom properties and @media print, renders in the PDF.

Free preview, Pro download

The preview applies your CSS for free, so you can iterate on a stylesheet without an account. Downloading a PDF with custom CSS and @page rules is a Pro feature; a free download uses the generated print stylesheet alone, driven by the font, size and paper you picked in the options bar. Stylesheets can be saved as presets and reused across documents on the Pro plan, and the same preset applies to Markdown to HTML output. See Pricing for the 7-Day Pass at $4.9.

Custom CSS: MDtoDOCX vs Pandoc + wkhtmltopdf vs browser print

Styling capabilityMDtoDOCXPandoc + wkhtmltopdfPrint from a Markdown preview
Where the CSS goes<style> block or .css file--css flagBrowser extension or none
@page size and marginsYesFlags only, not CSSPrint dialog only
Running headers and footers@page margin boxesSeparate HTML filesBrowser adds its own
Page numberscounter(page) / counter(pages)Flag with placeholdersBrowser default only
break-inside / break-afterYesPartial (old WebKit)Yes
Grid and flexboxYesNoYes
Remote web fonts fetched for youNo, bundled or locally installed families onlySometimesSometimes
Printed backgroundsAlways on, no switch to turn offFlagOff by default
Live preview of the styled pageYesNoPrint preview only
InstallNonePandoc + wkhtmltopdf (unmaintained)None

Frequently asked questions

How do I add custom CSS to my Markdown before converting to PDF?
Put a <style>…</style> block anywhere in the Markdown, usually at the top, or drop a .css file together with the .md file. Your rules are loaded after MDtoDOCX's print stylesheet, so they win.
Can I set the page size and margins with CSS?
Yes. @page { size: A4; margin: 2cm } is honoured, as are Letter, landscape and explicit millimetre dimensions. Named pages let one section be landscape.
How do I get page numbers and a running header?
Use @page margin boxes: @bottom-center { content: counter(page) " of " counter(pages) } for numbers and @top-right { content: "Title" } for a header. Use @page :first to remove them from the title page.
Will background colours and shaded table headers print?
Yes. print-color-adjust: exact is set on every element, so th { background: #eee } prints as written. This version has no switch to turn printed backgrounds off; for a toner-saving draft, add @media print { * { background: none !important } } to your own CSS.
Can I use Google Fonts or my own font file?
Not by URL. This version does not download remote font files, so an @import of a Google Fonts URL or an @font-face with a remote src is not fetched for you. Name one of the bundled families, or install the font locally and name it; the glyphs used are then embedded when the PDF is produced. It is a limitation of the current release, not a setting you have missed.
Can I reuse a Prism or highlight.js theme for code blocks?
Yes. Code tokens carry the standard .token.* classes, so any Prism theme applies. Add pre { break-inside: avoid } to keep blocks on one page.
Which CSS features do not work in the PDF?
JavaScript is stripped, position: fixed becomes static, and CSS Regions, string-set and footnote floats are not implemented. Grid, flexbox, custom properties and @media print all work.
Is custom CSS free?
The styled preview is free. Downloading a PDF with your CSS and @page rules applied is a Pro feature; the $4.9 7-Day Pass covers a single project. Nothing is uploaded; conversion runs in your browser.