Get the minimum innerWidth of a floated element sibling - javascript

Trying to solve one really tricky problem here. Hope you guys can help.
The situation is as follows: we have a floated picture, and an adjacent P element, that obviously aligns itself to the left. The problem is, that from a position point of view, the element still takes the full width. Which makes sense for the part that comes after the image, but not so much for the text "But I must explain..." which is on top.
Here is an image that illustrates the problem:
http://postimg.org/image/65r9v8qyz/
Now trick question: is there any way to get the innerWidth of the beginning of the element? boundingClientRect and getComputedStyle didn't work for me.
Any suggestions?

If the element is being floated, it's going to display over or under another element. You're not going to be able to get the innerWidth directly.
What you can do is take the innerWidth of the P(paragraph), then minus the innerWidth of the image from that(as well as any padding/margins/borders/other that might add to the image element's width). This should give you something reasonably accurate though tricky to manage and deal with.
Code example:
window.addEventListener('load', function() {
var imageElement = document.getElementById('IMAGE_ID_HERE');
var paragraphElement = document.getElementById('P_ID_HERE');
var topWidth = paragraphElement.innerWidth - (imageElement.innerWidth /* Add any padding, etc. to this */);
});

Related

Get scroll position of HTML element relative to visible portion of container

Right now I have a web page with:
A fixed header at the top of varying size, covering up the page's main content.
A page with a deeply nested scroll container.
Within that container, several other deeply nested elements.
What I want to do is scroll that container so that one of the elements inside lines up with the top of the visible portion of the container. I believe what I am looking for is the top of the nested element relative to the top of the visible portion of the container.
Unfortunately I cannot use .offsetTop because that only references an element's immediate parent, and due to the structure of the page these elements are too deeply nested for that to be of any use. It's always a fixed number. Same with the scroll container; its immediate parent is not the window. Frustratingly, the header is not of a fixed height, so I can't hardcode it into my calculations very easily. I also cannot use jQuery.
I tried using getBoundingClientRect for both the element and the container, but they are always a fixed distance away from each other and it doesn't give me the information I need about how far the element is scrolled relative to the container's visible area, unfortunately.
EDIT: We have a scrolling solution in place already, but we were hoping to improve it through a certain proposed means that I am trying to determine the feasibility of. I would like to ask that everyone please try to only answer the question in bold, rather than proposing alternate solutions. I really do appreciate any help on offer, but I am hoping to get some extremely specific information based on an extremely specific scenario.
I also had this kind of issue earlier, you can try this to auto scroll to the element
var elem = <some select operation that returns the element>;
elem.id = <some temp id> //if no id is there
var a = document.createElement('a');
a.href = "#" + elem.id;
a.click();
If you wish, you can remove the id from your element once its done.

jQuery offset, position element under another, where the right borders touch of the aligned elements

Ok, the subject is not super specific to the overall need I am looking to address. So I have this function that is called on a given element, which is a hidden submenu next to a triggering element. The way the page renders, and to keep the styling optimized I can't just style the position in via css. So I need javascript/jquerys help.
With that I have come up with a function that I can reuse as needed, and works fine all around. However my key problem is, that I have a couple cases where the submenu will overlap the edge of the <section> element it resides in. Which that elements overflow is set to hidden, that and its also about 30 pixels from the bottom of the page anyway. All in all the submenu element gets hidden a bit by either falling completely out of the pages view half way through the element, or it gets hidden by the section tags overflow state.
With that. In a case where this happens I am wanting to instead of have the element align to the bottom of the trigger element, have it align to the top instead so that way the menu in that case is above the trigger element and not below.
Problem is Im not sure how to compensate for that.
Here is the function I came up with to do what I need, now I just need some help in a sense catching when the menu element falls off the page so to speak, so I can adjust for it when it does.
function openSubOrgMenu(triggerID, elem)
{
orgSubOpenID = triggerID;
orgSubShowing = true;
elemOffset = elem.offset(); //trigger element
elemWidth = elem.width();
elemHeight = elem.height();
elemWrap = elem.siblings('.org_group_wrapper');//menu element
elemWrapWidth = elemWrap.width();
elemWrapHeight = elemWrap.height();
moveTop = elemHeight + elemOffset.top + 4;
moveLeft = elemOffset.left - (elemWrapWidth-elemWidth-15);
elemWrap.show().offset({top:moveTop, left:moveLeft});
}
Well here is a JS Fiddle, not necessarily showing a working logic of what I want, but demonstrating the desired effect when its an element that at the bottom of the page/section:
http://jsfiddle.net/4zwEr/

How to keep an absolutely positioned element directly over the position of inline one?

This is a follow up question to How can I stop an IFrame reloading when I change it's position in the DOM? if you want the background.
I have an inline div <div id="leaderboard-slot"></div> (with a fixed width and height) and another div ("leaderboard-loader") further down the page with the actual content for that div.
For various reasons (see previous thread), I am unable to simply do an appendChild or similar.
Instead, I'm hoping to position leaderboard-loader such that it takes up the space "reserved" by leaderboard slot. I've used some jQuery methods to do this:
var loader = $('leaderboard-loader');
var dest = $('leaderboard-slot');
var pos = dest.getPosition();
loader.setStyle('top', pos.y + 'px');
loader.setStyle('left', pos.x + 'px');
which I fire on document load and resize. However, if other elements within the page cause a reflow, then the target div moves, but the loader doesn't.
Is there a safe way of doing this - it needs to work when I know nothing else about the page (ie I can't just make this call on any other methods that might cause a reflow, because I don't know what those are).
Any help would be much appreciated - thank you :)
If I understand your question correctly, there is no need for Javascript. Just put leaderboard-loader in front of the leaderboard-slot tag, give it position: absolute and identical width and height. If slot is a normal element, loader will float above it and cover it perfectly.
<div id="leaderboard-loader"></div><div id="leaderboard-slot"></div>
I'm starting to regret my answer now. Hopefully you can find something better than the absolute positioning workaround. But, in the spirit of kludgey solutions, you could call the repositioning script on a timer. sigh.
You could put them both in the same relative positioned, 0 margin div, with the temporary div z-indexed on top of the slow loader.
Make them both absoluely positioned in the parent, not the window, at 0:0 and the same size.
You can use opacity and fade one in as you fade the other one out, or just swap visibility:hidden and visible for the two elements when you are ready..

