2. Styling & typography
Fonts, colors, spacing, and the styling cascade.
In Rivoli PDF, appearance lives in a single type: Style. You attach a Style to
a run of text, a paragraph, or the whole document, and the layout engine resolves
the effective look from those layers. This chapter walks through the fluent
Style API, then shows where to attach styles for per-run, per-paragraph, and
document-wide effects.
Style, Color, and the styling enums live in Rivoli.Pdf.Model and
Rivoli.Pdf.Styling:
using Rivoli.Pdf.Model;using Rivoli.Pdf.Styling; // TextAlignment, TextDecoration, FontWeight, FontStyleThe Style fluent API
Section titled “The Style fluent API”A Style is a mutable bag of formatting properties with a fluent configuration
API. Every With… method sets one property and returns the same Style, so they
chain:
var heading = new Style() .WithFontFamily("Helvetica") .WithFontSize(18) .Bold() .WithForegroundColor(Color.FromHex("#1a1a2e")) .WithTextAlignment(TextAlignment.Center) .WithParagraphSpacing(before: 0, after: 12);The methods you’ll reach for most:
| Method | Sets |
|---|---|
WithFontFamily(string) | Font family, e.g. "Helvetica", "Times-Roman", "Courier" |
WithFontSize(double) | Size in points |
Bold() / Italic() | Shortcuts for FontWeight.Bold / FontStyle.Italic |
WithForegroundColor(Color) | Text color |
WithBackgroundColor(Color) | Fill behind the text or block |
WithTextAlignment(TextAlignment) | Left, Center, Right, Justify |
WithTextDecoration(TextDecoration) | Underline, LineThrough, Overline (flags) |
WithLineHeight(double) | Line height (multiplier if < 10, absolute points if >= 10) |
WithLetterSpacing(double) | Tracking in points; negative tightens |
WithMargin(double) / WithMargin(h, v) | Space outside the block |
WithPadding(double) | Space inside the block, between border and content |
WithParagraphSpacing(before, after) | Space above and below a paragraph |
WithBorder(double width, Color) | A uniform border on all four sides |
For finer control you can also set the underlying properties directly (
FontWeight, FontStyle, MarginLeft, PaddingTop, BorderColor, and so on),
since Style is a plain object.
Colors
Section titled “Colors”Color is an RGB value. There are named statics for the common ones, plus three
factory methods:
Color.Black; Color.White; Color.Red; Color.Green; Color.Blue;Color.Yellow; Color.Cyan; Color.Magenta; Color.Gray;
Color.FromRgb(255, 128, 0); // bytes, 0–255Color.FromRgb(1.0, 0.5, 0.0); // doubles, 0.0–1.0Color.FromHex("#FF8000"); // "#RRGGBB" or "RRGGBB"Use them anywhere a color is expected:
var warning = new Style() .WithForegroundColor(Color.FromHex("#b00020")) .WithBackgroundColor(Color.FromRgb(255, 240, 240)) .Bold();Decorations are flags
Section titled “Decorations are flags”TextDecoration is a [Flags] enum, so you can combine decorations:
var struckLink = new Style() .WithTextDecoration(TextDecoration.Underline | TextDecoration.LineThrough);Where to attach a style
Section titled “Where to attach a style”The same Style type attaches at three levels. Pick the level that matches the
scope you want to affect.
Per run: styling part of a paragraph
Section titled “Per run: styling part of a paragraph”A Run is a span of text inside a paragraph. Give a single run its own style to
format just those words, leaving the rest of the line alone:
var emphasis = new Style().Bold().WithForegroundColor(Color.Red);
var para = new Paragraph();para.Inlines.Add(new Run("Status: "));para.Inlines.Add(new Run("OVERDUE") { Style = emphasis });section.Add(para);Only the second run is bold and red; the label stays plain. This is the level for inline emphasis, highlighted terms, and mixed formatting within a sentence.
Per paragraph: styling a whole block
Section titled “Per paragraph: styling a whole block”Attach a style to a Paragraph (or any Block) to format the entire block:
alignment, block-level spacing, borders, and the default font for the text inside
it. The AddParagraph overload that takes an Action<Style> is the concise way
to do this:
using Rivoli.Pdf.Builders;
section.AddParagraph("A centered, spaced lead paragraph.", style => style .WithFontSize(13) .WithTextAlignment(TextAlignment.Center) .WithParagraphSpacing(before: 0, after: 18));Some properties only make sense at the block level: TextAlignment,
WithParagraphSpacing, WithBorder, and WithPadding describe the box, not
individual characters. Set those on the paragraph, not on a run.
Document default: styling everything
Section titled “Document default: styling everything”Document.DefaultStyle is the base every node falls back to. Set the body font
and size once, and every paragraph inherits it unless it overrides:
var doc = Document.Create("Styled Report");doc.DefaultStyle = new Style() .WithFontFamily("Helvetica") .WithFontSize(11) .WithLineHeight(1.4) .WithForegroundColor(Color.FromHex("#222222"));With DocumentBuilder, the same thing reads as one expression:
using Rivoli.Pdf.Builders;
var doc = DocumentBuilder.Create("Styled Report") .WithDefaultStyle(s => s.WithFontFamily("Helvetica").WithFontSize(11)) .Build();How the layers combine
Section titled “How the layers combine”When a node needs a property (say the font size of a word in a run), the layout engine looks up the tree until it finds a value: the run’s own style first, then the paragraph’s, then the document default, then the built-in fallback. The closest setting wins, and unset properties fall through.
This is why the three levels compose so cleanly: set the body font on the document, alignment and spacing on the paragraph, and only the truly local emphasis on the run. For the precise resolution rules (including how the stylesheet and inheritance interact). Read The styling cascade.
A complete example
Section titled “A complete example”using Rivoli.Pdf;using Rivoli.Pdf.Builders;using Rivoli.Pdf.Model;using Rivoli.Pdf.Styling;
var doc = Document.Create("Styled Report");doc.DefaultPageSize = PageSize.A4;doc.DefaultMargin = Margin.Standard;doc.DefaultStyle = new Style() .WithFontFamily("Helvetica") .WithFontSize(11) .WithLineHeight(1.4);
var section = doc.AddSection();
section.AddParagraph("Styled Report", style => style .WithFontSize(22) .Bold() .WithTextAlignment(TextAlignment.Center) .WithForegroundColor(Color.FromHex("#1a1a2e")));
var note = new Paragraph();note.Inlines.Add(new Run("Note: "));note.Inlines.Add(new Run("figures are provisional.") { Style = new Style().Italic().WithForegroundColor(Color.Gray) });section.Add(note);
doc.SavePdf("styled-report.pdf");- Tables, lists, images: structured content and embedded media.