Controlling layout of phantom-html2pdf document - html

I'm using phantom-html2pdf to generate pdfs dynamically in a Node app. The conversion works but the layout is completely off. For example the html document is a form that consists of sections sometimes with two columns side-by-side.
I am using MUI css for some styling and layout which has been in-lined into the HTML before the PDF conversion. After the PDF conversion everything is in one column, despite the fact that I have divs with class="mui-col-md-6" which render fine in the browser.
I've tried adding custom CSS and adding pageSize values but no matter what I do it's not producing the result I'm after.
Here is what I have in options at the moment. Note I've passed through some css where I try to "reshape" the document to make it more like the original HTML but it seems to have limited effect on the final layout. Also I set a negative border which helps a bit but doesn't remove PDF border completely as I'd like.
var pdfOptions = {
html: html, // html with in-lined MUI styles - columns not rendering
css: pdfCss, // This CSS seems to have has limited control over final layout
paperSize: {format: 'A4', orientation: 'portrait', border: '-2cm'}
}
If anyone has any advice on how to get more control over the layout to make it look more like my HTML I'd be very grateful. Cheers!
UPDATE
It appears that phantom-html2pdf ignores any inline css and only applies css passed in as part of the options. Again, I'm open to any pointers so correct me if I'm wrong or missing some steps to have more control over the final layout.

Related

Nest an entire CSS to only target a single div [duplicate]

I am creating a mobile simulator that mocks the appearance and functionality of an iPhone (and other devices later) in a web browser, using 100% javascript, HTML5, and CSS, with the simulator fully functional with only client side code.
While trying to accomplish this task with as little modification as necessary to the original app projects themselves to be hosted in the simulator, I am injecting the <script> and <link> tags into the head of the page, then loading the html into a <div> screen.
The problem is that when I load in a new css file, it (obviously) overrides the one I'm using to style the page, and therefor some elements are affected (ex the background changes color).
My question is: Is there any way to limit the "scope" of an external .css file to apply only to objects within the <div> screen? Would it make any difference if instead of me injecting it into the <head> of the page, I inject it into a <style> element in the <div> screen?
UPDATE Support for this feature has been dropped. Please seek other options
Original Post:
You may want to look at scoped styles; see http://css-tricks.com/saving-the-day-with-scoped-css/.
The basic idea is
<div>
<style scoped>
#import "scoped.css";
</style>
</div>
However, you are on the bleeding edge here in terms of browser support. See http://caniuse.com/style-scoped.
One alternative would be to use an iframe.
Simply wrap all you css code inside the selector for parent element, say it's a div with id of foo you'd do the following:
div#foo{
//All your css
}
And convert it as less to css, it will prepend the right selectors. Note that you'll need to take care manually of things like #media queries and so on.
While writing this, the <style scoped> is deprecated by the Chrome team.
As a result I experimented with some approaches and released https://github.com/thgreasi/jquery.scopeLinkTags .
Note: you should only have to use this approach in case that you can't control the imported CSS file. If you can use SASS/LESS/anything to pre-process your CSS, you should prefer that.
A simple way is adding pre-class before all selector in css file.
I find a grunt script can do this:
https://github.com/ericf/grunt-css-selectors
This is how i do it if not using preprocessor in my project. Search for a online preprocessor then load copy paste the css under the parent class/id
.parent{
// copy paste here
}
Example
Find a preprocessor for example https://beautifytools.com/scss-compiler.php works very well for me (I have no affiliation with the given link)
if you are using from a URL add the URL using the load URL button.
Wrap the css code under parent and hit compile then minify.
I had a similar issue and found that Shadow DOM can solve it easily.
let output = d.querySelector('#output')
let shadow = output.attachShadow({
mode: 'closed'
});
shadow.innerHTML = HTMLcontent // HTML content and style injected
Source

Discrepancies between source and inspected html?

