CSS - margin top of 50% is more than 50% - html

I want a child div with a op-margin via percentage. The y-position shall be 50% percent of the parent div. But it is somehow more. Why isn't it 50% ?
js fiddle
HTML
<div class="content">
<header></header>
</div>
CSS
.content {
width: 300px;
height: 200px;
background: blue;
position: relative;
clear: both;
}
.content header {
width: 100px;
height: 100px;
margin-top: 50%;
background: red;
position: relative;
float: left;
}

This is because when it comes to top/bottom margins and paddings in percentages, the values will be taken as the fractional width of the parent element, not the height. According to the W3C definition:
The [margin] percentage is calculated with respect to the width of the
generated box's containing block. Note that this is true for
'margin-top' and 'margin-bottom' as well. If the containing block's
width depends on this element, then the resulting layout is undefined
in CSS 2.1.
This question has been addressed before in StackOverflow - see here.
Suggestion: If you would want to position an element in the center vertically, you can use the following trick instead:
Position the child element absolutely
Declare dimensions for the parent, such that the parent's dimensions do not rely on those of the child
Position the child element 50% from the top
Use a nifty trick of CSS 2D translation.
Here's the modified CSS from your fiddle that works:
.content header {
width: 100px;
height: 100px;
top: 50%;
background: red;
position: absolute;
-webkit-transform: translate(0, -50%);
transform: translate(0, -50%);
}
http://jsfiddle.net/teddyrised/73xkT/7/

Change child's position from relative to absolute.
Instead of margin-top use top
http://jsfiddle.net/73xkT/5/
.content header {
top: 50%;
position: absolute;
}

Related

HTML: How to place object relative to the screen size?

How to place object in percentage of the entire screen in HTML, not just placing next to the previous object? For example, <div> at the location of 50% screen's width, 30% screen's height.
There's some requirements for this:
Objects should be able to be placed to the desired location by percentage of the entire screen, no matter of other objects.
Objects should be able to overwrap other objects at the same location.
Sorry for poor English :|
I am not sure about your question. Let me try to answer it. In the css we have variable call vh for viewport height and vw for viewport width.
The idea is to place the element 30% of height = 30vh, and 50% width = 50vw. We can set the parent element to have relative, and the child that you want to set position with absolute position.
It would be something like below. Thanks
body {
position: relative;
width: 100%;
height: 100%;
display: block;
color: #fff;
background: #000;
}
#screen .child {
position: absolute;
top: 30vh;
left: 50vw;
background: red;
width: 100px;
height: 50px;
}
<div id="screen">
Parent
<div class="child">
</div>
</div>
Try this CSS
.fixed-div{
position: fixed;
left: 50vw;
top: 30vh;
transform: translate(-50%, -50%); /* Moves the center of the element to its original top left corner*/
z-index: 1;
}

CSS transform scale (down) doesn't center element using margin 0 auto when scaled element was bigger than container before scaling

