Get height of document content including absolute/fixed positioned elements - javascript

I need to resize an iframe to match its content, but the height properties I have tried don't account for elements with position: fixed.
Assume a document with only two elements with the absolute and fixed classes.
body { padding: 0; margin: 0; }
.absolute {
position: absolute;
height: 100px;
}
.fixed {
position: fixed;
height: 200px;
}
html.scrollHeight 0 (viewport height in Opera/Firefox)
html.offsetHeight 0
body.scrollHeight 0 (viewport height in Chrome)
body.offsetHeight 0
body.outerHeight 0
If I add html { position: relative; }, html.scrollHeight will be 100px in Chrome, but no value will be 200px. At first I also had an issue with floats, but I solved that by adding a clearfix to body.
I made a jsbin here: http://jsbin.com/ehixiq
If it's not possible to get the real height, what would be my best workaround? I only need to support the latest versions of Opera, Chrome and Firefox.

I've found the best way is to use javascript as it can get the height reliably after rendering. In a recent project I did this with jQuery to get full height of the window:
$(document).height()
You could do something like this for element heights:
$('.element2').height($('.element1').height())
Update:
$('iframe').height($('iframe').parent().height())

The only way I could figure out was to get the actual bottom position of all elements:
var els = Array.prototype.slice.call(document.body.getElementsByTagName('*'));
var elHeights = [];
for (var i = 0, l = els.length; i < l; i++) {
elHeights.push(els[i].scrollTop + els[i].offsetHeight);
}
var docHeight = Math.max.apply(Math, elHeights);
Browsers managed between 5-100k operations per second on a DOM with 100 elements, and in my case that's about the size most documents will have.

Related

How to change div height if browser height is less than a given number of pixels?

I have a div that I want to be one of two sizes.
If browser window height is smaller than a given height, then it uses the smaller height for the div
However, if browser window height is larger than given height, then it uses larger height for the div
I tried the following code but it's not working. I need help to get it working.
Here is the jsbin: http://jsbin.com/oFIRawa/1
And here is the code I have so far:
page.html
<div id="theDiv"> </div>
style.css
#theDiv {
background: #000;
border: 2px solid #222;
width: 300px;
height: 400px;
margin: 50px auto 0 auto;
}
script.js
$(document).ready(function () {
// call the method one time
updateWindowSize();
// subscribe the method to future resize events
$(window).resize(updateWindowSize);
// variables
var updateWindowSize = (function(){
var minAllowedWindowHeight = 500;
var largerDivHeight = 400;
var smallerDivHeight = 300;
// actual updateWindowSize function
return function(){
var winHeight = $(window).height();
var newHeight = winHeight < minAllowedWindowHeight ? smallerDivHeight : largerDivHeight;
$('#theDiv').height(newHeight);
};
})();
});
You can do this in CSS my good sir. It's called responsive design!
#media (max-height:500px) {
Enter special css conditions for 500px height.
}
#media (max-height:200px) {
Enter special css conditions for 200px height.
}
This is more commonly used for max-width because it can tell us when someone is using a mobile device (something like 360px max-width), then we can modify our page to look nice on mobile. No fancy javascript needed!
var threshhold;
var smallerHeight = 50;
var largerHeight = 100;
if ($(window).height() < threshold)
$('#theDiv').height(smallerHeight);
else
$('#theDiv').height(largerHeight);
FIDDLE
Demo

scrollHeight not resetting after programmatically changing content

