Fill a parent div while maintaining a ratio - css

I wish to have a div section that fills its div parent as much as possible while maintaining a ratio.
the render result would be like this :
What I do have so far :
html,
body {
height: 100%;
}
.parent {
/* Parent's height and width are unknown,
it could be dynamic, e.g. parent is part of a flex layout. */
height: 80%;
width: 90%;
border-style: solid;
border-width: 2px;
border-color: black;
}
.child {
width: 90vw;
/* 90% of viewport vidth */
height: 50.625vw;
/* ratio = 9/16 * 90 = 50.625 */
max-height: 90vh;
max-width: 160vh;
/* 16/9 * 90 = 160 */
margin: auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: #A0522D;
}
<div class="parent">
<div class="child">
content that is not images...
</div>
</div>
This css behaves like the way I want BUT this is using the viewport instead of the parent div which is a problem in real conditions.
I am looking for a way to fill based on the parent div.

Using aspect-ratio: 16 / 9; overflow: hidden; (aspect-ratio MDN docs) should give you the exact result you're looking for without needing to use the padding trick. Make sure the parent is set to display: grid or else it may not scale properly.
The aspect-ratio CSS property is supported by all major browsers (caniuse.com) except Safari, though Safari plans to add support this year. This is the best/correct way to achieve this effect, without having to resort to JavaScript or any hack solutions.
Related questions and answers here on Stack Overflow:
https://stackoverflow.com/a/66786774/3824249 (very similar to my solution)
https://stackoverflow.com/a/20593342/3824249 (another CSS-only alternative, though hackier using position: absolute for element positioning)
Here is my solution in action:
html, body { height: 100%; }
.parent {
display: grid;
resize: both;
height: 50%;
width: 90%;
border: 2px solid #000;
overflow: hidden;
}
.child {
width: 100%;
max-height: 100%;
margin: auto;
aspect-ratio: 16 / 9;
overflow: hidden;
box-sizing: border-box;
position: relative;
background: #a0522d;
text-align: center;
font-size: 20px;
color: white;
/* using the below to center the text, optional */
display: flex;
align-items: center;
justify-content: center;
}
<div style="padding: 5px 10px; margin-bottom: 10px; background: #f00; color: #fff; text-align: center; z-index: 1;">Resize the block below using the resize controls to see this in action.</div>
<div class="parent">
<div class="child">content that is not images...</div>
</div>

maybe add position absolute and it works, by setting top, right ,bottom,left to 0 with margin auto. you could as well use flex to center it or absolute with left 50% and transform -50% too.
body {
padding: 0;
margin: 0;
height: 100vh;
width: 100vh;
}
.child {
width: 90vw;
/* 90% of viewport vidth */
height: 50.625vw;
max-height: 90vh;
max-width: 160vh;
/* Adding this maybe min-width and min-height */
min-height: 90vh;
min-width: 160vh;
/* 16/9 * 90 = 160 */
background: #f7f7f7;
box-shadow: 0px 5px 30px 0px rgba(0, 0, 0, 0.18);
border-radius: 4px;
margin: auto;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Parent Child</title>
</head>
<body> <!-- parent -->
<div class="child"></div>
</body>
</html>

Use flexbox and padding. Use media queries to determine if the min-aspect-ratio of the viewport. Then adjust accordingly.
html,
body {
height: 100%;
}
.parent {
height: 100%;
width: 100%;
border-style: solid;
border-width: 2px;
border-color: black;
/* to center */
display: flex;
align-items: center;
justify-content: center;
}
.child {
width: 100vw;
/* 16:9 aspect ratio = 9 / 16 = 0.5625 = padding-bottom*/
padding-bottom: 56.25%;
background: #A0522D;
}
#media (min-aspect-ratio: 16/9) {
.child {
height: 100vh;
/*16:9 aspect ratio = 9 / 16 = 177.77 = width*/
width: 177.77vh;
padding: 0;
margin: 0px;
background: red;
}
}
<div class="parent">
<!-- the viewbox will provide the desired aspect ratio -->
<div class="child">
content that is not images...
</div>
</div>
Here's a fiddle.

