How can I have a div with 100% height that has a particular aspect ratio, e.g. 2:3?
For example, if the outer element has a height of 900px, the width of the inner element should be 600px, but this should be responsive.
I don't want to use any JavaScript for this.
Using the CSS3 flexible box model would be fine.
If you are targeting modern browsers that support CSS3, you can try the following.
Consider the following HTML snippet:
<div class="wrapper">
<div class="inner">Inner content...</div>
</div>
and apply the following CSS rules:
html, body {
height: 100%;
}
body {
margin: 0;
}
.wrapper {
background-color: lightblue;
height: 100%;
}
.wrapper .inner {
margin: 0 auto;
background-color: beige;
height: 100%;
width: 66.6666666666vh;
}
The .wrapper element takes up 100% of the view port height because I have set
height: 100% on the body and html elements.
The inner wrapper .inner has a height: 100% and fills up the parent block.
To set the .inner width, use the viewport-percentage length vh that scales with the height of the parent block.
In this example, 66.66vh means 66.66% of the vertical height, which corresponds to a 2:3 aspect ratio (width:height).
See demo at jsFiddle
Reference: http://www.w3.org/TR/css3-values/#viewport-relative-lengths
Browser Compatibility
The vh unit and other vertical percentage lengths have pretty good support with the latest browsers, see the reference below for more details.
See reference:
https://developer.mozilla.org/en-US/docs/Web/CSS/length#Browser_compatibility
Alternative Approach Using a Spacer Image
Consider the following HTML:
<div class="ratio-wrapper">
<img class="spacer" src="http://placehold.it/20x30">
<div class="content">Some content...</div>
</div>
and apply the following CSS:
.ratio-wrapper {
position: relative;
display: inline-block;
border: 1px solid gray;
height: 500px; /* set the height or inherit from the parent container */
}
.ratio-wrapper .spacer {
height: 100%; /* set height: 100% for portrait style content */
visibility: hidden;
vertical-align: top;
}
.ratio-wrapper .content {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
padding: 20px;
}
The .ratio-wrapper container has two child elements, an img.spacer and div.content.
The image as a portrait aspect ratio, for example, 20x30 (wxh) and is set to expand to fill the height of the parent container using height: 100%. The image is hidden from view but retains its space in the parent block.
The .content element is positioned absolutely to fill the parent container and can contain any content. Because .content is constrained in height and width, the content could overflow in some cases, so setting overflow: auto may be appropriate.
See demo at: http://jsfiddle.net/audetwebdesign/BVkuW/
Related question and answer:
In Fluid Container, Can I Make Elements as Tall as they Are Wide?
You can do this by sticking a 2px by 3px image and an inner div as siblings into an outer div which has display: inline-block; applied. Now when you set the image to have a height of 100%, and you absolutely position the inner div to be as high and wide as its ancestor, you can set the height of the outer div, and the width of all elements involved will be exactly equal and based on the aspect ratio of the image.
Here's a jsFiddle demonstrating this approach.
HTML
<div>
<div>2 by 3</div>
<img src=".../twobythree.png" />
</div>
CSS
body > div {
height: 300px;
position: relative;
display: inline-block;
}
img {
display: block;
height: 100%;
}
div > div {
position: absolute;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
}
Related
This question already has answers here:
Percentage Height HTML 5/CSS
(7 answers)
Closed 1 year ago.
I have the following code:
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
padding: 10px;
}
body {
position: relative;
}
#outer {
position: absolute;
top: 0;
left: 0;
border: 2px solid green;
padding: 5px;
max-width: 100%;
max-height: 100%;
}
#inner {
border: 2px solid red;
font-size: 5em;
overflow: auto;
height: 100%;
}
<html>
<body>
<div id="outer">
<div id="inner">
This is a loooooooonnnng<br>text.<br> Spanning
<br>multiple<br>lines.
</div>
</div>
</body>
</html>
Resize the browser window and you can see that the inner div is expanding more than the outer div in height. But, if I specify a height, say height: 1000px; on the outer div, the inner div gets resized to fit outer div's height. Why is it behaving like that? Isn't max-height supposed to work without specifying a height?
The max-height property sets the maximum height of an element. It prevents the used value of the height property from becoming larger than the value specified for max-height.
When you use max-height: 100% on the parent container, the percentage is calculated with respect to the height of the generated box's containing block. If the height of the containing block is not specified explicitly, and this element is not absolutely positioned, the percentage value is treated as none.
In terms of max-height, if the content is larger than the maximum height, it will overflow.
To allow the child container to always fit inside the parent container, you can just use CSS Flexbox or add overflow: auto to #outer so then it does fit 100% of the content within it's content-box. Without using either overflow or Flexbox, the child container's content is larger than the maximum height and therefore overflows out the bottom of #outer when the viewport height is small.
Removing the height: 100% declaration from #inner while making the parent container a Flexbox with display: flex seems to do the trick without having to add overflow: auto to #outer.
* {
box-sizing: border-box;
}
html,
body {
height: 100%;
padding: 10px;
}
body {
position: relative;
}
#outer {
position: absolute;
top: 0;
left: 0;
border: 2px solid green;
padding: 5px;
max-width: 100%;
max-height: 100%;
display: flex;
}
#inner {
border: 2px solid red;
font-size: 5em;
overflow: auto;
}
<html>
<body>
<div id="outer">
<div id="inner">
This is a loooooooonnnng<br>text.<br> Spanning
<br>multiple<br>lines.
</div>
</div>
</body>
</html>
Simply remove the max-height declaration from the #outer div.
To fix your issue, supply a height property to your #outer div.
#outer {
/* ... */
height: 100%;
}
I have a div (div1) inside some other divs. Now I want this div to have the same width as the body (take up full width of display), but always have the same height and position as its parent (div2). I've tried using position: absolute; on this div (div1). Then I can either
set body to position: relative; and have div1 take up 100% width, but now I'm having trouble making the height always follow div2.
or set the parent (div2) to position: relative; and have div 1 take up 100% height, but now I can't make it follow the width of body.
It would be cool if CSS had the option of saying:
.div1 {
height: 100%(.div2);
width: 100%(body);
position: 0(.div2);
}
Or something like that
JSFiddle with the relevant bits: https://jsfiddle.net/Hamleyburger/fqe5o46c/1/#&togetherjs=K02DaSO2nR
What I want is the div ".selectable" to have a div (inside?) that shows on hover and fits the heights of ".selectable" (parent) and the entire width of the body.
Extra, maybe relevant info:
I'm using Bootstrap and (Jinja2) templating. All the divs so far are taking their base widths from a wrapper container (.main) in my base template that I've set to be (responsively) narrower than body. If I were to remove .main
div I would have to set width on many individual divs. That would solve it (I could make all the divs that aren't div1 narrower), but it wouldn't be very DRY. I'm using SASS, if that helps.
It's possible to force a div to fill the whole viewport width using vw. It's a bit weird though:
body,
html {
margin: 0;
padding: 0;
}
.outer {
width: 300px;
height: 300px;
background-color: #eeeeee;
margin: 0 auto;
position: relative
}
.inner {
width: 100vw;
height: 100%;
background-color: rgba(0, 0, 0, 0.1);
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
}
<div class="outer">
<div class="inner"></div>
</div>
I'd recommend to make your outer div full width and give the inner one a specific width:
body,
html {
margin: 0;
padding: 0;
}
.outer {
width: 100%;
background-color: #eeeeee;
position: relative
}
.inner {
width: 300px;
height: 300px;
margin: 0 auto;
background-color: rgba(0, 0, 0, 0.1);
}
<div class="outer">
<div class="inner"></div>
</div>
<div class="ui-datatable-scrollable-view" style="
width: 100%;
position: relative;
">
<div class="ui-widget-header ui-datatable-scrollable-header" style="position:fixed;top:50px">
</div>
</div>
I have a div element which is stick on the top of the page. I have given the css as
width: 100%;
position: fixed;
z-index: 2;
But it is not taking the width.
I tried several ways to do that.
I tried making the parent div as position:relative but that is not working;
I think my element is taking the width equal to the width of screen.I tried giving the fixed width to it to fit the required size. But on change of screeen size it won't work proper.
I want it to take the width of its parent.
I just tried using your css and it works for me
HTML
<div class="container"></div>
CSS
.container {
width: 100%;
height: 100px;
position: fixed;
z-index: 2;
background-color: black;
}
Check if your html and body elements have a width of 100%
Link to codepen: https://codepen.io/athapliyal/pen/VzqyBX
#test {
width: 100vw;
position: fixed;
z-index: 2;
height: 50px;
background-color: blue;
}
<div id="test">
If you provide the width as percentage it is relative to the parent of the div, so you could define the parent with a width of 100% to make it working. To provide you an example we would need more code.
So the other solution is by defining the width with 100vw.
1vw = 1% of viewport (window) width.
This way it will be relative to the viewport and doesn´t care about the parent.
For the height you can use: vh (Viewport height)
I believe that the width is in fact 100%, however since you did not set a height, it appears invisible.
HTML
<div class="parent">
<div class="child"></div>
</div>
CSS
.parent {
width: 800px;
background-color: grey;
height: 600px;
}
.child {
position: fixed;
background-color: blue;
width: inherit; height: 100px;
}
I'm not too sure if this can be achieved in pure CSS, though it would be preferable. I have an image:
<img src="#" class="article-thumb">
CSS:
.article-thumb {
height: 55%;
}
So, how can I make the width to equal whatever the height is? I'm trying to achieve an image that's a perfect circle (so I obviously have some border-radius applied), and that can also scale to fill as much as it's container (actually to fill 55% of it's container in height to be specific)
Here is one way of doing it which involves some extra mark-up so it may not appeal to everyone.
Let .wrap be some parent, containing block with some width and height (can be in % values).
Define an inline-block child container, .framer, whose width is a % of the parent, for example, 23%.
Within .framer, place a square image .aspect-setter (dimensions not critical, just keep it small) and set the width to 100%. The image will then scale to the width of .framer and .framer will shrink-to-fit the image (because it is an inline-block) and keep its intrinsic shape (because height is auto). Use visibility: hidden to hide the image while keeping it in the content flow.
Define .avatar-container as an absolutely positioned element and use the offsets to scale it to fit .framer. Since .framer is square, .avatar-container will also be square.
Using an extra image is not overly elegant, but it gets the job done.
.wrap {
width: 400px;
height: 250px;
border: 1px dotted gray;
}
.framer {
display: inline-block;
position: relative;
border: 1px dashed blue;
width: 23%;
}
.aspect-setter {
vertical-align: top;
visibility: hidden;
width: 100%;
height: auto;
}
.avatar-container {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border-radius: 50%;
background-image: url('http://www.wisportsfan.com/siteresources/images/defaultavatar.jpg');
background-size: cover;
}
<div class="wrap">
<div class="framer">
<img class="aspect-setter" src="http://placehold.it/100x100">
<div class="avatar-container"></div>
</div>
</div>
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>