Determine maximum width a DOM element might grow to be? - javascript

I'm interested in querying the maximum size that a DOM element in a browser might grow to be. It is well known that an empty DOM element (without styling) has .clientWidth of 0, but adding text/images/etc. to the element might cause its width to grow. Take for instance the DOM element thisOne in the structure below:
<table style="padding: 20px; border-spacing: 100px">
<tr>
<td></td>
<td>
<div id="thisOne"></div>
</td>
</tr>
</table>
Currently #thisOne.clientWidth === 0 but if I append a large amount of text to it, its width will grow and grow, but not until it reaches document.body.clientWidth because of the columns, padding classes, etc. I am wondering how I can figure out the current maximum width of the object without doing something like:
const thisOne = document.getElementById('thisOne');
thisOne.style.visibility = 'hidden'; // do not display to user.
thisOne.innerHTML = 'blah '.repeat(2000);
const maxWidth = thisOne.clientWidth;
thisOne.innerHTML = '';
thisOne.style.visibility = 'visible';
JQuery based answers are fine, though knowing a pure HTML/JS version would be better.
(In case anyone's wondering, I'm planning on placing an SVG of music notation into the div, but I want it to have nice wrapping onto additional lines by giving the renderer a width to fit before adding it)

What you can do is to set the width of the table to 100% (so it takes all the available space of the container). Set the desired width of the other columns (<td>), either fixed or %. And set the width of the column containing #thisOne to 100%, it will span to the remaining space available (<div> is a block, so it will use the whole width by default).
<table style="padding: 20px; border-spacing: 100px; width: 100%">
<tr>
<td style="width: 100px"></td>
<td style="width: 100%">
<div id="thisOne"></div>
</td>
</tr>
</table>
Now, #thisOne will take all the available space and you can get it's width with #thisOne.clientWidth.
If you don't want #thisOne to take the whole width by default (i.e., when it's empty), you can simply not set his container td width to 100% and do it by code before you get the #thisOne.clientWidth (but you will have to get the clientWidth in a setTimeout because the browser needs to compute the layout before the clientWidth is changed).
As 小聪聪到此一游 pointed out, you can also use display: flex and flex-grow to achieve the same goal.
<div style="display: flex">
<div style="flex-grow: 0"></div>
<div style="flex-grow: 1" id="thisOne"></div>
</div>

Seems like the easiest way would be to get the width of the parent e.g.
element.parentNode().clientWidth
a div will grow only to it's parent element. unless, of course, white-space: nowrap is specified.
EDIT: this doesn't work

Related

CSS calc() using width and position of element

I have a table, where I would like to move element div (last div) to the right.
<thead>
<tr>
<th>...</th>
<th>...</th>
<th>...</th>
...
<th>
<div>
<span></span>
<span>
<div>Move me!</div>
</span>
</div>
</th>
<tr>
<thead>
The div has following CSS and it's important, that I can't change postion to relative
{
position: absolute;
top: 0;
width: max-content;
}
I would like to add property left like this:
left: calc(100% -(position+width)),
where postion is currently x-coord of div and width is the width of the div.
How could I access this values?
PS. Currently my div is placed in such way, that it crosses the border of main div and it leads to appearing of scrollbar. I would like to avoid this by moving div to left with negative value (for example if I assign
left: -20px;
it is moving to the right and I achieve whta I want, but I can't assign it to certain value, because the width of div always changes, ,so it should be dynamically calculated)
What could be possible soultion with Javascript? How could I extract the postion? Right now offsetLeft is 0...
What about right: 0; It should stay in your main div while positioning itself on the right side of it (0 pixels from the right side).
Can you post a codepen with an example so we might help you better :)

How to check if 2 elements displayed on the same row?

Assuming I have 2 elements on a responsive design like this:
<div id="container">
<div class="first"></div>
<div class="second"></div>
</div>
both of them with style contains:
width: auto;
display: inline-block;
float: left;
And because I'm expecting different screen sizes to view page, so, according to screen size, sometimes they will be rendered/displayed on the same row, and sometimes they will not!, the second DIV will be moved to a separate row.
So, I'm wondering, how can I check if they are on the same line with JavaScript?
Thank you
"on the same line" would require inline elements or floating block elements of the exact same height. DIVs are block elements by default. So either use <span> tags instead of <div>, or add display: inline-block;to the CSS rule of those DIVs
ADDITION after EDIT OF QUESTION:
width: auto for a <div> means 100% of the parent element (in this case full width). As I wrote: If you have blocks, use display: inline-block; in their CSS. If you want them to have the same height, put them into a common container DIV (which you already have) and apply the following CSS:
#container {
display: table;
}
.first, .second {
display: table-cell;
width: 50%;
}
Aha (edited question), Javascript: Well, read out the DIV widths, add them and compare the result to the (read-out) container width.
You can use the element bounding boxes and check for overlap:
var rect1 = $('.first')[0].getBoundingClientRect();
var rect2 = $('.second')[0].getBoundingClientRect();
var overlaps = rect1.top <= rect2.bottom && rect2.top <= rect1.bottom;
This checks for any overlap which will probably be sufficient for your use. I used jQuery to get the elements but you can use pure js in the same way, it would just be a bit more verbose.
There is no concept of line on a page. You can check the x and y position of any element in the window and then decide if that meets whatever criteria you have for "on the same line".
By default, a div is the full width of a window so the two divs inside your container in this HTML:
<div id="container">
<div class="first"></div>
<div class="second"></div>
</div>
will be one above the other unless there is some other CSS you have not disclosed that controls the layout to allow them to be in the same row. If they are indeed width: auto and don't have any other layout rules affecting this, then they will each be full width and thus first will be above second in the layout stream. They would never be "on the same line" by any typical definition of that phrase.
Feel free to try it out here: https://jsfiddle.net/jfriend00/y0k7hLr8/ by resizing the right pane to any width you want. In all cases, the first will stay on top of the second.
If, on the other hand, you allow the div elements to have a different type of layout such as let them be display: inline-block and define a width for them, then the layout engine will fit as many on a given row as possible like here: https://jsfiddle.net/jfriend00/229rs97p/
Something tells me display: flex might help you in this. Read https://css-tricks.com/snippets/css/a-guide-to-flexbox/ for more info.

