I would never think this is possible, but there are a lot of clever people here so I thought I'd ask. I'm looking for a way to have a full-height container whose width depends on how much content there is. I want the text to fill the area taking up the full height while using the smallest possible width. The height is known and hard-coded, the amount of content is not.
I'm working with something like this:
<div>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry.
Lorem Ipsum has been the industry's standard dummy text ever since the 1500s,
when an unknown printer took a galley of type and scrambled....</p>
</div>
div {
background:red url(http://lorempixel.com/600/400/);
float:left;
width:600px;
height:400px;
}
p {
background:#fff;
padding:20px;
margin:20px;
}
Normally content fills the page from top to bottom:
What I'm looking for is sort of the opposite, filling in left-to-right:
With less content, it should look like this:
Using full hard-coded height with width:auto produces this effect:
Is there any way to have the text fill the height with the smallest possible width, without hard-coding a width or having text overflow? It seems impossible and I have no idea how to approach it. Javascript/jQuery solutions welcome.
What I have in mind is a simple jQuery solution: in a while loop, set the condition such that the loop is run whenever the height exceeds the container height. In the loop, you increase the width of <p> pixel by pixel until the height no longer exceeds container height :)
$(document).ready(function() {
// The 400-80 is because you have to subtract the container padding and the element's own padding
while($("div > p").height() > 400 - 80) {
currentWidth = $("div > p").width();
$("div > p").width(currentWidth + 1);
}
});
http://jsfiddle.net/teddyrised/RwczR/4/
I have made some changes to your CSS, too:
div {
background:red url(http://lorempixel.com/600/400/);
float:left;
overflow: hidden;
width:600px;
height:400px;
padding: 20px;
box-sizing: border-box;
}
p {
background:#fff;
padding: 20px;
width: 1px;
}
This is not too difficult to do with JavaScript. I have no idea how to do it without JS (if that's even possible).
You can use another "invisible" div to measure dimensions until it gets to the 320px height while reducing its with by a set amount (even 1 pixel at a time, if you want to be as precise as possible).
var $measurer = $("<div>").css({'position': 'fixed', 'top': '100%'})
.text($("p").text()).appendTo('body');
var escape = 0;
while ($measurer.height() < 320) {
console.log($measurer.height());
$measurer.width(function (_, width) { return width - 1; });
console.log($measurer.width());
escape++;
if (escape > 2000) {
break;
}
}
$("p").width($measurer.width());
$measurer.remove();
http://jsfiddle.net/RwczR/2/
Try this:
var p = $('p');
var height = parseInt(p.height())-40;
p.height('auto');
p.width('auto');
for(var i=p.width(); i--; ) {
p.width(i);
if (p.height() > height) {
p.height(height+20);
p.width(i-1);
break;
}
}
p.height(height);
http://jsfiddle.net/RwczR/6/
You can use jQuery/JavaScript and checking the client vs the scroll heights keep increasing the width until it fits the text, similar to the below.
You need to also set overflow: hidden; in the CSS on the p tag for the scrollHeight to give you the actual height including the overflow.
The below code also takes margin and padding into account for both; height and width and adjusts accordingly.
Changing the height of the outer div ajdust accordingly.
$(document).ready(function(){
var $container = $("div");
var containerHeight = $container.height();
var containerWidth = $container.width();
var $textWrapper = $(">p", $container);
var paddingMarginHeight = $textWrapper.outerHeight(true) - $textWrapper.innerHeight();
var paddingMarginWidth = $textWrapper.outerWidth(true) - $textWrapper.innerWidth();
$textWrapper.innerHeight(containerHeight - paddingMarginHeight);
//SetMinWidth();
var maxWidth = containerWidth - paddingMarginWidth;
var visibleHeight = 0;
var actualHeight = 0;
for(i = 50; i <= maxWidth; i++){
$textWrapper.innerWidth(i);
visibleHeight = $textWrapper[0].clientHeight;
actualHeight = $textWrapper[0].scrollHeight;
if(visibleHeight >= actualHeight){
break;
console.log("ouyt");
}
}
});
DEMO - Grow width until text is fully visible
We can give the paragraph an overflow:auto;.
If the paragraph needs a vertical scroll bar, it will create one.
The trick is to keep tightening the width, until the scroll bar is created.
var hasScrollBar = false;
var p = document.getElementById('myParagraph');
while(!hasScrollBar)
{
if(p.scrollHeight>p.clientHeight)
{
//Has Scroll Bar
//Re-Increase Width by 1 Pixel
hasScrollBar=true;
p.style.width=(p.clientWidth+1)+"px";
}
else
{
//Still no Scroll Bar
//Decrease Width
p.style.width=(p.clientWidth-1)+"px";
}
}
Related
I have two side-by-side elements on a page. One elements has a fixed size (100vh) – .hero-half – and the other is fluid with text of varying lengths – .project-details. When the fluid text container extends to be taller than the image container, I want to apply a class to it that restricts the height of one of its child elements to bing the total text container height back to equal with the image height.
HTML:
<div class="project-details left">
<h1 class="project">Title</h1>
<div class="project-summary">
<div class="summary-container">
<p>A bunch of paragraphs here</p>
</div>
<a class="more" href="#">More</a>
<a class="less" href="#">Less</a>
</div>
</div>
<div class="hero hero-half right" style="background-image: url('/img/placeholder-vert1.jpg')"></div>
The relevant CSS:
.hero-half {
width: 50%;
height: 100vh;
}
.project-details {
width: 50%;
height: auto;
}
.project-summary .summary-container {
overflow: hidden;
&.restrict-height {
.summary-container {
// set max height
max-height: calc(100vh - 615px);
}
}
}
Here is my JS code:
$(function () {
var bpTab = 1024;
resize = function() {
var winWidth = $(window).width();
var heroHeight = $(".hero-half").outerHeight();
var boxHeight = $(".project-details").outerHeight();
var $box = $(".project-summary");
if ( boxHeight > heroHeight && winWidth > bpTab) {
// if on desktop layout AND if text is pusing box too big, restrict box height
$box.addClass("restrict-height");
} else {
// if not on desktop or text is not pushing box too big
$box.removeClass("restrict-height");
$box.removeClass("is-expanded");
};
};
// resize on window resize
$(window).bind("resize orientationchange", function(){
resize();
});
// resize on page load
resize();
});
So when the project-details div reaches a height taller than .hero-half, it adds a class that sets a max-height on one of the children, which brings the total height of .project-details back to equal or less than .hero-half.
However when I resize my window to force the the text to push the project-details height too tall and trigger the restrict-height class, it only works when the screen width and height add up to even numbers (either both width and height are even, or both odd). If it's an odd total the outerHeight of project-details seems to calculate incorrectly.
The problem, I think, is that the outerHeight of .project-details is sometimes being calculated at it's natural height before the text height it restricted, and sometimes it's being calculates after that class is applied and after the text height it restricted, which therefor decreases the .project-details height back into an acceptable range.
I've tried adding a timeout delay for the addition of the class hoping that the extra time would mean the outerHeight calculation was always correct, but it didn't make a difference.
How should I alter this JS code to make sure the .project-details outerHeight is always reading the height before the restrict-height class is applied?
And related: why would the odd pixel dimensions have any effect here?
The solution was at add a reset before the if/else loop to standardise the div height be removing the extra classes that may alter its height first.
var $box = $(".project-summary");
// reset
$box.removeClass("restrict-height");
$box.removeClass("is-expanded");
var winWidth = $(window).width();
var heroHeight = $(".hero-half").outerHeight();
var boxHeight = $(".project-details").outerHeight();
If you look at this page I'm developing: http://dev.aaronpitts.ch/test/ you will see three green buttons in rows saying 'Find out more'. I'm trying to get them to always be aligned using the following jQuery:
var maxHeight = 0;
$(".same-height-inner").each(function(){
if ($(this).height() > maxHeight) { maxHeight = $(this).height(); }
});
$(".same-height-inner").height(maxHeight);
The p block in .same-height-inner has a margin-bottom of 20px bottom but this isn't being included in the height of .same-height-inner. Also, if you look at this on a screen size of 1024 x 768 you will see the left hand column's text gets further miscalculation in height as it's not including the orphaned word which is broken to a new line. I've tried using
outerHeight(true)
but it makes no difference. How can I achieve the above?
You can simply add .find('p') to your jQuery code, so it would be:
var maxHeight = 0;
$(".same-height-inner").find('p').each(function(){
if ($(this).height() > maxHeight) { maxHeight = $(this).height(); }
});
$(".same-height-inner").height(maxHeight);
The same way if you'r using outerHeight(true), for example, I'm using this code:
function calculateHeight($el) {
var height = 0;
$el.children().find('a').each(function() {
height = height + $(this).outerHeight(true);
});
$el.data('oHeight', height);
}
Good luck.
This is because the paragraph element is larger than the enclosing div as it's an inline element inside a block element, just include the p in your selector
$(".same-height-inner p").each(function(){
if ($(this).height() > maxHeight) { maxHeight = $(this).height(); }
});
$(".same-height-inner").height(maxHeight);
You could alternatively make the enclosing div inline which will also fix the problem, but may have unintended consequences elsewhere on the site.
.same-height-inner {
display: inline-block;
}
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
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.
I want to put a bar on the bottom of my page containing a varying number of pictures, which (if wider than the page) can be scrolled left and right.
The page width is varying, and I want the pane to be 100% in width.
I was trying to do a trick by letting the middle div overflow and animate it's position with jquery.animate().
Like this:
Here is a fiddle without the js: http://jsfiddle.net/SoonDead/DdPtv/7/
The problems are:
without declaring a large width to the items holder it will not overflow horizontally but vertically. Is this a good hack? (see the width: 9000px in the fiddle)
I only want to scroll the middle pane if it makes sense. For this I need to calculate the width of the overflowing items box (which should be the sum of the items' width inside), and the container of it with the overflow: hidden attribute. (this should be the width of the browser window minus the left and right buttons).
Is there a way to calculate the length of something in js without counting all of it's childrens length manually and sum it up?
Is there a way to get the width of the browser window? Is there a way to get a callback when the window is resized? I need to correct the panes position if the window suddenly widens (and the items are in a position that should not be allowed)
Since the window's width can vary I need to calculate on the fly if I can scroll left or right.
Can you help me with the javascript?
UPDATE: I have a followup question for this one: Scroll a div vertically to a desired position using jQuery Please help me solve that one too.
Use white-space:nowrap on the item container and display:inline or display:inline-block to prevent the items from wrapping and to not need to calculate or set an explicit width.
Edit:: Here's a live working demo: http://jsfiddle.net/vhvzq/2/
HTML
<div class="hscroll">
<ol>
<li>...</li>
<li>...</li>
</ol>
<button class="left"><</button>
<button class="right">></button>
</div>
CSS
.hscroll { white-space:nowrap; position:relative }
.hscroll ol { overflow:hidden; margin:0; padding:0 }
.hscroll li { list-style-type:none; display:inline-block; vertical-align:middle }
.hscroll button { position:absolute; height:100%; top:0; width:2em }
.hscroll .left { left:0 }
.hscroll .right { right:0 }
JavaScript (using jQuery)
$('.hscroll').each(function(){
var $this = $(this);
var scroller = $this.find('ol')[0];
var timer,offset=15;
function scrollLeft(){ scroller.scrollLeft -= offset; }
function scrollRight(){ scroller.scrollLeft += offset; }
function clearTimer(){ clearInterval(timer); }
$this.find('.left').click(scrollLeft).mousedown(function(){
timer = setInterval(scrollLeft,20);
}).mouseup(clearTimer);
$this.find('.right').click(scrollRight).mousedown(function(){
timer = setInterval(scrollRight,20);
}).mouseup(clearTimer);
});
Thanks Phrogz for this part -- give the image container the white-space: nowrap; and display: inline-block;.
You can calculate the width without having to calculate the width of the children every time but you will need to calculate the width of the children once.
//global variables
var currentWidth = 0;
var slideDistance = 0;
var totalSize = 0;
var dispWidth = (winWidth / 2); //this should get you the middle of the page -- see below
var spacing = 6; //padding or margins around the image element
$(Document).Ready(function() {
$("#Gallery li").each(function () {
totalSize = totalSize + parseFloat($(this).children().attr("width"));// my images are wrapped in a list so I parse each li and get it's child
});
totalSpacing = (($("#Gallery li").siblings().length - 1) * spacing); //handles the margins between pictures
currentWidth = (parseFloat($("#Gallery li.pictureSelected").children().attr("width")) + spacing);
maxLeftScroll = (dispWidth - (totalSize + totalSpacing)); //determines how far left you can scroll
});
function NextImage() {
currentWidth = currentWidth + (parseFloat($("#Gallery li.pictureSelected").next().children().attr("width")) + spacing); //gets the current width plus the width of the next image plus spacing.
slideDistance = (dispWidth - currentWidth)
$("#Gallery").animate({ left: slideDistance }, 700);
}
There is a way to get the browser window with in javascript (jQuery example).
and there is a way to catch the resize event.
var winWidth = $(window).width()
if (winWidth == null) {
winWidth = 50;
}
$(window).resize(function () {
var winNewWidth = $(window).width();
if (winWidth != winNewWidth) {
window.clearTimeout(timerID);
timerID = window.setInterval(function () { resizeWindow(false); }, 100);
}
winWidth = winNewWidth;
});
On my gallery there's actually quite a bit more but this should get you pointed in the right direction.
You need to change your #items from
#items
{
float: left;
background: yellow;
width: 9000px;
}
to
#items {
background: yellow;
}
Then calculate the width very easily with jQuery
// #items width is calculated as the number of child .item elements multiplied by their outerWidth (width+padding+border)
$("#items").width(
$(".item").length * $(".item").outerWidth()
);
and simply declare click events for the #left and #right elements
$("#left").click(function() {
$("#middle").animate({
scrollLeft: "-=50px"
}, 'fast');
});
$("#right").click(function() {
$("#middle").animate({
scrollLeft: "+=50px"
}, 'fast');
});
jsFiddle link here
EDIT
I overlooked that detail about the varying image widths. Here is the correct way to calculate the total width
var totalWidth = 0;
$(".item").each(function(index, value) {
totalWidth += $(value).outerWidth();
});
$("#items").width(totalWidth);