Related
On my webpage there are Gridster widgets.In these widgets initially the images are displayed from JSON(the name of image comes from JSON which I then put in src of image)
The users can also add images by clicking + button.User can also delete an image by clicking X button on the image.
The Problem I am facing
When the images coming from JSON are more or when the user manually adds more images then the images go out of widgets.
My Desired Output
Now I was trying to restrict those images in widget such that images will lay only in boundaries of div.
When there are more images the other existing images will resize and all of the images will fit in that area.
When I delete an image the other images will get bigger.In any case the entire area will be occupied by the images.
JS:
//JSON which I get from backend
var json = [{
"html": "https://d30y9cdsu7xlg0.cloudfront.net/png/802768-200.png,https://d30y9cdsu7xlg0.cloudfront.net/png/802768-200.png,https://d30y9cdsu7xlg0.cloudfront.net/png/802768-200.png", //3 Images
"col": 1,
"row": 1,
"size_y": 2,
"size_x": 2
}
];
//Loop which runs over JSON to generate <li> elements in HTML
for (var index = 0; index < json.length; index++) {
var images = json[index].html.split(',');
var imageOutput = "";
for (var j = 0; j < images.length; j++) {
imageOutput += '<div class="imagewrap"><img src=' + images[j] + '> <input type="button" class="removediv" value="X" /></div></div>';
}
gridster.add_widget('<li class="new" ><button class="addmorebrands" style="float: left;">+</button><button class="delete-widget-button" style="float: right;">-</button>' + imageOutput + '<textarea>' + json[index].html + '</textarea></li>', json[index].size_x, json[index].size_y, json[index].col, json[index].row);
}
//Function to delete an image from widget
$(document).on('click', '.removediv', function() {
$(this).closest('div.imagewrap').siblings('textarea')
$(this).closest('div.imagewrap').remove();
});
//Function to delete a widget
$(document).on("click", ".delete-widget-button", function() {
var gridster = $(".gridster ul").gridster().data('gridster');
gridster.remove_widget($(this).parent());
});
//Function to add mode Images to widgets from Modal
var parentLI;
$(document).on("click", ".addmorebrands", function() {
parentLI = $(this).closest('li');
$('#exampleModalCenter').modal('show');
$('#exampleModalCenter img').click(function() {
$(this).addClass('preselect');
$(this).siblings().removeClass('preselect');
selectedImageSRC = $(this).attr('src');
})
});
$('#add-image').click(function() {
parentLI.append('<div class="imagewrap"><img src="' + selectedImageSRC + '"> <input type="button" class="removediv" value="X" /></div>');
parentLI.children('textarea').append(', ' + selectedImageSRC);
$('#exampleModalCenter').modal('hide');
})
HTML
<div class="gridster">
<!-- <li> from JSON are placed here images are a part of li -->
<ul>
</ul>
</div>
The Fiddle so far
I am not sure if this can achieved just with CSS or will require any JS along with that
Update 1
I have tried with a lot of different CSS but still not able to get the expected output so if someone can help me with it would be really helpful
Maybe Gridster has a built in way to arrange items inside the grid cells, in case you have not found a way yet, try this.
I added some css:
.image-wrap-container{
min-height: 70%
}
.image-wrap-container div.imagewrap{
width: 33%
}
.text-area-wrap{
bottom: 0px;
left: 0px;
margin: 0px;
padding: 0px;
width: 100%;
height: 30%;
display: inline-flex;
}
.new.gs-w{
width: 200px;
min-height: 200px
}
.addmorebrands{
position: absolute;
left:0
}
.delete-widget-button{
position: absolute;
right:0
}
and restructured a little bit your html so images fit good within the cell, I hope that does not break anything, javascript was the least modified, only to add the images according to the new html structure.
Note: I tried to make the lis' height adjust to the amount of elements it contains, but [data-sizey="2"] kept getting in my way, so before throwing some probably unnecessary hack on it, try and achieve that using the library's own options, good luck.
Also, I noticed you were using this to update your textareas:
parentLI.children('.imagenames').val(function(i, selectedImageSRC) {return selectedImageSRC + ', '});
which won't work because you are using the same name for the argument, conflicting with the original selectedImageSRC variable. In case you are still having problems in that front, I replaced it with:
parentLI.children('.imagenames').val(function(i, currentContent) {return currentContent + ',' + selectedImageSRC + ', '});
Bonus Feature
The buttons for removing an image were to big for the images and covered quite a big part, so I took the liberty:
.removediv{
visibility: hidden
}
.imagewrap:hover .removediv{
visibility: visible
}
hope it helps
How do I print the indicated div (without manually disabling all other content on the page)?
I want to avoid a new preview dialog, so creating a new window with this content is not useful.
The page contains a couple of tables, one of them contains the div I want to print - the table is styled with visual styles for the web, that should not show in print.
Here is a general solution, using CSS only, which I have verified to work.
#media print {
body * {
visibility: hidden;
}
#section-to-print, #section-to-print * {
visibility: visible;
}
#section-to-print {
position: absolute;
left: 0;
top: 0;
}
}
Alternative approaches aren't so good. Using display is tricky because if any element has display:none then none of its descendants will display either. To use it, you have to change the structure of your page.
Using visibility works better since you can turn on visibility for descendants. The invisible elements still affect the layout though, so I move section-to-print to the top left so it prints properly.
I have a better solution with minimal code.
Place your printable part inside a div with an id like this:
<div id="printableArea">
<h1>Print me</h1>
</div>
<input type="button" onclick="printDiv('printableArea')" value="print a div!" />
Then add an event like an onclick (as shown above), and pass the id of the div like I did above.
Now let's create a really simple javascript:
function printDiv(divName) {
var printContents = document.getElementById(divName).innerHTML;
var originalContents = document.body.innerHTML;
document.body.innerHTML = printContents;
window.print();
document.body.innerHTML = originalContents;
}
Notice how simple this is? No popups, no new windows, no crazy styling, no JS libraries like jquery. The problem with really complicated solutions (the answer isn't complicated and not what I'm referring to) is the fact that it will NEVER translate across all browsers, ever! If you want to make the styles different, do as shown in the checked answer by adding the media attribute to a stylesheet link (media="print").
No fluff, lightweight, it just works.
All the answers so far are pretty flawed - they either involve adding class="noprint" to everything or will mess up display within #printable.
I think the best solution would be to create a wrapper around the non-printable stuff:
<head>
<style type="text/css">
#printable { display: none; }
#media print
{
#non-printable { display: none; }
#printable { display: block; }
}
</style>
</head>
<body>
<div id="non-printable">
Your normal page contents
</div>
<div id="printable">
Printer version
</div>
</body>
Of course this is not perfect as it involves moving things around in your HTML a bit...
With jQuery it's as simple as this:
w=window.open();
w.document.write($('.report_left_inner').html());
w.print();
w.close();
Could you use a print stylesheet, and use CSS to arrange the content you wanted printed? Read this article for more pointers.
I didn't really like any of these answers as a whole. If you have a class (say printableArea) and have that as an immediate child of body, then you can do something like this in your print CSS:
body > *:not(.printableArea) {
display: none;
}
//Not needed if already showing
body > .printableArea {
display: block;
}
For those looking for printableArea in another place, you would need to make sure the parents of printableArea are shown:
body > *:not(.parentDiv),
.parentDiv > *:not(.printableArea) {
display: none;
}
//Not needed if already showing
body > .printableArea {
display: block;
}
Using the visibility can cause a lot of spacing issues and blank pages. This is because the visibility maintains the elements space, just makes it hidden, where as display removes it and allows other elements to take up its space.
The reason why this solution works is that you are not grabbing all elements, just the immediate children of body and hiding them. The other solutions below with display css, hide all the elements, which effects everything inside of printableArea content.
I wouldn't suggest javascript as you would need to have a print button that the user clicks and the standard browser print buttons wouldn't have the same effect. If you really need to do that, what I would do is store the html of body, remove all unwanted elements, print, then add the html back. As mentioned though, I would avoid this if you can and use a CSS option like above.
NOTE: You can add whatever CSS into the print CSS using inline styles:
<style type="text/css">
#media print {
//styles here
}
</style>
Or like I usually use is a link tag:
<link rel="stylesheet" type="text/css" media="print" href="print.css" />
Give whatever element you want to print the id printMe.
Include this script in your head tag:
<script language="javascript">
var gAutoPrint = true;
function processPrint(){
if (document.getElementById != null){
var html = '<HTML>\n<HEAD>\n';
if (document.getElementsByTagName != null){
var headTags = document.getElementsByTagName("head");
if (headTags.length > 0) html += headTags[0].innerHTML;
}
html += '\n</HE' + 'AD>\n<BODY>\n';
var printReadyElem = document.getElementById("printMe");
if (printReadyElem != null) html += printReadyElem.innerHTML;
else{
alert("Error, no contents.");
return;
}
html += '\n</BO' + 'DY>\n</HT' + 'ML>';
var printWin = window.open("","processPrint");
printWin.document.open();
printWin.document.write(html);
printWin.document.close();
if (gAutoPrint) printWin.print();
} else alert("Browser not supported.");
}
</script>
Call the function
Print
Step 1: Write the following javascript inside your head tag
<script language="javascript">
function PrintMe(DivID) {
var disp_setting="toolbar=yes,location=no,";
disp_setting+="directories=yes,menubar=yes,";
disp_setting+="scrollbars=yes,width=650, height=600, left=100, top=25";
var content_vlue = document.getElementById(DivID).innerHTML;
var docprint=window.open("","",disp_setting);
docprint.document.open();
docprint.document.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"');
docprint.document.write('"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">');
docprint.document.write('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">');
docprint.document.write('<head><title>My Title</title>');
docprint.document.write('<style type="text/css">body{ margin:0px;');
docprint.document.write('font-family:verdana,Arial;color:#000;');
docprint.document.write('font-family:Verdana, Geneva, sans-serif; font-size:12px;}');
docprint.document.write('a{color:#000;text-decoration:none;} </style>');
docprint.document.write('</head><body onLoad="self.print()"><center>');
docprint.document.write(content_vlue);
docprint.document.write('</center></body></html>');
docprint.document.close();
docprint.focus();
}
</script>
Step 2: Call the PrintMe('DivID') function by an onclick event.
<input type="button" name="btnprint" value="Print" onclick="PrintMe('divid')"/>
<div id="divid">
here is some text to print inside this div with an id 'divid'
</div>
<script type="text/javascript">
function printDiv(divId) {
var printContents = document.getElementById(divId).innerHTML;
var originalContents = document.body.innerHTML;
document.body.innerHTML = "<html><head><title></title></head><body>" + printContents + "</body>";
window.print();
document.body.innerHTML = originalContents;
}
</script>
The Best way to Print particular Div or any Element
printDiv("myDiv");
function printDiv(id){
var printContents = document.getElementById(id).innerHTML;
var originalContents = document.body.innerHTML;
document.body.innerHTML = printContents;
window.print();
document.body.innerHTML = originalContents;
}
hm ... use the type of a stylsheet for printing ... eg:
<link rel="stylesheet" type="text/css" href="print.css" media="print" />
print.css:
div { display: none; }
#yourdiv { display: block; }
Without CSS clowning, html and pure javascript with iframe does its work best. Then simply click the text, you want to print. Current example for id elements with text content;
html body:
<div id="monitor" onclick="idElementPrint()">text i want to print</div>
pure javascript:
//or: monitor.textContent = "click me to print textual content";
const idElementPrint = () => {
let ifram = document.createElement("iframe");
ifram.style = "display:none";
document.body.appendChild(ifram);
pri = ifram.contentWindow;
pri.document.open();
pri.document.write(monitor.textContent);
pri.document.close();
pri.focus();
pri.print();
}
printDiv(divId): A generalized solution to print any div on any page.
I had a similar issue but I wanted (a) to be able to print the whole page, or (b) print any one of several specific areas. My solution, thanks to much of the above, allows you to specify any div object to be printed.
The key for this solution is to add an appropriate rule to the the print media style sheet so that the requested div (and its contents) will be printed.
First, create the needed print css to suppress everything (but without the specific rule to allow the element you want to print).
<style type="text/css" media="print">
body {visibility:hidden; }
.noprintarea {visibility:hidden; display:none}
.noprintcontent { visibility:hidden; }
.print { visibility:visible; display:block; }
</style>
Note that I have added new class rules:
noprintarea allows you to suppress the printing of elements within your div- both the content and the block.
noprintcontent allows you to suppress the printing of elements within your div- the content is suppressed but and the allocated area is left empty.
print allows you to have items that show up in the printed version but
not on the screen page. These will normally have "display:none" for the screen style.
Then insert three JavaScript functions. The first merely toggles the print media style sheet on and off.
function disableSheet(thisSheet,setDisabled)
{ document.styleSheets[thisSheet].disabled=setDisabled; }
The second does the real work and the third cleans up afterward. The second (printDiv) activates the print media style sheet, then appends a new rule to allow the desired div to print, issues the print, and then adds a delay before the final housekeeping (otherwise the styles can be reset before the print is actually done.)
function printDiv(divId)
{
// Enable the print CSS: (this temporarily disables being able to print the whole page)
disableSheet(0,false);
// Get the print style sheet and add a new rule for this div
var sheetObj=document.styleSheets[0];
var showDivCSS="visibility:visible;display:block;position:absolute;top:30px;left:30px;";
if (sheetObj.rules) { sheetObj.addRule("#"+divId,showDivCSS); }
else { sheetObj.insertRule("#"+divId+"{"+showDivCSS+"}",sheetObj.cssRules.length); }
print();
// need a brief delay or the whole page will print
setTimeout("printDivRestore()",100);
}
The final functions deletes the added rule and sets the print style again to disabled so the whole page can be printed.
function printDivRestore()
{
// remove the div-specific rule
var sheetObj=document.styleSheets[0];
if (sheetObj.rules) { sheetObj.removeRule(sheetObj.rules.length-1); }
else { sheetObj.deleteRule(sheetObj.cssRules.length-1); }
// and re-enable whole page printing
disableSheet(0,true);
}
The only other thing to do is to add one line to your onload processing so that the print style is initially disabled thereby allowing whole page printing.
<body onLoad='disableSheet(0,true)'>
Then, from anywhere in your document, you can print a div. Just issue printDiv("thedivid") from a button or whatever.
A big plus for this approach it provides a general solution to printing selected content from within a page. It also allows use of existing styles for elements that are printed - including the containing div.
NOTE: In my implementation, this must be the first style sheet. Change the sheet references (0) to the appropriate sheet number if you need to make it later in the sheet sequence.
With CSS 3 you could use the following:
body *:not(#printarea) {
display: none;
}
Sandro's method works great.
I tweaked it to allow for allowing multiple printMe links, particularily to be used in tabbed pages and expanding text.
function processPrint(printMe){ <-- calling for a variable here
var printReadyElem = document.getElementById(printMe); <-- removed the quotes around printMe to ask for a variable
Print <-- passing the div ID to be printed on to the function to turn the printMe variable into the div ID. single quotes are needed
#Kevin Florida
If you have multiple divs with same class, you can use it like this:
<div style="display:none">
<div id="modal-2" class="printableArea">
<input type="button" class="printdiv-btn" value="print a div!" />
</div>
</div>
i was using Colorbox inner content type
$(document).on('click', '.printdiv-btn', function(e) {
e.preventDefault();
var $this = $(this);
var originalContent = $('body').html();
var printArea = $this.parents('.printableArea').html();
$('body').html(printArea);
window.print();
$('body').html(originalContent);
});
In my case I had to print a image inside a page. When I used the solution voted, I had 1 blank page and the other one showing the image. Hope it will help someone.
Here is the css I used:
#media print {
body * {
visibility: hidden;
}
#not-print * {
display: none;
}
#to-print, #to-print * {
visibility: visible;
}
#to-print {
display: block !important;
position: absolute;
left: 0;
top: 0;
width: auto;
height: 99%;
}
}
My html is:
<div id="not-print" >
<header class="row wrapper page-heading">
</header>
<div class="wrapper wrapper-content">
<%= image_tag #qrcode.image_url, size: "250x250" , alt: "#{#qrcode.name}" %>
</div>
</div>
<div id="to-print" style="display: none;">
<%= image_tag #qrcode.image_url, size: "300x300" , alt: "#{#qrcode.name}" %>
</div>
One more approch without affecting current page and it also persist the css while printing. Here selector must be specific div selector which content we need to print.
printWindow(selector, title) {
var divContents = $(selector).html();
var $cssLink = $('link');
var printWindow = window.open('', '', 'height=' + window.outerHeight * 0.6 + ', width=' + window.outerWidth * 0.6);
printWindow.document.write('<html><head><h2><b><title>' + title + '</title></b></h2>');
for(var i = 0; i<$cssLink.length; i++) {
printWindow.document.write($cssLink[i].outerHTML);
}
printWindow.document.write('</head><body >');
printWindow.document.write(divContents);
printWindow.document.write('</body></html>');
printWindow.document.close();
printWindow.onload = function () {
printWindow.focus();
setTimeout( function () {
printWindow.print();
printWindow.close();
}, 100);
}
}
Here provided some time out show that external css get applied to it.
Best css to fit space empty height:
#media print {
body * {
visibility: hidden;
height:0;
}
#section-to-print, #section-to-print * {
visibility: visible;
height:auto;
}
#section-to-print {
position: absolute;
left: 0;
top: 0;
}
}
All answers have trade-offs and cannot be used for all cases. They fall into 3 categories:
Use a printing style sheet. This requires building the whole website to be print-aware.
Hide all elements in <body> and only show the printable element. This works nicely for simple pages, but it is tricky for complex pages.
Open a new window with the content of the printable element or replace the <body> content with the content of the element. The first will lose all styles, and the second is messy and can break events.
There is no one solution that will work well for all cases, so it is good to have all those choices and I'm adding another solution that works much better in some cases. This solution is a hybrid of two categories: hide all content of <body>, then copy the content of the printable element to a new <div> and append it to <body>. After printing, remove the newly added <div> and show the content of <body> back. This way, you won't lose the styles or events, and you don't mess up with opening a new window. But like all other solutions, it won't work well for all cases. If your printable element's styles depends on its parents, you'll lose those styles. It is still much easier to style your printable elements independently from its parents than having to style the entire website for printing.
The only hurdle is figuring out how to select all content of <body>. For simple pages, the generic style body>* will do the trick. However, complex pages usually have <script> tags at the end of body' and also some `s that are used for dialogs, etc. Hiding all those is fine, but you don't want to show them after printing.
In my case, I build all may websites with three sections inside <body>: <header>, <footer>, and between them <div id="Content">. Adjust the first line of the function below for your case:
function PrintArea(selector) {
//First hide all content in body.
var all = $("body > header, body > #Content, body > footer")
all.hide();
//Append a div for printing.
$("body").append('<div id="PrintMe">');
//Copy content of printing area to the printing div.
var p = $("#PrintMe");
p.html($(selector).html());
//Call the print dialog.
window.print();
//Remove the printing div.
p.remove();
//Show all content in body.
all.show();
}
I used jQuery because it's cleaner and simpler, but you can easily convert it to vanilla JavaScript if you like. And of course, you can change var to let as recommended for the local variables.
It's better solution. You can use it Angualr/React
Html
<div class="row" id="printableId">
Your html
</div>
Javascript
function printPage(){
var printHtml = window.open('', 'PRINT', 'height=400,width=600');
printHtml.document.write('<html><head>');
printHtml.document.write(document.getElementById("printableId").innerHTML);
printHtml.document.write('</body></html>');
printHtml.document.close();
printHtml.focus(); = 10*/
printHtml.print();
printHtml.close();
return true;
}
I picked up the content using JavaScript and created a window that I could print in stead...
The printDiv() function came out a few times, but in that case, you loose all your binding elements and input values. So, my solution is to create a div for everything called "body_allin" and another one outside the first one called "body_print".
Then you call this function:
function printDiv(divName){
var printContents = document.getElementById(divName).innerHTML;
document.getElementById("body_print").innerHTML = printContents;
document.getElementById("body_allin").style.display = "none";
document.getElementById("body_print").style.display = "";
window.print();
document.getElementById("body_print").innerHTML = "";
document.getElementById("body_allin").style.display = "";
document.getElementById("body_print").style.display = "none";
}
You could use a separate CSS style which disables every other content except the one with the id "printarea".
See CSS Design: Going to Print for further explanation and examples.
I tried many of the solutions provided.None of them worked perfectly. They either lose CSS or JavaScript bindings. I found a perfect and easy solution that neither losses CSS nor JavaScript bindings.
HTML:
<div id='printarea'>
<p>This is a sample text for printing purpose.</p>
<input type='button' id='btn' value='Print' onclick='printFunc();'>
</div>
<p>Do not print.</p>
Javascript:
function printFunc() {
var divToPrint = document.getElementById('printarea');
var htmlToPrint = '' +
'<style type="text/css">' +
'table th, table td {' +
'border:1px solid #000;' +
'padding;0.5em;' +
'}' +
'</style>';
htmlToPrint += divToPrint.outerHTML;
newWin = window.open("");
newWin.document.write("<h3 align='center'>Print Page</h3>");
newWin.document.write(htmlToPrint);
newWin.print();
newWin.close();
}
I'm very late to this party, but I'd like to pitch in with yet another approach. I wrote a tiny JavaScript module called PrintElements for dynamically printing parts of a webpage.
It works by iterating through selected node elements, and for each node, it traverses up the DOM tree until the BODY element. At each level, including the initial one (which is the to-be-printed node’s level), it attaches a marker class (pe-preserve-print) to the current node. Then attaches another marker class (pe-no-print) to all siblings of the current node, but only if there is no pe-preserve-print class on them. As a third act, it also attaches another class to preserved ancestor elements pe-preserve-ancestor.
A dead-simple supplementary print-only css will hide and show respective elements. Some benefits of this approach is that all styles are preserved, it does not open a new window, there is no need to move around a lot of DOM elements, and generally it is non-invasive with your original document.
See the demo, or read the related article for further details.
I found the solution.
#media print {
.print-area {
background-color: white;
height: 100%;
width: auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index:1500;
visibility: visible;
}
#page{
size: portrait;
margin: 1cm;
}
/*IF print-area parent element is position:absolute*/
.ui-dialog,
.ui-dialog .ui-dialog-content{
position:unset !important;
visibility: hidden;
}
}
I tried many of the solutions provided.None of them worked perfectly. They either lose CSS or doesn't work in all browsers. I found a perfect and easy solution that neither losses CSS and work perfectly for all browsers.
Html
<div class="row" id="print-div">
Your html
</div>
TYPESCRIPT
let popupWin = window.open('', '_blank', 'width=1080,height=595');
let printContents = document.getElementById("print-div").innerHTML;
let printHead = document.head.innerHTML;
popupWin.document
.write(`<html>
${printHead}
<body onload="window.print();">${printContents}</body></html>`);
popupWin.document.close();
My approach - Simple CSS and JS. Works on React/NextJS too.
const handlePrint = e => {
e.preventDefault();
const bodyElement = document.getElementsByTagName('body')[0];
bodyElement.classList.add('printing');
window.print();
bodyElement.classList.remove('printing');
};
.printing {
visibility:hidden;
}
.printView {
visibility:visible;
}
.printing .printView {
/* You can have any CSS here to make the view better on print */
position:absolute;
top:0;
}
What it does?
Adds .printing class to body element. With CSS we hide all body content with visibility:hidden;
At the same time, we keep CSS ready with .printing .printView to have any kind of view we want for the print area.
Trigger window.print();
Remove .printing class from the body element when the user cancels / prints.
Example:
<button onclick="handlePrint">
Download PDF
</button>
<div>
<h1>Don't print this</h1>
<div class="printView">Print this</div>
</div>
Let me know if this helps anyone :)
Use a special Stylesheet for printing
<link rel="stylesheet" href="print.css" type="text/css" media="print" />
and then add a class i.e. "noprint" to every tag which's content you don't want to print.
In the CSS use
.noprint {
display: none;
}
Pleasantries
I've been playing around with this idea for a couple of days but can't seem to get a good grasp of it. I feel I'm almost there, but could use some help. I'm probably going to slap myself right in the head when I get an answer.
Actual Problem
I have a series of <articles> in my <section>, they are generated with php (and TWIG). The <article> tags have an image and a paragraph within them. On the page, only the image is visible. Once the user clicks on the image, the article expands horizontally and the paragraph is revealed. The article also animates left, thus taking up the entire width of the section and leaving all other articles hidden behind it.
I have accomplished this portion of the effect without problem. The real issue is getting the article back to where it originally was. Within the article is a "Close" <button>. Once the button is clicked, the effect needs to be reversed (ie. The article returns to original size, only showing the image, and returns to its original position.)
Current Theory
I think I need to retrieve the offset().left information from each article per section, and make sure it's associated with its respective article, so that the article knows where to go once the "Close" button is clicked. I'm of course open to different interpretations.
I've been trying to use the $.each, each(), $.map, map() and toArray() functions to know avail.
Actual Code
/*CSS*/
section > article.window {
width:170px;
height:200px;
padding:0;
margin:4px 0 0 4px;
position:relative;
float:left;
overflow:hidden;
}
section > article.window:nth-child(1) {margin-left:0;}
<!--HTML-->
<article class="window">
<img alt="Title-1" />
<p><!-- I'm a paragraph filled with text --></p>
<button class="sClose">Close</button>
</article>
<article class="window">
<!-- Ditto + 2 more -->
</article>
Failed Attempt Example
function winSlide() {
var aO = $(this).parent().offset()
var aOL = aO.left
var dO = $(this).offset()
var dOL = dO.left
var dOT = dO.top
var adTravel = dOL-aOL
$(this).addClass('windowOP');
$(this).children('div').animate({left:-(adTravel-3)+'px', width:'740px'},250)
$(this).children('div').append('<button class="sClose">Close</button>');
$(this).unbind('click', winSlide);
}
$('.window').on('click', winSlide)
$('.window').on('click', 'button.sClose', function() {
var wW = $(this).parents('.window').width()
var aO = $(this).parents('section').offset()
var aOL = aO.left
var pOL = $(this).parents('.window').offset().left
var apTravel = pOL - aOL
$(this).parent('div').animate({left:'+='+apTravel+'px'},250).delay(250, function() {$(this).animate({width:wW+'px'},250); $('.window').removeClass('windowOP');})
$('.window').bind('click', winSlide)
})
Before you go scratching your head, I have to make a note that this attempt involved an extra div within the article. The idea was to have the article's overflow set to visible (.addclass('windowOP')) with the div moving around freely. This method actually did work... almost. The animation would fail after it fired off a second time. Also for some reason when closing the first article, the left margin was property was ignored.
ie.
First time a window is clicked: Performs open animation flawlessly
First time window's close button is clicked: Performs close animation flawlessly, returns original position
Second time SAME window is clicked: Animation fails, but opens to correct size
Second time window's close button is clicked (if visible): Nothing happens
Thank you for your patience. If you need anymore information, just ask.
EDIT
Added a jsfiddle after tinkering with Flambino's code.
http://jsfiddle.net/6RV88/66/
The articles that are not clicked need to remain where they are. Having problems achieving that now.
If you want to go for storing the offsets, you can use jQuery's .data method to store data "on" the elements and retrieve it later:
// Store offset before any animations
// (using .each here, but it could also be done in a click handler,
// before starting the animation)
$(".window").each(function () {
$(this).data("closedOffset", $(this).position());
});
// Retrieve the offsets later
$('.window').on('click', 'button.sClose', function() {
var originalOffset = $(this).data("originalOffset");
// ...
});
Here's a (very) simple jsfiddle example
Update: And here's a more fleshed-out one
Big thanks to Flambino
I was able to create the effect desired. You can see it here: http://jsfiddle.net/gck2Y/ or you can look below to see the code and some explanations.
Rather than having each article's offset be remembered, I used margins on the clicked article's siblings. It's not exactly pretty, but it works exceptionally well.
<!-- HTML -->
<section>
<article>Click!</article>
<article>Me Too</article>
<article>Me Three</article>
<article>I Aswell</article>
</section>
/* CSS */
section {
position: relative;
width: 404px;
border: 1px solid #000;
height: 100px;
overflow:hidden
}
article {
height:100px;
width:100px;
position: relative;
float:left;
background: green;
border-right:1px solid orange;
}
.expanded {z-index:2;}
//Javascript
var element = $("article");
element.on("click", function () {
if( !$(this).hasClass("expanded") ) {
$(this).addClass("expanded");
$(this).data("originalOffset", $(this).offset().left);
element.data("originalSize", {
width: element.width(),
height: element.height()
});
var aOffset = $(this).data("originalOffset");
var aOuterWidth = $(this).outerWidth();
if(!$(this).is('article:first-child')){
$(this).prev().css('margin-right',aOuterWidth)
} else {
$(this).next().css('margin-left',aOuterWidth)
}
$(this).css({'position':'absolute','left':aOffset});
$(this).animate({
left: 0,
width: "100%"
}, 500);
} else {
var offset = $(this).data("originalOffset");
var size = $(this).data("originalSize");
$(this).animate({
left: offset + "px",
width: size.width + "px"
}, 500, function () {
$(this).removeClass("expanded");
$(this).prev().css('margin-right','0')
$(this).next().css('margin-left','0')
element.css({'position':'relative','left':0});
});
}
});
How do I print the indicated div (without manually disabling all other content on the page)?
I want to avoid a new preview dialog, so creating a new window with this content is not useful.
The page contains a couple of tables, one of them contains the div I want to print - the table is styled with visual styles for the web, that should not show in print.
Here is a general solution, using CSS only, which I have verified to work.
#media print {
body * {
visibility: hidden;
}
#section-to-print, #section-to-print * {
visibility: visible;
}
#section-to-print {
position: absolute;
left: 0;
top: 0;
}
}
Alternative approaches aren't so good. Using display is tricky because if any element has display:none then none of its descendants will display either. To use it, you have to change the structure of your page.
Using visibility works better since you can turn on visibility for descendants. The invisible elements still affect the layout though, so I move section-to-print to the top left so it prints properly.
I have a better solution with minimal code.
Place your printable part inside a div with an id like this:
<div id="printableArea">
<h1>Print me</h1>
</div>
<input type="button" onclick="printDiv('printableArea')" value="print a div!" />
Then add an event like an onclick (as shown above), and pass the id of the div like I did above.
Now let's create a really simple javascript:
function printDiv(divName) {
var printContents = document.getElementById(divName).innerHTML;
var originalContents = document.body.innerHTML;
document.body.innerHTML = printContents;
window.print();
document.body.innerHTML = originalContents;
}
Notice how simple this is? No popups, no new windows, no crazy styling, no JS libraries like jquery. The problem with really complicated solutions (the answer isn't complicated and not what I'm referring to) is the fact that it will NEVER translate across all browsers, ever! If you want to make the styles different, do as shown in the checked answer by adding the media attribute to a stylesheet link (media="print").
No fluff, lightweight, it just works.
All the answers so far are pretty flawed - they either involve adding class="noprint" to everything or will mess up display within #printable.
I think the best solution would be to create a wrapper around the non-printable stuff:
<head>
<style type="text/css">
#printable { display: none; }
#media print
{
#non-printable { display: none; }
#printable { display: block; }
}
</style>
</head>
<body>
<div id="non-printable">
Your normal page contents
</div>
<div id="printable">
Printer version
</div>
</body>
Of course this is not perfect as it involves moving things around in your HTML a bit...
With jQuery it's as simple as this:
w=window.open();
w.document.write($('.report_left_inner').html());
w.print();
w.close();
Could you use a print stylesheet, and use CSS to arrange the content you wanted printed? Read this article for more pointers.
I didn't really like any of these answers as a whole. If you have a class (say printableArea) and have that as an immediate child of body, then you can do something like this in your print CSS:
body > *:not(.printableArea) {
display: none;
}
//Not needed if already showing
body > .printableArea {
display: block;
}
For those looking for printableArea in another place, you would need to make sure the parents of printableArea are shown:
body > *:not(.parentDiv),
.parentDiv > *:not(.printableArea) {
display: none;
}
//Not needed if already showing
body > .printableArea {
display: block;
}
Using the visibility can cause a lot of spacing issues and blank pages. This is because the visibility maintains the elements space, just makes it hidden, where as display removes it and allows other elements to take up its space.
The reason why this solution works is that you are not grabbing all elements, just the immediate children of body and hiding them. The other solutions below with display css, hide all the elements, which effects everything inside of printableArea content.
I wouldn't suggest javascript as you would need to have a print button that the user clicks and the standard browser print buttons wouldn't have the same effect. If you really need to do that, what I would do is store the html of body, remove all unwanted elements, print, then add the html back. As mentioned though, I would avoid this if you can and use a CSS option like above.
NOTE: You can add whatever CSS into the print CSS using inline styles:
<style type="text/css">
#media print {
//styles here
}
</style>
Or like I usually use is a link tag:
<link rel="stylesheet" type="text/css" media="print" href="print.css" />
Give whatever element you want to print the id printMe.
Include this script in your head tag:
<script language="javascript">
var gAutoPrint = true;
function processPrint(){
if (document.getElementById != null){
var html = '<HTML>\n<HEAD>\n';
if (document.getElementsByTagName != null){
var headTags = document.getElementsByTagName("head");
if (headTags.length > 0) html += headTags[0].innerHTML;
}
html += '\n</HE' + 'AD>\n<BODY>\n';
var printReadyElem = document.getElementById("printMe");
if (printReadyElem != null) html += printReadyElem.innerHTML;
else{
alert("Error, no contents.");
return;
}
html += '\n</BO' + 'DY>\n</HT' + 'ML>';
var printWin = window.open("","processPrint");
printWin.document.open();
printWin.document.write(html);
printWin.document.close();
if (gAutoPrint) printWin.print();
} else alert("Browser not supported.");
}
</script>
Call the function
Print
Step 1: Write the following javascript inside your head tag
<script language="javascript">
function PrintMe(DivID) {
var disp_setting="toolbar=yes,location=no,";
disp_setting+="directories=yes,menubar=yes,";
disp_setting+="scrollbars=yes,width=650, height=600, left=100, top=25";
var content_vlue = document.getElementById(DivID).innerHTML;
var docprint=window.open("","",disp_setting);
docprint.document.open();
docprint.document.write('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"');
docprint.document.write('"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">');
docprint.document.write('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">');
docprint.document.write('<head><title>My Title</title>');
docprint.document.write('<style type="text/css">body{ margin:0px;');
docprint.document.write('font-family:verdana,Arial;color:#000;');
docprint.document.write('font-family:Verdana, Geneva, sans-serif; font-size:12px;}');
docprint.document.write('a{color:#000;text-decoration:none;} </style>');
docprint.document.write('</head><body onLoad="self.print()"><center>');
docprint.document.write(content_vlue);
docprint.document.write('</center></body></html>');
docprint.document.close();
docprint.focus();
}
</script>
Step 2: Call the PrintMe('DivID') function by an onclick event.
<input type="button" name="btnprint" value="Print" onclick="PrintMe('divid')"/>
<div id="divid">
here is some text to print inside this div with an id 'divid'
</div>
<script type="text/javascript">
function printDiv(divId) {
var printContents = document.getElementById(divId).innerHTML;
var originalContents = document.body.innerHTML;
document.body.innerHTML = "<html><head><title></title></head><body>" + printContents + "</body>";
window.print();
document.body.innerHTML = originalContents;
}
</script>
The Best way to Print particular Div or any Element
printDiv("myDiv");
function printDiv(id){
var printContents = document.getElementById(id).innerHTML;
var originalContents = document.body.innerHTML;
document.body.innerHTML = printContents;
window.print();
document.body.innerHTML = originalContents;
}
hm ... use the type of a stylsheet for printing ... eg:
<link rel="stylesheet" type="text/css" href="print.css" media="print" />
print.css:
div { display: none; }
#yourdiv { display: block; }
Without CSS clowning, html and pure javascript with iframe does its work best. Then simply click the text, you want to print. Current example for id elements with text content;
html body:
<div id="monitor" onclick="idElementPrint()">text i want to print</div>
pure javascript:
//or: monitor.textContent = "click me to print textual content";
const idElementPrint = () => {
let ifram = document.createElement("iframe");
ifram.style = "display:none";
document.body.appendChild(ifram);
pri = ifram.contentWindow;
pri.document.open();
pri.document.write(monitor.textContent);
pri.document.close();
pri.focus();
pri.print();
}
printDiv(divId): A generalized solution to print any div on any page.
I had a similar issue but I wanted (a) to be able to print the whole page, or (b) print any one of several specific areas. My solution, thanks to much of the above, allows you to specify any div object to be printed.
The key for this solution is to add an appropriate rule to the the print media style sheet so that the requested div (and its contents) will be printed.
First, create the needed print css to suppress everything (but without the specific rule to allow the element you want to print).
<style type="text/css" media="print">
body {visibility:hidden; }
.noprintarea {visibility:hidden; display:none}
.noprintcontent { visibility:hidden; }
.print { visibility:visible; display:block; }
</style>
Note that I have added new class rules:
noprintarea allows you to suppress the printing of elements within your div- both the content and the block.
noprintcontent allows you to suppress the printing of elements within your div- the content is suppressed but and the allocated area is left empty.
print allows you to have items that show up in the printed version but
not on the screen page. These will normally have "display:none" for the screen style.
Then insert three JavaScript functions. The first merely toggles the print media style sheet on and off.
function disableSheet(thisSheet,setDisabled)
{ document.styleSheets[thisSheet].disabled=setDisabled; }
The second does the real work and the third cleans up afterward. The second (printDiv) activates the print media style sheet, then appends a new rule to allow the desired div to print, issues the print, and then adds a delay before the final housekeeping (otherwise the styles can be reset before the print is actually done.)
function printDiv(divId)
{
// Enable the print CSS: (this temporarily disables being able to print the whole page)
disableSheet(0,false);
// Get the print style sheet and add a new rule for this div
var sheetObj=document.styleSheets[0];
var showDivCSS="visibility:visible;display:block;position:absolute;top:30px;left:30px;";
if (sheetObj.rules) { sheetObj.addRule("#"+divId,showDivCSS); }
else { sheetObj.insertRule("#"+divId+"{"+showDivCSS+"}",sheetObj.cssRules.length); }
print();
// need a brief delay or the whole page will print
setTimeout("printDivRestore()",100);
}
The final functions deletes the added rule and sets the print style again to disabled so the whole page can be printed.
function printDivRestore()
{
// remove the div-specific rule
var sheetObj=document.styleSheets[0];
if (sheetObj.rules) { sheetObj.removeRule(sheetObj.rules.length-1); }
else { sheetObj.deleteRule(sheetObj.cssRules.length-1); }
// and re-enable whole page printing
disableSheet(0,true);
}
The only other thing to do is to add one line to your onload processing so that the print style is initially disabled thereby allowing whole page printing.
<body onLoad='disableSheet(0,true)'>
Then, from anywhere in your document, you can print a div. Just issue printDiv("thedivid") from a button or whatever.
A big plus for this approach it provides a general solution to printing selected content from within a page. It also allows use of existing styles for elements that are printed - including the containing div.
NOTE: In my implementation, this must be the first style sheet. Change the sheet references (0) to the appropriate sheet number if you need to make it later in the sheet sequence.
With CSS 3 you could use the following:
body *:not(#printarea) {
display: none;
}
Sandro's method works great.
I tweaked it to allow for allowing multiple printMe links, particularily to be used in tabbed pages and expanding text.
function processPrint(printMe){ <-- calling for a variable here
var printReadyElem = document.getElementById(printMe); <-- removed the quotes around printMe to ask for a variable
Print <-- passing the div ID to be printed on to the function to turn the printMe variable into the div ID. single quotes are needed
#Kevin Florida
If you have multiple divs with same class, you can use it like this:
<div style="display:none">
<div id="modal-2" class="printableArea">
<input type="button" class="printdiv-btn" value="print a div!" />
</div>
</div>
i was using Colorbox inner content type
$(document).on('click', '.printdiv-btn', function(e) {
e.preventDefault();
var $this = $(this);
var originalContent = $('body').html();
var printArea = $this.parents('.printableArea').html();
$('body').html(printArea);
window.print();
$('body').html(originalContent);
});
In my case I had to print a image inside a page. When I used the solution voted, I had 1 blank page and the other one showing the image. Hope it will help someone.
Here is the css I used:
#media print {
body * {
visibility: hidden;
}
#not-print * {
display: none;
}
#to-print, #to-print * {
visibility: visible;
}
#to-print {
display: block !important;
position: absolute;
left: 0;
top: 0;
width: auto;
height: 99%;
}
}
My html is:
<div id="not-print" >
<header class="row wrapper page-heading">
</header>
<div class="wrapper wrapper-content">
<%= image_tag #qrcode.image_url, size: "250x250" , alt: "#{#qrcode.name}" %>
</div>
</div>
<div id="to-print" style="display: none;">
<%= image_tag #qrcode.image_url, size: "300x300" , alt: "#{#qrcode.name}" %>
</div>
One more approch without affecting current page and it also persist the css while printing. Here selector must be specific div selector which content we need to print.
printWindow(selector, title) {
var divContents = $(selector).html();
var $cssLink = $('link');
var printWindow = window.open('', '', 'height=' + window.outerHeight * 0.6 + ', width=' + window.outerWidth * 0.6);
printWindow.document.write('<html><head><h2><b><title>' + title + '</title></b></h2>');
for(var i = 0; i<$cssLink.length; i++) {
printWindow.document.write($cssLink[i].outerHTML);
}
printWindow.document.write('</head><body >');
printWindow.document.write(divContents);
printWindow.document.write('</body></html>');
printWindow.document.close();
printWindow.onload = function () {
printWindow.focus();
setTimeout( function () {
printWindow.print();
printWindow.close();
}, 100);
}
}
Here provided some time out show that external css get applied to it.
Best css to fit space empty height:
#media print {
body * {
visibility: hidden;
height:0;
}
#section-to-print, #section-to-print * {
visibility: visible;
height:auto;
}
#section-to-print {
position: absolute;
left: 0;
top: 0;
}
}
All answers have trade-offs and cannot be used for all cases. They fall into 3 categories:
Use a printing style sheet. This requires building the whole website to be print-aware.
Hide all elements in <body> and only show the printable element. This works nicely for simple pages, but it is tricky for complex pages.
Open a new window with the content of the printable element or replace the <body> content with the content of the element. The first will lose all styles, and the second is messy and can break events.
There is no one solution that will work well for all cases, so it is good to have all those choices and I'm adding another solution that works much better in some cases. This solution is a hybrid of two categories: hide all content of <body>, then copy the content of the printable element to a new <div> and append it to <body>. After printing, remove the newly added <div> and show the content of <body> back. This way, you won't lose the styles or events, and you don't mess up with opening a new window. But like all other solutions, it won't work well for all cases. If your printable element's styles depends on its parents, you'll lose those styles. It is still much easier to style your printable elements independently from its parents than having to style the entire website for printing.
The only hurdle is figuring out how to select all content of <body>. For simple pages, the generic style body>* will do the trick. However, complex pages usually have <script> tags at the end of body' and also some `s that are used for dialogs, etc. Hiding all those is fine, but you don't want to show them after printing.
In my case, I build all may websites with three sections inside <body>: <header>, <footer>, and between them <div id="Content">. Adjust the first line of the function below for your case:
function PrintArea(selector) {
//First hide all content in body.
var all = $("body > header, body > #Content, body > footer")
all.hide();
//Append a div for printing.
$("body").append('<div id="PrintMe">');
//Copy content of printing area to the printing div.
var p = $("#PrintMe");
p.html($(selector).html());
//Call the print dialog.
window.print();
//Remove the printing div.
p.remove();
//Show all content in body.
all.show();
}
I used jQuery because it's cleaner and simpler, but you can easily convert it to vanilla JavaScript if you like. And of course, you can change var to let as recommended for the local variables.
It's better solution. You can use it Angualr/React
Html
<div class="row" id="printableId">
Your html
</div>
Javascript
function printPage(){
var printHtml = window.open('', 'PRINT', 'height=400,width=600');
printHtml.document.write('<html><head>');
printHtml.document.write(document.getElementById("printableId").innerHTML);
printHtml.document.write('</body></html>');
printHtml.document.close();
printHtml.focus(); = 10*/
printHtml.print();
printHtml.close();
return true;
}
I picked up the content using JavaScript and created a window that I could print in stead...
The printDiv() function came out a few times, but in that case, you loose all your binding elements and input values. So, my solution is to create a div for everything called "body_allin" and another one outside the first one called "body_print".
Then you call this function:
function printDiv(divName){
var printContents = document.getElementById(divName).innerHTML;
document.getElementById("body_print").innerHTML = printContents;
document.getElementById("body_allin").style.display = "none";
document.getElementById("body_print").style.display = "";
window.print();
document.getElementById("body_print").innerHTML = "";
document.getElementById("body_allin").style.display = "";
document.getElementById("body_print").style.display = "none";
}
You could use a separate CSS style which disables every other content except the one with the id "printarea".
See CSS Design: Going to Print for further explanation and examples.
I tried many of the solutions provided.None of them worked perfectly. They either lose CSS or JavaScript bindings. I found a perfect and easy solution that neither losses CSS nor JavaScript bindings.
HTML:
<div id='printarea'>
<p>This is a sample text for printing purpose.</p>
<input type='button' id='btn' value='Print' onclick='printFunc();'>
</div>
<p>Do not print.</p>
Javascript:
function printFunc() {
var divToPrint = document.getElementById('printarea');
var htmlToPrint = '' +
'<style type="text/css">' +
'table th, table td {' +
'border:1px solid #000;' +
'padding;0.5em;' +
'}' +
'</style>';
htmlToPrint += divToPrint.outerHTML;
newWin = window.open("");
newWin.document.write("<h3 align='center'>Print Page</h3>");
newWin.document.write(htmlToPrint);
newWin.print();
newWin.close();
}
I'm very late to this party, but I'd like to pitch in with yet another approach. I wrote a tiny JavaScript module called PrintElements for dynamically printing parts of a webpage.
It works by iterating through selected node elements, and for each node, it traverses up the DOM tree until the BODY element. At each level, including the initial one (which is the to-be-printed node’s level), it attaches a marker class (pe-preserve-print) to the current node. Then attaches another marker class (pe-no-print) to all siblings of the current node, but only if there is no pe-preserve-print class on them. As a third act, it also attaches another class to preserved ancestor elements pe-preserve-ancestor.
A dead-simple supplementary print-only css will hide and show respective elements. Some benefits of this approach is that all styles are preserved, it does not open a new window, there is no need to move around a lot of DOM elements, and generally it is non-invasive with your original document.
See the demo, or read the related article for further details.
I found the solution.
#media print {
.print-area {
background-color: white;
height: 100%;
width: auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index:1500;
visibility: visible;
}
#page{
size: portrait;
margin: 1cm;
}
/*IF print-area parent element is position:absolute*/
.ui-dialog,
.ui-dialog .ui-dialog-content{
position:unset !important;
visibility: hidden;
}
}
I tried many of the solutions provided.None of them worked perfectly. They either lose CSS or doesn't work in all browsers. I found a perfect and easy solution that neither losses CSS and work perfectly for all browsers.
Html
<div class="row" id="print-div">
Your html
</div>
TYPESCRIPT
let popupWin = window.open('', '_blank', 'width=1080,height=595');
let printContents = document.getElementById("print-div").innerHTML;
let printHead = document.head.innerHTML;
popupWin.document
.write(`<html>
${printHead}
<body onload="window.print();">${printContents}</body></html>`);
popupWin.document.close();
My approach - Simple CSS and JS. Works on React/NextJS too.
const handlePrint = e => {
e.preventDefault();
const bodyElement = document.getElementsByTagName('body')[0];
bodyElement.classList.add('printing');
window.print();
bodyElement.classList.remove('printing');
};
.printing {
visibility:hidden;
}
.printView {
visibility:visible;
}
.printing .printView {
/* You can have any CSS here to make the view better on print */
position:absolute;
top:0;
}
What it does?
Adds .printing class to body element. With CSS we hide all body content with visibility:hidden;
At the same time, we keep CSS ready with .printing .printView to have any kind of view we want for the print area.
Trigger window.print();
Remove .printing class from the body element when the user cancels / prints.
Example:
<button onclick="handlePrint">
Download PDF
</button>
<div>
<h1>Don't print this</h1>
<div class="printView">Print this</div>
</div>
Let me know if this helps anyone :)
Use a special Stylesheet for printing
<link rel="stylesheet" href="print.css" type="text/css" media="print" />
and then add a class i.e. "noprint" to every tag which's content you don't want to print.
In the CSS use
.noprint {
display: none;
}
I am creating a chat using Ajax requests and I'm trying to get messages div to scroll to the bottom without much luck.
I am wrapping everything in this div:
#scroll {
height:400px;
overflow:scroll;
}
Is there a way to keep it scrolled to the bottom by default using JS?
Is there a way to keep it scrolled to the bottom after an ajax request?
Here's what I use on my site:
var objDiv = document.getElementById("your_div");
objDiv.scrollTop = objDiv.scrollHeight;
This is much easier if you're using jQuery scrollTop:
$("#mydiv").scrollTop($("#mydiv")[0].scrollHeight);
Try the code below:
const scrollToBottom = (id) => {
const element = document.getElementById(id);
element.scrollTop = element.scrollHeight;
}
You can also use Jquery to make the scroll smooth:
const scrollSmoothlyToBottom = (id) => {
const element = $(`#${id}`);
element.animate({
scrollTop: element.prop("scrollHeight")
}, 500);
}
Here is the demo
Here's how it works:
Ref: scrollTop, scrollHeight, clientHeight
using jQuery animate:
$('#DebugContainer').stop().animate({
scrollTop: $('#DebugContainer')[0].scrollHeight
}, 800);
Newer method that works on all current browsers:
this.scrollIntoView(false);
var mydiv = $("#scroll");
mydiv.scrollTop(mydiv.prop("scrollHeight"));
Works from jQuery 1.6
https://api.jquery.com/scrollTop/
http://api.jquery.com/prop/
alternative solution
function scrollToBottom(element) {
element.scroll({ top: element.scrollHeight, behavior: 'smooth' });
}
smooth scroll with Javascript:
document.getElementById('messages').scrollIntoView({ behavior: 'smooth', block: 'end' });
If you don't want to rely on scrollHeight, the following code helps:
$('#scroll').scrollTop(1000000);
Java Script:
document.getElementById('messages').scrollIntoView(false);
Scrolls to the last line of the content present.
My Scenario: I had an list of string, in which I had to append a string given by a user and scroll to the end of the list automatically. I had fixed height of the display of the list, after which it should overflow.
I tried #Jeremy Ruten's answer, it worked, but it was scrolling to the (n-1)th element. If anybody is facing this type of issue, you can use setTimeOut() method workaround. You need to modify the code to below:
setTimeout(() => {
var objDiv = document.getElementById('div_id');
objDiv.scrollTop = objDiv.scrollHeight
}, 0)
Here is the StcakBlitz link I have created which shows the problem and its solution : https://stackblitz.com/edit/angular-ivy-x9esw8
If your project targets modern browsers, you can now use CSS Scroll Snap to control the scrolling behavior, such as keeping any dynamically generated element at the bottom.
.wrapper > div {
background-color: white;
border-radius: 5px;
padding: 5px 10px;
text-align: center;
font-family: system-ui, sans-serif;
}
.wrapper {
display: flex;
padding: 5px;
background-color: #ccc;
border-radius: 5px;
flex-direction: column;
gap: 5px;
margin: 10px;
max-height: 150px;
/* Control snap from here */
overflow-y: auto;
overscroll-behavior-y: contain;
scroll-snap-type: y mandatory;
}
.wrapper > div:last-child {
scroll-snap-align: start;
}
<div class="wrapper">
<div>01</div>
<div>02</div>
<div>03</div>
<div>04</div>
<div>05</div>
<div>06</div>
<div>07</div>
<div>08</div>
<div>09</div>
<div>10</div>
</div>
You can use the HTML DOM scrollIntoView Method like this:
var element = document.getElementById("scroll");
element.scrollIntoView();
Javascript or jquery:
var scroll = document.getElementById('messages');
scroll.scrollTop = scroll.scrollHeight;
scroll.animate({scrollTop: scroll.scrollHeight});
Css:
.messages
{
height: 100%;
overflow: auto;
}
Using jQuery, scrollTop is used to set the vertical position of scollbar for any given element. there is also a nice jquery scrollTo plugin used to scroll with animation and different options (demos)
var myDiv = $("#div_id").get(0);
myDiv.scrollTop = myDiv.scrollHeight;
if you want to use jQuery's animate method to add animation while scrolling down, check the following snippet:
var myDiv = $("#div_id").get(0);
myDiv.animate({
scrollTop: myDiv.scrollHeight
}, 500);
I have encountered the same problem, but with an additional constraint: I had no control over the code that appended new elements to the scroll container. None of the examples I found here allowed me to do just that. Here is the solution I ended up with .
It uses Mutation Observers (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) which makes it usable only on modern browsers (though polyfills exist)
So basically the code does just that :
var scrollContainer = document.getElementById("myId");
// Define the Mutation Observer
var observer = new MutationObserver(function(mutations) {
// Compute sum of the heights of added Nodes
var newNodesHeight = mutations.reduce(function(sum, mutation) {
return sum + [].slice.call(mutation.addedNodes)
.map(function (node) { return node.scrollHeight || 0; })
.reduce(function(sum, height) {return sum + height});
}, 0);
// Scroll to bottom if it was already scrolled to bottom
if (scrollContainer.clientHeight + scrollContainer.scrollTop + newNodesHeight + 10 >= scrollContainer.scrollHeight) {
scrollContainer.scrollTop = scrollContainer.scrollHeight;
}
});
// Observe the DOM Element
observer.observe(scrollContainer, {childList: true});
I made a fiddle to demonstrate the concept :
https://jsfiddle.net/j17r4bnk/
Found this really helpful, thank you.
For the Angular 1.X folks out there:
angular.module('myApp').controller('myController', ['$scope', '$document',
function($scope, $document) {
var overflowScrollElement = $document[0].getElementById('your_overflow_scroll_div');
overflowScrollElement[0].scrollTop = overflowScrollElement[0].scrollHeight;
}
]);
Just because the wrapping in jQuery elements versus HTML DOM elements gets a little confusing with angular.
Also for a chat application, I found making this assignment after your chats were loaded to be useful, you also might need to slap on short timeout as well.
Like you, I'm building a chat app and want the most recent message to scroll into view. This ultimately worked well for me:
//get the div that contains all the messages
let div = document.getElementById('message-container');
//make the last element (a message) to scroll into view, smoothly!
div.lastElementChild.scrollIntoView({ behavior: 'smooth' });
small addendum: scrolls only, if last line is already visible. if scrolled a tiny bit, leaves the content where it is (attention: not tested with different font sizes. this may need some adjustments inside ">= comparison"):
var objDiv = document.getElementById(id);
var doScroll=objDiv.scrollTop>=(objDiv.scrollHeight-objDiv.clientHeight);
// add new content to div
$('#' + id ).append("new line at end<br>"); // this is jquery!
// doScroll is true, if we the bottom line is already visible
if( doScroll) objDiv.scrollTop = objDiv.scrollHeight;
Just as a bonus snippet. I'm using angular and was trying to scroll a message thread to the bottom when a user selected different conversations with users. In order to make sure that the scroll works after the new data had been loaded into the div with the ng-repeat for messages, just wrap the scroll snippet in a timeout.
$timeout(function(){
var messageThread = document.getElementById('message-thread-div-id');
messageThread.scrollTop = messageThread.scrollHeight;
},0)
That will make sure that the scroll event is fired after the data has been inserted into the DOM.
This will let you scroll all the way down regards the document height
$('html, body').animate({scrollTop:$(document).height()}, 1000);
You can also, using jQuery, attach an animation to html,body of the document via:
$("html,body").animate({scrollTop:$("#div-id")[0].offsetTop}, 1000);
which will result in a smooth scroll to the top of the div with id "div-id".
Scroll to the last element inside the div:
myDiv.scrollTop = myDiv.lastChild.offsetTop
You can use the Element.scrollTo() method.
It can be animated using the built-in browser/OS animation, so it's super smooth.
function scrollToBottom() {
const scrollContainer = document.getElementById('container');
scrollContainer.scrollTo({
top: scrollContainer.scrollHeight,
left: 0,
behavior: 'smooth'
});
}
// initialize dummy content
const scrollContainer = document.getElementById('container');
const numCards = 100;
let contentInnerHtml = '';
for (let i=0; i<numCards; i++) {
contentInnerHtml += `<div class="card mb-2"><div class="card-body">Card ${i + 1}</div></div>`;
}
scrollContainer.innerHTML = contentInnerHtml;
.overflow-y-scroll {
overflow-y: scroll;
}
<link href="https://cdn.jsdelivr.net/npm/bootstrap#4.5.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
<div class="d-flex flex-column vh-100">
<div id="container" class="overflow-y-scroll flex-grow-1"></div>
<div>
<button class="btn btn-primary" onclick="scrollToBottom()">Scroll to bottom</button>
</div>
</div>
Css only:
.scroll-container {
overflow-anchor: none;
}
Makes it so the scroll bar doesn't stay anchored to the top when a child element is added. For example, when new message is added at the bottom of chat, scroll chat to new message.
Why not use simple CSS to do this?
The trick is to use display: flex; and flex-direction: column-reverse;
Here is a working example. https://codepen.io/jimbol/pen/YVJzBg
A very simple method to this is to set the scroll to to the height of the div.
var myDiv = document.getElementById("myDiv");
window.scrollTo(0, myDiv.innerHeight);
On my Angular 6 application I just did this:
postMessage() {
// post functions here
let history = document.getElementById('history')
let interval
interval = setInterval(function() {
history.scrollTop = history.scrollHeight
clearInterval(interval)
}, 1)
}
The clearInterval(interval) function will stop the timer to allow manual scroll top / bottom.
I know this is an old question, but none of these solutions worked out for me. I ended up using offset().top to get the desired results. Here's what I used to gently scroll the screen down to the last message in my chat application:
$("#html, body").stop().animate({
scrollTop: $("#last-message").offset().top
}, 2000);
I hope this helps someone else.
I use the difference between the Y coordinate of the first item div and the Y coordinate of the selected item div. Here is the JavaScript/JQuery code and the html:
function scrollTo(event){
// In my proof of concept, I had a few <button>s with value
// attributes containing strings with id selector expressions
// like "#item1".
let selectItem = $($(event.target).attr('value'));
let selectedDivTop = selectItem.offset().top;
let scrollingDiv = selectItem.parent();
let firstItem = scrollingDiv.children('div').first();
let firstItemTop = firstItem.offset().top;
let newScrollValue = selectedDivTop - firstItemTop;
scrollingDiv.scrollTop(newScrollValue);
}
<div id="scrolling" style="height: 2rem; overflow-y: scroll">
<div id="item1">One</div>
<div id="item2">Two</div>
<div id="item3">Three</div>
<div id="item4">Four</div>
<div id="item5">Five</div>
</div>