[html] 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

_x000D_
_x000D_
.base{_x000D_
        background-color:green;_x000D_
     width:200px;_x000D_
     height:200px;_x000D_
     overflow:auto;_x000D_
     position:relative;_x000D_
 }_x000D_
_x000D_
    .vert-align{_x000D_
  padding-top:50%;_x000D_
  height:50%;_x000D_
 }
_x000D_
<!-- and used the following div structure. -->_x000D_
_x000D_
    <div class="base">_x000D_
       <div class="vert-align">_x000D_
        Content Here_x000D_
       </div>_x000D_
    </div>
_x000D_
_x000D_
_x000D_

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?

This question is related to html css vertical-alignment

The answer is


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.

_x000D_
_x000D_
.base{_x000D_
    background-color: green;_x000D_
    width: 200px;_x000D_
    height: 200px;_x000D_
    overflow: auto;_x000D_
    position: relative;_x000D_
}_x000D_
    _x000D_
.vert-align {_x000D_
    position: absolute;_x000D_
    top: 50%;_x000D_
    transform: translate(0, -50%);_x000D_
}
_x000D_
    <div class="base">_x000D_
        <div class="vert-align">_x000D_
            Content Here_x000D_
        </div>_x000D_
    </div>
_x000D_
_x000D_
_x000D_

There is another a solution using flex box.

_x000D_
_x000D_
.base{_x000D_
    background-color:green;_x000D_
    width: 200px;_x000D_
    height: 200px;_x000D_
    overflow: auto;_x000D_
    display: flex;_x000D_
    align-items: center;_x000D_
}
_x000D_
<div class="base">_x000D_
    <div class="vert-align">_x000D_
        Content Here_x000D_
    </div>_x000D_
</div>
_x000D_
_x000D_
_x000D_

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.

_x000D_
_x000D_
.resize {_x000D_
  width: 400px;_x000D_
  height: 200px;_x000D_
  resize: both;_x000D_
  overflow: hidden;_x000D_
}_x000D_
_x000D_
.outer {_x000D_
  height: 100%;_x000D_
  background-color: red;_x000D_
}_x000D_
_x000D_
.middle {_x000D_
  writing-mode: vertical-lr;_x000D_
  margin: 0 10%;_x000D_
  width: 80%;_x000D_
  height: 100%;_x000D_
  background-color: yellow;_x000D_
}_x000D_
_x000D_
.inner {_x000D_
  writing-mode: horizontal-tb;_x000D_
  margin: 10% 0;_x000D_
  width: 100%;_x000D_
  height: 80%;_x000D_
  background-color: blue;_x000D_
}
_x000D_
<div class="resize">_x000D_
  <div class="outer">_x000D_
    <div class="middle">_x000D_
      <div class="inner"></div>_x000D_
    </div>_x000D_
  </div>_x000D_
</div>
_x000D_
_x000D_
_x000D_

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;
}

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.


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.


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>

Examples related to html

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment

Examples related to css

need to add a class to an element Using Lato fonts in my css (@font-face) Please help me convert this script to a simple image slider Why there is this "clear" class before footer? How to set width of mat-table column in angular? Center content vertically on Vuetify bootstrap 4 file input doesn't show the file name Bootstrap 4: responsive sidebar menu to top navbar Stylesheet not loaded because of MIME-type Force flex item to span full row width

Examples related to vertical-alignment

How to center div vertically inside of absolutely positioned parent div Bootstrap how to get text to vertical align in a div container How to vertically center a container in Bootstrap? vertical align middle in <div> Vertically align an image inside a div with responsive height Why is width: 100% not working on div {display: table-cell}? Align text to the bottom of a div How to display list items as columns? Add vertical whitespace using Twitter Bootstrap? vertical alignment of text element in SVG