Absolutely position element based on center - javascript

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.

Related

Expand absolutely positioned width only if it overflows parent

I have a parent div(A) which is relatively positioned and there'll be two divs(X and Y) inside the parent div. Y is a small element and will be rendered on top of X so I've added position: absolute on Y. Y will also cover z% of its parent's size. There'll be more elements below parent div A.
Codepen link: https://codepen.io/shiva3/full/eYjXxxy
/* A element */
.parent {
position: relative;
height: 20em;
width: 40em;
}
/* X element */
.big {
width: 100%;
height: 100%;
}
/* Y Element */
.rectangle {
height: calc(100% - 2em);
width: 30%;
background-color: pink;
z-index: 2;
bottom: 0;
position: absolute;
}
This is the output
The issue I'm facing is, whenever Y has large content(or when we zoom in) it overflows and interferes with the element below it.
Overflown content
I want to change the width of the element only if Y overflows.
Create a id or a class to your paragraph in html
Just go in CSS and put max-height (like 250px seems good) and a overflow-y scroll

How to anchor one div to another and keep them responsive

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>

re-center div when content change

I have a div that is centered on the middle of the screen. I need to pass some text to the div and the text will be of various lengths. The problem is that when I pass text to the div, it changes size but wont stay centered. Here's a JSFiddle that demonstrates the problem.
I currently center the div like this:
position: absolute;
top: 50%;
left: 50%;
Add this line:
#divError{
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
http://jsfiddle.net/h0d097vp/3/
Your div is not centered. The existing positioning centered the top left corner of the div.
Try this:
#divError{
position: absolute;
top: 50%;
left: 50%;
transform:translate(-50%,-50%);
}
JSfiddle Demo
Can you set constant width?, if so here's your answer JSFiddler
Just added
width: 100px;
right: 0;
left: 0;
margin: auto;
Your div is not centered in the beginning either. left: 50% means that the diff starts at 50%, which means that the start of the div is at the center of the page.
When the div has a width of 200px, than still only the start will be at the center.
You can give the div a fixed width, and than add a negative margin of half the width so the div will really be in the center of the page.
Like
#divError{
width: 200px;
margin-left: -100px;
}
When using top and left they position whichever side they are named directly at the position given. So left: 50% will always have the leftmost side positioned directly at the 50% mark. This is not the center, but starts the left side of the div at the center. The same occurs with top: 50%. In order to use top and left you'd need to know the overall width and height and subtract half of their value from their respective top and left (e.g left: calc(50% - ([width of element] / 2)). Since you are using dynamic content you can't know either the height or the width (unless you make them static.)
So what can you do? There are a few ways, but my favorite at the moment is fairly new. It's called flexbox. It's support is decent. There's a nice snippet from css-tricks as well.
The relevant code to center an element both vertically and horizontally would go like this:
$(document).ready(function() {
$("button").click(function() {
$.get("http://lorem.mannfolio.com/", function(data) {
var lorem = data.split("\n\n");
$(".centered").html(lorem[0]);
});
});
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
height: 100%;
}
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
border: 1px solid black;
}
button {
position: fixed;
top: 10px;
left: 10px;
}
<button>Change text</button>
<div class="container">
<div class="centered">I'm centered No matter what you put in me.</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

CSS rotate transform - left and top issue