So as to make child's dimensions dependent on parent container set position:relative of the parent container.
Normally when we make an element position:absolute it is positioned relative to initial containing block(i.e the <body>) unless any other closest parent container is given a position other than static(which is by default).So, by giving relative position to parent container we positioned .child element relative to .parent which was earlier positioned relative to the document or body.
This will work for you
html,
body {
height: 100%;
}
.parent {
/* Parent's height and width are unknown,
it could be dynamic, e.g. parent is part of a flex layout. */
position:relative;
height: 80%;
width: 90%;
border-style: solid;
border-width: 2px;
border-color: black;
}
.child {
width: 90%;
/* 90% of viewport vidth */
height: 50.625%;
/* ratio = 9/16 * 90 = 50.625 */
max-height: 90%;
max-width: 160%;
/* 16/9 * 90 = 160 */
margin: auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: #A0522D;
}
<div class="parent">
<div class="child">
content that is not images...
</div>
</div>

Related

How to resize images inside a flexbox without using a background image?

I know there are a LOT of examples of this, and I have tried all of them to no avail. I am trying to create a carousel component that resizes images according to its boundary. I am using it in a myriad of places, in a myriad of different ways, so it MUST be responsive. I also need the images to be clickable as normal images for a11y and customers (managing expectations).
Here is my fiddle so far: https://codepen.io/skamansam/pen/NWvroeY?editors=1100
I can get all of the elements to resize accordingly (using max-width/height). when I use an image that is wider than taller, all works well. When I use an image that is taller than wider and exceeds the height of the box, the image overflows instead of respecting the max-width/height properties.
The most common answer involves wrapping the image in an html element and setting the width/height there, which I have done, but it doesn't solve the problem. Another common answer involves using combinations of position values, which didn't give any better results than I already have. Using the inspector, you can clearly see that all the elements EXCEPT the image are correctly sized, and the image overflows the container.
Is there any other way to get the img tag to respect height: 100% in the same way it respects width: 100%?
you are using image with a very high resolution (500x800) , you have use little lower resolution otherwise you have to use overflow:hidden; on your wrapping div.Using max-width:100%; the image is already resizing itself but cannot resize further more, inspect the element to get a better understanding.
I made three changes:
Your slide needs width: auto; and height: 100%;
Your image needs width: 100%; and height: 100%;
Your image needs object-fit: contain; (not cover)
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.jumbotron {
display: block;
width: 100%;
margin: 0;
padding: 0;
background-color: #aaa;
/* overflow: hidden; */
height: 150px;
}
.jumbotron .container {
width: 100%;
height: 100%;
}
.my-carousel {
background-color: #77f;
max-height: 100%;
max-width: 100%;
height: 100%;
width: 100%;
display: flex;
flex-direction: row;
// overflow: hidden;
}
.my-carousel .previous-btn, .my-carousel .next-btn {
font-size: 200%;
padding: 0px 10px;
display: flex;
flex-direction: column;
justify-content: center;
}
.my-carousel .content {
max-height: 100%;
max-width: 100%;
align-self: center;
flex-grow: 1;
position: relative;
width: 100%;
height: 100%;
}
.my-carousel .content .slide {
height: 100%;
//max-width: 100%;
display: none;
position: relative;
// width: 100%;
vertical-align: middle;
padding: 0px;
margin: 0px;
overflow: visible;
}
.my-carousel .content .slide.active {
display: block;
}
.my-carousel .content .slide img {
//position: relative;
// margin: 0px auto;
// box-sizing: border-box;
// vertical-align: middle;
height: 100%;
width: 100%;
// max-width: 100%;
// max-height: 100%;
object-fit: contain;
object-position: center;
overflow: hidden;
}
.my-carousel .content .slide .caption {
position: absolute;
background-color: rgba(0,0,0,.4);
text-shadow: 2px 2px 4px #fff, -2px -2px 4px #fff;
stroke: 2px #fff;
padding: 10px;
bottom: 0px;
width: 100%;
font-size: 150%;
// color: #000;
// -webkit-text-stroke-width: 1px;
// -webkit-text-stroke-color: #fff;
}
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#6.3.95/css/materialdesignicons.min.css" rel="stylesheet"/>
<main role="main">
<section class="jumbotron text-center">
<div class="container">
<div class="my-carousel">
<div class="previous-btn">
<span class="mdi mdi-transfer-left"></span>
</div>
<div class="content">
<div class="slide active">
<img src="https://picsum.photos/500/800?random=1" />
<div class="caption">This is only a WIP to figure out how to style this carousel properly.</div>
</div>
<div class="slide">
<img src="https://picsum.photos/1000/400?random=1" />
</div>
</div>
<div class="next-btn">
<span class="mdi mdi-transfer-right" />
</div>
</div>
</div>
</section>
</main>
luckily, the answer is inside "picksum" itself, it allows you to choose the resolution of the image you want, you chose (500x800) that is way too large, you can use the following reduced resolutions >(50x80), (100x160), (180x288), (190x304), (200x320). I am sure you will get your desired result by using (180x288) or (190x304)
for example:<img src="https://picsum.photos/190/304?random=1" />
Use max-width and max-height
Like this
.slide {
width: 100px;
height: 100px;
max-width: 100%;
max-height: 100%;
overflow: hidden;
}
.slide .img {
max-width: 100%;
max-height: 100%;
}