It appears that when scaling down an element which previously did not fit in its container, margin: 0 auto will no longer center the element within its parent (note that using transform-origin: center center does not solve this). This is because the auto margins seem to apply before the scaling rather than after (I expected the latter).
While playing with this, I eventually managed to center the element within its container, but only using absolute positioning:
position: absolute;
transform: translateX(-50%) scale(0.5, 0.5);
left: 50%;
This is a very popular technique, but in this particular case, it is important to place the translateX function before the scale function, as these are executed in the defined order.
Following is a snippet of code to illustrate the issue (also on CodePen: https://codepen.io/liranh85/pen/qVewQp)
.container {
border: 3px solid black;
width: 500px;
height: 200px;
margin: 0 auto;
position: relative;
}
.scaled {
background-color: blue;
width: 600px;
/* width: 400px; */
height: 100%;
transform: scale(0.5, 0.5);
/* transform: translateX(-50%) scale(0.5, 0.5); */
margin: 0 auto;
/* position: absolute;
left: 50%; */
}
<div class="container">
<div class="scaled"></div>
</div>
Notice that:
The element is not centered using auto margins when its width is bigger than its container's.
When giving the scaled element a width smaller than its container, it will remain centered after scaling (e.g. try using width: 400px).
When using absolute positioning, as mentioned above, it is possible to center the element.
I'm wondering:
Has anyone else run into this issue?
Is this the best way to center such an element?
Am I correct to say the auto margin cannot be used to center such an element?
You need to use
transform-origin: center;
Take a look at some of the docs on this
https://developer.mozilla.org/en-US/docs/Web/CSS/transform-origin
Your suspicions are correct: when the element is too wide to fit within its parent, margin: 0 auto will not horizontally center the element. It will instead cause the element to overflow at the far right edge of its parent.
You can center your element properly by using translateX(-50%) before you scale the element, on top of positioning the element absolutely and using left: 50%. The reason why this works is because by absolutely positioning your child element, you are taking it out of the layout flow of the parent and therefore can position it in the horizontal center of the parent.
Note: This solution assumes that you are using height: 100%. If vertical centering of a non-full-height element is required, update the styles so that you're using translate(-50%, -50% and top: 50%; left: 50%.
Here is a proof-of-concept example based on your code you've provided:
.container {
border: 3px solid black;
width: 500px;
height: 200px;
margin: 0 auto;
position: relative;
}
.scaled {
background-color: blue;
width: 600px;
height: 100%;
transform: translateX(-50%) scale(0.5, 0.5);
position: absolute;
left: 50%;
}
<div class="container">
<div class="scaled"></div>
</div>

CSS positioning relative to div

I have two images inside a div. I'd like to position these images using percent relatively to the parent div.
Here's a fiddle to understand: http://jsfiddle.net/b9ce626s/
I tried to set position: absolute; on the image but it uses window width.
I need the image on the very right be positioned at 95% of the red div, and not the window. I also don't want the left image impacts the positionning of the right one.
Add position: relative on #main so the position of the images are both based on that element (and not on the root element).
Example: http://jsfiddle.net/b9ce626s/1/
A page element with relative positioning gives you the control to absolutely position children elements inside of it.
https://css-tricks.com/absolute-positioning-inside-relative-positioning/
As a side note, if you assign a width with a percentage value to the images, it will be now based on the parent element width.
Try this..
Html
<div id="main">
<img id="card1" src="http://dynamic-projets.fr/wp-content/uploads/2012/08/attach_image.png" alt="KH" />
<img id="card2" src="http://www.rotaryd1650.org/images/main/IconesCollectionPro/128x128/image_gimp.png" alt="9H" />
</div>
Css
body, html {
width: 100%;
height: 100%;
margin: 0;
}
#main {
display: block;
width: 50%;
height: 50%;
background-color: red;
position:relative;
}
img {
position: absolute;
width: 5%;
}
#card1 {
left:5%;
}
#card2 {
right: 5%;
}
Fiddle Sample
#main {
display: block;
width: 50%;
height: 50%;
background-color: red;
position: relative;
}
Give main position: relative; like so:
#main {
display: block;
width: 50%;
height: 50%;
background-color: red;
position:relative;
}
This keyword lays out all elements as though the element were not positioned, and then adjust the element's position, without changing layout (and thus leaving a gap for the element where it would have been had it not been positioned). The effect of position:relative on table-*-group, table-row, table-column, table-cell, and table-caption elements is undefined.
JSFiddle Demo

margin-top: 50% works strange