Javascript clientHeight and alternatives

I am currently trying to modify a Javascript function that "slides in" a <div>. The script as it is requires you to define the height of the div, so it is mostly useless in dynamically filled <div>s. I found some text on the clientHeight property in javascript, but it would appear that it doesn't support <div>s with display set to none (which is the method used to slide the div in). That makes sense, as the height of that div in the client window is nothing.
Basically I was wondering what other methods you all know of, or if there's a way to get around the clientHeight = 0 when display: none.
Thanks!
Oh, and here's the function I'm using:
function getDivHeight(objName) {
return boxHeight = document.getElementById(objName).clientHeight;
}
A simple solution is to set it's visibility to "hidden" and it's display to "block" and measure it. However, some modern browsers will manage to update the page layout during this short time and you will get a nasty flicker. The easiest way to overcome this is to place the element in an absolutely positioned container with overflow set to "hidden".
I've had luck cloning the element, moving it offscreen, then displaying it to get the client height:
var original = document.getElementById(some_id);
var new_item = original.cloneNode(true);
document.body.appendChild(new_item); // item already hidden, so it won't show yet.
// you may wish to validate it is hidden first
new_item.style.position = "absolute";
new_item.style.left = "-1000px";
new_item.style.display = "block";
var height = new_item.clientHeight;
EDIT: Looking through the jQuery code, they do exactly what Tsvetomir Tsonev suggests. jQuery temporarily sets the style to "display: block; position: absolute; visibility: none", and then measures the height, swapping the properties back after the measurement.
So, it looks like you're stuck with having to do something hackish, whether it's cloning the node or risking having it flicker in some browsers... I like Tsvetomir's suggestion better than my initial hack as it, at least, doesn't involve cloning a node into the DOM that you don't need. Either way, the element must not be set to "display: none" in order to measure it's height. Isn't the DOM wonderful? :-)
EDIT 2: Also worth noting that, after jQuery gathers the height, it adds allowances for padding, margin and border sizes, so you may need to as well.
Yes, an element that is not displayed on the page has no dimensions.
It kind of makes sense. Consider an element that has been created and filled with a bunch of text, but not yet added to the document tree. How high is it? Depends on font-size. How big is font-size? Depends where in the document that div is inserted; its parent font-size would inherit through.
Similarly for an element with “display: none”. It's not rendered, so it has no dimensions. Couldn't we ask “how high would this be if it were ‘display: block’”? Turns out no, because if it were displayed, that in itself could change the dimensions of its parent block, and then the dimension of displayed elements would be inconsistent with the dimensions of non-displayed elements!
The typical solution is to unset “display: none”, measure the height of the element, and then immediately re-set “display: none”. The browser won't redraw in the middle of a bit of JavaScript, so you won't see a flicker on the page.
I nkow you guys solved this a long time ago but I thought I should share this since it quite tricky to get the height of a hidden div tag.
heres what I did after reading your post,
I placed the div i want to slide inside a 1px height div with overflow set to hidden.
you dont even need to set the display of the inner div to none since it is already there and if you use offsetHeight it should return the proper height for all browsers and you can use that height to slide your div up an down.
PEACE!!!
In IE you could try scrollHeight, but I'm not sure if it will work or if it is cross browser.