I have a parent div on which I am applying a rotation transform of -90 deg. Inside the div, one of the child should not transform, I tried transform:none and all its variants but nothing worked and it gets transformed anyways. So, I had to apply a reverse rotation on the child element to set it horizontal.
Now the problem which occurs is that changing the left of child on which reverse rotation was applied actually changes its top and changing top changes its left when altered using Firebug. So the child element is displayed at a wrong position.
if(self._sOrientation == "vertical"){
self.RotatePH($thisComp.closest('.ComponentFrame'),"-90deg");
if(self.isIE==false){
self.RotatePH($thisComp.find('.revertTransform'),"90deg");
// $thisComp.find('.revertTransform').css('-moz-transform', 'none');
}
Actually the component is too complex to provide any usable code on stack overflow
Edit:
I believe the second rotation should be about the axis of the main component instead of rotating about itself. Is it possible to change axis of rotation?
The child has position:fixed; if that matters
I've created a Fiddle to better understand your problem, and i think it's not something related to transformation axis.
More simply, when you alter top, or left position of the child element, it moves correctly referring to it's parent and then the transformation take place.
The child div alter it's position refering to parent div and inheriting it's transformations.
So the final effect that you see is that the object is altering it's left position when you tweak the top and viceversa, but in fact it's not.
Child div seems to moved top and left, but in fact it's not.
I suggest you to change your approach if it's applicable in your situation, and create a fake_parent element that is a child instead (you can see that in the fiddle).
//INSTEAD OF THIS APPROACH
<div class="parent">PARENT DIV
<div class="child">CHILD DIV</div>
</div>
//USE THIS APPROACH
<div class="fake_child">CHILD DIV
<div class="fake_parent">PARENT DIV</div>
</div>
CSS
.parent {
width:100px;
margin:3em;
padding:2em;
transform:rotate(45deg);
-ms-transform:rotate(45deg);
/* IE 9 */
-webkit-transform:rotate(45deg);
background-color:rgb(0, 112, 255);
}
.child {
background-color: #fff;
position: absolute;
padding:1em;
transform:rotate(-45deg);
-ms-transform:rotate(-45deg);
-webkit-transform:rotate(-45deg);
}
.fake_child{
width: 100px;
background-color: #fff;
padding: 1em;
margin: 3em;
position: relative;
}
.fake_parent{
position:absolute;
width:100%;
height:200%;
background-color: rgb(0,121,255);
top:0;
left: 0;
transform:rotate(45deg);
-ms-transform:rotate(45deg);
/* IE 9 */
-webkit-transform:rotate(45deg);
z-index: -1;
}
body {
background-color: #ccc;
font-family: Arial, sans-serif;
}
can't you use transform-origin (http://css-tricks.com/almanac/properties/t/transform-origin/):
-webkit-transform-origin: center center;
-moz-transform-origin: center center;
-o-transform-origin: center center;
transform-origin: center center;
I believe the second rotation should be about the axis of the main component instead of rotating about itself. Is it possible to change axis of rotation?
Yes, if you know the width of the parent (or the ratio of the child's width to the parent's width, I believe). You can use transform-origin to have the child rotate back to its original position by setting transform-origin: hpw hpw, where hpw is half the width of the parent.
If we only rotated the parent and the child was at (0,0) relative to the parent, the child would end up in the bottom left corner of the parent. Imagine a box with its width and height both set to the width of the parent, and positioned at (0,0) relative to the rotated parent. (It follows that the child is in the bottom left corner of this box.) It should be clear that rotating this box will put the child back to it's original position and rotation.
The top and left of the child will still be relative to the rotated parent, so you'll have to position the child with left: your_top * -1 and top: your_left.
Demo: http://jsfiddle.net/HTCwL/1/
Edit: Here's an animated version of the demo to make things clearer http://jsfiddle.net/HTCwL/2/
Relevant CSS:
#parent {
width: 150px;
height: 300px;
border: 1px solid blue;
position: relative;
top: 10px; left: 150px;
-webkit-transform: rotate(-90deg);
}
#child {
position: absolute;
width: 100px;
height: 100px;
left: -10px;
top: 150px;
border: 1px solid red;
-webkit-transform: rotate(90deg);
-webkit-transform-origin: 75px 75px;
}
Edit: Yes, the child having position fixed matters. From https://developer.mozilla.org/en-US/docs/Web/CSS/transform,
If the property has a value different than none [...] the object will act as a containing block for position: fixed elements that it contains.
The containing block for fixed elements is normally the html element (see http://www.w3.org/wiki/CSS_absolute_and_fixed_positioning#Containing_blocks) but when the parent of a fixed element has a transform set it becomes their containing block. I'm not aware of any way to avoid that.

keep html contents at same position and size ratio in full screen mode

I have being researching regarding this question for a long time but I was not lucky. Here is the situation. Assume you have a blue rectangle in the center of the page. When you go full screen, we can use percentage for height and width to preserve the ratio of rectangle. However, the position of rectangle changes and it moves up and you end up with extra space at the bottom of the page.
So what should I do to keep rectangle in the center of the page (equal vertical and horizontal distance) when full screen mode is enabled? In other words, if your screen is 1280x800, center of rectangle be at (640,400)
If you check home page of Chrome browser, when you go full screen, the position of apps stay the same and you don't end up with extra space at the bottom. Appreciate your help
Define width of the rectangle and use margin: 0 auto; to center it in page horizontally.
If you want to center a div horizontally and vertically, use something like this
HTML
<div id="rectangle"></div>
CSS
#rectangle {
width: 30%; //can set any value here
height: 20%; //can set any value here
position: absolute;
left: 50%;
top: 50%;
margin-left: -15%; //negative half of width
margin-top: -10%; //negative half of height
background-color: red;
}​
See the fiddle here.
OR
HTML
<div id="wrapper">
<div id="container">
<div id="rectangle"></div>
</div>
</div>​
CSS
body, html {
height: 100%;
overflow:hidden;
}
#wrapper {
width: 100%;
height: 100%;
overflow: visible;
position: relative;
}
#wrapper[id] {
display: table;
position: static;
}
#container[id] {
display: table-cell;
vertical-align: middle;
width: 100%;
}
#rectangle {
width: 200px;
height: 100px;
margin-left: auto;
margin-right: auto;
background-color: blue;
}
​
See the fiddle here.
Have you tried also using percentages for the margins, for example if you centre square was 60% tall and wide you could add the 20% as a margin so that would also scale up. Without trying I don't know if it would give you the desired effect but it should fix the issue of the square moving up.
oops,
I forget that I am working on an iMac.
the if addition in the script solved my problem.
function vertical_center()
{
var ww = $(window).width();
if (ww < 1600)
{
$("#character").css({'width': ww + 'px','height': (ww/4) + 'px', 'margin-top': -(ww/8) + 'px'});
}
else
$("#character").css({'width': ww + 'px'})
}
Yet, I would be glad if someone looks over my code telling me where some silly things remain.
Hope this post added something nevertheless, thank you guys

Categories