Skip to content

필사 모드: The Real Reason Web Editors Have No Ruler — The Ruler Is Not Missing, the Paper Is

English
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

The point where a document pasted from Word falls apart

There is a requirement that comes up in almost every project that moves an internal document tool onto the web: give us a ruler like the one in Word. That tool where you drag triangles to set the left margin per paragraph, indent only the first line, and grab table column boundaries on the scale.

From the development side this requirement looks trivial, because it seems like you draw one ruler-shaped scale and put drag handles on it. But once you start, you get stuck on day one. To write 3cm on the scale you need to know how many screen pixels are 3cm, and there is no answer to that.

It is not that nobody built it

This is not an empty spot because nobody was building it. The README of the recently published editor-ruler sums up the situation like this: the classic web WYSIWYG editors — the likes of Froala, TinyMCE, CKEditor 5, and Quill — ship without a ruler, and the ones that have a ruler are only the heavy components that carry a whole document model, like Syncfusion, DevExpress, and ONLYOFFICE.

That classification is the hint. What separates the side with a ruler from the side without is not development headcount or product maturity but whether it holds a document model.

The web has no page

The reason a ruler works in Word is that the paper is decided first. Choose A4 and the width is fixed at 210mm, and if the left and right margins are 25mm each the body width is 160mm. The ruler is a rule that draws this 160mm, and dragging a triangle to the 3cm position means 3cm from the left edge of the paper. Change the screen size and this number does not change, because the paper exists independently of the screen.

The web has no such paper. The width of the editing area keeps changing with the browser window size, the sidebar state, and the zoom level. And the browser's physical units are not actual physical lengths. In CSS one inch is defined as 96 pixels, and how many millimetres those 96 pixels actually are on a screen differs from monitor to monitor.

So drawing a ruler in a web editor means assuming a piece of paper that does not exist. The problem is not the technique of drawing a rule but deciding what to measure against.

The choice of treating content width as the paper

The approach editor-ruler took shows up directly in its core API. The caller is required to pass a function that reports the current state.

import { createRuler } from '@devslab/editor-ruler';

const ruler = createRuler(mountElement, {
  unit: 'cm',
  getMetrics: () => ({ contentWidth, leftMargin, rightMargin, firstLineIndent }),
  onChange(change, phase) {
    // apply the pixel value to the current paragraph. phase becomes commit on release
  },
});
ruler.refresh(); // call whenever the selection or the content changes

What you should read here is not the first argument but getMetrics. The ruler does not know the paper width by itself; it asks the host every time. That is, the thing playing the role of paper is the current content width of the editing area, and when that width changes the ruler's numbers are recomputed.

There is a price to this choice. Narrow the screen and the 3cm position on the ruler actually points somewhere else. So this rule shares only a name with the rule in Word; it is measuring something different. The Word rule measures the paper that will be printed; this rule measures the editing area as currently laid out on screen. That is a difference you absolutely have to tell users about when you introduce it to a team.

The structure split into core and adapters

This project keeps a dependency-free core that handles only the scale, the drag handling, and the unit conversion, and separates the per-editor differences into thin adapters. Froala, Tiptap, CKEditor 5, and Summernote adapters each ship as a separate package.

The reason this structure is needed is that every editor stores indentation in a different place. The Tiptap adapter stores indentation as a node attribute and renders it with inline CSS. The CKEditor 5 adapter stores it as a model attribute and turns it into inline CSS at the down-cast stage. The Froala and Summernote adapters touch the DOM directly. The calculation the ruler does is the same; where the result gets written differs in all four.

Here the earlier argument returns. Attaching a ruler means deciding where a paragraph margin is stored. Whether it is a node attribute or an inline style changes the behaviour of pasting, exporting, and collaborative editing entirely. This is not a decision about adding one UI part.

When printing enters, the paper comes back

Here is the second point where the decision splits. If this document is only ever read on screen, there is no paper all the way through. But most internal document tools eventually get printed or go out as PDF. At that moment the paper comes back.

If there is a print path, what the ruler has to measure is not the width of the editing area but the body width of the paper to be printed. The place where you declare that paper on the web is the CSS @page rule, and that is where the sheet size and margins are set. In other words, deciding the ruler's reference becomes a matter of making it look at the same values as the print stylesheet.

Mixing the two produces the worst outcome. The user sets 3cm against the screen, prints, and on paper it is not 3cm. Then the ruler loses trust precisely by existing. So there are effectively two options: make the editing area a fixed-width fake paper so screen and print agree, or say clearly in the UI that what the ruler measures is not the printed result. Doing neither is also why many tools today do not include a ruler.

The small things you only hit by building it

The README of this project has a few entries only someone who actually built it could write. Two are especially practical.

First, the unit of undo. One drag produces dozens of value changes. Leave it as-is and you have to press undo twenty times to get back to the original position. This project states that it groups one drag into one undo step. That is why phase in the API above distinguishes the commit.

Second, the layout shift when toggling the vertical ruler on and off. When the vertical rule appears, the body is pushed over by that much. This project provides an option that reserves the space in advance, and explains that behaviour by analogy with the CSS scrollbar-gutter: stable. The analogy pins down the nature of the problem exactly: UI that may appear later has to take its place before it appears.

Writing this project's current state as it is

Let me be clear about the part that cannot be exaggerated. This repository is only a few days old, the star count is in single digits, and it was made by an individual or a very small team. The licence is Apache-2.0, the language is TypeScript, and npm packages are published. The README carries a line saying it is stable from 1.0.0, but that is the author's own declaration and not a third-party assessment.

So I am not recommending in this post that you use this library. Whether to adopt it in production is something to verify for yourself. The reason this project is worth looking at right now lies elsewhere. It comes with documentation that states the problem precisely. The author wrote up separately what a ruler can mean in the absence of a page model, and what tripped them up while building it. Whether or not you plan to build one yourself, that problem statement is worth the read.

Summary and sources

The absence of a ruler in web editors is not a missing feature but a missing premise. Without settling the paper you cannot measure, and the moment you settle the paper it becomes a document model decision rather than a UI one. If you have been asked for this feature in an internal tool, agree on what counts as the paper before you estimate the implementation.

  • devslab-kr/editor-ruler repository — the core API, the per-adapter storage approach, undo handling, the vertical rule space-reservation option. Everything said about this project in the body was confirmed in the README.
  • Every web rich-text editor is missing a ruler — the author's background post, linked from the repository
  • Confirmed from repository metadata: licence Apache-2.0, language TypeScript, repository creation time and star count. The statements about maturity rest on those figures and are not an assessment of code quality.
  • That one inch is defined as 96 pixels in CSS follows from the absolute length unit definitions in the CSS Values and Units specification.

현재 단락 (1/34)

There is a requirement that comes up in almost every project that moves an internal document tool on...

작성 글자: 0원문 글자: 7,279작성 단락: 0/34