Height of the table to be constant

I'm trying to make a table let's say 400px height, and I want this value to never change when I modify the height of table rows with `Javascript? Is there any property that allows height of rows never to be bigger than a certain value?
I am not sure what exactly you are looking for. From your question I can guess that your table should not exceed more than 400px height even your total rows contains height more than 400px.
As per my understanding I would suggest you to put your table into div (having height of 400px and and overflow auto) as mentioned in below example :
<div style="max-height:400px;overflow:auto">
<table>
<tr style="height:500px">
<td>
Spider Code
</td>
</tr>
</table>
</div>
[Note: You can remove height from tr. I have put it just to indicate overflow.]
As per the above solution, if height exceeds 400px then scrollbar will be displayed.
And if you want your row height never exceed more than some pixels then set the max-height to row as mentioned below.
tr
{
max-height:20px;
overflow:hidden;
}
What ever you set in tr's height in javascript it is meaning less if it exist the max-height. so give max-height property to your tr which will restrict you tr to grow more than max-height.
use css max-height property for the table
tr{
max-height: 20px;
overflow:hidden;
}
table{
max-height:400px;
overflow:hidden;
}

Wrapping multiple superimposed divs

TLDR: How do get a container to wrap multiple superimposed fluid-height divs?
I have a div with some objects:
<div class="container">
<div class="a" style="height: 300px;">Tab page a</div>
<div class="b" style="height: 100px; display: none;">Tab page b</div>
<div class="c" style="height: 200px; display: none;">Tab page c</div>
...
</div>
Based on a user action, I want to fade b in as a fades out (i.e. crossfade them). This requires them both being aligned to the top-left corner of container. Normally, I'd just use position: absolute; with the defaults top: 0; and left: 0; to superimpose them. The problem with this is that then the container collapses to 0px tall (rather than the height of its contents, which I want), as a and b have been removed from the flow.
Ok, so I can't user absolute positioning on a and b. How else can I get them to overlap? A negative margin-top also won't work since I don't know the heights of the children (they can change dynamically based on their content), and there could be any number of them.
Is this even possible without JS? If it isn't, what's the least hacky way that doesn't assume A) a small number of children in container or B) the children are a fixed size (known ahead of time or otherwise).
If you know the dimensions of your cross-fading elements, your best bet is to set the height and width of your container element, either through CSS if you only need one width/height, or through javascript if you'd like the container to adapt to new dimensions on cross-fade.
The Javascript method I described can be seen in action here: http://jsfiddle.net/mkd9s/2/
The important part is:
// Get Heights
var aHeight = $('.a').height(),
bHeight = $('.b').height();
// Set Height on Load
$('.container').height( aHeight );
// Fade on Click
$('.fade').on('click', function(event) {
event.preventDefault();
$('.a').fadeOut("slow");
$('.b').fadeIn("slow");
$('.container').animate({ height: bHeight });
});
Which first sets the height of the container, then animates the height of the container to be the height of the second element when a button is clicked.
Note that this will rapidly become unwieldy if you've got more than 2 elements in the container.

How to tell how many pixels an element is cut off by with overflow: hidden on parent

<div class="parent" style="width: 50px; overflow: hidden;">
<div class="child" style="white-space: nowrap;">Some string of text wider than 50 pixels</div>
</div>
Both .parent, and .child report width of 50px, but .child should be extending beyond 50 pixels. Is there a way to determine by how much a child element overflows its parent?
e.g. something like if .child were position: absolute, how wide would it be, without actually making it position: absolute?
You want to know scrollwidth. E.g., http://jsfiddle.net/y8uZe/1
document.getElementById("child").scrollWidth;
​
Edit: Definitely looks like some sort of bug in Firefox having to do with the white-space:nowrap.
Take a look at this fiddle:
http://jsfiddle.net/y8uZe/2
You can clearly see here how scrollHeight is giving you the right value, and scrollWidth is actually giving the right value as well because the text is wrapping. But when you tell the div NOT to wrap that text, weird things happen.
In any case. SOME of the browsers have a bug. Either it's Safari/IE/Chrome or Opera/Firefox. And since Opera ALWAYS has bugs, I'm going to bet on it being wrong. :)
Also, as I read the definition from http://www.quirksmode.org/dom/w3c_cssom.html, scrollWidth is definitely the right property to use: "The width and height of the entire content field, including those parts that are currently hidden."
One last edit: If you change the inner div to display: table. It fixes the issue. You may or may not be able to do that depending on your CSS, but at least it's good to know. Example: http://jsfiddle.net/y8uZe/3/

Categories