# legible notebook printing

**URL:** <https://talk.observablehq.com/t/legible-notebook-printing/3971>\
**Category:** Feedback\
**Created:** [October 3, 2020, 8:02pm UTC](https://talk.observablehq.com/t/legible-notebook-printing/3971 "2020-10-03T20:02:09Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![jrus](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/jrus/32/586_2.png) [@jrus](https://talk.observablehq.com/u/jrus)\
**Post date:** [October 3, 2020, 8:02pm UTC](https://talk.observablehq.com/t/legible-notebook-printing/3971/1 "2020-10-03T20:02:09Z")

</div>

Hi Observable folks,

When I try to print a notebook from Safari (I think because of the way Observable uses an iframe to hold notebook content?) the result is basically unusable. Whatever amount of the notebook content fits on each page will print, cutting off halfway down a line of text or KaTeX formula. The default print stylesheet picks a narrow notebook width, so text ends up enormous.

In Firefox it’s even worse: I only get whatever part of the content fits on page 1, followed by a mostly blank page 2 with nothing but the container page’s footer.

I am not at all an expert in browser printing, print CSS stylesheets, or the like, but if you ever get a chance some better default printing would be greatly appreciated!

---

<div class="post-metadata">

**Author:** ![jrus](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/jrus/32/586_2.png) [@jrus](https://talk.observablehq.com/u/jrus)\
**Post date:** [October 4, 2020, 12:02am UTC](https://talk.observablehq.com/t/legible-notebook-printing/3971/2 "2020-10-04T00:02:57Z")

</div>

As a back-up idea: if it turns out to be impossible to get the browser to produce good results by naïvely printing the page, maybe there could be some way to add a separate “turn the current page into a PDF” option somewhere built on [http://pdfkit.org](http://pdfkit.org) or something.

---

<div class="post-metadata">

**Author:** ![Cobus](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/cobus/32/9670_2.png) [@Cobus](https://talk.observablehq.com/u/Cobus)\
**Post date:** [October 6, 2020, 3:33am UTC](https://talk.observablehq.com/t/legible-notebook-printing/3971/3 "2020-10-06T03:33:22Z")

</div>

Thank you for this feedback! We will definitely look into this suggestion.

---

<div class="post-metadata">

**Author:** ![asg017](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/asg017/32/2159_2.png) [@asg017](https://talk.observablehq.com/u/asg017)\
**Post date:** [October 6, 2020, 6:28am UTC](https://talk.observablehq.com/t/legible-notebook-printing/3971/4 "2020-10-06T06:28:09Z")

</div>

Hey @jrus, [`observable-prerender`](https://github.com/asg017/observable-prerender) might be a solution for this. Under the hood, `observable-prerender` uses Puppeteer to render notebooks, and Puppeteer [can save webpages as PDFs](https://pptr.dev/#?product=Puppeteer&version=v5.3.1&show=api-pagepdfoptions). When trying this out, I added a new `.pdf()` method and fixed a few bugs (so thanks for the idea!), so here’s how you can do it with one of your notebooks, as of `v0.2.0`:

```auto
const { load } = require("@alex.garcia/observable-prerender");

(async function () {
  const notebook = await load("@jrus/scpie");
  await notebook.pdf("notebook.pdf");
  await notebook.browser.close();
})();

```

You can see the [ouput PDFs in this notebook](https://observablehq.com/d/7994ba629f00dd3d)!

However, it won’t be an exact match of what you see on [observablehq.com](http://observablehq.com). `observable-prerender` embeds the [Observable Inspector stylesheet](https://github.com/observablehq/inspector/blob/master/src/style.css), but there’s more styling that exists on [observablehq.com](http://observablehq.com) that doesn’t appear to be open-sourced. If you dig around in devtools network tab, you can find the custom stylesheets (which add things like fonts, styling, etc.), but it’s not easily available for non [observablehq.com](http://observablehq.com) use.

One workaround is to copy-paste that custom stylesheets into the notebook itself. This won’t change anything for the [observablehq.com](http://observablehq.com) notebook, but it will change the output of the observable-prerender notebook. I did this [in this fork](https://observablehq.com/compare/217388fd3dbaf3a6@5389...d2faf59bd6493a6d@5488) of your notebook.

Whipping out node and writing a custom script can be a hassle, though. There is a CSS [`@media print`](https://developer.mozilla.org/en-US/docs/Web/CSS/@media) query that may be helpful, and you might be able to do some more magic with [Puppeteer’s `pdf()` method](https://pptr.dev/#?product=Puppeteer&version=v5.3.1&show=api-pagepdfoptions) to really carve out the PDF as you like.

---

<div class="post-metadata">

**Author:** ![jrus](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/jrus/32/586_2.png) [@jrus](https://talk.observablehq.com/u/jrus)\
**Post date:** [October 6, 2020, 8:48am UTC](https://talk.observablehq.com/t/legible-notebook-printing/3971/5 "2020-10-06T08:48:28Z")

</div>

@asg017 It looks like you forgot to share your draft [https://observablehq.com/d/7994ba629f00dd3d](https://observablehq.com/d/7994ba629f00dd3d)

---

<div class="post-metadata">

**Author:** ![asg017](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/asg017/32/2159_2.png) [@asg017](https://talk.observablehq.com/u/asg017)\
**Post date:** [October 6, 2020, 3:13pm UTC](https://talk.observablehq.com/t/legible-notebook-printing/3971/6 "2020-10-06T15:13:25Z")

</div>

Ah my bad, fixed

---

<div class="post-metadata">

**Author:** ![Fil](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/fil/32/207_2.png) [@Fil](https://talk.observablehq.com/u/Fil)\
**Post date:** [November 30, 2020, 9:28pm UTC](https://talk.observablehq.com/t/legible-notebook-printing/3971/7 "2020-11-30T21:28:21Z")

</div>

Chiming in as I just had to solve this same problem. I tried exporting a 9-page notebook to a PDF, containing only md & katex (not that it matters much).

Printing directly from the notebook, pagination didn’t work: text was often cut in the middle of a line, or a katex formula chopped up in two.

Printing from the embed iframe would print just the first page and the embed’s footer.

What I ended up doing was to render the notebook on its own with the very basic [visionscarto.net/obs/](http://visionscarto.net/obs/) viewer, and this was good enough in Chrome and Firefox (all the pages and without chopping the formulas).

Firefox was even a bit better since it allows to personalize the page headers and footers, so I could hide the title and url and keep only the page numbers.

---

<div class="post-metadata">

**Author:** ![mootari](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/mootari/32/581_2.png) [@mootari](https://talk.observablehq.com/u/mootari)\
**Post date:** [November 30, 2020, 10:12pm UTC](https://talk.observablehq.com/t/legible-notebook-printing/3971/8 "2020-11-30T22:12:24Z")

</div>

Could you guys/folks/fellow O’s share a few problematic notebook URLs (SVG and 2D / 3D canvas are also welcome)? There’s something I’d like to try.

**Edit** The basic idea is as follows:

1. Printing is only a problem due to the iframe (no printing from the inside, and printing from the outside sucks). Due to the sandboxing we also cannot open new windows.
2. However, we can create an object URL and assign that as href to a link:

```auto
html`<a target=_blank
  href="${URL.createObjectURL(new Blob(['<h3 style="color:red">Look, ma, no iframe!'], {type: 
'text/html'}))}"
>Click me`

```

3. Now, using a TreeWalker we can create a copy of the current DOM (or any part of it), turn its outerHTML into a Blob, that Blob into a URL, and open that URL in a new page.
4. Some elements need special treatment:
  - `script` should be stripped
  - `canvas` contents need to be copied over and serialized (object URL + init? background image?)

I haven’t fully tested yet which limitations apply wrt external resources. However, assuming that everything works out as planned (naturally!) we get a few more benefits:

- inject conditional stylesheets
- hasslefree printing of subsections
- can be turned into a bookmarklet, to work on any notebook
- might be used to save static copies of notebooks? (this one might be a stretch)

---

<div class="post-metadata">

**Author:** ![jrus](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/jrus/32/586_2.png) [@jrus](https://talk.observablehq.com/u/jrus)\
**Post date:** [December 1, 2020, 12:43am UTC](https://talk.observablehq.com/t/legible-notebook-printing/3971/9 "2020-12-01T00:43:24Z")

</div>

> [@mootari](#):
>
> Printing is only a problem due to the iframe

This is the biggest problem for sure, but definitely doesn’t make for a perfect experience. Browser printing overall is pretty mediocre when left on its own. (A good print CSS stylesheet might be able to ameliorate some of it?)

It would also be nice to do somewhat smarter layout. E.g. never put a heading at the bottom of a page, never put the last line of a paragraph at the top of a page, try not to put the first few lines of a code listing at the bottom of a page, allow authors to specify a particular state of an animated cell for printing, fix up the margins, possibly add page numbers, …

---

<div class="post-metadata">

**Author:** ![jrus](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/jrus/32/586_2.png) [@jrus](https://talk.observablehq.com/u/jrus)\
**Post date:** [March 15, 2021, 3:32am UTC](https://talk.observablehq.com/t/legible-notebook-printing/3971/10 "2021-03-15T03:32:57Z")

</div>

I put up a github issue:

> <https://github.com/observablehq/feedback/issues/44>
>
> Problem description: Long notebooks are sometimes nice to read on paper instead of on screen. This can be especially helpful when...

---

<div class="post-metadata">

**Author:** ![tomlarkworthy](https://yyz2.discourse-cdn.com/flex030/user_avatar/talk.observablehq.com/tomlarkworthy/32/5940_2.png) [@tomlarkworthy](https://talk.observablehq.com/u/tomlarkworthy)\
**Post date:** [January 20, 2022, 3:46pm UTC](https://talk.observablehq.com/t/legible-notebook-printing/3971/11 "2022-01-20T15:46:39Z")

</div>

I just hit this too . Running it through blogify (the static renderer) kinda fixed the issue

> **[Blogify](https://observablehq.com/@tomlarkworthy/blogify)**
>
> Creates a link to a pre-rendered static snapshot of any notebook. The goal is to make writing blog posts easier on Observable, by allowing notebooks to be exported as plain HTML. This makes it much easier to syndicate to other sites like dev.to or...