Fit child div with `aspect-ratio` to parent in Firefox [duplicate]

I wish to have a div section that fills its div parent as much as possible while maintaining a ratio.
the render result would be like this :
What I do have so far :
html,
body {
height: 100%;
}
.parent {
/* Parent's height and width are unknown,
it could be dynamic, e.g. parent is part of a flex layout. */
height: 80%;
width: 90%;
border-style: solid;
border-width: 2px;
border-color: black;
}
.child {
width: 90vw;
/* 90% of viewport vidth */
height: 50.625vw;
/* ratio = 9/16 * 90 = 50.625 */
max-height: 90vh;
max-width: 160vh;
/* 16/9 * 90 = 160 */
margin: auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: #A0522D;
}
<div class="parent">
<div class="child">
content that is not images...
</div>
</div>
This css behaves like the way I want BUT this is using the viewport instead of the parent div which is a problem in real conditions.
I am looking for a way to fill based on the parent div.
Using aspect-ratio: 16 / 9; overflow: hidden; (aspect-ratio MDN docs) should give you the exact result you're looking for without needing to use the padding trick. Make sure the parent is set to display: grid or else it may not scale properly.
The aspect-ratio CSS property is supported by all major browsers (caniuse.com) except Safari, though Safari plans to add support this year. This is the best/correct way to achieve this effect, without having to resort to JavaScript or any hack solutions.
Related questions and answers here on Stack Overflow:
https://stackoverflow.com/a/66786774/3824249 (very similar to my solution)
https://stackoverflow.com/a/20593342/3824249 (another CSS-only alternative, though hackier using position: absolute for element positioning)
Here is my solution in action:
html, body { height: 100%; }
.parent {
display: grid;
resize: both;
height: 50%;
width: 90%;
border: 2px solid #000;
overflow: hidden;
}
.child {
width: 100%;
max-height: 100%;
margin: auto;
aspect-ratio: 16 / 9;
overflow: hidden;
box-sizing: border-box;
position: relative;
background: #a0522d;
text-align: center;
font-size: 20px;
color: white;
/* using the below to center the text, optional */
display: flex;
align-items: center;
justify-content: center;
}
<div style="padding: 5px 10px; margin-bottom: 10px; background: #f00; color: #fff; text-align: center; z-index: 1;">Resize the block below using the resize controls to see this in action.</div>
<div class="parent">
<div class="child">content that is not images...</div>
</div>
maybe add position absolute and it works, by setting top, right ,bottom,left to 0 with margin auto. you could as well use flex to center it or absolute with left 50% and transform -50% too.
body {
padding: 0;
margin: 0;
height: 100vh;
width: 100vh;
}
.child {
width: 90vw;
/* 90% of viewport vidth */
height: 50.625vw;
max-height: 90vh;
max-width: 160vh;
/* Adding this maybe min-width and min-height */
min-height: 90vh;
min-width: 160vh;
/* 16/9 * 90 = 160 */
background: #f7f7f7;
box-shadow: 0px 5px 30px 0px rgba(0, 0, 0, 0.18);
border-radius: 4px;
margin: auto;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Parent Child</title>
</head>
<body> <!-- parent -->
<div class="child"></div>
</body>
</html>
Use flexbox and padding. Use media queries to determine if the min-aspect-ratio of the viewport. Then adjust accordingly.
html,
body {
height: 100%;
}
.parent {
height: 100%;
width: 100%;
border-style: solid;
border-width: 2px;
border-color: black;
/* to center */
display: flex;
align-items: center;
justify-content: center;
}
.child {
width: 100vw;
/* 16:9 aspect ratio = 9 / 16 = 0.5625 = padding-bottom*/
padding-bottom: 56.25%;
background: #A0522D;
}
#media (min-aspect-ratio: 16/9) {
.child {
height: 100vh;
/*16:9 aspect ratio = 9 / 16 = 177.77 = width*/
width: 177.77vh;
padding: 0;
margin: 0px;
background: red;
}
}
<div class="parent">
<!-- the viewbox will provide the desired aspect ratio -->
<div class="child">
content that is not images...
</div>
</div>
Here's a fiddle.
So as to make child's dimensions dependent on parent container set position:relative of the parent container.
Normally when we make an element position:absolute it is positioned relative to initial containing block(i.e the <body>) unless any other closest parent container is given a position other than static(which is by default).So, by giving relative position to parent container we positioned .child element relative to .parent which was earlier positioned relative to the document or body.
This will work for you
html,
body {
height: 100%;
}
.parent {
/* Parent's height and width are unknown,
it could be dynamic, e.g. parent is part of a flex layout. */
position:relative;
height: 80%;
width: 90%;
border-style: solid;
border-width: 2px;
border-color: black;
}
.child {
width: 90%;
/* 90% of viewport vidth */
height: 50.625%;
/* ratio = 9/16 * 90 = 50.625 */
max-height: 90%;
max-width: 160%;
/* 16/9 * 90 = 160 */
margin: auto;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: #A0522D;
}
<div class="parent">
<div class="child">
content that is not images...
</div>
</div>