I would like to center a div both horizontally, and vertically. I tried to manage it like this:
div {
background: red;
width: 200px;
height: 200px;
position: absolute;
margin-top: 50%;
margin-left: 50%;
top: -100px;
left: -100px;
}
The margin-top xx% depends on the width of the page for some reason, not the height.
jsFiddle: http://jsfiddle.net/MxE8Y/embedded/result/
What do I wrong? How to fix it without using javascript?
the reason of vertical % related to parent's width:
The percentage is calculated with respect to the width of the generated box's containing block. Note that this is true for 'margin-top' and 'margin-bottom' as well. If the containing block's width depends on this element, then the resulting layout is undefined in CSS 2.1.
http://www.w3.org/TR/CSS2/box.html#margin-properties
the answer of Hashem Qolami tells you what to do instead :)
Else, you can keep everything in the flow using display: (display:table) http://jsfiddle.net/MxE8Y/2/
body, html {
background: green;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
display:table;
}
body {
display:table-cell;
vertical-align:middle;
}
div {
background: red;
width: 200px;
height: 200px;
margin:auto;
}
or http://codepen.io/anon/pen/iJgbv/ (display:flex) :
html,body {
height:100%;
width:100%;
margin:0;
}
body {
display:flex;
}
div {
width:100px;
height:100px;
background:gray;
margin:auto;
}
A percentage value for top/bottom padding/margin is relative to the width of box's containing block.
8.3 Margin properties: 'margin-top', 'margin-right', 'margin-bottom', 'margin-left', and 'margin'
<percentage> The percentage is calculated with respect to the width
of the generated box's containing block. Note that this is true for
'margin-top' and 'margin-bottom' as well. If the containing block's
width depends on this element, then the resulting layout is undefined
in CSS 2.1.
Try using top and left properties for positioning the absolutely positioned element and use negative values on top/left margin:
EXAMPLE HERE
div {
background: red;
width: 200px;
height: 200px;
position: absolute;
top: 50%;
left: 50%;
margin-top: -100px;
margin-left: -100px;
}
A 2016 option using the translate -50% method
css
div {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
}
fiddle
http://jsfiddle.net/Hastig/MxE8Y/6/

How to set the margin or padding as percentage of height of parent container?