I am editing a HTML website template, and I need to change the banner height so I edited external CSS. However, somehow it is taking an inline CSS height property so there is a space left in between.
Please let me know, if I have not written any inline CSS (and there is no inline CSS in html page), from where is that height property coming from.
Code I see in console is:
<div style="display: block; height: 445px;" id="camera" class="camera-wrap camera_wrap">
And my code is:
<div id="camera" class="camera-wrap">
<div data-src="images/Battery-Banner.jpg">
I have no idea why it is taking class camera_wrap twice.
Usually JS plugins put dynamic css that is calculated during runtime. It will be placed in inline style tag. Otherwise any static code will go to external css file. Try checking how plugin is calculating that height and than modify your HTML/css.
Try viewing the HTML source in your browser (not using inspect element, use view-source). This will show you the markup prior to any other client side processing aka. JavaScript. If the inline style isn't there when you view source then that indicates that it may be a rogue bit of JavaScript that is adding it in.
In any case can you please provide more information on the issue? Possibly a little more background on what type of website, what parts it has CSS, JS etc. With more information we may be able to help more.
If your source is showing 1 class, and when you are using inspect element it is showing other classes, then it is definitely added by js/jquery plugin.
If you want to overwrite other class css properties, either use !important in your class or use deeper dom traversing like #camera.camera-wrap{}. Than this will be given higher priority. Try which works for you.

Format a HTML document into multiple A4 size sections

