I would like to know if it is possible to print an HTML page containing an IFRAME that spans multiple pages. For some reason the browser keeps truncating the IFRAME after the first page. Here is a minimalistic example that demonstrates the issue outlined above. At first, here is a simple HTML page containing an IFRAME that should be optimized for printing:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TEST</title>
<style>
html, body {
height: 100%;
}
iframe {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<iframe src="iframe-content.html">
</iframe>
</body>
</html>
And here is the page I want to embed:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TEST-CONTENT</title>
</head>
<body>
<p>
Some very, very long text spawning multiple pages.
</p>
</body>
</html>
Using JavaScript is not an option. I'm looking for a solution that uses CSS only. Any help would be greatly appreciated.
You could specify in the meta of the parent doc because CSS does not have the ability specify the page to be printed, just how it looks.
<link rel=alternate media=print href="printme.html">
If you are trying to print the whole iframe inside the parent, you need to embed a print specific CSS doc. using this along with print preview will help you zero-in.
<link rel="stylesheet" href="print.css" media="print">
Only CSS solution - have to set iframe width to static size. For A4 Portrait the value of width is near of 670 pixels. For Landscape printing the value will be another.
iframe {
width: 670px;
}
Working in chromium browser.
My solution uses javascript to manipulate the DOM.
Also, your iframe needs an id attribute as shown below -- id='iframe1'
<body>
<iframe id='iframe1' src="iframe-content.html">
</iframe>
</body>
here is the javascript code:
<script>
pages =[] // initiate an empty list here
function printPage() {
// get the iframe and push its innerHTML into the list
var frame_content = document.getElementById('iframe1');
pages.push(frame_content.contentWindow.document.body.innerHTML);
if (pages && pages.length) {
// this if statement, just checks to ensure our list is not empty before running the code.
// Then we now set the parent window to be equal to pages
window.content.document.body.innerHTML = pages;
// then we print this new window that contains the iframe's innerHTML
window.print();
}
else {
// do nothing
}
}
With this solution, the print will not truncate your pages.
Also, in case you have multiple iframes, it generates only one print dialogue box.
Someone may wonder why i am pushing to a list. This caters for cases where you have more than one iframe hence you can easily push and concatenate all their innerHTML.
Remember that in your parent page HTML you will have the code below to call the printPage function.
<input type="submit" value="Print All"
onclick="javascript:printPage()"
/>
Related
Implementing a nextjs 13 app with the app directory and the Client and Server Component.
When displaying the source HTML, my body is empty and only contains scripts and JSON.
<!DOCTYPE html>
<html id="__next_error__">
<head>
<script src="/_next/static/chunks/polyfills.js" nomodule=""></script>
</head>
<body>
<script src="/_next/static/chunks/webpack.js" async=""></script>
<script src="/_next/static/chunks/main-app.js" async=""></script>
</body>
</html>
The JSON/script part is after this html and contains the whole page. As you can see, my body is empty, which I would like to avoid for SEO reasons.
When trying with the former manner with a page, I have the html displaying correctly in the body in an html tag.
Did I miss something that prevents SSR in nextjs 13?
In my Layout, I have a Client Component that wraps the whole App like that :
<AppWrapper appCurrentLang="{appCurrentLang}"> {children} </AppWrapper>;
I don't think it causes the SSR to fail, because even if I add a <p> tag on the root layout, it still doesn't display in the body tag in the source.
Here is the first part of the content displayed after the html :
<script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"M1:{\"id\":\"./node_modules/next/dist/client/components/app-router.js\",\"name\":\"\",\"chunks\":[\"app-client-internals:app-client-internals\"],\"async\":false}\nM2:{\"id\":\"./app/providers.jsx\",\"name\":\"Providers\",\"chunks\":[\"app/layout:app/layout\"],\"async\":false}\nM3:{\"id\":\"./node_modules/next/dist/client/components/layout-router.js\",\"name\":\"\",\"chunks\":[\"app-client-internals:app-client-internals\"],\"async\":false}\nM4:{\"id\":\"./node_modules/next/dist/client/components/render-from-template-context.js\",\"name\":\"\",\"chunks\":[\"app-cl"])</script><script>self.__next_f.push([1,"ient-internals:app-client-internals\"],\"async\":false}\n"])</script><script>self.__next_f.push([1,"J0:[\"$\",\"#1\",null,{\"assetPrefix\":\"\",\"initialCanonicalUrl\":\"/posts/teslas-biggest-threat\",\"initialTree\":[\"\",{\"children\":[\"posts\",{\"children\":[[\"postURL\",\"teslas-biggest-threat\",\"oc\"],{\"children\":[\"\",{}]}]}]},null,null,true],\"initialHead\":[\"$\",\"title\",null,{\"children\":\"My TEST Next.js App\"}],\"children\":[[],[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/app/layout.css?ts=1676839989010\",\"precedence\":\"high\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"data-test\":\"test\",\"children\":[\"$\",\"body\",null,{\"children\":[[\"$\",\"p\",null,{\"children\":\"okkk\"}],[\"$\",\"#2\",null,{\"langHeaders\":\"fr-FR\",\"children\":[\"$\",\"#3\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"hasLoading\":false,\"template\":[\"$\",\"#4\",null,{}],\"notFound\":[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"-apple-system, BlinkMacSystemFont, Roboto, \\\"Segoe UI\\\", \\\"Fira Sans\\\", Avenir, \\\"Helvetica Neue\\\", \\\"Lucida Grande\\\", sans-serif\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}]}],[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"\\n body { margin: 0; color: #000
Would anyone have an idea ?
Not sure if I'm doing something wrong here or whether this indeed is a Chrome rendering bug.
Here is my very small example:
.hover-test span {
opacity: 0;
transition-property: opacity;
transition-duration: 1000ms;
}
.hover-test:hover span {
opacity: 1;
}
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>TEST opacity</title>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<link href="styles.css" rel="stylesheet">
</head>
<body>
<button class="hover-test">hover me<span>hidden</span></button>
</body>
</html>
It works in all browsers I checked like expected.
It does work in Chrome as well, when I put the CSS in a style tag directly in the HTML file.
It does NOT work in Chrome (91.0.4472.101), when I put the CSS in a separate file and include it with a link tag.
With "not working" I mean, that on page load the span is shown and then faded out, without the mouse cursor being near the button.
Is this a Chrome bug, or am I doing something wrong here?
How can I achieve the desired behaviour in Chrome, which is: span is hidden on page load and only shown/hidden on hover?
It looks like it is a Chrome bug,as written here: https://www.hawkbydesign.com/weird-google-chrome-css-transition-on-load-bug/
Well, after making some further updates and refreshing the page, I noticed that the transition was firing on page load. What I mean by this is instead of being hidden on page load, as they should be, the elements were visible and would transition to their hidden state.
this is exactly the problem reported.
More:
The bug happens whenever you don’t have any script tags on the page, apparently. For whatever reason, this causes css transitions to trigger upon page load. While I was also digging, it appears that this happens sometimes with the form tag as well. What a weird bug!
The solution is to include a script tag in your page. Whenever I found the solution, they said to include a space in the script tag, but I found that it works fine even without the space.
I actually added jQuery on the page using the CDN link and the bug seems gone.
You appear to be bumping up against a timing problem.
Try this code with your styles file:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>TEST opacity</title>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<link href="style.css" rel="stylesheet">
<style>
</style>
</head>
<body>
<script>
function insert() {
document.body.innerHTML = '<button class="hover-test">hover me<span>hidden</span></button>';
}
window.onload = insert;
</script>
</body>
</html>
This waits for loading before putting the button in the document and on Chrome (and Edge) on Windows10 at least all is well.
Chrome/Edge seem to differ from say Firefox in whether loading is synchronous or not - or maybe it's just a lot faster writing the document.
I need to get the element which is inside the iframe by hovering over the element for example if the button is available inside the iframe means i need to get the button element.
I have used query selector (:hover) to get the hovered element but I am able to get the elements upto iframe only from the top document. I cannot able to get the element inside the iframe.
Has any one come across this?
It is restricted by CORS (so generally you can not observe widgets included from 3rd-party sites this way), but otherwise doable in recent browsers, you just have to work with the contentWindow of the iframe, and perhaps use elementFromPoint().
Example frame.html:
<div>Test1</div>
<div>Test2</div>
<div>Test3</div>
<div>Test4</div>
<div>Test5</div>
And containing test.html:
<!DOCTYPE html>
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<script>
function startup(){
frame.contentWindow.document.addEventListener("click",function(event){
frame.contentWindow.document
.elementFromPoint(event.clientX,event.clientY).innerHTML+="!";
});
}
</script>
</head>
<body onload="startup()">
<iframe id="frame" width="300" height="200" src="frame.html"></iframe>
</body>
</html>
Click on the elements of the iframe and their content will get appended with exclamation marks.
I have the most basic PHP code with just these 13 lines:
<!DOCTYPE html>
<html>
<head>
<link href="design/faq.css" media="display" rel="stylesheet" type="text/css" />
<script src="js/jquery.main.js" type="text/javascript"></script>
</head>
<body>
<?php
print_r( $_GET );
echo "hey";
?>
</body>
</html>
When I am opening this page as: faq.php?code=sth; The PHP code is getting executed correctly, but the CSS is not working at all(in any browser). Since I primarily use Opera, here are screenshots:
Parsed Page
Code
The faq.css
What I tried
My first instinct was to check if the faq.css was accessible or not. Yes, the file has write property as 0644 same as all other files.
Then I checked if the path was not getting parsed correctly, but that is not the case either, as I later tried it with full path too.
Trouble
I am completely stumped at such a behavior from the least troublesome of languages as CSS. What could be the problem here? The CSS file contains only these 4 lines.
body {
background-color: #DC2826;
margin-top: 0px;
}
You're using media="display". This is not a valid type for the media attribute.
See this link for valid types of devices (all, aural, braille, handheld, projection, print, screen, tty, tv).
How do I stop the flash of unstyled content (FOUC) on a web page?
The problem with using a css style to initially hide some page elements, and then using javascript to change the style back to visible after page load, is that people who don't have javascript enabled will never get to see those elements. So it's a solution which does not degrade gracefully.
A better way therefore, is to use javascript to both initially hide as well as redisplay those elements after page load. Using jQuery, we might be tempted to do something like this:
$(document).ready(function() {
$('body').hide();
$(window).on('load', function() {
$('body').show();
});
});
However, if your page is very big with a lot of elements, then this code won't be applied soon enough (the document body won't be ready soon enough) and you might still see a FOUC. However, there is one element that we CAN hide as soon as script is encountered in the head, even before the document is ready: the HTML tag. So we could do something like this:
<html>
<head>
<!-- Other stuff like title and meta tags go here -->
<style type="text/css">
.hidden {display:none;}
</style>
<script type="text/javascript" src="/scripts/jquery.js"></script>
<script type="text/javascript">
$('html').addClass('hidden');
$(document).ready(function() { // EDIT: From Adam Zerner's comment below: Rather use load: $(window).on('load', function () {...});
$('html').show(); // EDIT: Can also use $('html').removeClass('hidden');
});
</script>
</head>
<body>
<!-- Body Content -->
</body>
</html>
Note that the jQuery addClass() method is called *outside* of the .ready() (or better, .on('load')) method.
This is the one that has worked for me and does not require javascript and it works great for pages with many elements and lots of css:
First, add a dedicated <STYLE> setting for the <HTML> tag with visibility 'hidden' and opacity as '0' at the top of your HTML, e.g, in the beginning of the <HEAD> element, for example, at the top of your HTML add:
<!doctype html>
<html>
<head>
<style>html{visibility: hidden;opacity:0;}</style>
Then, at the end of your last .css stylesheet file, set the visibility and opacity styles to 'visible' and '1', respectively:
html {
visibility: visible;
opacity: 1;
}
If you already have an existing style block for the 'html' tag, then move the entire 'html' style to the end of the last .css file and add the 'visibility' and 'opacity' tags as described above.
https://gist.github.com/electrotype/7960ddcc44bc4aea07a35603d1c41cb0
A CSS-only solution:
<html>
<head>
<style>
html {
display: none;
}
</style>
...
</head>
<body>
...
<link rel="stylesheet" href="app.css"> <!-- should set html { display: block; } -->
</body>
</html>
As the browser parses through the HTML file:
The first thing it will do is hide <html>.
The last thing it will do is load the styles, and then display all the content with styling applied.
The advantage to this over a solution that uses JavaScript is that it will work for users even if they have JavaScript disabled.
Note: you are allowed to put <link> inside of <body>. I do see it as a downside though, because it violates common practice. It would be nice if there was a defer attribute for <link> like there is for <script>, because that would allow us to put it in the <head> and still accomplish our goal.
A solution which doesn't depend on jQuery, which will work on all current browsers and do nothing on old browsers, include the following in your head tag:
<head>
...
<style type="text/css">
.fouc-fix { display:none; }
</style>
<script type="text/javascript">
try {
var elm=document.getElementsByTagName("html")[0];
var old=elm.class || "";
elm.class=old+" fouc-fix";
document.addEventListener("DOMContentLoaded",function(event) {
elm.class=old;
});
}
catch(thr) {
}
</script>
</head>
Thanks to #justastudent, I tried just setting elm.style.display="none"; and it appears to work as desired, at least in current Firefox Quantum. So here is a more compact solution, being, so far, the simplest thing I've found that works.
<script type="text/javascript">
var elm=document.getElementsByTagName("html")[0];
elm.style.display="none";
document.addEventListener("DOMContentLoaded",function(event) { elm.style.display="block"; });
</script>
An other quick fix which also works in Firefox Quantum is an empty <script> tag in the <head>. This however, penalizes your pagespeed insights and overall load time.
I had 100% success with it. I think it's also the main reason, why above solutions with other JS in the works.
<script type="text/javascript">
</script>
None of the CSS-only solutions presented here work with modern browsers (asynchronous loading of css and fonts). You have to use Javascript. What I've done to avoid FOUC is:
<html>
<body onload="document.body.style.visibility=`visible`;">
<script>document.body.style.visibility=`hidden`;</script>
With this approach the body of my web page is kept hidden until the full page and CSS files are loaded. Once everything is loaded, the onload event turns the body visible. So, the web browser remains empty until a point when everything pops up on the screen.
It is a simple solution but so far it is working.
This will not affect users who have disabled Javascript because the <script> tag is ignored.
No one has talked about CSS #import
That was the problem for me i was loading two extra style sheets directly in my css file with #import
Simple solution: Replace all #import links with <link />
Every answer on this page slows down the load and it only hides the underlying issue. If you're experiencing FOUC, find out WHY it's happening and fix that.
At the core, this is happening:
because your stylesheets are not being loaded correctly: they should be loaded via link tag in the HTML, not via JavaScript
because you placed script tags before link tags, which may force a "layout operation" and trick the browser into rendering before it even attempts to load the style.
For reference, here's an example of FOUC:
I came up with a way that requires no real code change whatsoever, woohoo! My issue was related to importing several css files AFTER some javascript files.
To resolve the issue I just moved my CSS links so that they would be above my javascript imports. This allowed all my CSS to be imported and ready to go ASAP, so that when the HTML appears on the screen, even if the JS isn't ready, the page will be properly formatted
Here is my code .. hope it solve your problem
set <body style="opacity:0;">
<script>
$(document).ready(function() {
$("body").css('opacity', 1);
});
</script>
A simple solution to avoid a flash of unstyled content without javascript:
<!DOCTYPE html>
<html>
<head>
<title>Bla bla</title>
<link href="..." rel="stylesheet" />
<link href="..." rel="stylesheet" />
</head>
<body style="opacity: 0">
<!-- All HTML content here -->
<script src="..."></script>
<script src="..."></script>
<style>
body {
opacity: 1 !important;
}
</style>
</body>
</html>
When the parser arrives at the body, it is faded out using "opacity: 0". When the parser finally arrives at the very bottom after everything else is parsed, the body is faded in again using an in-page style. The !important keyword there is important ;-), because it overrules the previous inline style of the body tag.
In this case, using "opacity: 0" to fade out is better than "display: none", because if you have layout operations done by javascript, they may not work when the affected element is not rendered.
That worked for me.
The best solution I found till now is like this:
Add all styles of your header to a <style/> tag in <head/>
at the top of style tag add .not-visible-first{visibility: hidden} + other header style
Add css via JS at the end of body
document.getElementsByTagName("head")[0].insertAdjacentHTML("beforeend","<link rel=\"stylesheet\" href=\"/css/main.min.css?v=1.2.4338\" />");
And remember to add .not-visible-first{visibility: visible} to the end of main.min.css
This option will create better user experience
You could try this with vanilla
function js_method(){
//todos
var elementDiv = document.getElementById("main");
elementDiv.style.display ="block";
}
<body onload="js_method()" id="main" style="display:none">
//todos
<h2>Hello</h2>
</body>