I am trying to learn a few things without jQuery. Here is one of the challenges I'm facing.
I have a fixed contenteditable div that when adding text to the div, if the scrollHeight exceeds the clientHeight I shrink the font until content fits the div.
Occasionally I "rebuild" the text which replaces the innerHTML programmatically. Or the user can delete text which should reduce the scrollHeight, but in both cases, the scrollHeight remains the maximum value. I need some way to increase the font size to "fit" the div again. (that ideally isn't super expensive)
Example:
My clientHeight = 142, and the scrollHeight = 158. A loop reduces the font size, until scrollHeight is 142.
Then, the user deletes a line of text, but the scrollHeight is still 142, no change.
code to reduce/increase height:
var textBox = document.getElementById('text');
var current, min = 6, max = 14;
current = textBox.style.fontSize.substr(0, textBox.style.fontSize.length - 2);
current = parseInt(current);
if (textBox.clientHeight < textBox.scrollHeight) {
while (textBox.clientHeight < textBox.scrollHeight) {
current--;
if (current < min) break;
textBox.style.fontSize = '' + current + 'pt';
}
} else if (textBox.clientHeight > textBox.scrollHeight) {
while (textBox.clientHeight > textBox.scrollHeight) {
current++;
if (current > max) break;
textBox.style.fontSize = '' + current + 'pt';
}
}
html (incase it matters):
<div id="text" contenteditable="true"></div>
css (incase it matters):
#text {
position: relative;
border: 1px solid blue;
top: 180px;
left: 31px;
width: 300px;
height: 132px;
padding: 5px;
font-family: 'mplantin';
font-size: 14pt;
font-weight: 200;
}
I was on the same boat, but with an iframe; I'm not sure if my solution suits your chat window because its for page transitioning, but after some testing this is my hack. "content" is the id of an iframe and this is executed inside a javascript function that is called when the page change is needed:
var c=document.getElementById("content");
c.width=0;
c.height=0;
c.src="page.html";
the `src' assignment method expands the values set to 0 right after, achieving the desired result; there may be a way for you to constantly re-size a text area like that; however, I had visual issues with you; I ended up using timers so that the change would take place while the transition between pages was transparent.
This seemed to fix my issue:
element.style.height = "auto";
both answers from #nixahn and #jeff are working for me (chrome,ff)
iframe.style.height ="0"; // or "auto"
iframe.contentWindow.document.open();
iframe.contentWindow.document.write('<style>'+css+'</style>');
iframe.contentWindow.document.write(html);
iframe.contentWindow.document.close();
I have used a div with a fixed height, and the problem with auto is that it resizes the element, I fixed that with the following code after my inner HTML was set:
element.style.height = "auto";
element.style.height = "400px";
now scrollHeight is resetted correctly and gives the real height of the inner HTML
I had this same issue -- A content editable div whose scrollHeight wouldn't shrink when lines were removed.
The accepted answer didn't fix the problem for me, however, removing the div's parent's display: flex; did.

media queries vs javascript for changing div position based on screen size

I have a large banner that contains a slider on my site, the position is absolute, because the banner is so wide when I look at it on smaller screens , all you can see is the left side of it.
I was originally using media screen only to adjust for mobile and various screen sizes, I would basically apply a different left negative left position for every size but this seems inefficient and also it doesnt seem to work perfeclty as I need to take into account every possible size for it to be neat.
Then I thought about javascript, but unfortunately I dont know much of it at all. Im wondering is there is a simple bit of code that I could apply to a div in js that changes its left position automatically based on screen size.
Or even any suggestions based on media screen only would be great thanks. My big issue with that is not knowing what left position I should apply to what resolution.
If you need more info let me know. Thank you
Adrian
I wrote an article a while ago with some useful snippets, this is one of them:
This utility is a simple approach to set width breakpoints when
working on responsive designs. It's a quick way to relate CSS media
queries in your JavaScript code as you go.
function isBreakPoint(bp) {
// The breakpoints that you set in your css
var bps = [320, 480, 768, 1024];
var w = $(window).width(); // or window.innerWidth with plain JS
var min, max;
for (var i = 0, l = bps.length; i < l; i++) {
if (bps[i] === bp) {
min = bps[i-1] || 0;
max = bps[i];
break;
}
}
return w > min && w <= max;
}
Then in your script:
if ( isBreakPoint(320) ) {
// breakpoint at 320 or less
}
if ( isBreakPoint(480) ) {
// breakpoint between 320 and 480
}
I'm not sure why you need to absolutely position a banner, but assuming you need to, if the banner is an image and resizable you can use method 1.
If it has to be in its original pixel-perfect size, use method 2 to center it in the screen.
method 1
#banner {
/* Your normal banner code */
position: absolute;
/* positioning etc. */
}
#media (max-width: {banner-size}px) {
#banner {
position: absolute;
top: 0;
left: 0;
right: 0;
}
}
method 2
#banner {
position: absolute;
top: 20px; /* anything you want */
left: 50%; /* you can adjust to off-center */
margin-left: -{width/2}px;
}

Dynamical size of textarea

I'm using CodeMirror 2 editor. The trouble is that I can't make it fullsize (100%; 100%). I added to the main style:
.CodeMirror {
height: 100%;
width: 100%;
}
And this doesn't work for me in any browser. Any ways?
I'm using the following code in http://jsbin.com to stretch the CodeMirror frame (note that JS Bin in particular stretches to half screen width, but the example code below does "fullscreen"):
.CodeMirror {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
I don't remember whether CodeMirror adds the class by default, but if it doesn't, you'll also want to add it in the JavaScript (assuming you've not solved this already):
CodeMirror.fromTextArea('ID_OF_TEXTAREA', {
// .. some other options...
iframeClass: 'CodeMirror'
});
You can't do that with CSS, instead you can use JavaScript:
window.onload = function() {
var oTextarea = document.getElementById("myText");
var oParent = oTextarea.parentNode;
oTextarea.style.width = (oParent.scrollWidth - 30) + "px";
oTextarea.style.height = (oParent.scrollHeight - 30) + "px";
};
This will set the size of the textarea based on its parent size.
Added some "padding" but you can remove or reduce it.
html, body, .container, .subContainer, .CodeMirror {
height: 100%;
width: 100%;
}
Should work as well.

How can I access style properties on javascript objects which are using external style sheets?

I have an external style sheet with this in it:
.box {
padding-left:30px;
background-color: #BBFF88;
border-width: 0;
overflow: hidden;
width: 400px;
height: 150px;
}
I then have this:
<div id="0" class="box" style="position: absolute; top: 20px; left: 20px;">
When I then try to access the width of the div:
alert(document.getElementById("0").style.width);
A blank alert box comes up.
How can I access the width property which is defined in my style sheet?
NOTE: The div displays with the correct width.
You should use window.getComputedStyle to get that value. I would recommend against using offsetWidth or clientWidth if you're looking for the CSS value because those return a width which includes padding and other calculations.
Using getComputedStyle, your code would be:
var e = document.getElementById('0');
var w = document.defaultView.getComputedStyle(e,null).getPropertyValue("width");
The documentation for this is given at MDC : window.getComputedStyle
offsetWidth displays the actual width of your div:
alert(document.getElementById("0").offsetWidth);
This width can be different to what you have set in your css, though.
The jQuery way would be (I really don't want to mention them all the time, but that's what all the libraries are there for):
$("#0").width(); // should return 400
$("#0").offsetWidth(); // should return 400 as well
$("#0").css("width"); // returns the string 400px
I hope this is helpful:
function changecss(theClass,element,value) {
//Last Updated on June 23, 2009
//documentation for this script at
//http://www.shawnolson.net/a/503/altering-css-class-attributes-with-javascript.html
var cssRules;
var added = false;
for (var S = 0; S < document.styleSheets.length; S++){
if (document.styleSheets[S]['rules']) {
cssRules = 'rules';
} else if (document.styleSheets[S]['cssRules']) {
cssRules = 'cssRules';
} else {
//no rules found... browser unknown
}
for (var R = 0; R < document.styleSheets[S][cssRules].length; R++) {
if (document.styleSheets[S][cssRules][R].selectorText == theClass) {
if(document.styleSheets[S][cssRules][R].style[element]){
document.styleSheets[S][cssRules][R].style[element] = value;
added=true;
break;
}
}
}
if(!added){
if(document.styleSheets[S].insertRule){
document.styleSheets[S].insertRule(theClass+' { '+element+': '+value+'; }',document.styleSheets[S][cssRules].length);
} else if (document.styleSheets[S].addRule) {
document.styleSheets[S].addRule(theClass,element+': '+value+';');
}
}
}
}
It is taken from here.
The answers are mostly correct, but will do your head in when you try to use them as they depend on the rendering mode of the browser (aka strict/quirks mode, browser vender, etc) - the last answer is the best... use jquery.

Categories

Resources