When I’m tinkering with my own browser, Omoikane , I’ve found that the tiny differences that are taken for granted in existing browsers can be more troublesome than implementing a single large web API.

The changes I added this time are the default margin for body, declarative Shadow DOM, and the orientation of characters in vertical text. Each of these looks like a small visual tweak, but each relies on assumptions in the CSS cascade, HTML parsing, and text rendering, respectively.

The 8 px of body is not merely a margin

When HTML without any explicit styles is opened in Firefox or similar browsers, the content of body is placed slightly inward from the edge of the viewport. This is due to the default margin: 8px provided by the browser’s user‑agent stylesheet.

Omoikane didn’t have this, so pages with no explicit styling started at the very edge of the screen. If it were only a visual difference, a simple fix—such as adding an 8 px margin at the end of the layout—might appear to work at first glance.

However, this margin exists as a UA‑origin declaration that is weaker than the author’s stylesheet.

<style>
  body { margin: 0; }
</style>

In such pages, the author’s margin: 0 takes precedence. Also, if the author uses revert, it reverts to the UA’s 8 px margin. It is also incorrect for the number of author stylesheets in the document or the CSSOM to include a nonexistent UA stylesheet.

Therefore, in this fix we added the 8 px margin in all four directions for body as a UserAgent origin to the style‑resolver candidates, inserting it into the cascade before the author CSS.

UA origin: body margin is 8px
    ↓
author origin: body { margin: 0 }
    ↓
Computed style is 0px

By letting this default participate in the cascade rather than writing it directly into the computed style, we can treat author CSS, revert, and the CSSOM in a natural, unified way.

We also added a Firefox comparison fixture for this change. In the default state, the content and list markers start at (8, 8), and when set to 0 via author CSS they become (0, 0); we compare them pixel‑by‑pixel using a 500 × 160 capture. Even an 8 px shift moves the entire page, so the difference is quite noticeable in the diff image.

Declarative Shadow DOM is special only at the moment the HTML is read

Next is Declarative Shadow DOM. It provides a mechanism for declaring a shadow root directly in HTML, like this:

<div id="host">
  <template shadowrootmode="open">
    <span id="inside">shadow tree</span>
  </template>
</div>

When parsing a normal document, this template becomes the shadow root of the host, and the template element itself does not remain in the light DOM. If shadowrootmode="closed" is used, an internal root is created, but it cannot be retrieved via host.shadowRoot from JavaScript.

What we had to be careful about here is when the same string is passed to innerHTML.

host.innerHTML = '<template shadowrootmode="open"><span>...</span></template>';

In this implementation, we do not enable Declarative Shadow DOM along this fragment‑parser path. In that case, no shadow root is created and the template remains as a normal template.

If we treat the initial HTML load and fragment parsing for DOM manipulation in the same way, a shadow root will be automatically created later from the string inserted into innerHTML. Also, if the template is left as a child of the host, the contents of the shadow tree become visible from the light DOM.

On the parser side, we only allow declarations when parsing a normal Document and also verify that the host does not have a shadow root. For invalid hosts, a second declaration, or when using the fragment parser, we treat the template as‑is. Simply making the syntax parseable was not enough; we also had to track the parsing context as part of the state.

The column direction of vertical text and character orientation are separate

The fix for vertical text also seemed simple at first.

.vertical {
  writing-mode: vertical-rl;
}

vertical-rl and vertical-lr indicate the direction in which the columns progress. However, the orientation of rotating Latin characters or keeping Japanese characters upright is a separate issue.

Previously, the character rotation direction was determined from the block direction. As a result, vertical-lr had a path that treated even Latin letters in the opposite orientation. The direction of the column progression and the physical rotation of the characters themselves were handled with the same value.

In the fix, we treat vertical-rl and vertical-lr as mixed orientation, and determine each character’s orientation using Unicode Vertical Orientation data.

Vertical writing with mixed orientation
    -> Latin characters: rotated and placed
    -> Kanji, kana, Hangul: placed upright
    -> Emojis and Japanese punctuation: placed upright

Combining characters do not determine their own rotation direction; they inherit the orientation of the preceding base character. sideways-rl and sideways-lr are handled separately, and in this case the entire character is rotated to the specified direction.

As for vertical typesetting, we have not yet implemented substitution to vertical‑specific glyph forms. For example, the long vowel mark ー currently falls back to a rotated rendering. Nonetheless, referencing Unicode’s character orientation rather than rotating every glyph solely based on the column direction brings the layout closer to the true appearance of vertical text.

Compatibility fixes don’t end with rendering alone

These changes may look like they affect only the visual appearance.

  • The 8 px margin involves the CSS origin and revert.
  • Shadow roots are tied to the HTML‑parser context and the separation of the DOM tree.
  • Vertical text concerns the logical writing direction and the physical glyph rotation.

In this way, each issue reaches a different layer of implementation.

In the same update we also added optimizations that skip the DOM‑removal hook when it isn’t needed, and changes that avoid unnecessary layout during CDP accessibility checks. Simply adding more compatibility handling can affect the performance of pages that don’t use those features. It is necessary to treat conformance to the specification and the avoidance of heavy verification or ordinary DOM operations as separate concerns.

When you use a browser, you usually don’t notice the 8 px margin or the placement of punctuation in vertical text. However, achieving a state where you don’t have to think about them requires aligning, one by one, which origin the default values belong to, the context in which the HTML is parsed, and what determines each character’s orientation.