From 77980e4b9cae5a67e0d075e24d4b8f2989e7b704 Mon Sep 17 00:00:00 2001 From: Steffen Becker Date: Sat, 8 Aug 2026 12:25:22 +0000 Subject: [PATCH] fix: a block ending in a hard break is not a line taller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reserved paragraph mark is inline content past the block's last BR, so it opened a line of its own: LibreOffice set the next paragraph 4.7mm higher than we did, and a fixture paid for every one of them. The empty-block rule already pulled the mark out of flow for exactly this reason — it now covers any block that ends in a break, seating the glyph on the last line rather than the first. --- src/styles/editor.css | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/styles/editor.css b/src/styles/editor.css index 1028e29..b99875e 100644 --- a/src/styles/editor.css +++ b/src/styles/editor.css @@ -638,33 +638,34 @@ display: none; } -/* Empty block fix: a paragraph/heading/li-paragraph holding only the ProseMirror - trailing-break BR would render the inline ¶ on a second line, doubling its height. - Pull ::after out of flow. Applied always so the reserved ¶ stays zero-height. */ -.paper .tiptap p:has(> br.ProseMirror-trailingBreak:only-child), -.paper .tiptap h1:has(> br.ProseMirror-trailingBreak:only-child), -.paper .tiptap h2:has(> br.ProseMirror-trailingBreak:only-child), -.paper .tiptap h3:has(> br.ProseMirror-trailingBreak:only-child), -.paper .tiptap h4:has(> br.ProseMirror-trailingBreak:only-child), -.paper .tiptap h5:has(> br.ProseMirror-trailingBreak:only-child), -.paper .tiptap li > p:has(> br.ProseMirror-trailingBreak:only-child) { +/* A block ProseMirror ends with a trailing-break BR — an empty one, or one ending in a + hard break — puts the inline ¶ on a line of its own past that BR, so the block renders + one line too tall. Pull ::after out of flow, onto the last line. */ +.paper .tiptap p:has(> br.ProseMirror-trailingBreak), +.paper .tiptap h1:has(> br.ProseMirror-trailingBreak), +.paper .tiptap h2:has(> br.ProseMirror-trailingBreak), +.paper .tiptap h3:has(> br.ProseMirror-trailingBreak), +.paper .tiptap h4:has(> br.ProseMirror-trailingBreak), +.paper .tiptap h5:has(> br.ProseMirror-trailingBreak), +.paper .tiptap li > p:has(> br.ProseMirror-trailingBreak) { position: relative; } -.paper .tiptap p:has(> br.ProseMirror-trailingBreak:only-child)::after, -.paper .tiptap h1:has(> br.ProseMirror-trailingBreak:only-child)::after, -.paper .tiptap h2:has(> br.ProseMirror-trailingBreak:only-child)::after, -.paper .tiptap h3:has(> br.ProseMirror-trailingBreak:only-child)::after, -.paper .tiptap h4:has(> br.ProseMirror-trailingBreak:only-child)::after, -.paper .tiptap h5:has(> br.ProseMirror-trailingBreak:only-child)::after, -.paper .tiptap li > p:has(> br.ProseMirror-trailingBreak:only-child)::after { +.paper .tiptap p:has(> br.ProseMirror-trailingBreak)::after, +.paper .tiptap h1:has(> br.ProseMirror-trailingBreak)::after, +.paper .tiptap h2:has(> br.ProseMirror-trailingBreak)::after, +.paper .tiptap h3:has(> br.ProseMirror-trailingBreak)::after, +.paper .tiptap h4:has(> br.ProseMirror-trailingBreak)::after, +.paper .tiptap h5:has(> br.ProseMirror-trailingBreak)::after, +.paper .tiptap li > p:has(> br.ProseMirror-trailingBreak)::after { position: absolute; - top: 0; + /* Out of flow, so restore the paragraph's line-height (the base rule zeroes it) to + seat the glyph on a line instead of the collapsed top edge — the last one, which + for an empty block is also the first. */ + line-height: inherit; + top: calc(100% - 1lh); left: 0; margin-left: 0; - /* Out of flow, so restore the paragraph's line-height (the base rule zeroes it) to - seat the glyph on the empty line instead of the collapsed top edge. */ - line-height: inherit; } .paper.show-formatting-marks .tiptap .pm-space-mark {