FULL CSS SOLUTION
I have written a CSS print stylesheet solution that should solve 80-90% of this problem occurring for sites that require the icons(glyphicons) from bootstrap to show up when printing without requiring the user to turn on "print background images" in their browser and this solution will work in ALL major browsers(Chrome, Safari, Firefox, IE).
This solution is detailed referencing the bootstrap issue specifically but it should be possible leverage it for other similar issues of background images not printing when needed. It also assumes you are using a separate @media print {}
stylesheet. I'll explain 10-20% of situations it doesn't solve and why at the end(as well as a fix for these occurrences).
The issue of background-image
, background-position
and width height
properties being used exclusively to position and size sprite images is solved by replacing with the properties content: url()
, clip: rect()
, margin-top
and margin-left
along with some overrides.
In my case we were using the <i class="icon-globe"></i>
to show links for courses available internationally and so users frequently printed this list but the important indicating information was removed by the browser. I had found the solution of copying all the CSS to display the icons into our print stylesheet along with adding the property value
-webkit-print-color-adjust:exact;
to the
[class^="icon-"], [class*=" icon-"] {
background-image: url("../img/glyphicons-halflings.png");
background-position: 14px 14px;
background-repeat: no-repeat...
}
but this only solved the problem in Chrome and Safari with no indication from the community that Firefox or IE would be supporting this webkit property any time soon.
So we need to completely change how <i class="icon-globe"></i>
is rendered when the page is sent to the printer driver by the browser.
The standard method with executing sprites is to declare a visible opening space(14px by 14px in this case) and then reposition the background-image
behind that space so the appropriate icon can show through.
To effectively replicate this in the foreground we will use the content: url()
to call the image and then clip: rect()
to cut this image down to the appropriate icon and then use negative values in margin-top
and margin-left
to position the new foreground image back where the background image icon had originally been positioned.
A difficulty is cutting the image down using clip requires 4 coordinates(top, right, bottom, left) while background-position
only requires 2 coordinates(xpos, ypos - the pixel distances from the top left corner). The other difficulty in using the clip
property is that unlike padding
or margin
these coordinates are not calculated from their respective outside border in but from the top and left sides only which actually makes our math conversion from background-position
a little easier but may take some time to get used to.
More info on clip property
(ran out of links due to my low reputation so you'll need to figure out what sneaky thing I've done)
www.ibloomstudios[dot]com/articles/misunderstood_css_clip/
css-tricks[dot]com/css-sprites-with-inline-images/
tympanus[dot]net/codrops/2013/01/16/understanding-the-css-clip-property/
THE ACTUAL CODE
Getting back to the <i class="icon-globe"></i>
example, we want to convert
[class^="icon-"], [class*=" icon-"] {
display: inline-block;
width: 14px;
height: 14px;
*margin-right: .3em;
line-height: 14px;
vertical-align: text-top;
background-image: url("../img/glyphicons-halflings.png");
background-position: 14px 14px;
background-repeat: no-repeat;
}
//skipping other icons...
.icon-globe {
background-position: -336px -144px;
}
into this in the print stylesheet
i[class^="icon-"], i[class*=" icon-"] {
display: inline-block;
vertical-align: text-top;
width: 14px;
background-image:none!important;
background-repeat:no-repeat;
background-position: 0 0!important;
}
//skipping other icons...
i.icon-globe::after {
clip: rect(144px 350px 158px 336px)!important;
margin-left: -336px!important;
margin-top: -144px!important;
content: url('../img/glyphicons-halflings.png')!important;
position:absolute!important;
width:auto!important;
height:auto!important;
}
We can see that taking the background-position(xpos & ypos OR left & top) coordinates and changing to positives are the same as clip: rect(top, left+14px, top+14px, left).
Then we use the original negative background-position: left top;
as margin-left
and margin-top
.
This CSS also includes some !important
overrides in case the original bootstrap icon is displayed over top of our new clipped image which is stripped out upon printing.
That worked for the globe-icon and solved my specific problem but then I wondered how many other indicating icons were not being printed and so I used some clever replace all commands in notepad to create a single line version of the bootstrap icon CSS and tab delimited each element (plus added some px to the zeros so columns would line up)...
.icon-glass { background-position: 0 px 0 px ; }
.icon-music { background-position: -24 px 0 px ; }
.icon-search { background-position: -48 px 0 px ; }
.icon-envelope { background-position: -72 px 0 px ; }
.icon-heart { background-position: -96 px 0 px ; }
.icon-star { background-position: -120 px 0 px ; }
.icon-star-empty { background-position: -144 px 0 px ; }
.icon-user { background-position: -168 px 0 px ; }
.icon-film { background-position: -192 px 0 px ; }
.icon-th-large { background-position: -216 px 0 px ; }
.icon-th { background-position: -240 px 0 px ; }
.icon-th-list { background-position: -264 px 0 px ; }
.icon-ok { background-position: -288 px 0 px ; }
.icon-remove { background-position: -312 px 0 px ; }
.icon-zoom-in { background-position: -336 px 0 px ; }
.icon-zoom-out { background-position: -360 px 0 px ; }
.icon-off { background-position: -384 px 0 px ; }
.icon-signal { background-position: -408 px 0 px ; }
.icon-cog { background-position: -432 px 0 px ; }
.icon-trash { background-position: -456 px 0 px ; }
.icon-home { background-position: 0 px -24 px ; }
.icon-file { background-position: -24 px -24 px ; }
.icon-time { background-position: -48 px -24 px ; }
.icon-road { background-position: -72 px -24 px ; }
.icon-download-alt { background-position: -96 px -24 px ; }
.icon-download { background-position: -120 px -24 px ; }
.icon-upload { background-position: -144 px -24 px ; }
.icon-inbox { background-position: -168 px -24 px ; }
.icon-play-circle { background-position: -192 px -24 px ; }
.icon-repeat { background-position: -216 px -24 px ; }
.icon-refresh { background-position: -240 px -24 px ; }
.icon-list-alt { background-position: -264 px -24 px ; }
.icon-lock { background-position: -287 px -24 px ; }
.icon-flag { background-position: -312 px -24 px ; }
.icon-headphones { background-position: -336 px -24 px ; }
.icon-volume-off { background-position: -360 px -24 px ; }
.icon-volume-down { background-position: -384 px -24 px ; }
.icon-volume-up { background-position: -408 px -24 px ; }
.icon-qrcode { background-position: -432 px -24 px ; }
.icon-barcode { background-position: -456 px -24 px ; }
.icon-tag { background-position: 0 px -48 px ; }
.icon-tags { background-position: -25 px -48 px ; }
.icon-book { background-position: -48 px -48 px ; }
.icon-bookmark { background-position: -72 px -48 px ; }
.icon-print { background-position: -96 px -48 px ; }
.icon-camera { background-position: -120 px -48 px ; }
.icon-font { background-position: -144 px -48 px ; }
.icon-bold { background-position: -167 px -48 px ; }
.icon-italic { background-position: -192 px -48 px ; }
.icon-text-height { background-position: -216 px -48 px ; }
.icon-text-width { background-position: -240 px -48 px ; }
.icon-align-left { background-position: -264 px -48 px ; }
.icon-align-center { background-position: -288 px -48 px ; }
.icon-align-right { background-position: -312 px -48 px ; }
.icon-align-justify { background-position: -336 px -48 px ; }
.icon-list { background-position: -360 px -48 px ; }
.icon-indent-left { background-position: -384 px -48 px ; }
.icon-indent-right { background-position: -408 px -48 px ; }
.icon-facetime-video { background-position: -432 px -48 px ; }
.icon-picture { background-position: -456 px -48 px ; }
.icon-pencil { background-position: 0 px -72 px ; }
.icon-map-marker { background-position: -24 px -72 px ; }
.icon-adjust { background-position: -48 px -72 px ; }
.icon-tint { background-position: -72 px -72 px ; }
.icon-edit { background-position: -96 px -72 px ; }
.icon-share { background-position: -120 px -72 px ; }
.icon-check { background-position: -144 px -72 px ; }
.icon-move { background-position: -168 px -72 px ; }
.icon-step-backward { background-position: -192 px -72 px ; }
.icon-fast-backward { background-position: -216 px -72 px ; }
.icon-backward { background-position: -240 px -72 px ; }
.icon-play { background-position: -264 px -72 px ; }
.icon-pause { background-position: -288 px -72 px ; }
.icon-stop { background-position: -312 px -72 px ; }
.icon-forward { background-position: -336 px -72 px ; }
.icon-fast-forward { background-position: -360 px -72 px ; }
.icon-step-forward { background-position: -384 px -72 px ; }
.icon-eject { background-position: -408 px -72 px ; }
.icon-chevron-left { background-position: -432 px -72 px ; }
.icon-chevron-right { background-position: -456 px -72 px ; }
.icon-plus-sign { background-position: 0 px -96 px ; }
.icon-minus-sign { background-position: -24 px -96 px ; }
.icon-remove-sign {