Element with negative margin covered by previous one

I am trying to make element position with negative margin - one element should cover a bit the previous one. But it's bit complicated - negative margin should have only child div of #content. See example below. I need to have red element, than yellow element and gray element inside the red one should have negative margin and cover bottom of red one.
I have already tried relative and absolute position, change z-index, but none of these worked for me.
#sectionTitle {
height: 150px;
text-align: center;
margin: 0 auto;
width: 100%;
position: relative;
z-index: 1;
background: red;
}
#content {
background: yellow;
position: relative;
width: 100%;
height: auto;
min-height: 300px;
overflow: auto;
z-index: 20;
}
#content .block {
position: relative;
background: #eee;
width: 90%;
top: -50px;
margin: 0 auto 0 auto;
box-sizing: border-box;
height: auto;
min-height: 400px;
z-index: 30;
}
<div id="sectionTitle">
...some text...
</div>
<div id="content">
<div class="block">
...element which should cover bottom of #sectionTitle element
</div>
</div>
Now when I inspect the element, .block goes 50px to #sectionTitle, but it's not visible, because sectionTitle element covers it.
Simply remove z-index (to avoid the creation of a stacking context1) and overlow:auto (to avoid the creation of a block formatting context2) from the #content div:
#sectionTitle {
height: 150px;
text-align: center;
margin: 0 auto;
width: 100%;
position: relative;
z-index: 1;
background: red;
}
#content {
background: yellow;
width: 100%;
height: auto;
min-height: 300px;
}
#content .block {
position: relative;
background: #eee;
width: 90%;
top: -50px;
margin: 0 auto 0 auto;
box-sizing: border-box;
height: auto;
min-height: 400px;
z-index: 30;
}
<div id="sectionTitle">
...some text...
</div>
<div id="content">
<div class="block">
...element which should cover bottom of #sectionTitle element
</div>
</div>
1Why can't an element with a z-index value cover its child?
2What formatting context applies to elements that don't create their own?

CSS calc works with vh but not %

I have the following:
body {
overflow-x: hidden;
overflow: hidden;
height: 100%;
min-height: 100%;
}
html {
height: 100%;
min-height: 100%;
}
.navbar-header {
background: green;
}
.sidebar {
background-color: #333;
border-right: 1px solid #000;
color: #fff;
position: fixed;
width: 178px;
height: 100%;
}
.content {
border: 1px solid #ddd;
height: calc(100% - 150px);
background-color: #ffffff;
overflow: scroll;
overflow-x: hidden;
margin-left: 178px;
}
.footer {
border: 1px solid #ddd;
min-height: 78px;
margin-top: 10px;
padding: 20px;
background-color: #f6f9fb;
position: fixed;
bottom: 0;
width: calc(100% - 178px);
left: 185px;
}
<div class="navbar-header">
header
</div>
<nav class="sidebar">
sidebar
</nav>
<div class="content">
content
</div>
<div class="footer">
footer
</div>
But in my project to make the calc work I changed % per vh to make it work, I am sorry I can't provide my local code, but I would like understand why my code just worked with vh instead of %.
height: calc(100vh - 150px);
height: -moz-calc(100vh - 150px);
height: -webkit-calc(100vh - 150px);
A percentage value for height (also in calc) only works if either the parent element has a fixed height, or if all parents, grandparents etc. up to the body (or up to an ancestor with fixed px width) have a percentage height (i.e. no auto height).
vhis the viewport height, the area where your elements render. Setting your elements to 100vh is basically telling them to occupy the whole height of your view port.
Using % in the other hand is telling your elements to use all the space they need. If your divis empty, then your viewport will be empty.

