Glyphicons are missing when I hit 'Print', but are shown correctly in browser window.
I'm talking about a simple page with static content, except for latest twitter bootstrap.
Is it possible to get Bootstrap icons shown in print?
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 { background-position: -48 px -96 px ; }
.icon-ok-sign { background-position: -72 px -96 px ; }
.icon-question-sign { background-position: -96 px -96 px ; }
.icon-info-sign { background-position: -120 px -96 px ; }
.icon-screenshot { background-position: -144 px -96 px ; }
.icon-remove-circle { background-position: -168 px -96 px ; }
.icon-ok-circle { background-position: -192 px -96 px ; }
.icon-ban-circle { background-position: -216 px -96 px ; }
.icon-arrow-left { background-position: -240 px -96 px ; }
.icon-arrow-right { background-position: -264 px -96 px ; }
.icon-arrow-up { background-position: -289 px -96 px ; }
.icon-arrow-down { background-position: -312 px -96 px ; }
.icon-share-alt { background-position: -336 px -96 px ; }
.icon-resize-full { background-position: -360 px -96 px ; }
.icon-resize-small { background-position: -384 px -96 px ; }
.icon-plus { background-position: -408 px -96 px ; }
.icon-minus { background-position: -433 px -96 px ; }
.icon-asterisk { background-position: -456 px -96 px ; }
.icon-exclamation-sign { background-position: 0 px -120 px ; }
.icon-gift { background-position: -24 px -120 px ; }
.icon-leaf { background-position: -48 px -120 px ; }
.icon-fire { background-position: -72 px -120 px ; }
.icon-eye-open { background-position: -96 px -120 px ; }
.icon-eye-close { background-position: -120 px -120 px ; }
.icon-warning-sign { background-position: -144 px -120 px ; }
.icon-plane { background-position: -168 px -120 px ; }
.icon-calendar { background-position: -192 px -120 px ; }
.icon-random { background-position: -216 px -120 px ; }
.icon-comment { background-position: -240 px -120 px ; }
.icon-magnet { background-position: -264 px -120 px ; }
.icon-chevron-up { background-position: -288 px -120 px ; }
.icon-chevron-down { background-position: -313 px -119 px ; }
.icon-retweet { background-position: -336 px -120 px ; }
.icon-shopping-cart { background-position: -360 px -120 px ; }
.icon-folder-close { background-position: -384 px -120 px ; }
.icon-folder-open { background-position: -408 px -120 px ; }
.icon-resize-vertical { background-position: -432 px -119 px ; }
.icon-resize-horizontal { background-position: -456 px -118 px ; }
.icon-hdd { background-position: 0 px -144 px ; }
.icon-bullhorn { background-position: -24 px -144 px ; }
.icon-bell { background-position: -48 px -144 px ; }
.icon-certificate { background-position: -72 px -144 px ; }
.icon-thumbs-up { background-position: -96 px -144 px ; }
.icon-thumbs-down { background-position: -120 px -144 px ; }
.icon-hand-right { background-position: -144 px -144 px ; }
.icon-hand-left { background-position: -168 px -144 px ; }
.icon-hand-up { background-position: -192 px -144 px ; }
.icon-hand-down { background-position: -216 px -144 px ; }
.icon-circle-arrow-right { background-position: -240 px -144 px ; }
.icon-circle-arrow-left { background-position: -264 px -144 px ; }
.icon-circle-arrow-up { background-position: -288 px -144 px ; }
.icon-circle-arrow-down { background-position: -312 px -144 px ; }
.icon-globe { background-position: -336 px -144 px ; }
.icon-wrench { background-position: -360 px -144 px ; }
.icon-tasks { background-position: -384 px -144 px ; }
.icon-filter { background-position: -408 px -144 px ; }
.icon-briefcase { background-position: -432 px -144 px ; }
.icon-fullscreen { background-position: -456 px -144 px ; }
...and then I could use an excel spreadsheet to do all the calculations in one go,
I setup an excel sheet to do any sprite modifications as long as the formatting above is used and we only need 3 variables to replicate this process -img path, width and height, I will update with exact formula in those cells if people request those details but for now here is the result(after a bit more clever replace all commands in notepad++ to remove spaces between integers and px and adding some carriage returns)...
i.icon-glass::after{
clip: rect( 0px 14px 14px 0px)!important;
margin-top: 0px!important;
margin-left: 0px!important;
content: url('../img/glyphicons-halflings.png')!important; position:absolute!important;
width:auto!important;
height:auto!important;
}
i.icon-music::after{
clip: rect( 0px 38px 14px 24px)!important;
margin-top: 0px!important;
margin-left: -24px!important;
content: url('../img/glyphicons-halflings.png')!important;
position:absolute!important;
width:auto!important;
height:auto!important;
}
i.icon-search::after{
clip: rect( 0px 62px 14px 48px)!important;
margin-top: 0px!important;
margin-left: -48px!important;
content: url('../img/glyphicons-halflings.png')!important;
position:absolute!important;
width:auto!important;
height:auto!important;
}
Arg I ran out of character space and hyperlinks since my reputation is too low which you can help me with)
I posted the entire CSS result in the Bootstrap Issue Report referenced in an earlier answer
https://github.com/twitter/bootstrap/issues/4412
WHEN IT WONT WORK
Now anyone that has tested this by viewing in their browser window using their print stylesheet instead of screen will see that it works perfectly and as I said earlier this solution as far as I can tell will work except in 10%-20% percent of cases. The exceptions to this solution will only show up when actually printing the pages(or printing to a file for paperless debugging).
What happens is the new foreground images sprites can overflow outside printable areas because of the position: absolute; property which is required to use clip property. When it comes to the W3C standard the rendering of these images is undefined as stated in the CSS Paged Media Module Level 3 in section 4.2-Content outside the page box;
This specification does not define how boxes positioned outside the page box are handled.
(Also check this for an older but better explanation HTML print with absolute postitions )
So what do the browser giants do when no standard has been agreed upon, they all do something different. What happens is the entire sprite image(non-visible portion) that overflows along the top, bottom and sides of the printable page area forces the browsers to decide how to handle and reconcile the CSS and printable page areas. This browser correction is not visible when viewing the in the browser because it is all one page and images can overflow side limits without issue. I'll explain what each one does as of May 28 2014 and most likely why it is happening this way.
First lets go with the browser that handles it the best,
Internet Explorer!
(I bet you though I was going to say anything else)
The image is clipped properly but is pushed away from limiting printable area edges and so will appear in the wrong place on print out.
Safari and Chrome behave similarly, the image is moved by limiting printable area edges but the clip remains in the spot is was designated so wrong or no icon is shown.
Firefox appears to handle this the worst by only printing icons on the first page and if overflow occurs then forces all remaining icons into the top page on top of one another within the div or section it exists. (one might argue that this precludes Firefox from the overall solution but the fact that the first page works makes me hopeful that Mozilla will resolve in the future if we ask nicely)
Why do I say this will work for 80-90%? because the size of the sprite and the distance from printable area are 2 determining factors that will vary widely from page to page and should only effect in most cases up to 20% of the printable area.
SOLUTION FOR THESE 10-20% OF OCCURRENCES
In my case the icon is being used in a large list across many pages and so the globe-icon at the top of almost every page is misaligned or the wrong icon depending on which browser.
Since I know this page will be printed often and needs to be accurate then I need to make sure this works at least 99% of the time. I'll do this by cutting out the globe-icon from the sprite and and insert it without all the extra positioning and clipping CSS (which is the original best answer for this issue).
i.icon-globe::after{
content: url('../img/globe-glyphicon.png')!important;
}
and what about that 1% of users that still cant print this off properly, I print to a PDF file from a browser that does work and I make that available to download and print.
Thx for reading (#_#)
From Bootstrap's mdo: "It's a background image and they are likely being removed by the browser when printing."
https://github.com/twitter/bootstrap/issues/4412
I was stumped on this one for a good bit too. I ended up making a dedicated image of the glyph I was using instead of using the glyphicon system. Then I used #print and :content to inject the image wherever the icon should be.
#media print {
i.glyphicon-arrow-right{ content: url(../img/arrow.png) !important;}
}
For older versions of Bootstrap (for example 2.3.2), there is a #media print block at the bottom of _reset.scss that fails to improve upon the browser print css decisions. All recent browsers let you configure whether you want background images when printing. This is overridden by a * { background: transparent !important; } line in this block, breaking icon libraries that use background images even if you select the 'print background images' option in the print dialog.
If you are using an up to date Bootstrap version and this is still an issue, the print media css was separated into its own file which you can exclude using the Bootstrap customizer.
Related
I spent full-day to solve this issue, however, I couldn't fix this yet.
I tried to animate opacity from 0 to 1 by webkit animation for ios. however it doesn't work, and the element I applied the animation does not appear. I don't have the same issue with other devices. thank you for your help in advance.
these are solutions I tried.
set visibility:visible to web-kitKeyframes
change "from - to" to"0% to 100%" of web-kitKeyframes
.hello {
position: absolute;
top: 50%;
left: 100%;
transform: translate(-50%, -50%);
text-align: center;
font-size: 5em;
/* for iOS's opacity issue */
color: white;
opacity:0;
-webkit-opacity: 0;
-webkit-text-stroke-width: 1px;
-webkit-text-stroke-color: #f75998;
animation:fadein 0.5s 0.8s forwards;
-webkit-animation: fadein 0.5s 0.8s forwards; /* Safari, Chrome and Opera > 12.1 */
-moz-animation: fadein 0.5s 0.8s forwards; /* Firefox < 16 */
-ms-animation: fadein 0.5s 0.8s forwards; /* Internet Explorer */
-o-animation: fadein 0.5s 0.8s forwards; /* Opera < 12.1 */
}
#-webkit-keyframes fadein {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
appear the element by following the animation setting.
-webkit-opacity has its fallback a plain opacity. Try modeling that with your keyframe by writing:
#keyframes fadein {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
In your animation you animate the opacity property, and don't the -webkit-opacity property. However you can try to remove all -webkit- prefixes and look in a webkit browser if it works.
I'm developing a mobile app with Cordova Phonegap that uses gradients that stack on top of eachother. On Android everything works as it is supposed to but on iOS the gradients shows up different. The edges are green whereas when I preview it in my browser it is blue as it's supposed to be. There's also this weird transition at the bottom of the page.
This is my css:
#gradient2Layer1 {
position: fixed;
height: 100px;
bottom: 0;
left: 0;
height: 20%;
width: 100%;
color = "blue";
background: -webkit-linear-gradient(270deg, rgba(15,431,28,0) 35%, #b3c6ff 50%,rgb(128,128,128) 100%);
z-index: 100; }
#gradient2Layer2 {
position: fixed;
height: 100px;
bottom: 0;
left: 0;
height: 20%;
width: 100%;
opacity: 0.5;
color = "blue";
background: -webkit-linear-gradient(270deg, rgba(15,431,28,0) 35%, blue 50%, blue 100%);
animation: fadeIn 5s infinite alternate;
z-index: 100; }
How can I fix this?
I really believe this is a typo and you wanted to use rgba(15,43,128,0) (which is the shade of blue you're looking for) instead of rgba(15,431,28,0), which is not even a valid RGB value (limited to 0..255).
Having border-radius issues on iPad(3.2), iPad 2 (4.3.2).
Here's the code:
.articles .post .left img{
width:100%;
border-radius: 0 0 100% 0;
-moz-border-radius: 0 0 100% 0;
-khtml-border-radius: 0 0 100% 0;
-webkit-transition: border-radius 1s;
transition-delay: 0.1s;
transition-duration: 0.5s;
transition-property: all;
transition-timing-function: ease;
}
And this is the result I'm getting:
Any ideas on how to get the desired result I'm after?
On iOS 4, use border-radius css on the container of img and set over-flow:hidden.
the container will 'cut' the img into rounded cornor.
its a tweak.
Try adding
-webkit-border-radius: 0 0 100% 0;
As Safari on IOS5 needs that to render border radius.
Is it possible to have the two divs with box-shadow overlap with fully transparent edges? In my example, I want to keep the faded, kind of rounded edge, but it's important that the underlying box is visible through the fade. But as you can see the faded edge is not entirely transparent so it will show a white border rather than let the blue color shine through..
Is it possible to make this work without resorting to png or similar?
Example
.bg {
background-image: -moz-linear-gradient(right top , rgba(255, 255, 255, 0) 0%, #FF0000 100%);
box-shadow: 0 0 90px 90px rgba(255, 255, 255, 0) inset;
-webkit-box-shadow: 0 0 90px 90px rgba(255, 255, 255, 0) inset;
-moz-box-shadow: 0 0 90px 90px rgba(255, 255, 255, 0) inset;
opacity: 0.7;
position: absolute;
}
I don't know whether this is possible with inset box-shadow; however you can make them overlap seamlessly with outset box-shadow for the overlapping element.
All you have to do is give the overlapping element a box-shadow color that is the same as its background-color.
I have edited your sample here: (I didn't copy all the vendor-specific prefixes, just used box-shadow).
http://jsbin.com/orajot/4/edit
Basically, i want to use the grid option to snap a draggable div toa 30 x 30 grid but i want to keep the dragging smooth. So is there a way i can snap to the grid on mouse release (or something similar)
correction to #Zed
this will use the center for deciding which grid to place it in. which ever most of the draggable is in is the one it goes.
stop: function(e, ui) {
var grid_x = 30;
var grid_y = 30;
var elem = $( this );
var left = parseInt(elem.css('left'));
var top = parseInt(elem.css('top'));
var cx = (left % grid_x);
var cy = (top % grid_y);
var new_left = (Math.abs(cx)+0.5*grid_x >= grid_x) ? (left - cx + (left/Math.abs(left))*grid_x) : (left - cx);
var new_top = (Math.abs(cy)+0.5*grid_y >= grid_y) ? (top - cy + (top/Math.abs(top))*grid_y) : (top - cy);
ui.helper.stop(true).animate({
left: new_left,
top: new_top,
opacity: 1,
}, 200);
},
If that is all you want to do with the grid, you could emulate it:
$("#myobj").draggable({
...
stop: function(event, ui) {
t = parseInt($(this).css(top);
l = parseInt($(this).css(left);
$(this).css(top , t - t % 30);
$(this).css(left, l - l % 30);
}
...
});
Try transition!
A nice little something I just discovered now is, that if you give the dragged element the css property of transition it will have an effect on the speed it snaps to grid.
$(function() {
$(".draggable").draggable({
containment: 'window',
grid: [30, 30]
});
});
.draggable {
background: #333;
color: whitesmoke;
font-family: 'sans-serif', 'arial';
padding: 5px 12px;
display: inline-block;
transition: top 0.05s ease-in-out, left 0.05s ease-in-out
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<div class="draggable">Drag Me!</div>