CSS relative position left works, but top doesn't - html

I'm trying to position arbitrary elements arbitrarily within an arbitrary container. I want to specify a position as a percentage where
0% means "left edge aligned with the left of the container,"
100% means "right edge aligned with the right of the container,"
Any value in between is linearly interpolated, so 50% would be "middle aligned with middle"
To achieve this, the container has position: relative;. The element has position: absolute; with left and top equal to the percentages - these percentages will be relative to the container's size. Then, the element's contents are shifted back with position: relative; and left and top equal to negative the percentage, as this will be relative to the element's size.
Demo:
#container {
position: relative;
width: 200px;
height: 150px;
background-color: #cfc;
}
#item {
position: absolute;
left: 80%;
top: 80%;
background-color: #fcc;
}
#item>img {
position: relative;
display: block;
left: -80%;
top: -80%;
}
<div id="container">
<div id="item">
<img src="//placehold.it/100x100" />
</div>
</div>
In the demo, the green box is the container, the red box is the element's "real" position, while the placeholder image is the actual content. The coordinate used here is (80%,80%) making it appear in the lower-right corner.
As you can see, the left component works absolutely fine. It is exactly where it should be. The top, however, is not doing the "shift back" thing. It's not moving at all.
Of course there are many similar questions, but all of the ones I've seen stem from the "relative to" element being the relative one, not the absolute, which meant the container had zero height - fair enough. Indeed, explicitly setting the height on my red box in the demo fixes the issue. However, did I mention how arbitrary these components are? I cannot explicitly set the height of the element, I need it to vary based on the content, which may change dynamically.
Any ideas how I might go about this?

As already noticed, the main issue here is that top with percentage values will only work if the parent has a height specified which is not the case here. So in order to fix this we need to find a way to give the item a specified height equal to its content height and different from auto.
And idea would be to consider another div within the #item and make this one a flex container. This will make the new div to be stretched and have a height specified (yes flex is magic) thus the top value on the img will work fine.
#container {
position: relative;
width: 200px;
height: 150px;
background-color: #cfc;
overflow:hidden;
}
#item {
position: absolute;
display:flex;
animation: change-1 1s linear infinite alternate;
}
#item img {
position: relative;
display: block;
animation: change-2 1s linear infinite alternate;
}
#keyframes change-1 {
from {
top:0%;
left:0%;
}
to {
top:100%;
left:100%;
}
}
#keyframes change-2 {
from {
top:0%;
left:0%;
}
to {
top:-100%;
left:-100%;
}
}
<div id="container">
<div id="item">
<div>
<img src="//placehold.it/100x100" >
</div>
</div>
</div>

Here you can use transform property to the placeholder and give value to x and y coordinates the same i.e -80%. Hope this helps you out.
#container {
position: relative;
width: 200px;
height: 150px;
background-color: #cfc;
}
#item {
position: absolute;
left: 80%;
top: 80%;
background-color: #fcc;
}
#item>img {
position: relative;
display: block;
transform: translate(-80%,-80%);
}
<div id="container">
<div id="item">
<img src="//placehold.it/100x100" />
</div>
</div>

You should specify a height of the parent element :)
UPDATE
You can also try to set for your img a negative margin-top: -80% instead of top: 80%, and set the margin-bottom: 80% to preserve parent element height:
#container {
position: relative;
width: 200px;
height: 150px;
background-color: #cfc;
}
#item {
position: absolute;
left: 80%;
top: 80%;
background-color: #fcc;
}
#item>img {
position: relative;
display: block;
left: -80%;
margin-top: -80%;
margin-bottom: 80%;
}
<div id="container">
<div id="item">
<img src="//placehold.it/100x100" />
</div>
</div>
The only trick is that margin in percents is setting relative to the parent element width, so, obviously, if you will have not square image, it will work incorrectly.

I have "resolved" the issue by having JavaScript set margin-left and margin-top based on the pixel size of the content, and added event handlers for the window resizing and the content changing. While this works, I don't like it. A CSS-only solution would trump this by far.

Related

absolute div inside absolute div cuts off with respect to relative position