This is my current problem.
I want to generate a HTML page, which contains about 40 coupons. Each coupon must be with one A4 sized section.
So, if I were to print the HTML document, I would like each printed page to contain 1 coupon.
Ideas on how I could accomplish this ?
The following CSS should achieve what you need, subistitute the class name for whatever is appropriate for your DOM structure
#media print {
.coupon-class
{
page-break-after:always;
}
}
This will always insert a page break after the element you can also use page-break-before to achieve a page break before an element.
You'll never get a very precise solution using HTML, as every browser decides its way of printing HTML is best and adds all sorts of headers and footers that change the page dimensions and how the clients printer actually prints it.
You would be better off generating a PDF of your coupons which you can easily do with PHP extensions.
You can do the steps below:
Define the width:100 for each coupon in its css styles. This will use maximum width of your paper.
Use page-break-after:always in css properties of each coupon. This will force the next coupon to be shown in the next page. (http://msdn.microsoft.com/en-us/library/ms530842(v=vs.85).aspx)
Don't forget to be careful about your coupons height. Try to avoid putting lots of rows in them.
You can use <fieldset> tag for each coupon and apply css properties on it.

How to break up HTML documents into pages for ebook?

For an iPhone ebook application I need to break arbitrarily long HTML documents up into pages which fit exactly on one screen. If I simply use UIWebView for this, the bottom-most lines tend to get displayed only partly: the rest disappears off the edge of the view.
So I assume I would need to know how many complete lines (or characters) would be displayed by the UIWebView, given the source HTML, and then feed it exactly the right amount of data. This probably involves lots of calculation, and the user also needs to be able to change fonts and sizes.
I have no idea if this is even possible, although apps like Stanza take HTML (epub) files and paginate them nicely. It's a long time since I looked at JavaScript, would that be an option worth looking at?
Any suggestions very much appreciated!
update
So I've hit upon a possible solution, using JavaScript to annotate the DOM-tree with sizes and positions of each element. It should then be possible to restructure the tree (using built-in XSLT or JavaScript), cutting it up in pages which fit exactly on the screen.
Remaining problem here is that this always breaks the page on paragraph-boundaries, since there is no access to the text at a lower level than the P-element. Perhaps this can be remedied by parsing the text into words, encapsulating each word in a SPAN-tag, repeating the measurement procedure above, and then only displaying the SPAN elements that fit onto the screen, inserting the remaining ones at the front of the next page.
All this sounds rather complicated. Am I talking any sense? Is there a simpler way?
You should look at the PagedMedia CSS module: http://www.w3.org/TR/css3-page/
CSS3 also support multicolumn layouts (google for "css3-multicol". I don't have enough Karma to include a second link here :-)
About your update: how about doing the layout of one single page, then use a DIV with overflow:hidden for the text part. Next thing would be to overlay a transparent item on top of that, that would programmatically scroll the inner content of the DIV PAGE_HEIGHT pixels up or down according to some navigation controls (or gestures).
The other option is to have a parent <div> with multiple css3 columns: link1, link2.
This works on Android:
<style type='text/css'>
div {
width: 1024px; // calculated
-webkit-column-gap: 0px;
-webkit-column-width: 320px; // calculated
}
p {
text-align: justify;
padding:10px;
}
</style>
The CSS multicol suggestions are very interesting! However, and I hope it's ok to respond with another question: how would you go from splitting one or more long <p> elements into columns to having one particular of these columns being rendered in a WebView? The DOM hasn't changed, so you can't pick out an element and render it. What am I missing?

JSON as HTML data in Flex - Hyperlink Rollovers

I am using JSON to parse HTML data with customized html tags in Flex. Flex's support for HTML is pretty minimal, so I am wondering if it's possible to do a simple font color change rollover effect on these links. Currently I have found that Flex only supports a few HTML tags, but also supports CSS through Flex's whack CSS methods.
Can I manipulate HTML that is written in my JSON files through an external CSS file? Or better still using a simple tag with the JSON file?
Short answer: I don't think there's a magic bullet for this. It's going to be a lot of pain.
You can start by extending the Text class in a way that adds a static StyleSheet property (e.g., styleSheet:StyleSheet = null). Then create an array which contains the following styles, the only ones supported by Flex:
listOfStyles:Array = ['fontSize', 'color', 'fontWeight', 'fontFamily', 'fontStyle', 'textDecoration'];
Then you have to initialize the StyleManager.selectors, creating an array of selectors you are going to use. Basically, you are finding the "A" tag and adding the listOfStyles above to it, then creating a new CSSStyleDeclaration for each of those styles.
This will allow you to apply the above-named styles to the htmlText property of your extended class. So far so good. This enables you to set different styles to your anchor tags upon load, using an external stylesheet. To apply a rollover effect, however, where each link changes color on rollover within the HTML, would be problematic, since MouseEvent.MOUSE_OVER would apply to the class as a whole, not the individual HTML elements within it. You would have to figure out if the mouse was over an anchor within that HTML text (not impossible, but I don't have time to work that out right now) and change your selector within that. It would involve getting the text range, and that always means a lot of work. I had to mess with that when a client wanted emoticons to appear in the text flow (something else Flex's implementation of HTML fails to support) and it was extremely gnarly.
I believe Flex 4 is going to add more support natively for this kind of thing, but I haven't researched that specifically.
Sorry I don't have a magic bullet for you, but I hope this sheds a little light on the topic.
I don't use Flex often so not much in depth framework knowledge, but I think I
needed to something similar:
do a simple font color change rollover
effect
Here is a snippet:
var linkRegEx:RegExp = new RegExp("(https?://)?(www\\.)?([a-zA-Z0-9_%]*)\\b\\.[a-z]{2,4}(\\.[a-z]{2})?((/[a-zA-Z0-9_%]*)+)?(\\.[a-z]*)?(:\\d{1,5})?","g");
var link:String = 'generic links: www.google.com http://www.yahoo.com stackoverflow.com';
link = addLinks(linkRegEx,link);
textField.htmlText = link;//textField is a TextField I have on stage
function addLinks(pattern:RegExp,text:String):String{
var result = '';
while(pattern.test(text)) result = text.replace(pattern, "<font color=\"#0000dd\">$&</font>");
if(result == '') result+= text;//if there was nothing to replace
return result;
}
I just used inline font tag, css might be better. Here is my original question.
HTH,
George