Scenario :
I am having trouble getting an image to autofit a flexbox with a border around it. The image will be dynamically generated so sometimes the width or the height might be the longer side. Sometimes the image will be smaller or larger than the box it should be in, but it should automatically fit the size of the box and retain its proper proportions.
Tried Case :
The best I've come up with is to set both width and height of the image to 100%, and then use object-fit: contain.
However, object-fit: contain does not work well with borders. Instead of surrounding just the image the border is surrounding the entire parent div.
The Problem: If there is a tall skinny image it might enlarge or shrink to 30% width and 100% height. I would like the border to be also at the 30% and 100% region as well. However, the border is being placed at the 100% width and 100% height area which is not what I want.
What other method would work better for me here?
Here is a simplified look at my code:
<!DOCTYPE html>
<html>
<style>
html, body { width: 100%; height: 100% }
#outer {
width: 100%;
height: 100%;
display: flex;
background-color: green;
flex-direction: column
}
#top, #bottom {
flex: 1;
display: flex;
border: solid black 1px;
}
#first, #third {
flex: 1;
background-color: blue;
}
#second {
flex: 3;
background-color: yellow;
}
#second img {
border: solid black 5px;
object-fit: contain;
width: 100%;
height: 100%;
box-sizing: border-box;
}
</style>
<body>
<div id="outer">
<div id="top">
<div id="first">First</div>
<div id="second">
<img src="https://via.placeholder.com/350x800/faa">
</div>
<div id="third">Third</div>
</div>
<div id="bottom">
Bottom
</div>
</div>
</body>
</html>
If you run the above code snippet you will see the thick border is surrounding the entire parent region (shown in yellow), rather than just appearing around the image itself (pink area).
What can I do so that the border is only around the image itself?
Clarification
I need something that meets the following criteria:
Smaller images are scaled up to meet the size of the parent div
Larger images are scaled down to meet the size of the parent div
Images should be proportional (i.e. images must retain their aspect ratio and not become distorted)
The image should be centered within the parent div
The image should have a border only around the image and not the larger area
Code must work for both portrait and landscape images
In most cases only two sides of the image will touch the parent boundary, leaving the rest of the parent div empty (i.e. the yellow background in my code sample)
I'm actually quite surprised given how far CSS has come that there seems to be no simple solution for this.
Do you want only with height 100%? If not height 100% is depend on image's prop, you can use object-fit: fill; and height:auto;
<!DOCTYPE html>
<html>
<style>
html, body { width: 100%; height: 100% }
#outer {
width: 100%;
height: 100%;
display: flex;
background-color: green;
flex-direction: column
}
#top, #bottom {
flex: 1;
display: flex;
border: solid black 1px;
}
#first, #third {
flex: 1;
background-color: blue;
}
#second {
flex: 3;
background-color: yellow;
}
#second img {
border: solid black 5px;
object-fit: contain;
width: 100%;
height: auto;
box-sizing: border-box;
}
</style>
<body>
<div id="outer">
<div id="top">
<div id="first">First</div>
<div id="second">
<img src="https://picsum.photos/800/800">
</div>
<div id="third">Third</div>
</div>
<div id="bottom">
Bottom
</div>
</div>
</body>
</html>
Used object-fit: cover
so that the image will cover the entire parent.
Other solution will be inserting an image already having a border on it.Image can be edited online to attach a border to itself.
<!DOCTYPE html>
<html>
<style>
html, body { width: 100%; height: 100% }
#outer {
width: 100%;
height: 100%;
display: flex;
background-color: green;
flex-direction: column
}
#top, #bottom {
flex: 1;
display: flex;
border: solid black 1px;
}
#first, #third {
flex: 1;
background-color: blue;
}
#second {
flex: 3;
background-color: yellow;
}
#second img {
border: solid black 5px;
object-fit: cover;
width: 100%;
height: 100%;
box-sizing: border-box;
}
</style>
<body>
<div id="outer">
<div id="top">
<div id="first">First</div>
<div id="second">
<img src="https://via.placeholder.com/350x800/faa">
</div>
<div id="third">Third</div>
</div>
<div id="bottom">
Bottom
</div>
</div>
</body>
</html>
Updated Solution:
So, to achieve this, we can put image inside a container that will be
take height and width according to image. Put this image container div inside the main div container.
So, in this case, we have put the following code into #second conatiner, and adjusted the corresponding css to achieve the desired result.
html, body { width: 100%; height: 100% }
img {
max-width: 100%;
max-height: 100%;
width: auto;
height: auto;
transform: translate(-50%, -50%);
position: relative;
left: 50%;
top: 50%;
}
#testing {
display: inline-block;
/* text-align: center; */
}
#outer {
width: 100%;
height: 100%;
display: flex;
background-color: green;
flex-direction: column
}
#top, #bottom {
flex: 1;
display: flex;
border: solid black 1px;
}
#first, #third {
flex: 1;
background-color: blue;
}
#second {
flex: 3;
background-color: yellow;
display: flex;
margin: 0 auto;
justify-content: center;
}
#second img {
border: solid black 5px;
object-fit: contain;
box-sizing: border-box;
}
<!DOCTYPE html>
<html>
<body>
<div id="outer">
<div id="top">
<div id="first">First</div>
<div id="second">
<div id='testing'>
<img src="https://via.placeholder.com/1000x350/faa">
</div>
</div>
<div id="third">Third</div>
</div>
<div id="bottom">
Bottom
</div>
</div>
<div id="outer">
<div id="top">
<div id="first">First</div>
<div id="second">
<div id='testing'>
<img src="https://via.placeholder.com/350x1000/faa">
</div>
</div>
<div id="third">Third</div>
</div>
<div id="bottom">
Bottom
</div>
</div>
</body>
</html>
did you mean something like this?
changes are, move width: 100% and height: 100% to parent, add max-height: 100% on img, and add text-align: center on parent
update:
- add another div inside #second
- make #second display: flex; flex-direction: column; justify-content: center
- add max-width: 100% to img
- add max-height: 100%; max-width: 100%; height: fit-content; to the added div
html, body { width: 100%; height: 100% }
#outer {
width: 100%;
height: 100%;
display: flex;
background-color: green;
flex-direction: column
}
#top, #bottom {
flex: 1;
display: flex;
border: solid black 1px;
}
#first, #third {
flex: 1;
background-color: blue;
}
#second {
flex: 3;
background-color: yellow;
width: 100%;
height: 100%;
text-align:center;
display: flex;
flex-direction: column;
justify-content: center;
}
#second img {
border: solid black 5px;
box-sizing: border-box;
max-height: 100%;
max-width: 100%;
}
#vcenter{
max-height: 100%;
max-width: 100%;
height: fit-content;
}
<!DOCTYPE html>
<html>
<body>
<div id="outer">
<div id="top">
<div id="first">First</div>
<div id="second">
<div id="vcenter">
<img src="https://via.placeholder.com/350x800/faa">
</div>
</div>
<div id="third">Third</div>
</div>
<div id="bottom">
Bottom
</div>
</div>
</body>
</html>
same code for landscape images
html, body { width: 100%; height: 100% }
#outer {
width: 100%;
height: 100%;
display: flex;
background-color: green;
flex-direction: column
}
#top, #bottom {
flex: 1;
display: flex;
border: solid black 1px;
}
#first, #third {
flex: 1;
background-color: blue;
}
#second {
flex: 3;
background-color: yellow;
width: 100%;
height: 100%;
text-align:center;
display: flex;
flex-direction: column;
justify-content: center;
}
#second img {
border: solid black 5px;
box-sizing: border-box;
max-height: 100%;
max-width: 100%;
}
#vcenter{
max-height: 100%;
max-width: 100%;
height: fit-content;
}
<!DOCTYPE html>
<html>
<body>
<div id="outer">
<div id="top">
<div id="first">First</div>
<div id="second">
<div id="vcenter">
<img src="https://via.placeholder.com/1350x200/faa">
</div>
</div>
<div id="third">Third</div>
</div>
<div id="bottom">
Bottom
</div>
</div>
</body>
</html>
Related
I'm having problem with my div with contenteditable=true which break my whole page.
When you type a lot of text, instead adding scrollbar it make div bigger so it move others parts of the page...
So what I would like my editable div fill remaining width and height of the page but add scrollbar when text being too big whitout moving others elments of the page. Thanks
JsFiddle
HTML
<body>
<h1>TEXT</h1>
<div class="all">
<div class="container">
<div class="lines"></div>
<div class="editor" contenteditable="true" spellcheck="false"></div>
</div>
<div class="manage">
<h1>TEXT</h1>
</div>
</div>
</body>
CSS
html, body {
margin: 0;
padding: 0;
display: flex;
height: 100%;
width: 100%
}
h1 {
margin: 20px;
}
.all {
display:flex;
flex-direction: column;
width: 100%;
height: 100%;
}
.container {
display: flex;
width: 100%;
height: 400px;
overflow: auto;
}
.lines {
background-color: red;
border-radius: 20px 0 0 20px;
height: 100%;
width:40px;
}
.editor {
border-radius: 0 20px 20px 0;
background-color: orange;
width: 100%;
height: 100%;
}
All you need to do is to add a max-width property to your .editor class.
Here is a working code: https://codesandbox.io/s/html-code-editor-forked-g27d9o?file=/index.html
This is sort of a two in problem.
I have a body with height: 100vh similar to how my example is in the jsFiddle (except in there I put 20vh.
I have a similar structure as this, where the innerRight container can be quite large compared to the rest of the content, and only that conatiner is to obtain it's own scroll bar. I sort of got this working in my main project, but the outer container (similar to how I displayed outer in the example) still expands past the the parents height container main. Be it 100vh, or 20vh it doesn't matter it doesn't stay within with display:flex.
.main {
height: 20vh;
}
.outer {
display: flex;
overflow: hidden;
}
.innerLeft {
height: 200px;
width: 50px;
display: flex;
flex-direction: column;
flex-grow: 1;
background-color: green;
}
.innerRight {
overflow: auto;
height: 500px;
background-color: red;
width: 100%;
}
<div class="main">
<div class="header">
some random text
</div>
<div class="outer">
<div class="innerLeft">
</div>
<div class="innerRight">
</div>
</div>
</div>
Can you please check the below code? Hope it will work for you.
You have to set height:100vh; in .main and set width:calc(100% - 50px); to .innerRight.
Remove height from innerleft and innerright element.
Please refer to this link: https://jsfiddle.net/yudizsolutions/9Lsyzg64/1/
body {
margin: 0;
}
.main {
height: 100vh;
}
.outer {
display: flex;
height: calc(100vh - 19px);
overflow: hidden;
}
.innerLeft {
width: 50px;
background-color: green;
}
.innerRight {
overflow: auto;
background-color: red;
width: calc(100% - 50px);
}
<div class="main">
<div class="header">
some random text
</div>
<div class="outer">
<div class="innerLeft">
</div>
<div class="innerRight">
</div>
</div>
</div>
You need to set height to outer class.
.main {
height: 20vh;
}
.outer {
display: flex;
height: 200px;
overflow:hidden;
}
.innerLeft {
width: 50px;
display: flex;
flex-direction: column;
flex-grow: 1;
background-color: green;
}
.innerRight {
overflow: auto;
height: 500px;
background-color: red;
width:100%;
}
<div class="main">
<div class="header">
some random text
</div>
<div class="outer">
<div class="innerLeft">
</div>
<div class="innerRight">
</div>
</div>
</div>
I want to make two div inside other div. But the second(green) div is passing the size of the main(black). I tried to set the height to 100%, but something happens that is going beyond the size of the main box, does anyone have any solutions?
.block {
width: 300px;
height: 200px;
background: black;
}
.box1 {
width: 200px;
height: 50px;
background: red;
vertical-align: top;
margin: auto;
}
.box2 {
width: 200px;
height: 100%;
background: green;
margin: auto
}
<div class="block">
<div class="box1">
</div>
<div class="box2">
</div>
</div>
If you set child's height to 100% then the height of the parent will be inherited. If you are looking for an option where the 2nd box (green) fill the remaining space leftover by 1st box(red)
.block {
width: 300px;
height: 200px;
background: black;
display: flex;
flex-direction: column;
align-items: center;
}
.box1 {
width: 200px;
height: 50px;
background: red;
vertical-align: top;
}
.box2 {
flex: 1;
width: 200px;
background: green;
}
<div class="block">
<div class="box1">
</div>
<div class="box2">
</div>
</div>
I am using Flex and there is no need to use overflow: hidden
You should add the overflow: hidden; to the main black box, just like the below snippet. This will make the overflow clipped.
.block {
width: 300px;
height: 200px;
background: black;
overflow: hidden;
}
.box1 {
width: 200px;
height: 50px;
background: red;
margin: auto;
}
.box2 {
width: 200px;
height: 100%;
background: green;
margin: auto;
}
<div class="block">
<div class="box1">
</div>
<div class="box2">
</div>
</div>
But if you don't want to get rid of the remaining piece of the second box, you can do it with flexbox also. This will not trim the green box but instead, it will resize it to make sure the green box will remain in the parent black box.
.block {
width: 300px;
height: 200px;
background: black;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.box1 {
width: 200px;
height: 50px;
background: red;
}
.box2 {
width: 200px;
height: 100%;
background: green;
}
<div class="block">
<div class="box1">
</div>
<div class="box2">
</div>
</div>
NOTE: In the flexbox version, you also won't need to use margin: auto; in the child boxes, because in the flexbox column direction align-items: center; will take care of child positions with the available attributes it gave to us.
This question already has answers here:
Why don't flex items shrink past content size?
(5 answers)
Fill remaining vertical space with CSS using display:flex
(6 answers)
Closed 3 years ago.
I have a <div> that takes up 60% of the window space, and it contains two things:
a narrow header line
an image that I want to take up the remainder of the div.
How can I do this with pure CSS (no Javascript)? I've been trying a bunch of things, no luck.
This is the closest I can get; the image sneaks outside of the green border of the div.container
html, body {
height: 100%;
overflow: hidden;
margin: 0px;
}
div.container {
height: 60%;
border: 2px solid green;
box-sizing: border-box;
}
div.rest {
height: 40%;
border: 2px solid red;
box-sizing: border-box;
}
div.img-container {
height: 100%; /* this is wrong, but what do I do? */
}
div.img-container img {
max-height: 100%;
max-width: 100%;
height: auto;
width: auto;
opacity: 0.5;
}
<html>
<body>
<div class="container">
<div class="header">hieronymus bosch last judgement</div>
<div class="img-container"><img src="https://i.imgur.com/TT6drhn.jpg"></div>
</div>
<div class="rest">
<h1>blah blah blah</h1>
</div>
</body>
</html>
Here's my attempt at using flex but that fails.
html, body {
height: 100%;
overflow: hidden;
margin: 0px;
}
div.container {
height: 60%;
border: 2px solid green;
box-sizing: border-box;
display: flex;
flex-direction: column
}
div.rest {
height: 40%;
border: 2px solid red;
box-sizing: border-box;
}
div.img-container {
flex: 1;
}
div.header {
flex: 0;
}
div.img-container img {
max-height: 100%;
max-width: 100%;
height: auto;
width: auto;
opacity: 0.5;
}
<html>
<body>
<div class="container">
<div class="header">hieronymus bosch last judgement</div>
<div class="img-container"><img src="https://i.imgur.com/TT6drhn.jpg"></div>
</div>
<div class="rest">
<h1>blah blah blah</h1>
</div>
</body>
</html>
#Christian's approach works if you know the height of the header element, however alternatively you could use flex.
This allows the element to grow to fill the remaining space dynamically, so your header can be any height.
html,
body {
height: 100%;
overflow: hidden;
margin: 0px;
}
div.container {
height: 60%;
border: 2px solid green;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
div.rest {
height: 40%;
border: 2px solid red;
box-sizing: border-box;
}
div.img-container {
flex: 1;
position: relative;
}
div.img-container img {
opacity: 0.5;
height: 100%;
position: absolute;
}
<html>
<body>
<div class="container">
<div class="header">hieronymus bosch last judgement</div>
<div class="img-container"><img src="https://i.imgur.com/TT6drhn.jpg"></div>
</div>
<div class="rest">
<h1>blah blah blah</h1>
</div>
</body>
</html>
If you look at div.img-container in Chrome Inspector, you can see what the issue is - the img element is doing its job and filling its container, but the container itself is overflowing.
This is happening because it is set to height: 100% - what this says is "make my height 100% of my parent's height", but this does not mean "fill the remaining space." The browser just reads the computed height of the element's parent, and then multiplies it by your % value - basically, it's all in absolute terms. You can see that the blue box is 100% as tall as the box outlined in green, but because it sits below a line of text, it overflows by the height of that text.
flex could be used to solve this problem, but you can patch this pretty quickly by using calc to subtract out the height of that text. In your example, it's 19px, and I would recommend manually setting the height of that text element container just to be sure nothing will break in edge cases. Then, the .img-container gets height: calc(100% - 19px) and it works as expected.
html, body {
height: 100%;
overflow: hidden;
margin: 0px;
}
div.container {
height: 60%;
border: 2px solid green;
box-sizing: border-box;
}
div.rest {
height: 40%;
border: 2px solid red;
box-sizing: border-box;
}
div.img-container {
height: 100%; /* this is wrong, but what do I do? */
}
div.img-container img {
max-height: 100%;
max-width: 100%;
height: auto;
width: auto;
opacity: 0.5;
}
/*
ADDED CODE BELOW
*/
/* optional, just to be safe */
.header {
height: 19px;
}
/* overrides .img-container from above */
.img-container {
height: calc(100% - 19px) !important;
}
<html>
<body>
<div class="container">
<div class="header">hieronymus bosch last judgement</div>
<div class="img-container"><img src="https://i.imgur.com/TT6drhn.jpg"></div>
</div>
<div class="rest">
<h1>blah blah blah</h1>
</div>
</body>
</html>
With Flex, you may use the flex property and overflow (or min-height). Example:
html, body {
height: 100vh;
margin: 0px;
display:flex;
flex-direction:column;
}
div.container {
flex:6;/* instead height:xx% */
border: 2px solid green;
box-sizing: border-box;
display: flex;
flex-direction: column;
overflow:hidden; /* or min-height:0 if scroll is needed */
}
div.rest {
flex:4;/* instead height:xx% */
border: 2px solid red;
box-sizing: border-box;
}
div.img-container {
flex: 1;
min-height:0; /* or overflow:hidden; */
}
div.header {
min-height:1.6em; /* if you need something alike ?? */
}
div.img-container img {
max-height: 100%;
opacity:0.5;
}
<html>
<body>
<div class="container">
<div class="header">hieronymus bosch last judgement</div>
<div class="img-container"><img src="https://i.imgur.com/TT6drhn.jpg"></div>
</div>
<div class="rest">
<h1>blah blah blah</h1>
</div>
</body>
</html>
I have a container that is 100vh (minus the fixed nav height).
<section class="container">
Inside this container I have some text:
<div class="text">
<p>title</p>
</div>
Which can be of any length as the content is dynamic.
Below this text I have an image:
<div class="image">
<img src="https://s-media-cache-ak0.pinimg.com/736x/d1/a6/64/d1a664bca214bf785a293cbc87950fc4.jpg">
</div>
The image needs to fill the rest of the 100vh (- nav height) container.
I use:
.container{
display:flex;
flex-flow: column nowrap;
....
Fiddle
The issue I am having is that I need the image to be the height of the rest of the space.
How can I do this? In my fiddle, if your screen is small it is being cut off and if your screen is large it does not fill the space. Height: 100% fails to work, making it too large.
Flex solutions only please, no table tricks - thanks!
Make the image container (.image) a flex container with height: 100%.
You can then fine-tune the image's aspect ratio and alignment with object-fit / object-position.
nav {
position:fixed;
background:grey;
width:100%;
height: 100px;
}
main {
padding-top: 100px;
}
.container {
display:flex;
flex-flow: column nowrap;
height: calc(100vh - 100px);
background: green;
border: 3px solid brown;
}
.text { background: yellow; }
/* ***** NEW ***** */
.image {
display: flex;
justify-content: center;
height: 100%;
}
img {
width: 100%;
object-fit: contain;
}
<nav>Nav</nav>
<main>
<section class="container">
<div class="text"><p>title</p></div>
<div class="image">
<img src="https://s-media-cache-ak0.pinimg.com/736x/d1/a6/64/d1a664bca214bf785a293cbc87950fc4.jpg">
</div>
</section>
<section class="container">
<div class="text"><p>hello</p></div>
<div class="image">
<img src="https://s-media-cache-ak0.pinimg.com/736x/d1/a6/64/d1a664bca214bf785a293cbc87950fc4.jpg">
</div>
</section>
</main>
Revised Fiddle
Note that the object-fit property is not supported by IE. For more details and a workaround see: https://stackoverflow.com/a/37127590/3597276
Maybe not exactly what you wanted, but if you move the image to a div and use it as a background, you can get the desired effect.
Fiddle
HTML:
Nav
title
<section class="container">
<div class="text">
<p>hello</p>
</div>
<div class="imageWrap">
<div class="image"></div>
</div>
</section>
</main>
CSS:
nav {
background: grey;
width: 100%;
height: 100px;
position: fixed;
}
main{
padding-top: 100px;
}
.container{
display: flex;
flex-flow: column nowrap;
height: calc(100vh - 100px);
background: green;
border: 3px solid brown;
}
.imageWrap {
flex: 1;
display: flex;
}
.image {
flex: 1;
background-size: contain;
background-repeat: no-repeat;
background-image: url(https://s-media-cache-ak0.pinimg.com/736x/d1/a6/64/d1a664bca214bf785a293cbc87950fc4.jpg)
}
.text{
background: yellow;
}