I had been racking my brains over creating a vertical alignment in css using the following
.base{
background-color:green;
width:200px;
height:200px;
overflow:auto;
position:relative;
}
.vert-align{
padding-top:50%;
height:50%;
}
<!-- and used the following div structure. -->
<div class="base">
<div class="vert-align">
Content Here
</div>
</div>
While this seemed to work for this case, i was surprised that when i increased or decreased the width of my base div, the vertical alignment would snap. I was expecting that when I set the padding-top property, it would take the padding as a percentage of the height of the parent container, which is base in our case, but the above value of 50 percent is calculated as a percentage of the width. :(
Is there a way to set the padding and/or margin as a percentage of the height, without resorting to using JavaScript?
The fix is that yes, vertical padding and margin are relative to width, but top and bottom aren't.
So just place a div inside another, and in the inner div, use something like top:50% (remember position matters if it still doesn't work)
An answer to a slightly different question: You can use vh units to pad elements to the center of the viewport:
.centerme {
margin-top: 50vh;
background: red;
}
<div class="centerme">middle</div>
Here are two options to emulate the needed behavior. Not a general solution, but may help in some cases. The vertical spacing here is calculated on the basis of the size of the outer element, not its parent, but this size itself can be relative to the parent and this way the spacing will be relative too.
<div id="outer">
<div id="inner">
content
</div>
</div>
First option: use pseudo-elements, here vertical and horizontal spacing are relative to the outer. Demo
#outer::before, #outer::after {
display: block;
content: "";
height: 10%;
}
#inner {
height: 80%;
margin-left: 10%;
margin-right: 10%;
}
Moving the horizontal spacing to the outer element makes it relative to the parent of the outer. Demo
#outer {
padding-left: 10%;
padding-right: 10%;
}
Second option: use absolute positioning. Demo
#outer {
position: relative;
}
#inner {
position: absolute;
left: 10%;
right: 10%;
top: 10%;
bottom: 10%;
}
To make the child element positioned absolutely from its parent element you need to set relative position on the parent element AND absolute position on the child element.
Then on the child element 'top' is relative to the height of the parent. So you also need to 'translate' upward the child 50% of its own height.
.base{
background-color: green;
width: 200px;
height: 200px;
overflow: auto;
position: relative;
}
.vert-align {
position: absolute;
top: 50%;
transform: translate(0, -50%);
}
<div class="base">
<div class="vert-align">
Content Here
</div>
</div>
There is another a solution using flex box.
.base{
background-color:green;
width: 200px;
height: 200px;
overflow: auto;
display: flex;
align-items: center;
}
<div class="base">
<div class="vert-align">
Content Here
</div>
</div>
You will find advantages/disavantages for both.
This can be achieved with the writing-mode property. If you set an element's writing-mode to a vertical writing mode, such as vertical-lr, its descendants' percentage values for padding and margin, in both dimensions, become relative to height instead of width.
From the spec:
. . . percentages on the margin and padding properties, which are always calculated with respect to the containing block width in CSS2.1, are calculated with respect to the inline size of the containing block in CSS3.
The definition of inline size:
A measurement in the inline dimension: refers to the physical width (horizontal dimension) in horizontal writing modes, and to the physical height (vertical dimension) in vertical writing modes.
Example, with a resizable element, where horizontal margins are relative to width and vertical margins are relative to height.
.resize {
width: 400px;
height: 200px;
resize: both;
overflow: hidden;
}
.outer {
height: 100%;
background-color: red;
}
.middle {
writing-mode: vertical-lr;
margin: 0 10%;
width: 80%;
height: 100%;
background-color: yellow;
}
.inner {
writing-mode: horizontal-tb;
margin: 10% 0;
width: 100%;
height: 80%;
background-color: blue;
}
<div class="resize">
<div class="outer">
<div class="middle">
<div class="inner"></div>
</div>
</div>
</div>
Using a vertical writing mode can be particularly useful in circumstances where you want the aspect ratio of an element to remain constant, but want its size to scale in correlation to its height instead of width.
Other way to center one line text is:
.parent{
position: relative;
}
.child{
position: absolute;
top: 50%;
line-height: 0;
}
or just
.parent{
overflow: hidden; /* if this ins't here the parent will adopt the 50% margin of the child */
}
.child{
margin-top: 50%;
line-height: 0;
}
This is a very interesting bug. (In my opinion, it is a bug anyway) Nice find!
Regarding how to set it, I would recommend Camilo Martin's answer. But as to why, I'd like to explain this a bit if you guys don't mind.
In the CSS specs I found:
'padding'
Percentages: refer to width of containing block
… which is weird, but okay.
So, with a parent width: 210px and a child padding-top: 50%, I get a calculated/computed value of padding-top: 96.5px – which is not the expected 105px.
That is because in Windows (I'm not sure about other OSs), the size of common scrollbars is per default 17px × 100% (or 100% × 17px for horizontal bars). Those 17px are substracted before calculating the 50%, hence 50% of 193px = 96.5px.
A 50% padding wont center your child, it will place it below the center. I think you really want a padding-top of 25%. Maybe you're just running out of space as your content gets taller? Also have you tried setting the margin-top instead of padding-top?
EDIT: Nevermind, the w3schools site says
% Specifies the padding in percent of the width of the containing element
So maybe it always uses width? I'd never noticed.
What you are doing can be acheived using display:table though (at least for modern browsers). The technique is explained here.
CSS Grid with empty row
This approach probably only makes sense if you're already using css-grid for the container in question, but if you are you can create an empty row with a percentage that (because it is a row) will be a percentage of the height.
.wrapper
{
border: 2px solid red;
width: 400px;
height: 200px;
display: grid;
grid-template-rows: 10% 1fr;
}
.child
{
background: orange;
width: 50px;
height: 50px;
grid-area: 2/1;
}
<div class="wrapper">
<div class="child">
</div>
</div>