Scrolling Overflowed DIVs with JavaScript

I've got a div that uses overflow:auto to keep the contents inside the div as it is resized and dragged around the page. I'm using some ajax to retrieve lines of text from the server, then append them to the end of the div, so the content is growing downwards. Every time this happens, I'd like to use JS to scroll the div to the bottom so the most recently added content is visible, similar to the way a chat room or command line console would work.
So far I've been using this snippet to do it (I'm also using jQuery, hence the $() function):
$("#thediv").scrollTop = $("#thediv").scrollHeight;
However it's been giving me inconsistent results. Sometimes it works, sometimes not, and it completely ceases to work if the user ever resizes the div or moves the scroll bar manually.
The target browser is Firefox 3, and it's being deployed in a controlled environment so it doesn't need to work in IE at all.
Any ideas guys? This one's got me stumped. Thanks!
scrollHeight should be the total height of content. scrollTop specifies the pixel offset into that content to be displayed at the top of the element's client area.
So you really want (still using jQuery):
$("#thediv").each( function()
{
// certain browsers have a bug such that scrollHeight is too small
// when content does not fill the client area of the element
var scrollHeight = Math.max(this.scrollHeight, this.clientHeight);
this.scrollTop = scrollHeight - this.clientHeight;
});
...which will set the scroll offset to the last clientHeight worth of content.
scrollIntoView
The scrollIntoView method scrolls the element into view.
Using a loop to iterate over a jQuery of one element is quite inefficient. When selecting an ID, you can just retrieve the first and unique element of the jQuery using get() or the [] notation.
var div = $("#thediv")[0];
// certain browsers have a bug such that scrollHeight is too small
// when content does not fill the client area of the element
var scrollHeight = Math.max(div.scrollHeight, div.clientHeight);
div.scrollTop = scrollHeight - div.clientHeight;
$("#thediv").scrollTop($("#thediv")[0].scrollHeight);
It can be done in plain JS. The trick is to set scrollTop to a value equal or greater than the total height of the element (scrollHeight):
const theDiv = document.querySelector('#thediv');
theDiv.scrollTop = Math.pow(10, 10);
From MDN:
If set to a value greater than the maximum available for the element,
scrollTop settles itself to the maximum value.
While the value of Math.pow(10, 10) did the trick using a too high value like Infintiy or Number.MAX_VALUE will reset scrollTop to 0 (Firefox 66).
I had a div wrapping 3 divs that were floating left, and whose contents were being resized. It helps to turn funky-colored borders/background on for the div-wrapper when you try to resolve this. The problem was that the resized div-content was overflowing outside the div-wrapper (and bled to underneath the area of content below the wrapper).
Resolved by using #Shog9's answer above. As applied to my situation, this was the HTML layout:
<div id="div-wrapper">
<div class="left-div"></div>
<div id="div-content" class="middle-div">
Some short/sweet content that will be elongated by Jquery.
</div>
<div class="right-div"></div>
</div>
This was the my jQuery to resize the div-wrapper:
<script>
$("#div-content").text("a very long string of text that will overflow beyond the width/height of the div-content");
//now I need to resize the div...
var contentHeight = $('#div-content').prop('scrollHeight')
$("#div-wrapper").height(contentHeight);
</script>
To note, $('#div-content').prop('scrollHeight') produces the height that the wrapper needs to resize to. Also I am unaware of any other way to obtain the scrollHeight an actual jQuery function; Neither of $('#div-content').scrollTop() and $('#div-content').height would produce the real content-height values. Hope this helps someone out there!

Categories

Resources