Div Won't Adjust to adjusting browser window

I am very new to web design, so I might be completely over my head here.. but I can not seem to figure out how to work this. I have an image inside my first div, underneath this I want to have to more divs with the background colors in which I will add content. But for some reason my divs are not adjusting with the browser. Everytime I adjust the browser to be smaller, the divs backgrounds are separating and a white space is coming in between them.
Any help would be highly appreciated.. Also any critical feedback on my obvious coding skills, would be highly appreciated.
<!DOCTYPE html>
<html>
<head> <link rel="stylesheet" type="text/css" href="index.css">
</head>
<body>
<div class="container">
<div class= "header">
<div class="large-logo-wrap">
<img src="Assets/Giadaslogoindexwhitebig.png" draggable="false"></img>
</div>
<div class="middle">
</div>
<div class="end">
</div>
</body>
</html>
CSS
body{
margin: 0px;
padding: 0px;
overflow: hidden;
}
.container{
width:100%;
margin: 0px;
padding: 0px;
}
.header{
width:100%;
height:768px;
background-image: url('Assets/header.jpg');
background-size: 100%;
background-repeat: no-repeat;
margin: 0px;
padding: 0px;
}
.large-logo-wrap {
margin-left: auto;
margin-right: auto;
width: 100%;
height: 100%;
max-width: 700px;
}
.middle{
position: absolute;
top: 768px;
background-color: rgb(229,225,209);
width: 100%;
height:100%;
background-size: 100%;
overflow-y: auto;
}
.end{
position: absolute;
top: 1500px;
background-color: rgb(29,25,29);
width: 100%;
height:768px;
background-size: 100%;
}
be nice. Cheers!
I suggest you take a closer look at the code and strip out as much as you can to see what is actually necessary to get where you are going. Here is a fiddle with some cleaned up code that does what I think you are going for. Hopefully it helps.
HTML
<header class="container global-header">
<div class="inner-w">
<div class="large-logo-wrap">
<img src="http://placehold.it/400x300" />
</div>
</div>
</header>
<section class="container section01">
<div class="inner-w">
Middle - arbitrary set height - I suggest you let the content decide the height
</div>
</section>
<section class="container section02">
<div class="inner-w">
Other section - arbitrary set height
</div>
</section>
CSS
*, *:before, *:after { /* get your box model so that padding and margins go inside the box instead of outside, and add to the overall size of the box */
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
body {
margin: 0;
}
.container { /* things the sections have in common */
width: 100%;
float: left;
}
.inner-w {
max-width: 700px;
margin-right: auto;
margin-left: auto;
padding: 1em;
border: 1px solid rgba(0,0,0,.05); /* just so you can see */
/* by using an inner div in your container... you allow yourself to maintain a background-color across the whole page if you wish. If you don't want that, then you just style the inner div for each section with the background color */
}
.global-header {
background-color: lightblue;
text-align: center; /* centers inline, and inline-block elements (logo) */
}
.large-logo-wrap {
display: inline-block;
max-width: 8em; /* set max image size */
}
.large-logo-wrap img { /* responsive image */
display: block;
width: 100%; /* fits whatever you set the wrapper to */
height: auto;
}
.section01 { /* arbitray section */
background-color: rgb(229,225,209);
color: rgb(0,0,0);
min-height: 234px; /* if you absolutly must - choose a height... use min */
}
.section02 { /* arbitray section */
background-color: rgb(29,25,29);
color: rgb(229,225,209);
min-height: 346px; /* if you absolutly must - choose a height... use min */
}
Please change your css with this one:
body{
margin: 0px;
padding: 0px;
overflow: hidden;
}
.container{
width:100%;
margin: 0px;
padding: 0px;
}
.header{
width:100%;
height:768px;
background-image: url('Assets/header.jpg');
background-repeat: no-repeat;
margin: 0px;
padding: 0px;
}
.large-logo-wrap {
margin-left: auto;
margin-right: auto;
max-width: 700px;
}
.middle{
margin-left: auto;
margin-right: auto;
max-width: 700px;
background-color: rgb(229,225,209);
}
.end{
margin-left: auto;
margin-right: auto;
max-width: 700px;
background-color: rgb(29,25,29);
}
Some of your css styles were wrong, for example you used width and height with %100 which is wrong and effects on all of your css styles.
Also, you used position:absolute for all of div which effects on div to be nonadjustable.

Resources