Getting CSS styles in a web page

June 27, 2019

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 innerTexts.

const d = new Printd()
const styles = [].slice.call(document.getElementsByTagName('style'))
let cssText = styles.map(s => s.innerText).join(`\n`)
d.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.

let styleSheets = []
for (const s of document.styleSheets) { styleSheets.push(s) }
let cssArr = []
styleSheets.map((sheet) => {
	for (let rule of sheet.cssRules) {
		cssArr.push(rule.cssText)
	}
})
const cssText = cssArr.join(`\n`)
d.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:

const cssText = [].slice.call(document.styleSheets)
			.map(x => [].slice.call(x.cssRules)
			.map(r => r.cssText))
			.flat()
			.join(`\n`)

Now the page looks the same in browser and in print 🥳.

Other writings: