How to anchor one div to another and keep them responsive - javascript

I have a UI built in vue.js that I need to add tooltips to. I need the tooltips to be placed to the left or right of a specific div in the UI. I've been able to get my desired look by setting the tooltips to position absolute but this is not responsive so on some screens the tooltip does not align with the target div.
The UI is fairly complex so I'm trying to avoid having to rebuild the layout with flexbox/grid. I'm looking for a way to 'anchor' the tooltip to its corresponding divs using javascript.
https://codepen.io/joeymorello/pen/ZEeWmGd Here I am playing with append to and insertBefore but I would still need to fine-tune each tooltip location using CSS. Is there a way to just anchor one div right next to another div so the tooltip always follows its parent div?
const head = document.querySelector('.head')
const body = document.querySelector('.body')
const toolTipOne = document.querySelector('.tool-tip-1')
const toolTipTwo = document.querySelector('.tool-tip-2')
$(toolTipOne).appendTo(head);
$(toolTipTwo).insertBefore(body);

Apply position: relative to .body and append the tooltip inside it. Then you can easily position it with absolute relative to position of .body using top, left etc:
https://codepen.io/tilwinjoy/pen/QWpNJdY

Why not use pure css for this? You can use position relative on the element, then use its pseudo ::after element and set its position to absolute. Then call on the left, top, right and/or bottom properties to place your pseudo element on the page relative to its parent that has position relative set.
// example of how to change the content of a pseudo tag with JS and CSS variables using the root element
let root = document.documentElement
let headTTInfo = 'Maybe you want to change the Head tooltips content via JS?'
let bodyTTInfo = 'Here is content for your body elements tool tip generated with JS.'
root.style.setProperty('--body', `"${bodyTTInfo}"`)
root.style.setProperty('--head', `"${headTTInfo}"`)
:root {
--head: 'this is content for your head elements tool tip';
--body: 'this is content for your body elements tool tip'
}
/* This min-width on the body will ensure that your absolutely positioned element
is within the body and its display is not completely taken out of the
viewable container,
125px(tooltip offset) + 500px(width of parents) + 125px(tooltip offset) = 750
gives us 10px padding on each side if screen width less than the width of the
parents elements, we do this because postion absolute takes its positioned elements
out of the normal flow of the document. */
body {
min-width: 770px;
}
.head {
margin: 0 auto;
width: 500px;
height: 250px;
background-color: green;
position: relative;
}
.body {
margin: 1rem auto;
width: 500px;
height: 250px;
background-color: pink;
position: relative;
}
.head::after {
content: var(--head);
position: absolute;
left: -125px;
top: 40%;
width: 100px;
height: auto;
padding: 5px;
background-color: teal;
}
.body::after {
content: var(--body);
position: absolute;
left: 515px;
top: 40%;
width: 100px;
height: auto;
padding: 5px;
background-color: orange;
}
<div class="container">
<div class="head">HEAD</div>
<div class="body">body</div>
</div>

Related

Why does position absolute work this way with particles.js in bootstrap?

I'm trying to understand why position absolute works the way it does in this scenario on elements.
I know that an element with position absolute is positioned relative to its first positioned (not static) ancestor element. In this case, it would be the body element.
If that's the case, why doesn't about.js overlap with the navigation element then (its static!)? Why is it overlapping particles.js (which is what I was trying to achieve).
Now if you put the div with id particles.js on top of the div with class about, then about overlaps with the portfolio section. Can someone explain this?
Here is my JS Fiddle:
https://jsfiddle.net/apasric4/ojnx2Lt7/1/
Here is a sample of my CSS:
* {
box-sizing: border-box;
}
img[alt="Profile Picture"] {
width: 40%;
}
/* why do this work idk */
img {
width: 200px;
height: 200px;
}
.about {
position: absolute;
border: 10px pink solid;
z-index: 1;
height: 100vh;
width: 100vw;
}
#particles-js {
background: rgb(29, 114, 243);
height: 100vh;
width: 100vw;
}
Thanks
To prevent the about section from overlapping the particles section, you want to remove the position: absolute rule from .about. This rule is taking .about out of the flow block positioned elements and making it overlap.
Also, the navigation element is not being overlapped by the .about section. The navigation elements color is transparent and making it appear this way. Try adding background-color: white rule to the navigation element.

How i can make div cover the object tag on html for IE11?

