Background
A client wanted to have an option to print the page (like paper/pdf) in a web app I built. Being a Vue app it wasn’t as easy as just hitting cmd-p
(for reasons I don’t have enough knowledge to explain).
After some searching I found the printd-library and decided to use it for this. It has an optional argument for adding custom CSS-styles which I had to provide to make the page print as it should.
Attempt 1
The first attempt was pretty straight forward: Find all the <style>
-tags and join their innerText
s.
1const d = new Printd()2const styles = [].slice.call(document.getElementsByTagName('style'))3let cssText = styles.map(s => s.innerText).join(`\n`)4d.print(document.getElementById('printMe'), [cssText])
This works great when in development mode as there are style
-tags. 👌🏽
But in production, when everything is all bundled and stuff, it won’t work. (Styles are bundled in one .css
-file rather than inline styles).
Btw, an explanation for the [].slice.call()
-syntax can be found in StackOverflow.
Attempt 2 - a working solution
Then I found about the document.styleSheets
property.
1let styleSheets = []2for (const s of document.styleSheets) { styleSheets.push(s) }3let cssArr = []4styleSheets.map((sheet) => {5 for (let rule of sheet.cssRules) {6 cssArr.push(rule.cssText)7 }8})9const cssText = cssArr.join(`\n`)10d.print(document.getElementById('printMe'), [cssText])
This solution works in dev and in prod as it finds the stylesheets, no matter how the styles are defined.
Using the [].slice.call()
-syntax this can be shortened to an one-liner:
1const cssText = [].slice.call(document.styleSheets)2 .map(x => [].slice.call(x.cssRules)3 .map(r => r.cssText))4 .flat()5 .join(`\n`)
Now the page looks the same in browser and in print 🥳.