I'm generating a pdf with wicked_pdf, and centain pages will have a div with a black border. This div may or may not be big enough to break between pages, which leads to the following effect:
Div with open bottom
The div breaks like it should, but it is open between pages, and i need it to have a closing border. I was able to achieve a border using a footer with the right width and height to match the bottom break, but there are pages that shouldn't have it. Besides, there is the problem that the top of the div on the next page remains open
Using footer to close the bottom
I was able to make the footer disappear, from specific pages, like the last one, but there isn't a way to know how many pages the pdf will have, or which pages should or should not have it. I used the following code to do so:
var vars = {};
var x = document.location.search.substring(1).split('&');
for (var i in x) {
var z = x[i].split('=', 2);
vars[z[0]] = unescape(z[1]);
}
var x = ['frompage', 'topage', 'page', 'webpage', 'section', 'subsection', 'subsubsection'];
for (var i in x) {
var y = document.getElementsByClassName(x[i]);
for (var j = 0; j < y.length; ++j) y[j].textContent = vars[x[i]];
if (vars["topage"] == vars["page"]) {
document.getElementById("footer-line").style.display = "none";
}
};
<div id="footer" style="display: inline-block; width: 100%">
<div id="footer-line" style="margin-left: 2px; width: 99.6%; height: 60px;border-top: 2px solid black;"><div>
</div>
But it doesn't solve the problem, since the footer with the line remains on pages which it shouldn't be or its not needed, cause the div itself migth have ended and is, therefore, already closed.
I also tried to use box-decoration-break, but it looks like the html is first rendered and then turned into pdf, so this rule doesn't work apparently
I guess it would make a lot of sense for css to have a border feature on page-breaks, but i couldn't find anything like that. How could a closement for it be made?
Related
I have an application where I want to create a full sized HTML page for displaying on a Kiosk.
Javascript will change the number of images depending on how many people are interacting with the kiosk (this side is all handled).
I could have one image, it could be two, three, four, anything up to 7x7 = 49.
I want to create a layout that looks very similar in how 'Zoom' creates the gallery view.
For instance:
One image: would be 100% width and height of the page
Two images: would do 50% width/height, showing eachother side by side with letterboxing top and bottom of the page
Three images: two on the top line, one on the bottom - with the bottom one horizontally centred
Four images: 2x2 grid
Five images: three on the top line, two on the bottom line
etc
Nine images: 3x3 grid
You get the picture!
I've spent a good few hours today trying to solve this. I don't really have working code to show any more as I have tried lots of options. I have tried pure CSS, jquery manipulating tables, utilities that create masonry galleries, etc. None seem to achieve what I want.
Does anyone have any bright ideas on how to make this happen?
It's running on Chrome in a controlled environment so don't need to worry about cross browser compatibility and can generally get away with using most options for technologies to get this to work.
Thanks
If you wanted the new people to come in at the bottom/left then grid would be the answer. But to get the bottom row centered we need to turn to flex.
As you will probably be using JS to insert or remove people you can calculate how many columns you need each time and reorganize the screen.
Here's a snippet showing the calculation. Change the number of divs in #container to see the effect. The aspect ratio for the person div is set in JS as variable personAspect. Currently set to 16:9 but can be altered as required.
<head>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#screen {
position: relative;
width: 100vw;
height: 100vh;
background-color: black;
overflow: hidden;
}
#container {
position: relative;
top: 50%;
margin: auto;
display: flex;
flex-wrap: wrap;
justify-content: center;
}
.person {
background-image: url(https://i.stack.imgur.com/ju8HY.jpg);
background-size: cover;
background-repeat: no-repeat;
}
</style>
<style id="person">
</style>
</head>
<div id="screen" >
<div id="container">
<div class="person"></div>
<div class="person"></div>
<div class="person"></div>
<div class="person"></div>
<div class="person"></div>
</div>
</div>
<script>
const personAspect = 16/9; /* SET TO WHAT YOU WANT IT TO BE FOR EACH PERSON DIV */
const maxCols = 7;
const screen = document.getElementById("screen");
const container = document.getElementById("container");
function reorganize() {
const people = container.querySelectorAll('.person');
const numPeople = people.length;
const screenAspect = window.innerWidth/window.innerHeight;
let cols = 1;
for (cols; cols <= maxCols; cols++) {
if (numPeople <= (cols * cols)) { break; }
}
let w = 0; //will be of the container in px
let h = 0; //will be height of the container in px
if (numPeople > (cols * (cols-1))) {// > OK for 5 and 6 not OK for 7
h = window.innerHeight;
w = h * personAspect;
} else {
w = window.innerWidth;
h = w / personAspect;
}
container.style.width = w + 'px';
document.getElementById('person').innerHTML = '.person {flex: 0 0 ' + (100/cols) + '%; height: ' + (h/cols) + 'px;}';
if (numPeople <= (cols * (cols-1))) {h = h- h/cols;}// for when last row is empty
container.style.marginTop = (- h)/2 + 'px';
}
reorganize();
window.onresize = reorganize;//not needed for final production but to make it easier to use the real window aspect ratio when developing
</script>
</body>
Here's the layout I'm trying to achieve:
My content currently is a series of basic, block HTML elements (h[1-5], p, ul, etc.) contained in a div, and if possible I'd like to keep them that way. All of the images are inside their own p in order to responsively resize
I've been able to add a div style="float:right" to the top of the content which creates the sidebar and wraps "normal" text content around it - specifically the first paragraph in my diagram above. However, the img, which is set to 100% does not wrap, it flows below the sidebar.
So really, I want images to have one of two widths - either 100%-width(sidebar) if the top of the image "should be" above the bottom of the sidebar, or 100% if the top of the image is below the bottom of the sidebar.
I can of course manually set the width on an image when debugging a page, to a value less than 100%-width(sidebar) and it jumps right up into place, so clearly the browser knows what that size is to not "push" the image down below the sidebar...
Here's the actual page where I'd like to get this to work; note that the first image is below the sidebar:
https://adventuretaco.com/?p=3655&draftsforfriends=kIq7mVDhNtCSklITGCJs2HAcE9xuPX8d
additionally, here is the CSS and HTML that I currently have for the post content:
CSS
p {
margin: 0 0 1.25em 0;
}
ol, ul {
margin: 0 1.5em 1.25em 1.5em;
}
.full-width-container {
width: 100%;
}
.full-width-container img {
display: block;
margin-left: auto;
margin-right: auto;
overflow: hidden;
transition: 0.5s;
}
.full-width-container img.flickrPhoto {
display: block;
width: 100%;
margin-left: auto;
margin-right: auto;
overflow: hidden;
transition: 0.5s;
}
HTML
<div class="post-content">
<p>As you may recall, we'd just cancelled our flight home due to the unknowns of Covid-19, but were still in exploration mode as we entered the Valley of Fire State Park in southeastern Nevada.</p>
<p id="photoContainer132" class="full-width-container"><img id="photo132" class="flickrPhoto" src="https://live.staticflickr.com/65535/49714173358_d19b1c2e70_n.jpg" /></p>
<p>Our trip to the Valley of Fire was somewhat opportunistic to say the least. A year before this trip ever even crossed my mind, I'd seen a photo on Flickr that had caught my eye. Sharp as ever, I completely forgot to save the photo or a link to the photo <img src="https://www.tacomaworld.com/styles/default/my/smilies/annoyed_gaah.gif" />, but - luckily for me - the photo had been geotagged <em>and</em> I'd saved a point of interest in my Google Earth map of Nevada. I'd noticed that point as I'd planned this trip, and mapped out the route, excited to see what nature had in store. So yeah, apparently, I'm not <em>always</em> as dumb as I look. <img src="https://www.tacomaworld.com/styles/default/my/smilies/original/wink.png" /> In researching Valley of Fire, I also discovered a second hike -rumored to have petroglyphs - and since it was on our way to the main attraction, we decided to stop off there first.</p>
<p id="photoContainer133" class="full-width-container"><img id="photo133" class="flickrPhoto" src="https://live.staticflickr.com/65535/49715029457_a61cffc61b_n.jpg" /></p>
</div>
I think you first need to downsize a little your images, due to their size, it becomes a little difficult to manipulate them within the scope of what you would like to do. You can alter them inside the tag, or from the css file. Then after, you can use inside of that code a "float: left;" in the .full-width-container img, give it a margin that should put them side to side.
OK, so after a bunch more research, trial and error, I've come to the conclusion that the answer to this question is that it cannot be solved with CSS / layout alone.
In the end, incorporated Javascript to solve the problem. It's not perfect - if images have been downsized to flow around the sidebar, then when the browser window gets larger, they don't get larger as ideally as they could.
Here's where I ended up; working sample at (scroll down here to see the sidebar)
https://adventuretaco.com/hidden-valleys-secret-tinaja-mojave-east-5/#photoContainer190
// start shortly after page is rendered
setTimeout(resizeImagesForFacebookEmbed, 500);
function resizeImagesForFacebookEmbed() {
var tryAgain = true;
// find each of the elements that make up the post, and iterate through each of them
var content = jQuery('div.post-content').children().each(function () {
if (this.tagName.toLowerCase() == 'p') {
var firstChild = this.firstChild;
var firstElementChild = this.firstElementChild;
if (firstChild != null && firstChild == this.firstElementChild && firstElementChild.tagName.toLowerCase() == 'img') {
var pRect = this.getBoundingClientRect();
var imgRect = firstChild.getBoundingClientRect();
var difference = imgRect.top - pRect.top;
// if the image contained in the p is not at the top of the p, then make it smaller
// so it will fit next to the embed, which is 350px wide
if (difference > 25 || imgRect.width < (pRect.width - 400)) {
var sidebarLeft = document.getElementById("fbSidebar").getBoundingClientRect().left;
var imgLeft = firstChild.getBoundingClientRect().left;
var imgWidth = (sidebarLeft - imgLeft) * .95;
firstChild.style.width = imgWidth + "px";
tryAgain = false;
setTimeout(resizeImagesForFacebookEmbed, 1000);
} else {
// do nothing
}
}
}
});
if (tryAgain)
setTimeout(resizeImagesForFacebookEmbed, 1000);
}
var waitForFinalEvent = (function () {
var timers = {};
return function (callback, ms, uniqueId) {
if (!uniqueId) {
uniqueId = "Don't call this twice without a uniqueId";
}
if (timers[uniqueId]) {
clearTimeout(timers[uniqueId]);
}
timers[uniqueId] = setTimeout(callback, ms);
};
})();
// handle window resize event to re-layout images
jQuery(function () {
jQuery(window).resize(function () {
waitForFinalEvent(function () {
resizeImagesForFacebookEmbed();
}, 500, "atFbEmbedId"); // replace with a uniqueId for each use
});
});
I want to put the div behind the scrolling header like it is for the footer.
The footer is
#rt-footer-surround {
color: #686868;
background-color: #2E244E;
height: 40px;
width: 100%;
z-index: 900;
bottom: 0;
left: 0;
padding: 10px;
position: fixed;
}
but I cannot replicate it for the header.
the site in question is here:
site with z-index issue
To use the z-index style, you must also use either position:fixed;, position:absolute;, ,or position:relative; on the same object you wish to style.
Then, you can simply use a div to represent your header, footer, and main content section as follows:
<div class="head"></div>
<div class="mainbody"></div>
<div class="foot"></div>
Or alternatively, you can use the <head>,<main> and <footer> tags instead of divs. As far as coding and visuals are concerned, there is no difference.
Also, you don't have to put a massive number on the z-index. As long as one element's z-index is greater than another one's, that element will always be layered above, whether it is 900 over 1, or 2 over 1.
Ok here is what I came up with to solve the problem. Jquery.
Essentially my question was asking for this in the first place.
If you have content in a div you can place a nav bar in that div as a position:relative i.e. relative to that div.
What you cannot do via css is have the content in that div scroll up and stay underneath the nav bar you created. Furthermore when the nav menu area scrolls beyond the top of the screen it will then disappear.
So the jquery code I used does two things. It allows you to take a nav menu bar i.e. width 600px / height 50px and place it in its relative position anywhere you like. Furthermore, when it reachs the top of a users screen it will stop/halt and allow that to be the menu that is visible while everything else scrolls underneath that menu area.
Now, I don't think this is anything really new from Jquery but what is ultra convenient is that you can define a menu nav bar in any div position you want. Have a regular menu at the top and another menu perhaps below a slider or some content further down the page.
I will share the code if that is ok with SO... I paid for it myself.
Oh and here are two websites I have employed it on.
http://isaerudition.com/study-pages &
This is for a client I am preparing his website...
// JavaScript Document
/* jQuery(document).ready(function(){
if(jQuery('header,div,p,span,h1,h2,h3,h4,a').hasClass('isa-scroll-fixed')){
var el = jQuery('.isa-scroll-fixed'),
elTop = jQuery(el).offset().top;
elLeft = jQuery(el).offset().left;
//alert(elTop);
jQuery(document).scroll(function(){
var height = jQuery(window).height();
var scrollTop = jQuery(window).scrollTop();
if(scrollTop>=elTop){
//add fixed
jQuery(el).addClass('scroll_fixed').css("left",elLeft+"px");
}else{
//clear fixed
jQuery(el).removeClass('scroll_fixed').attr('style','');
}
})
}
})
*/
// JavaScript Document
/* jQuery(window).load(function(){
if(jQuery('header,div,p,span,h1,h2,h3,h4,a').hasClass('isa-scroll-fixed')){
var el = jQuery('.isa-scroll-fixed'),
elTop = jQuery(el).offset().top;
elLeft = jQuery(el).offset().left;
//alert(elTop);
var scrollTop = jQuery(window).scrollTop();
scrollFixed(el,elTop,elLeft);
}
}) */
var setInter = null;
var session = null;
setInter = setInterval(function(){
if(jQuery('header,div,p,span,h1,h2,h3,h4,a').hasClass('isa-scroll-fixed')){
var el = jQuery('.isa-scroll-fixed');
session = jQuery(el).attr('set-scroll');
//alert(session);
if(session == '2'){
jQuery(el).attr('set-scroll','2');
}else{
jQuery(el).attr('set-scroll','1');
}
if(session == '1'){
setValue(el);
}
}
}, 200);
function setValue(el){
var setScroll = jQuery(el).attr('set-scroll');
elTop = jQuery(el).offset().top;
elLeft = jQuery(el).offset().left;
//alert(elTop);
jQuery(el).attr('set-scroll','2');
scrollFixed(el,elTop,elLeft);
};
function scrollFixed(el,elTop,elLeft){
jQuery(document).unbind('scroll').scroll(function(){
//alert(elTop);
var height = jQuery(window).height();
var scrollTop = jQuery(window).scrollTop();
if(scrollTop>=elTop){
//add fixed
jQuery(el).addClass('scroll_fixed').css("left",elLeft+"px");
}else{
//clear fixed
jQuery(el).removeClass('scroll_fixed').attr('style','');
}
})
}
here's something i never thought i would type: chrome breaks the layout, but IE (or any other browser for that matter) doesnt...
there's a featured slider with position: relative; with elements inside with position: absolute;
the javascript loops through the elements to create a rotating images
see: http://guardianweb.edulence.com/model10/
i've added a margin-top of 304px to the two elements below the featured slider, but the gap is huge in every browser besides google chrome
What is happening is that other browsers are incorrectly applying a height of 305px and width of 940px to your #featured division. I have no idea why they'd do that. Chrome is correctly rendering that element with a height of 0, because there is no content inside the element (absolutely positioned elements don't take up any space in the flow of the document).
In Chrome:
In Firefox:
I suppose one way you could work around this is to manually specify the width and height on your #featured element so that all the browsers, including Chrome, act the same.
I believe the issue is here:
// stretch container
var reshape = opts.containerResize && !$cont.innerHeight();
if (reshape) { // do this only if container has no size http://tinyurl.com/da2oa9
var maxw = 0, maxh = 0;
for(var j=0; j < els.length; j++) {
var $e = $(els[j]), e = $e[0], w = $e.outerWidth(), h = $e.outerHeight();
if (!w) w = e.offsetWidth || e.width || $e.attr('width');
if (!h) h = e.offsetHeight || e.height || $e.attr('height');
maxw = w > maxw ? w : maxw;
maxh = h > maxh ? h : maxh;
}
if (maxw > 0 && maxh > 0)
$cont.css({width:maxw+'px',height:maxh+'px'});
}
!$cont.innerHeight() seems to be false in chrome but true in other browsers. This is causing the plugin to set a specific height and width to the div where as in chrome no height is set, meaning it is still 0.
This is not Chrome's fault. If you inspect the #featured element, you'll notice that this element has a height and width set via CSS inline styles in Firefox, but not in Chrome.
Firefox: <div id="featured" style="width: 940px; height: 305px;">
Chrome: <div id="featured">
The height of that DIV is zero in Chrome.
That style attribute is added to the DIV via JavaScript, so you'll have to figure out why it's added for Firefox, but not for Chrome...
So I have this:
clicking here
<a name="link">goes here</a>
Simple, but the problem is that my site has a fixed position header that stays at the top of the page, so when a user clicks on the link, the place I want them to go to is hidden by the header. So I guess where I really want them to end up a certain amount of pixels above what I actually want them to see. I've tried putting the destination link above where I want them to end up, but it's a block of text so it changes with different screen sizes and therefore isn't consistent.
I'm wondering if there is any way to solve this problem, perhaps something with css.
Thanks in advance.
I realise this is over a year old, but for the benefit of anyone else who comes across it:
A slightly simpler solution is to put padding at the top of the section you are targeting with the link.
HTML:
<section id="section_name">
...Your stuff here...
</section>
CSS:
#section_name {
padding-top: 40px;
}
You could use a jQuery method so that when a link with a # is clicked, it finds the position of the element it's meant to go to and then moves to a position X number of pixels above the target.
Something like this:
$(function(){
var positionOffset = 50;
$('a[href=*"#"]').click(function(){
var targetHash = this.hash;
if(targetHash.length > 0 && targetHash == window.location.hash){
var elementPosition;
if($(targetHash).length){
elementPosition = $(targetHash).offset();
} else {
var targetAnchor = targetHash.replace("#", "");
elementPosition = $('a[name="' + targetAnchor + '"]').position();
}
$(window).scrollTop(elementPosition.top - positionOffset);
return false;
} else {
return true;
}
});
});