How can I make div cover the object tag on HTML for IE11, object tag is activeX for IE.
I want to make div layer cover the object tag.
The trick is to wrap your object tag in a container div. Set the dimensions of the activex component on the container and set the containers position to relative.
Drop another div - as a sibling to your activex component, and set its position to absolute. This will allow it to float/start at the start of the container (just like your activex) by setting its top to 0. Set this div's height and width to 100% to fill the whole container. Since your container has the same dimensions that your activex, this should cover it up.
#container {
position: relative;
height: 200px;
width: 200px;
}
#object {
height: 200px; /* emulate the objectx height */
width: 200px; /* emulate the objectx width */
background-color: yellow;
}
#overlay {
height: 100%;
width: 100%;
background-color: green;
position: absolute;
top: 0;
}
<div id="container">
<div id="object"></div>
<div id="overlay"></div>
</div>
http://plnkr.co/edit/H405MbFN9a1wxzqXkYXz?p=preview
Play around with the Plunker to see what happens and learn how it works.

Three vertically stacked Divs, dynamic height

I want to have three vertically stacked divs.
The first div is at the top, it has a fixed height of 60px.
The middle div may or may not contain content, it will often contain content vertically larger than it, so it is set to overflow: auto. Regardless of if it contains content or not, it must consume the rest of the window's height minus the first div's height and the last div's height.
The last div has a minimum height of 40px. This div accepts user input, and can have a height between and up to 400px. This div expands upwards as the user inputs text, once it has reached the max height, it scrolls.
Here is a diagram:
+-----------+
| Header |
+-----------+
| ^|
| ||
| Scroll ||
| ||
| v|
+-----------+
| ^|
| Footer ||
| v|
+-----------+
I am having trouble getting the second (middle div) to shrink as the third div expands. I would like to accomplish this without js if possible.
CSS Tricks: A guide to Flexbox in combination with max-height.
*See new fiddle below
additional footer CSS:
.footer {
position: absolute;
bottom: 0;
width: 100%;
max-height: 400px;
background: #efefef;
}
Is that what you are going for?
EDIT:
NEW FIDDLE
I've actually implemented something like this before for a chat client. I don't have it to hand but this was the gist of it! I added a few styling niceties and the text entry mechanics so you can get an idea of how it would work.
I'm afraid it doesn't make the middle section shrink persay, but it does appear to get smaller. As the footer expands with its text it extends over the top of the middle block.
var inputBox = document.getElementsByClassName("footer")[0];
var contentBox = document.getElementsByClassName("content")[0];
inputBox.addEventListener('keydown', function(e) {
if (e.keyCode == 13) {
e.preventDefault();
createMessage(inputBox.textContent);
inputBox.textContent = "";
}
}, false);
function createMessage (str) {
var message = document.createElement('div');
message.style.cssText = "background: #3AF; padding: 10px; border-radius: 5px; margin: 10px 0; color: white;";
message.textContent = str;
contentBox.appendChild(message);
}
createMessage("Sent messages appear here!")
createMessage("Type a message in the footer and press enter to send")
createMessage("This list will become scrollable if there is enough content")
createMessage("The text entry will also dynamically resize as you type")
/* border box reset, as per http://www.paulirish.com/2012/box-sizing-border-box-ftw/ */
html {
box-sizing: border-box;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
/*
base container class, height can be relative or absolute (but it must have height
requires position relative or absolute so we can position the header and footer
finally requires vertical padding the same height as the the header/footer
*/
.container {
height: 600px;
background-color: rgb(220, 220, 220);
position: relative;
padding: 50px 0;
}
/*
header class, must have a height and width
should be top 0 and left 0 so that it positions inside the containers padding
must be positioned absolute
*/
.container .header {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 50px;
background-color: rgb(120, 120, 120);
text-align: center;
line-height: 30px;
padding: 10px;
color: white;
font-size: 22px;
}
/*
content box, the easiest really
height to 100% (so it will be the container minus the padding, which the header/footer sits in)
overflow-y: auto; so if we exceed the size of the content box we scroll instead
*/
.container .content {
height: 100%;
overflow-y: auto;
padding: 10px;
}
/*
positioned absolutely again, but bottom left this time.
use min height to specify the basic height then as the user types it will grow accordingly
set max-height to prevent it growing too tall, overflow: auto; again so we can scroll in that situation
VERY IMPORTANTLY MUST HAVE THE CONTENT EDITABLE FLAG ON THE HTML ELEMENT
*/
.container .footer {
position: absolute;
bottom: 0;
left: 0;
min-height: 50px;
max-height: 300px;
width: 100%;
overflow-y: auto;
background-color: rgb(120, 120, 120);
padding: 15px;
line-height: 20px;
color: white;
}
<div class="container">
<div class="header">HEADER</div>
<div class="content"></div>
<div class="footer" contenteditable></div>
</div>
The JS section isn't required, I've added it to the example to give it a bit more life.
It attaches a listener for the "enter" key on the text entry and uses the text to create a new "message" inside the content box. The actual layout is all done in CSS.

Should I use CSS, javascript or both to make this fixed element expand the parent element?

I know that a an element with position:fixed acts like its parent element with position:relative (Or no position specified) doesn't exist, and that's my concern. I've seen the very same question being asked here on StackOverflow, but not the very same problem.
I have a wrapper, an element with relative position, and an element with a fixed position inside the relative element. The element with fixed position should expand the element with relative position as you scroll the page, but what's happening is that when you scroll the page, the element with fixed position will go out of the main container, instead of expanding. How can I make the main element push the container element bellow, instead of getting an offset?
Fiddle
http://jsfiddle.net/T2PL5/515/
Here my code:
CSS
body {
background: #ccc;
}
.wrapper {
margin: 0 auto;
height: 600px;
width: 650px;
background: green;
}
.sidebar {
background-color: #ddd;
float: left;
width: 300px;
height: 350px;
position: relative;
}
.main {
background-color: yellow;
width: 200px;
height: 100px;
position: fixed;
margin: auto;
}
HTML
<div class="wrapper">wrapper
<div class="sidebar"> Sidebar
<div class="main">main</div>
</div>
</div>

Absolutely position element based on center

A convenient way to make an absolutely-positioned hovering element that lets height vary with content using Javascript is to specify the width, top and left as style fields. For instance:
popup.style.width = foo.offsetWidth - 10 + 'px';
popup.style.top = document.getElementById(bar)
.getBoundingClientRect().top + 'px'; // for IE7, can't use offsetTop
popup.style.left = '15px';
How can I adapt this code to absolutely position the popup based on its center, rather than its top? I'd like to do popup.style.center instead of popup.style.top, but that's not how CSS works. A completely naive solution is to add it to the DOM, then measure its height, and subtract half the height from the top.
Alternatively, is there a completely different approach that would still allow setting an arbitrary position for each corner of the element?
I'm looking for a pure Javascript solution (e.g. no jquery).
Important: I'm not trying to center the popup inside another element. Rather, I want the center point of the popup to be specified as a pixel offset from the top of the screen. This pixel offset may be based on another element, or it may be a raw number.
In your important note you are dealing with two different notions:
The first one, offset from the top of the screen, can be achieved with position:fixed.
The second one, offset based on another element, is where absolute positioning is useful, and will be relative to the first position:relative parent element.
As suggest Table-Cell centering (thanks to Itay comment) it makes sense in your case to use table display because it's exactly its purpose: adapt the container to its content.
You need some extra html:
<div class="container">
<div class="popup">
<div class="content">
<!-- CONTENT -->
</div>
</div>
</div>
And apply this css:
.container {
position: absolute; /* or fixed */
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.popup {
display: table;
height: 100%;
}
.content {
display: table-cell;
vertical-align: middle;
}
Thanks to the table-cell display you can use vertical-align: middle, no more need of javascript.
For horizontal centering you can still add a classic width: 50%; margin: 0 auto; on popup class.
To do this in jquery would be pretty simple
DEMO jsFiddle
jQuery.fn.center = function(parent) {
if (parent) {
parent = this.parent();
} else {
parent = window;
}
this.css({
"position": "absolute",
"top": ((($(parent).height() - this.outerHeight()) / 2) + $(parent).scrollTop() + "px"),
"left": ((($(parent).width() - this.outerWidth()) / 2) + $(parent).scrollLeft() + "px")
});
return this;
}
$("div.target").center(true);
I had been thinking about this for a while. You can actually absolute position an element from the center of a container instead of the corners by adding a div inside the container. This inner container, or reference container, is 50% height and 50% width of the parent container. Then you can position relative to the bottom right corner.
HTML
<div class="container">
<div class="container-inner">
<div class="pointer pointer-1" data-name="pointer-1"></div>
<div class="pointer pointer-2" data-name="pointer-2"></div>
</div>
</div>
CSS
This is the container we want to place pointers in
html, body {
height: 100%;
}
.container {
height: 80%;
width: 80%;
margin: 0 auto;
border: 1px solid blue;
}
We use this container to get a center point that we can use as a reference. We use the bottom right corner of this div as our reference point.
.container-inner {
border: 1px dashed red;
height: 50%;
width: 50%;
position: relative;
}
Create a couple of targets 60px in diameter
.pointer {
height: 40px;
width: 40px;
background-color: orange;
border: 10px solid red;
border-radius: 60px;
position: absolute;
}
Center target one in the center of the container
.pointer-1 {
bottom: calc(-0% - 30px);
right: calc(-0% - 30px);
}
Position target 2 25% right and down from the container center.
.pointer-2 {
bottom: calc(-50% - 30px);
right: calc(-50% - 30px);
}
You can see a working demo of this JSBin.
Would this work?
.popup {
margin-top: -50%;
}
In the end, I decided to just add the element to the DOM, measure its height, and subtract half the height from the top. I make the element invisible before adding it, and visible again after adjusting the height, to avoid flickering.

Categories