I have 3 divs on top of each other having following css.
.d1 {
position: relative;
background-color: yellow;
height: 50px;
width: 100px;
overflow: hidden;
}
.d2 {
position: absolute;
background-color: green;
height: 25px;
width: 50px;
}
.d3 {
position: absolute;
left: 83px;
}
and the divs that have classes are as follows:
<div class="d1">
<div class="d2">
<div class="d3">text</div>
</div>
</div>
and as a result I see content of d3 cut off because of overflow:hidden in d1.
How can I avoid cut off content of d3 without modifying d1?
Getting around the overflow..
An element can overflow from a relative or absolute positioned parent by setting its position to fixed. An element that has position: fixed will have the default left,right,top, and bottom styles set as auto. This will position .d3 to the top-left of .d2, and then the left: 83px style will push it to the left from there.
Making up the additional space..
However, to get that additional movement to the right as the original markup, you will need to add margin-left: 8px, which will make-up the additional ~8px needed to replicate the original. Further adjustments to the position of .d3 will need to be done by setting the margin style (see below).
Your updated code should look like this..
.d1 {
position: relative;
background-color: yellow;
height: 50px;
width: 100px;
overflow: hidden;
}
.d2 {
position: absolute;
background-color: green;
height: 25px;
width: 50px;
}
.d3 {
position: fixed;
margin-left: 8px;
left: 83px;
}
Some considerations and caveats..
As a previous commenter mentioned, best practice would be to fix your html markup because this solution could cause issues if you ever need to move the position of .d3. For example, setting left,right,top, or bottom will cause the default setting of this style, auto, from being unset, and the element will be positioned relative to the viewport rather than the parent relative or absolute element.

Having trouble mixing absolute and relative positions

I am wondering how I should organize things. I want my screen to be organized like this, and to be responsive:
So here is what I did:
.container-map {
position: relative;
}
.map-background {
z-index: 10;
width: 100%;
height: 50%;
position: absolute;
top: 0;
left: 0;
}
.map-filter {
z-index: 100;
margin-left: 10%;
margin-top: 5%;
position: absolute;
}
.map-search-results{
position: absolute;
margin-top: 50%;
width: 100%;
}
<div class="container-map">
<div class="map-background"></div>
<div class="map-filter"></div>
<div class="map-search-results"></div>
</div>
It is working for the map and the filter, but for the search-results section, this seems very dirty to me.
It seems like adding a div around map-background and map-filter should be the solution, but how do I make its position "more important" than the absolute positions of the two other divs?
It's not clear what you mean by "more important" but I think I know what you mean. One of the main issues is the fact that the top map background and map filter are not positioned together but independently, and then just aligned with absolute positioning. This makes the style brittle and prone to errors from changes - whether that be changes in code or change in viewport etc.
Instead this might be the kind of thing you are after:
.top-container{
height:50vh;
position:relative;
}
.map-background {
height: 100%;
background-color:yellow;
outline:2px solid yellow;
}
.map-filter {
position: absolute;
top:15%;
left:10%;
min-height:50px;
min-width:200px;
background-color:lightblue;
outline:2px solid lightblue;
}
.map-search-results{
height:50vh;
background-color:red;
outline:2px solid red;
}
<div class="container-map">
<div class="top-container">
<div class="map-background">
Background
</div>
<div class="map-filter">
Filter
</div>
</div>
<div class="map-search-results">
Search Results
</div>
</div>
Now the top section is held in it's own container and only the filter is positioned absolutely, but that's absolutely relative to the wrapping container. Remember that position: absolute will position an element relative to the nearest ancestor with position: absolute or position: relative.[1]
This means that the top section is effectively 'grouped' and if the container is repositioned, whether that be with new CSS rules, changes to the DOM, changes to the the outer dimensions etc etc, then all the children should also be naturally repositioned as well (barring any other complications).
I have also cleaned up the code somewhat.
Your height definitions weren't working because a percentage height needs a parent with absolute height to work. Instead I have defined the two main blocks as having height: 50vh but you can set it to whatever you need.
There's also no need for z-index in this case (and z-index with absolute positioning is a recipe for confusion). The map-filter is the only thing 'on top' of something else and that will appear on top anyway since it is absolutely positioned and the map-background is not.
So if you take out the code I created for demonstration this is the core CSS:
.top-container{
height:50vh;
position:relative;
}
.map-background {
height: 100%;
}
.map-filter {
position: absolute;
top:15%;
left:10%;
}
.map-search-results{
height:50vh;
}
You don't need position: absolute for any of these:
<div class="container-map">
<div class="map-background">
<div class="map-filter"></div>
</div>
<div class="map-search-results"></div>
</div>
.container-map {
width: 400px; /*set as much as you like */
}
.map-background , .map-search-results {
display: block;
height: 50%;
}
.map-background {
padding: 15px; /* set as much as you want - to affect the height/position of .map-filter */
}
.map-filter {
width: 200px;
height: 100%; /* top/bottom padding of [.map-background] will create the height differential here */
}
First thing you need to know is when dealing with absolute it's better to use left, right, top & bottom,
Second thing you need to know is the relatively positioned element should have width and height in order to place the absolute positioned item inside it
Consider reading this article to know what is the difference between this properties ( relative & absolute )https://css-tricks.com/absolute-relative-fixed-positioining-how-do-they-differ/
I tried to make an example like the image in your question :
.container-map {
position: relative;
background:#000;
width:100vw;
height:100vh;
}
.map-background {
z-index: 10;
width: 100%;
height: 50%;
position: absolute;
top: 0;
left: 0;
background:#ff0000;
}
.map-filter {
z-index: 100;
left: 5%;
top: 5%;
width:130px;
height:40%;
background:orange;
position: absolute;
}
.map-search-results{
position: absolute;
top: 50%;
width: 100%;
height:50%;
background:#00ff00;
}
<div class="container-map">
<div class="map-background"></div>
<div class="map-filter"></div>
<div class="map-search-results"></div>
</div>

itHow do I make div/ div images not move when resizing, while also allowing them to have a % from the top

I want to be able to resize the window while my divs keep their position on the page AND resize to a % of width and height I declare.
HTML:
<body>
<div class="view">
<div class="Tree">
<img id="tree" src="img/tree.png">
</div>
<div class="Ground">
<div class="g"></div>
</div>
</div>
</body>
CSS:
.Tree {
position: absolute;
}
.Tree #tree {
position: relative;
height: 75%;
width: 75%;
left: 30%; }
.Ground {
z-index: 2;
width: 100%;
height: 100%; }
.Ground .g {
background-color: green;
opacity: .5;
position: relative;
height: 50%;
width: 100%; }
The tree stays pretty constant, but when the window is the largest it can be on my macbook, it slides over to the left a little. The ground element vertically takes up half the page, I instead want it to only be placed 50% from the top. When I try to apply the 'top' style to either of them nothing happens. I know this is because the #tree is relative to .Tree and I don't declare a height/ width. I don't declare a h/w because it makes my #tree image's w/h off.
Thank you for the help!
Edit, added clarification:
I want the divs to resize according to the window width. I don't want them to change their left position. And I want to be able to set a 'top' % because I currently can't.
Fiddle: https://jsfiddle.net/sqdgzbp6/
Notice on this website: anniwang.com that if you resize your entire window the drawings seem to also resize BUT they don't loose their position on the page. I want to recreate an effect similar to hers.
As the .Tree is an absolute positioned element, it need a height/width set explicit or else no child with percent will have anything to calculate their percent from, so in this sample I gave it a height and now top will work.
.Tree {
position: absolute;
height: 100%;
width: 100%;
}
#tree {
position: relative;
height: auto;
width: 60%;
left: 30%;
top: 20%;
}
.Ground {
z-index: 2;
width: 100%;
height: 100%;
}
.Ground .g {
background-color: green;
opacity: .5;
position: relative;
height: 50%;
width: 100%;
}
<div class="view">
<div class="Tree">
<img id="tree" src="http://www.placehold.it/200/100">
</div>
<div class="Ground">
<div class="g"></div>
</div>
</div>
By the sound of it, you want divs to stop resizing when you've previously set a size of 50%. Remember this is only 50% of the window screen, so no matter how big or small the window, it will always scale to 50% of whatever you're viewing on. If you want it to be fixed, you could use 500px that way it doesn't move because it's set to a fixed 500.
Hope this helps.

how to retain fixed positions of elements inside transformed elements?

it's a known 'bug' that elements with fixed position loose their position if the container is translated. For example, if i've got a structure like this:
<div class="container">
<div class="fixed"></div>
</div>
and, say, the container is scrolled, when the conteiner gets transformed (say, translate(x,y), rotate(), or so..), then the fixed element behaves like it was positioned relative and it scrolls with the container. I can see it on the latest firefox, for example.
How can one fix this kind of problem? Is there any way?
This behaviour is not a bug. It's actually the specs recommended behaviour.
(See this post by Eric Meyer, or this question here on SO which accepted solution only provides a link to the same meyer's post)
For those who don't know this issue, and because you didn't provide a snippet into your question, here's one.
document.addEventListener('click', function() {
document.getElementById('container').classList.toggle('transformed')
}, false);
#bg {
border: 1px solid #AFA;
height: 100%;
width: 100%;
position: fixed;
top: 0;
left: 0;
}
#container {
border: 1px solid #FAF;
height: 50%;
width: 75%;
position: relative;
margin: 0 auto;
overflow: auto;
}
#content {
background: rgba(125, 175, 0, .7);
position: fixed;
width: 100%;
top: 0;
left: 0;
}
.transformed {
transform: translate(0, 5em);
}
<div id="bg">
<div id="container" class="transformed">
.<br>.<br>.<br>.<br>.<br>.<br>.
this is a scrollable paragraph
<br>.<br>the "fixed" content does scroll with the paragraph
<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.
you can click to toggle the transformation On/Off
<br>.<br>.<br>.<br>.<br>.
<span id="content">relatively fixed content</span>
</div>
</div>
However, I did find something that may help others facing the same issue.
It's not really a solution, since the "fixed" element will be only inside the container, (except for IE browsers where it will really be fixed to the document). But in my case, it's actually what I wanted and maybe it'll be fine for others too.
If you add a wrapper, set its height:100%; width:100%; and overflow:auto, then your "fixed" content won't scroll with the container.
Actually it's not you container which scrolls anymore, but the wrapper. So you might want to set the container's overflow:visible or hidden to avoid unwanted scrolling of the not so well "fixed" element.
Also, note that you need your wrapper be a block or inline-block element.
#bg {
border: 1px solid #AFA;
height: 100%;
width: 100%;
position: fixed;
top: 0;
left: 0;
}
#container {
border: 1px solid #FAF;
height: 50%;
width: 75%;
position: relative;
margin: 0 auto;
overflow: visible;
}
#wrapper {
height: 100%;
width: 100%;
overflow: auto;
}
#content {
background: rgba(125, 175, 0, .7);
position: fixed;
width: 100%;
top: 0;
left: 0;
}
.transformed {
transform: translate(0, 50%);
}
<div id="bg">
<div id="container" class="transformed">
<div id="wrapper">
.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.
<span id="content">relatively fixed content</span>
</div>
</div>
</div>
I am not familiar with this bug, but when you use positioned: fixed; the element is positioned relative to the browser window, so it doesn't really make any sense to put it inside a container.
This markup would be my recommendation:
<div class="fixed"></div>
<div class="container"></div>
Once you use position: fixed; on any element it is positioned relative to the view-port. Directly from page in MDN about position property.
fixed
Do not leave space for the element. Instead, position it at a specified position relative to the screen's viewport and don't move it when scrolled.
So what you are experiencing is a what it is actually supposed to work like and not a 'bug'.
Now if what you want is something that is positioned with relation to the .container div and translate with it than you will have to use absolute positioning here. Take a look at this fiddle. The important CSS is-
.container {
width: 200px;
height: 100px;
position: relative;
}
.absolute {
position: absolute;
width: 20px;
height: 10px;
top: 50px;
left: 50px;
}
Notice that with positioning the inner div as absolute I have also positioned the outer div as relative as the inner div takes its position in reference to the closest parent div positioned as anything different from static.

CSS I want a div to be on top of everything

How do I make an html div tag to be on top of everything? I tried adding z-index: 1000, but it remains the same.
In order for z-index to work, you'll need to give the element a position:absolute or a position:relative property. Once you do that, your links will function properly, though you may have to tweak your CSS a bit afterwards.
Yes, in order for the z-index to work, you'll need to give the element a position: absolute or a position: relative property... fine.
But... pay attention to parents!
The element's z-index may be limited by its parent's z-index value.
You have to go down the nodes of the elements to check if at the level of the common parent the first descendants have a defined z-index.
All other descendants can never be in the foreground if at the base there is a lower definite z-index.
In this snippet example, div1-2-1 has a z-index of 1000 but is nevertheless under the div1-1-1 which has a z-index of 3.
This is because div1-1 has a z-index greater than div1-2.
.div {
}
#div1 {
z-index: 1;
position: absolute;
width: 500px;
height: 300px;
border: 1px solid black;
}
#div1-1 {
z-index: 2;
position: absolute;
left: 230px;
width: 200px;
height: 200px;
top: 31px;
background-color: indianred;
}
#div1-1-1 {
z-index: 3;
position: absolute;
top: 50px;
width: 100px;
height: 100px;
background-color: burlywood;
}
#div1-2 {
z-index: 1;
position: absolute;
width: 200px;
height: 200px;
left: 80px;
top: 5px;
background-color: red;
}
#div1-2-1 {
z-index: 1000;
position: absolute;
left: 70px;
width: 120px;
height: 100px;
top: 10px;
color: red;
background-color: lightyellow;
}
.blink {
animation: blinker 1s linear infinite;
}
#keyframes blinker {
50% {
opacity: 0;
}
}
.rotate {
writing-mode: vertical-rl;
padding-left: 50px;
font-weight: bold;
font-size: 20px;
}
<div class="div" id="div1">div1</br>z-index: 1
<div class="div" id="div1-1">div1-1</br>z-index: 2
<div class="div" id="div1-1-1">div1-1-1</br>z-index: 3</div>
</div>
<div class="div" id="div1-2">div1-2</br>z-index: 1</br><span class='rotate blink'><=</span>
<div class="div" id="div1-2-1"><span class='blink'>z-index: 1000!!</span></br>div1-2-1</br><span class='blink'> because =></br>(same</br> parent)</span></div>
</div>
</div>
More simply :
For z-index:1000 to have an effect you need a non-static positioning scheme.
Add position:relative; to a rule selecting the element you want to be on top
You need to add position:relative; to the menu. Z-index only works when you have a non static positioning scheme.
z-index property enables you to take your control at front. the bigger number you set the upper your element you get.
position property should be relative because position of html-element should be position relatively against other controls in all dimensions.
element.style {
position:relative;
z-index:1000; //change your number as per elements lies on your page.
}
I gonna assumed you making a popup with code from WW3 school, correct?
check it css. the .modal one, there're already word z-index there. just change from 1 to 100.
.modal {
display: none; /* Hidden by default */
position: fixed; /* Stay in place */
z-index: 1; /* Sit on top */
padding-top: 100px; /* Location of the box */
left: 0;
top: 0;
width: 100%; /* Full width */
height: 100%; /* Full height */
overflow: auto; /* Enable scroll if needed */
background-color: rgb(0,0,0); /* Fallback color */
background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}
It seems like nesting an element inside a <dialog> element puts it on top of everything. It is placed both horizontally and vertically centered to the screen if you use showModal() but you lose the interactivity with other elements in the page.
document.querySelector("dialog").showModal();
<dialog>
<div class="element">I am on top of everything else</div>
</dialog>
<div class="backdrop">Backdrop element</div>
If you still want interactivity with the background elements, you can use the show() method. It is placed only horizontally centered to the screen.
document.querySelector("dialog").show();
<dialog>
<div class="element">I am on top of everything else</div>
</dialog>
<div class="backdrop">Backdrop element to check if I am underneath or not.</div>