I have a solution to printing that works well in Chrome but I am getting odd results in IE11. The solution involves scaling down the content of the web page to fit onto the printed page.
In IE I am seeing my content cut off about halfway down the page.
I have created a simplified example of what I believe is the cause of my issue, which is that the scaled content only seems to take up that percent of the page. E.g. if I scale the content by 50% (0.5), it only takes up half of the page space when I print it. If scaled by 75% it takes up about three quarters of the page space. Example below.
HTML structure
<body>
<div class="content">
... content goes here ...
</div>
</body>
CSS
.content {
transform: scale(0.5);
transform-origin: left top;
}
Here is a hosted version you can see in action, with borders for debugging: https://neisha.github.io/ieprintingissue/
Image of the behaviour in IE
I have tried all sorts of different permutations of css to get it to work but I am at a loss. Also I'm not sure if this a bug in IE or expected behaviour. I can't imagine who would want this behaviour. Is there a css guru out there who can shine some light on this?
I'm still convinced it's an IE bug, but I've managed to partially crack this using a specific hierarchy of elements and some restrictions.
I can get it to render correctly in the print/print preview, but only if the content fits on a single page.
This requires having the scaled element absolutely positioned within an absolutely positioned container element, and behaves differently depending on whether the container is relative to an element in it's ancestry (in the flow of the DOM), or whether the container elements is completely outside of the flow of the DOM.
I will explain each of these restrictions using the example below:
HTML structure
<body>
<div class="relativeAncestor">
<div class="container">
<div class="content">
... content goes here ...
</div>
</div>
</div>
</body>
Cannot allow content to go over multiple pages
The absolutely positioned container and it's ancestors must also not be allowed to go over multiple pages. i.e. they cannot be more than the view height.
Example CSS to enforce restriction 1
.container {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
}
The absolutely positioned parent is outside the flow of the DOM so that it doesn't have ancestors
Example CSS to enforce restrictions 1 and 2
// html, body and .relativeAncestor will have position: static by default
.container {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
}
.content {
position: absolute;
transform: scale(0.5);
transform-origin: left top;
}
If it is within the flow of the DOM (has a relative ancestor), it must start from the top of the page with no gap
This means:
no margin top
if a border if present, box-sizing needs to be set to border-box
padding is ok
Example CSS to enforce restrictions 1 and 3
html, body {
width: 100%;
height: 100%;
}
body {
margin-top: 0;
}
.relativeAncestor {
position: relative;
width: 100%;
height: 100%;
}
.container {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
overflow: hidden;
}
.content {
position: absolute;
transform: scale(0.5);
transform-origin: left top;
}
In cases 2 and 3, margin on the absolutely positioned container is ok.
This works for part of my use case where I am scaling the viewport onto a single page. When I have to scale and have it go over multiple pages I am still in trouble.
Here is a hosted version of the partial workaround you can see in action: https://neisha.github.io/ieprintingissue/workaround.html
Image of the expected behaviour
I don't have an in-depth answer for why this magical combination makes it render correctly, but hopefully this will help someone. Please comment if you have any insight as to what is going on.
Related
I'm using CSS position: sticky to stick some elements to my page. I'm using <div>s to produce a grid-like structure (<table>s aren't appropriate to my use case). Please note that this is specifically a position: sticky question - I'm not looking for a Javascript solution, and I believe that position: sticky should work as desired based on the spec and the behaviour in other browsers.
I need to stick a row for vertical scrolling, and the first cell in that row for horizontal scrolling. If I use position: sticky; left: 0; on the first cell without sticking the row, the cell sticks to the left just fine. However, in Safari if I use eg.
.row {
position: sticky;
top: 10px;
width: ...
}
.cell {
position: sticky;
left: 0;
width: ...
}
the row sticks when vertically scrolling as desired but the cell does not stick when horizontally scrolling.
The code behaves as desired in Chrome and Firefox, and in an iframe in Safari.
Here's some code for a minimal example:
CSS:
.row {
position: -webkit-sticky;
position: sticky;
top: 10px;
white-space: nowrap;
width: 2000px;
z-index: 30;
}
.cell {
display: inline-block;
width: 100px;
}
.sticky {
position: -webkit-sticky;
position: sticky;
left: 0;
font-weight: bold;
}
HTML:
<div class="row">
<div class="cell sticky">Sticky</div>
<div class="cell">Content</div>
<div class="cell">Content</div>
...
</div>
Uploaded files here (can't use codepen/jsfiddle as they load into an iframe):
https://qcn.github.io/minimal_sticky.html Minimal example: doesn't work in Safari, works in Chrome/Firefox
https://qcn.github.io/minimal_sticky_iframe.html The same minimal example loaded into an iframe: does work in Safari!
Another interesting thing I noticed was that if I scroll the page horizontally and then refresh, the sticky cell renders at the left of the viewport, and then scrolls normally in that position (ie. it still doesn't stick, but it knows where it should have been on page load!). This and the fact that the behaviour works inside an iframe and in other browsers makes me suspect it's a browser bug, but I'm unable to find other references to it.
Try adding a unit. It worked when I wanted to sticky a nested header to the top. I haven't tried your horizontal situation. Hope it helped.
left: 0px; instead of left: 0;
This appears to be an instance of this bug: https://bugs.webkit.org/show_bug.cgi?id=106062
I worked around my issue by wrapping the page in a scrolling div to contain it, rather than using viewport scroll. Not ideal but it appears to be a browser bug.
I finally found a solution to this!!!
using display: contents;
https://css-tricks.com/get-ready-for-display-contents/
Disclaimer - I understand there exists questions around fixed elements in safari, and fixed elements weren't supported, but now are and so forth. However I can't find a question that addresses this exact question.
Given the simplest of fixed sidebars, something like:
.sidebar {
position: fixed;
top: 10px;
right: 10px;
}
And a relatively long page, with input elements.
When an input element is focused, any fixed element becomes absolute - I understand the why, safari is trying to declutter the viewport - thats fine, but not always appropriate. I ask that I get to choose the best experience for the user (i know best naturally).
So the Question..
Is there any way to leave fixed elements as fixed even when input elements are focused?
I have attempted to do a bit of $(window).on('scroll', magic and position elements manually on scroll, but its quite jittery on the ipad.
Safari has supported position: fixed since at least version 9.2, but if you're seeing difficult issues, you can fully create the fixed position effect by making the document element and body full screen and then using absolute positioning. Scrolling then occurs in some main container element rather than the body. Your "fixed" elements can exist anywhere in the markup using this method.
jsfiddle here
html,
body,
.mainContainer {
height: 100%;
width: 100%;
overflow: hidden;
margin: 0;
}
.mainContainer {
overflow: auto;
}
.fixed {
position: absolute;
bottom: 20px;
left: 20px;
}
In order to achieve the effect you desire you need to change your approach to the layout. Instead of positioning the sidebar with position:fixed you need to use position:absolute within a position:relative container that is set to the height of the viewport within that position:relative container you need another div that uses overflow-y: scroll and -webkit-overflow-scrolling : touch
Caveat: I generally avoid using position fixed on tablet & mobile if possible although the browser support is there, in my experience it'll be janky and javascript solutions leave a lot to be desired, my first response would be to challenge the pattern with the designer. If I'm given designs that include a position fixed element when there are input elements, I'm more likely to seek a design solution than a development one as the focus issues you're describing are difficult to circumvent and maintain a quality user experience.
THE MARKUP:
<div class="outer">
<div class="sidebar">
<ul>
<li>Dummy list nav or something</li>
</ul>
</div>
<div class="container">
<input type="text" />
<!-- I added 10000 inputs here as a demo -->
</div>
</div>
THE CSS:
html,body{
-webkit-overflow-scrolling : touch !important;
overflow: auto !important;
height: 100% !important;
}
.outer {
position: relative;
overflow: hidden;
/* I'm using Viewport Units here for ease, but I would more likely check the height of the viewport with javascript as it has better support*/
height: 100vh;
}
.sidebar {
position: absolute;
top: 10px;
right: 10px;
/*added bg colour for demo */
background: blue;
}
.container {
height: 100vh;
overflow-y: scroll;
-webkit-overflow-scrolling: touch
}
input {
display: block;
}
Here's a CodePen for you to open in your simulator (presentation view):
https://codepen.io/NeilWkz/full/WxqqXj/
Here's the editor view for the code:
https://codepen.io/NeilWkz/pen/WxqqXj
I'm currently having a problem with a page I'm working on. I have a nice grid with different content blocks on them.
When I click on a block I open a modal, and the grid zooms out. I'm adding this class to my grid to zoom-out:
#container.overlay-open {
transform: translate3d(0,0,-1500px);
}
The css of the container itself:
#container {
.transition(0.7s all);
transform-style: preserve-3d;
position: absolute;
left: 0px;
right: 0px;
top: 100px;
bottom: 100px;
}
This works perfectly for the first row. However when I scroll down a bit and click on an other block the grid-container keeps zooming out, but the container is moved a bit to the top of the screen, it's not centered anymore (picture 3).
How can I keep the content centered after zooming (picture 2)?
Instead of using "translate3d", you could use "scale". I believe that should achieve your desired effect.
#container.overlay-open {
transform: scale(0.5);
}
I'm building a web application that occupies all the browser's visible area without scrollbars. The window is divided into panes that will have their own scrollbars when necessary.
I've laid out the elements neatly with absolute positioning. Demo: http://jsbin.com/adozul/6/edit
Extract:
<body>
<header id="header"></header>
<div id="main">
<section class="pane"></section>
<section class="pane"></section>
<section class="pane"></section>
<section class="pane"></section>
</div>
</body>
#header, #main, .pane {
bottom: 0;
left: 0;
position: absolute;
right: 0;
top: 0;
}
#header {
bottom: none;
height: 35px;
}
#main {
top: 36px;
}
.pane:nth-child(1) {
left: 0;
right: 75%;
}
.pane:nth-child(2) {
left: 25%;
right: 50%;
}
.pane:nth-child(3) {
left: 50%;
right: 25%;
}
.pane:nth-child(4) {
left: 75%;
right: 0;
}
Everything looks fine except that a wild horizontal scrollbar appears (both in Firefox and Chrome).
The weird thing is that according to FireBug, the blank space at the right side does not belong to any element on the page, and no element has any margins either.
UPD: as Passerby pointed out, there IS an element that exceeds the width, it's inside the fourth pane, so the solution is pretty obvious.
I've tracked the issue down to this rule:
.pane:nth-child(4) {
left: 75%;
}
When i disable this very rule, the horizontal scrollbar disappears. Disabling any other panes' positioning rules doesn't affect the scrollbar.
I can get rid of the scrollbar with html { overflow: hidden; }. But why does the scrollbar appear in the first place and how do i prevent it from appearing (rather then dealing with it when it's already there) without breaking the four-pane layout?
PS If you feel that the task could be solved in a more elegant way, please don't hesitate to point that out. But please take into consideratoin that i'm going to let the user resize panes with jQuery UI Resizable.
It looks like it's your <iframe> inside 4th panel that exceeds the width;
Add this
.pane:nth-child(4) iframe {
width:100%;
}
seems to solve the problem on my 1024 width screen.
http://jsbin.com/onotur/1/edit
Edit:
Seems this would be better:
.pane .editor {
width:100%;
}
I have these two divs, one inside another, and I have the styles defined. The encapsulating one is relative and the child is absolute.
Isn't the child supposed to be positioned according to the left top corner of the outer div, #RightSection?
Instead, it's doing it according to the browser window, any leads?
<div id="RightSection">
<div id="Panels">
</div>
</div>
#RightSection
{
position: relative;
}
#Panels
{
position: absolute;
background-color: Blue;
width: 100px;
height: 100px;
z-index: 9000;
}
I have also found that if I do not declare the top and left css parameters for absolutely positioned elements it seems to ignore a parent above it and just jump to the body of the page.
Try just giving it top and left parameters, see if it helps,
#Panels
{
position: absolute;
top: 0;
left: 0;
background-color: Blue;
width: 100px;
height: 100px;
z-index: 9000;
}
It should look just fine once you add in those default parameters.
Absolute positioning inside of relative positioned elements is supposed to do what you describe, but it's not always supported behaviour. What browser are you use and what DTD are you serving?
See http://www.brainjar.com/css/positioning/default4.asp for details. It also has a demo of the positioning so that you can verify it works or not in your browser.
I can confirm that this does not work in IE6. I can't vouch for other browsers while I'm at work, though. Brief searching online leads me to believe that this problem exists in IE7 too, and would conceivably be an issue in IE8 as long as it's rendering in IE7 mode.