Skip to content

Pagination broken when loaded in shadowRoot #1641

@DavidMulder0

Description

@DavidMulder0

I was trying to do a quick and dirty POC using vivliostyle, and I had some style leakage breaking into the viewer causing the viewer to render incorrectly. Figured that would be simple enough to solve by loading the viewer within a shadow root together with the global styles that are injected into the <head> by the CoreViewer, and initially everything seemed to work, except I realized that all "page overflow" is missing:

import("https://esm.run/@vivliostyle/core").then(({default: vivliostyle}) => {
  const { CoreViewer } = vivliostyle;
  const host = document.createElement("div");
  document.body.appendChild(host);
  const el = document.createElement("div");

  // # broken scenario: 
  const shadowRoot = host.attachShadow({ mode: "open" });
  shadowRoot.appendChild(el);

  // # functioning scenario:
  // host.appendChild(el);

  const viewer = new CoreViewer({
    viewportElement: el,
  });

  const str = `<!DOCTYPE html>
<html>
  <head>
    <style>
      @page {
        size: a5;

        @bottom-left {
          content: "Page " counter(page) "/" counter(pages);
        }
      }

      p {
        line-height: 1.5em;
      }
      #page-break-before {
        page-break-before: always;
      }
    </style>
  </head>
  <body>
      <p
        >1 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla eget
        ante feugiat, imperdiet massa vel, sagittis mi. Aenean metus velit,
        blandit quis metus ac, suscipit aliquet nulla. Aenean ut enim dictum,
        porta metus et, ultricies metus. Phasellus malesuada nisl lorem.
        Praesent sagittis dui nulla, dictum luctus sem scelerisque ac. Nam
        consequat a velit eu congue. Nulla id vestibulum orci. Sed quis
        condimentum justo. Nunc bibendum tincidunt ipsum, ut pellentesque orci
        egestas at. Curabitur pulvinar vitae purus et malesuada. Duis ex orci,
        placerat ut lectus posuere, posuere rhoncus arcu. Vivamus in risus quis
        mauris commodo venenatis id quis justo. Fusce interdum tincidunt
        eleifend.</p
      >

      <p
        >2 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla eget
        ante feugiat, imperdiet massa vel, sagittis mi. Aenean metus velit,
        blandit quis metus ac, suscipit aliquet nulla. Aenean ut enim dictum,
        porta metus et, ultricies metus. Phasellus malesuada nisl lorem.
        Praesent sagittis dui nulla, dictum luctus sem scelerisque ac. Nam
        consequat a velit eu congue. Nulla id vestibulum orci. Sed quis
        condimentum justo. Nunc bibendum tincidunt ipsum, ut pellentesque orci
        egestas at. Curabitur pulvinar vitae purus et malesuada. Duis ex orci,
        placerat ut lectus posuere, posuere rhoncus arcu. Vivamus in risus quis
        mauris commodo venenatis id quis justo. Fusce interdum tincidunt
        eleifend.</p
      >

      <p
        >3 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla eget
        ante feugiat, imperdiet massa vel, sagittis mi. Aenean metus velit,
        blandit quis metus ac, suscipit aliquet nulla. Aenean ut enim dictum,
        porta metus et, ultricies metus. Phasellus malesuada nisl enim lorem. 
        THIS TEXT IS MISSING. THIS TEXT IS MISSING. THIS TEXT IS MISSING.
        THIS TEXT IS MISSING. THIS TEXT IS MISSING. THIS TEXT IS MISSING.
        THIS TEXT IS MISSING. THIS TEXT IS MISSING. THIS TEXT IS MISSING.
        THIS TEXT IS MISSING. THIS TEXT IS MISSING. THIS TEXT IS MISSING.
        THIS TEXT IS MISSING. THIS TEXT IS MISSING. THIS TEXT IS MISSING.</p
      >
      <p id="page-break-before"
        >4 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla eget
        ante feugiat, imperdiet massa vel, sagittis mi. Aenean metus velit,
        blandit quis metus ac, suscipit aliquet nulla. Aenean ut enim dictum,
        porta metus et, ultricies metus. Phasellus malesuada nisl lorem.
        Praesent sagittis dui nulla, dictum luctus sem scelerisque ac. Nam
        consequat a velit eu congue. Nulla id vestibulum orci. Sed quis
        condimentum justo. Nunc bibendum tincidunt ipsum, ut pellentesque orci
        egestas at. Curabitur pulvinar vitae purus et malesuada. Duis ex orci,
        placerat ut lectus posuere, posuere rhoncus arcu. Vivamus in risus quis
        mauris commodo venenatis id quis justo. Fusce interdum tincidunt
        eleifend.</p
      >
  </body>
</html>`;

  const blob = new Blob([str], { type: "text/html" });
  const blobUrl = URL.createObjectURL(blob);

  viewer.loadDocument(
    {
      url: blobUrl,
    },
    undefined
  );

  window.viewer = viewer; // viewer.navigateToPage("next")

  // the following isn't actually necessary to reproduce this issue
  const vivlioStyles = [
    "vivliostyle-viewport-screen-css",
    "vivliostyle-viewport-css",
    "vivliostyle-polyfill-css",
    "vivliostyle-page-rules",
  ];

  vivlioStyles.forEach((id) => {
    const styleTag = document.getElementById(id);
    if (styleTag) {
      shadowRoot.appendChild(styleTag);
    } else {
      console.warn(`Style tag with id "${id}" not found.`);
    }
  });
});

Expected result: 3 pages, with page 2 stating "THIS TEXT IS MISSING.".

This can be observed by changing lines 7 to 12 to enable either the broken or functioning scenario.

I am well aware that loading the CoreViewer into a shadow root is probably... not the most standard thing to do, but I figured it was worth reporting anyway 🤷. Might even be a good idea for the CoreViewer in general to always load itself into the shadowRoot of the specified element, as that way it would guarantee that the styling will be the same as when the document would be printed from an iframe (as both an iframe and a shadowRoot would provide sandboxing of styles).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions