top/bottom:[%] based on parent element's borders instead of height - html

I found a weird behavior when positioning a child element using top:[%]. On mobile-safari, given top/bottom borders of sufficient size, the behavior seems to switch: Instead of the percentage being applied to the parent's height, its applied to the parent's borders (plus a little extra).
The following code reproduces the bug:
.parent {
position: relative;
border-bottom: 200px;
border-style: solid;
height: 100px;
width: 100%;
}
.normal {
position: absolute;
top: 10px;
width: 50%;
background-color: blue;
}
.defective {
position: relative;
top: 10%;
width: 50%;
left: 50%;
background-color: red;
}
* {
/*style reset*/
margin: 0;
border: 0;
}
<body>
<div class="parent">
<div class="normal">
<p>The top is 10px</p>
</div>
<div class="defective">
<p>I should be at the same height</p>
</div>
</div>
In this example, the top should be 10px, but when I inspect the element, it's actually 20.3px. Here is what it looks like:
Other details:
The bug seems to kick in when the sum of the vertical borders of the parent are 98% or more of its height.
The child element doesn't have to be a div, it can be an image.
The bug does NOT appear if the child has position:absolute.
Am I the only one who sees this? Is is documented somewhere?
Reproduced on the following:
iPhone XS Max 12 (real device on browserstack.com)
iPad mini iOS 9
iPhone8, with Safari 13.6 (simulated on lamdatest.com)

The relatively placed element is displaced vertically depending on the width of the border on some versions of IOS. This did not show on an iPad running Safari IOS14 but did on a mini iPad running IOS 9.
This appears to be a bug in at least some IOS versions.
A workaround might be to put the border into a pseudo element on parent. This snippet then worked on IOS 9 on the mini iPad:
<style>
.parent {
position: relative;
height: 100px;
width: 100%;
}
.parent::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
border-bottom: 200px;
border-style: solid;
}
.normal {
position: absolute;
top: 10px;
width: 50%;
background-color: blue;
rdisplay: none;
}
.defective {
position: relative;
top: 10%;
width: 50%;
left: 50%;
background-color: red;
}
* {
/*style reset*/
margin: 0;
border: 0;
}
</style>
<body>
<div class="parent">
<div class="defective">
<p>I should be at the same height</p>
</div>
<div class="normal">
<p>The top is 10px</p>
</div>
</div>

Related

Absolute positioned elements have same width but look different

I have 3 absolute positioned elements within a container, each with a width of 1px. However, these elements do not look to be all the same size when rendered. Why is this?
.container {
position: relative;
border: 1px solid red;
width: 100px;
height: 100px;
margin: 50px;
}
div > * {
position: absolute;
width: 1px;
height: 100%;
top: 0px;
border: 1px solid red;
}
#child1 {
left: -15px;
}
#child2 {
left: -21px;
}
#child3 {
left: -27px;
}
<div class="container">
<div id="child1"></div>
<div id="child2"></div>
<div id="child3"></div>
</div>
JSFiddle here
Here is what I see in my browser (using Chrome 102.0.5005.115):
The second child does not seem to be the same width as the other children.
Looks like a bug on your browser. For me, the code snippet works on Chrome(Version 103.0.5060.53), Firefox (Version 102.0), and Safari(Version 15.5).
I suggest updating Chrome from chrome://settings/help.

Position:sticky element which is nested into another sticky element doesn't work in Edge

I'm trying to develop table with fixed header and fixed sevelar columns.
I use position: sticky for this and it works well in Chrome/Safari/Firefox, but I found issue in Microsoft Edge.
If you create element with position:sticky; top: 0; and insert other element with position: sticky; left: 0;, Edge ignores nested element.
Open this example in Edge and check this: https://codepen.io/finethanks/pen/aRWByx
Is it a bug of Edge?
.wrapper {
border: 1px solid #ccc;
width: 200px;
height: 200px;
overflow: auto;
}
.content {
width: 1000px;
height: 1000px;
}
.sticky-wrapper {
height: 30px;
background: red;
position: sticky;
top: 0;
}
.item {
width: 50px;
height: 20px;
background: yellow;
position: sticky;
left: 0;
}
<div class="wrapper">
<div class="content">
<div class="sticky-wrapper">
<div class="item"></div>
</div>
</div>
</div>
"sticky" value not supported in Edge version less than 16.
Please see the browser compatibility of position css property on this link: https://developer.mozilla.org/en-US/docs/Web/CSS/position#Browser_compatibility

IE with position absolute element will create horizontal scroll

I want to use position: absolute to create a centered element, but it will create a horizontal scrollbar on Internet Explorer 11. Please see the script below. Anyone here knows how to fix this problem?
*Update: I figured out that using overflow:hidden seems to solve this problem somehow. But when there are another one outside of the container, it will be hidden as well.
.container {
width: 80%;
margin: 0 auto;
height: 100vh;
border: 1px solid green;
position: relative;
overflow: hidden; /*This one is not the solution, though*/
}
.content {
width: 80%;
height: 30px;
position: absolute;
top: 50px;
left: 50%;
transform: translate(-50%, 0);
border: 1px solid red;
}
.another-content {
width: 40px;
height: 40px;
border: 1px solid blue;
position: absolute;
bottom: 20px;
right: -20px;
}
<div class="container">
<div class="content"></div>
<div class="another-content"></div>
</div>
You need to add following properties with the position absolute in IE
position: absolute;
top:0;
right: 0;
left: 0;
bottom:0; //specify all including bottom:0
The scrollbar show up in all browsers, not only IE. You can do the following:
The biggest issue is that the left: 50% and width: 80% together are adding to the total width and forcing the horizontal scrollbar to show up in some browsers (e.g. Internet Explorer and MS Edge). You set the width to 80%, so divide the remaining 20% between the left and right border and you'll end up with 10% each. Simply use left: 10% to achieve the same result, but without the side effect of the horizontal scrollbar.
Also when you set the size to 100% and then add border, those borders will be out of the view and cause the scrollbars to show up. This is the same in all browsers. Use box-sizing: border-box to force the browser to include the border in the height and width calculation.
The height: 100vh makes the box height equals to the view port. However, the body has default margins which vary from one browser to another. You can either set those margins to zero body { margin: 0; }, or change the height to height: 100% which is 100% of the container which the body in this case.
Try this:
.container {
width: 100%;
height: 100%;
border: 1px solid green;
position: relative;
box-sizing: border-box;
}
.content {
width: 80%;
height: 30px;
position: absolute;
top: 50px;
left: 10%;
border: 1px solid red;
}
<div class="container">
<div class="content"></div>
</div>
Thanks for your replies. Though they are not direct solution, they helped me a lot to figure out how to solve it.
The cause is as what Racil Hilan said. When I use left:50% and width:80%, the content width will be added up and create a horizontal scroll, which is not ignored by only IE. And my point is to avoid creating that added-up width. Here is my two way to workaround this one.
* {
box-sizing: border-box;
}
.container {
width: 100%;
height: 100vh;
border: 1px solid green;
position: relative;
}
.content {
width: 80%;
height: 30px;
position: absolute;
top: 50px;
left: 0;
right: 0;
border: 1px solid red;
margin: 0 auto;
}
.content-wrapper {
border: 1px solid black;
height: 30px;
position: absolute;
top: 100px;
left: 0;
right: 0;
}
.another-content {
width: 80%;
display: block;
height: 100%;
border: 1px solid red;
margin: 0 auto;
}
<div class="container">
<div class="content"></div>
<div class="content-wrapper">
<div class="another-content"></div>
</div>
</div>

JQuery Mobile Button - Absolute position FROM center?

I'm trying to create something in JQuery Mobile, however I need to be able to position a button from the center. Right now, the button is positioned from the top-left corner, and as such if I resize the window, everything is horribly off-center.
<body>
<button>Button</button>
<div />
</body>
div {
position: absolute;
width: 200px;
height: 200px;
background-color: black;
}
button {
position: absolute;
top: 200px;
left: 200px;
}
Fiddle: http://jsfiddle.net/chpt3x1v/4/
I couldn't get JQM working in JSFiddle (didn't know how without it showing loads of errors), so I just used a regular button, but the same premise applies.
TWO IMAGES:
As you can see, it is completely off-center.
UPDATED ANSWER:
You need to give the button a set width and height, and then set the top margin to negative one half the height, and the left margin to negative half the width:
Updated DEMO
<div class="thediv"></div>
<button data-role="none" class="theButton">Button</button>
.thediv {
position: absolute;
width: 200px;
height: 200px;
background-color: black;
}
.theButton {
position: fixed; /* or absolute */
top: 200px;
left: 200px;
width: 80px;
height: 80px;
margin-top: -40px;
margin-left: -40px;
}
ORIGINAL ANSWER:
You can use fixed positioning and a negative margin to keep it centered:
<div data-role="page" id="page1">
<div role="main" class="ui-content">
<div class="centered"><button>Button</button></div>
</div>
</div>
.centered {
position: fixed; /* or absolute */
top: 50%;
left: 50%;
background-color: black;
width: 200px;
height: 200px;
margin-top: -100px;
margin-left: -100px;
}
.centered button {
margin: 0 !important;
height: 100%;
}
Updated FIDDLE
Firstly your code doesn't have an opening tag. Secondly, you need to have the parent element, i.e. the div, positioned as relative.
Third, you've positioned your button to the very edge of the div by using the same dimensions. Try:
<body>
<div>
<button>Button</button>
<div />
</body>
div {
position: relative;
width: 200px;
height: 200px;
background-color: black;
}
button {
position: absolute;
top: 50%;
left: 50%;
z-index: 1;
}
The z-index property will allow the button to overlay the div.

Padding not working for my text

html:
<div id="main">
<div style="position: absolute; height: 150px; width: 400px; left: 290px;"><img src="HEAD-IMAGE.jpg" /></div>
<div style="position: absolute; height: 300px; width: 233px; top: 180px;"><img src="LEFT-IMAGE.jpg" />(below head)</div>
<div style="position: absolute; top: 200px; left: 270px;">TEXT (next to left image)</div>
</div>
css:
div#main{
position: absolute;
top: 141px; left: 50%;
height: 100%; width: 960px;
padding: 10px;
margin-left: -490px;
text-align: justify;
background-color: yellow;
}
my padding from #main works for my images but not for my text (right & bottom padding).
Why is this happening?
In your example, only the text div has a top and left property. The two divs containing the images only contain one of these properties:
The header div has left: 290px;, so it gets its y-axis position moved by the top padding.
The left div has top: 180px; so it gets its x-axis position moved by the left padding.
The text div has top: 200px; left: 270px; so its x and y-axis are not affected by the padding.
To illustrate this, for this example the text div has had its left property removed. It is now affected by the left padding of its container:
("Show code snippet" and run it)
#main {
position: absolute;
top: 141px;
left: 50%;
height: 100%;
width: 960px;
padding: 50px;
margin-left: -290px;
text-align: justify;
background-color: yellow;
}
.header {
position: absolute;
height: 150px;
width: 400px;
left: 290px;
background: #F00;
}
.left {
position: absolute;
height: 300px;
width: 233px;
top: 180px;
background: #F00;
}
.text {
position: absolute;
top: 200px;
background: #F00;
}
<div id="main">
<div class="header">
<img src="http://www.placehold.it/200" />
</div>
<div class="left">
<img src="http://www.placehold.it/200" />
</div>
<div class="text">You can't handle the truth, soldier!</div>
</div>
Is position: absolute the best way to layout my elements?
Depends... position: absolute removes elements from the normal flow of the document. That is, each element is essentially invisible to the other. This is particularly problematic if you wish to create a flexible layout, which can re-size in accordance with the users browser height / width.
Can you show me another way to layout HTML elements?
Sure! There are many ways to layout a page without resorting to position: absolute. Here is a basic example using display: flex — a newer way to layout elements. It does not enjoy 100% browser support yet, so this is purely an example of one technique :)
Read more:
about vw and vh units on the MDN
about flexbox over on CSS-Tricks - A Complete Guide to Flexbox
about flexbox browser support
Flex example
Note how the elements resize when the example is made full-screen.
* {
margin: 0;
padding: 0;
}
body {
width: 80vw;
max-width: 800px;
margin: 0 auto;
background: #424242;
}
header {
background: #e91e63;
height: 20vh;
}
.wrap {
display: flex;
}
.left {
background: #fce4ec;
flex: 1;
}
.content {
background: #fafafa;
min-height: 70vh;
flex: 2;
}
footer {
height: 10vh;
background: #c51162;
}
<header>
I am header
</header>
<div class="wrap">
<div class="left">
I am sidebar
</div>
<div class="content">
I am content
</div>
</div>
<footer>
I am footer, hear me roar! RWAR!
</footer>
Define a class .child for your <div>
<div class="child">
and define style accordingly
.child { padding: 10px; }
Use position: relative; on the child divs to make them account for the parent divs padding.
problem is you give left and top to text div that why not accept padding,simply remove left to text div then it will accept the padding...