I have a flexbox layout with two columns. Column one contains an image, at design time the aspect ratio of the image is unknown. I want to display the whole image while maintaining its aspect ratio. Column two contains several lines of text, length is unknown at design time. The container should not have a fixed height.
How can I maximize the space available in column one for the image, without the image height exceeding the height of (the text in) column two?
In the code snippet below I want the height of the black image to be less than or of the same height as the right column with gray background, it should never be taller.
.row {
display: flex;
padding: 5px;
margin: 5px;
align-items: flex-start;
background-color: blue;
}
.col1 {
flex-grow: 1;
background-color: yellow;
align-self: stretch;
}
.col2 {
background-color: lightgray;
padding: 10px;
min-width: 300px;
}
img {
width: 100%;
height: 100%;
max-height: 100%;
object-fit: contain;
}
<div class="container">
<div class="row">
<div class="col1">
<img src="https://dummyimage.com/256x256/000/fff">
</div>
<div class="col2">
<p>Here's some text</p>
<p>And some more text</p>
<p>And some more text</p>
</div>
</div>
</div>
You could have an average result via height:0; + min-height:100% , but parent's width will hardly be update .
.row {
display: flex;
padding: 5px;
margin: 5px;
background-color: blue;
justify-content:start;
}
.col1 {
flex: 1 1 auto;
background-color: yellow;
align-self: stretch;
}
.col2 {
background-color: lightgray;
padding: 10px;
flex:1 0 auto;
}
img {
height:0;
min-height: 100%;
min-width:100%;
object-fit: contain;
}
<div class="container">
<div class="row">
<div class="col1">
<img src="https://dummyimage.com/256x256/000/fff">
</div>
<div class="col2">
<p>Here's some text</p>
<p>And some more text</p>
<p>And some more text</p>
</div>
</div>
</div>
To achieve this kind of result you need to have one of the column's widths fixed.
In the below example I have fixed the width of the image to 256px.
.row {
display: flex;
padding: 5px;
margin: 5px;
align-items: flex-start;
background-color: blue;
}
.col1 {
flex: 0 0 256px;
background-color: yellow;
}
.col1 > img {
width: 256px;
}
.col2 {
flex: 1;
background-color: lightgray;
padding: 10px;
}
<div class="container">
<div class="row">
<div class="col1">
<img src="https://dummyimage.com/600x600/000/fff">
</div>
<div class="col2">
<p>Here's some text</p>
<p>And some more text</p>
<p>And some more text</p>
<p>And some more text</p>
<p>And some more text</p>
<p>And some more text</p>
</div>
</div>
</div>
Related
I would like the lines at the bottom of each div/bottom border to align. When text on one side is longer than the other, the bottom border looks disjointed.
.one {
display: flex;
flex-direction: row;
justify-content: space-evenly;
margin-top: 5%;
}
.inner {
padding: 5px;
width: 100%;
}
.two {
padding: 5px;
}
.innerTxt {
width: 90%;
border-bottom: 2px solid blue;
}
<div class="one">
<div class="inner">
<img src="https://via.placeholder.com/370x236">
<div class="innerTxt">
<h4>Wings</h4>
<p>Lorem Ipsum. This text is shorter</p>
</div>
</div>
<div class="two">
<img src="https://via.placeholder.com/370x236">
<div class="innerTxt">
<h4>Other</h4>
<p>Some other text on this page that happens to be longer than the previous</p>
</div>
</div>
</div>
A height style can be applied to the <p> element if the content inside the <p> element is not dynamic.
.one {
display: flex;
flex-direction: row;
justify-content: space-evenly;
margin-top: 5%;
}
.inner {
padding: 5px;
width: 100%;
}
.two {
padding: 5px;
}
.innerTxt {
width: 90%;
border-bottom: 2px solid blue;
}
p {
height: 50px;
}
<div class = "one">
<div class="inner">
<img src="https://via.placeholder.com/370x236">
<div class="innerTxt">
<h4>Wings</h4>
<p>Lorem Ipsum. This text is shorter</p>
</div>
</div>
<div class="two">
<img src="https://via.placeholder.com/370x236">
<div class="innerTxt">
<h4>Other</h4>
<p>Some other text on this page that happens to be longer than the previous</p>
</div>
</div>
</div>
You could use an absolutely-positioned pseudo element to draw the border while maintaining the 90% width of innerTxt.
Because the flex elements are stretched vertically they'll be aligned at the bottom.
.one {
display: flex;
flex-direction: row;
justify-content: space-evenly;
margin-top: 5%;
}
.inner {
padding: 5px;
width: 100%;
}
.two {
padding: 5px;
}
.innerTxt {
width: 90%;
}
.one>* {
position: relative;
}
.one>*::after {
content: '';
position: absolute;
bottom: 0;
border-bottom: 2px solid blue;
display: block;
width: 90%;
}
<div class="one">
<div class="inner">
<img src="https://via.placeholder.com/370x236">
<div class="innerTxt">
<h4>Wings</h4>
<p>Lorem Ipsum. This text is shorter</p>
</div>
</div>
<div class="two">
<img src="https://via.placeholder.com/370x236">
<div class="innerTxt">
<h4>Other</h4>
<p>Some other text on this page that happens to be longer than the previous</p>
</div>
</div>
</div>
try adding to the .inner div align-self: flex-end;
.inner{
align-self: flex-end;
}
or to the parent div :
.one {
align-items: flex-end;
}
I have some text that can overflow the parent container:
body {
margin: 200px;
}
.container {
width: 100px;
height: 50px;
background-color: #bbb;
text-align: center;
}
.header {
white-space: nowrap;
}
<div class="container">
<div class="header">
Short Text
</div>
<div class="header">
Very long text that should not wrap and be center aligned
</div>
</div>
When text is short, it is center aligned, as expected.
However, when the text overflows the container, it's not center aligned anymore.
How could I align the text horizontally regardless of the length of the text?
Desired outcome:
html:
<div class="container">
<div class="header">
<div>Short Text</div>
</div>
<div class="header">
<div>Very long text that should not wrap and be center aligned</div>
</div>
</div>
</body>
</html>
css:
body {
margin: 200px;
}
.container {
width: 100px;
height: 50px;
background-color: #bbb;
display: flex;
flex-wrap: wrap;
}
.header {
white-space: nowrap;
position: relative;
left: 50%;
transform: translateX(-50%);
}
for demo here, https://jsfiddle.net/jinny/qs7wL4nv/33/
Use text-indent:
body {
margin: 200px;
}
.container {
width: 100px;
height: 50px;
background-color: #bbb;
text-align: center;
}
.header {
white-space: nowrap;
text-indent: -8em;
}
<div class="container">
<div>
Short Text
</div>
<div class="header">
Very long text that should not wrap and be center aligned
</div>
</div>
flexbox can do this easily
body {
margin:0 200px;
}
.container {
width: 100px;
height: 50px;
background-color: #bbb;
display:flex;
flex-wrap:wrap;
justify-content:center;
}
.header {
white-space: nowrap;
}
<div class="container">
<div class="header">
Short Text
</div>
<div class="header">
Very long text that should not wrap and be center aligned
</div>
</div>
I'm trying to create two centered div, which are seperated by a border like this.
Didn't know how to insert the border between the two div.
the two div are clickable.
.homescreen-content {
display: flex;
flex-direction: column;
max-height: 100% !important;
}
.goto {
margin-top:20%;
left:0;
height: 100% ;
width: 100% !important;
background-color: green;
text-align: center;
}
.no {
left:0;
height: 100%;
width: 100% !important;
background-color: red;
text-align: center;
}
<div class="homescreen-content" scroll="false">
<div (click)="open()" class="goto">
<h2>TITLE 1 CENTRED</h2>
<p>SOME CENTRED TEXT</p>
</div>
<hr class="border">
<div (click)="open()" class="no">
<h2>TITLE 2 CENTRED</h2>
<p>SOME CENTRED TEXT</p>
</div>
</div>
As mentioned by Fabio, you could replace your <hr> tag with a <div> and set the height of the <div> to be the thickness of the border you want.
.homescreen-content {
display: flex;
flex-direction: column;
max-height: 100% !important;
}
.goto {
margin-top:20%;
left:0;
height: 100% ;
width: 100% !important;
background-color: green;
text-align: center;
}
.no {
left:0;
height: 100%;
width: 100% !important;
background-color: red;
text-align: center;
}
.border {
width:100%;
height:10px;
background:blue;
}
<div class="homescreen-content" scroll="false">
<div (click)="open()" class="goto">
<h2>TITLE 1 CENTRED</h2>
<p>SOME CENTRED TEXT</p>
</div>
<div class="border"></div>
<div (click)="open()" class="no">
<h2>TITLE 2 CENTRED</h2>
<p>SOME CENTRED TEXT</p>
</div>
</div>
You can add border using CSS, look my CSS carefully !
.homescreen-content {
display: flex;
flex-direction: column;
max-height: 100% !important;
}
.goto {
margin-top:20%;
left:0;
height: 100% ;
width: 100% !important;
background-color: green;
text-align: center;
border-bottom : 15px solid white ;
}
.no {
left:0;
height: 100%;
width: 100% !important;
background-color: red;
text-align: center;
border-top : 15px solid white ;
}
<div class="homescreen-content" scroll="false">
<div (click)="open()" class="goto">
<h2>TITLE 1 CENTRED</h2>
<p>SOME CENTRED TEXT</p>
</div>
<div (click)="open()" class="no">
<h2>TITLE 2 CENTRED</h2>
<p>SOME CENTRED TEXT</p>
</div>
</div>
You can change border color,
Border : 15px solid red ;
You can also change border type,
Border : 15px dotted blue ;
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;
}
I'm trying to get a two-column flexbox with some content on the left, and the remaining space taken up by an image. The image should be centred in the remaining space and shrink-to-fit. Here's what I've got:
* {
box-sizing: border-box;
}
.small_margin {
margin: 5px;
}
.small_padding {
padding: 5px;
}
.red {
background: #faa;
}
.blue {
background: #aaf;
}
.green {
background: #afa;
}
.small_container {
width: 500px;
display: flex;
flex-direction: row;
}
.large_container {
width: 900px;
display: flex;
flex-direction: row;
}
.image {
max-width: 100%; /* Why does this not work? If you change it to a fixed value (not a percentage) it works. */
max-height: 20em;
}
.image_holder {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
}
<div class="red large_container">
<div class="blue small_margin small_padding" style="width: 120px;">
<h1>This Works</h1>
<p>This is what I want when there is space for the full-size image (restricted to its max-height). It should be centred in the div to the right.</p>
<p>This is good.</p>
</div>
<div class="green small_margin image_holder">
<img class="image" src="http://www.gstatic.com/webp/gallery/1.jpg"/>
</div>
</div>
<br>
<div class="red small_container">
<div class="blue small_margin small_padding">
<h1>This Doesn't</h1>
<p>There is now no longer space for the image but instead of reducing its size to 100% of its parent div it just overflows.</p>
</div>
<div class="green small_margin image_holder">
<img class="image" src="http://www.gstatic.com/webp/gallery/1.jpg"/>
</div>
</div>
As you can see, the image overflows the flexbox and isn't shrunk-to-fit by the max-width: 100%. Presumably 100% doesn't actually mean "100% the width of the parent div"?
Anyway, is there any way to make this work?
The image has max-width: 100%. That means that it shouldn't be wider than its parent (the flex item). And this works.
Instead, the problem is that the flex item overflows the flex container. That happens because Flexbox introduces auto as the initial value of min-width. When overflow is visible, that auto forces the flex item to grow so that its content doesn't overflow.
Therefore, you can use min-width: 0.
.image_holder {
min-width: 0;
}
* {
box-sizing: border-box;
}
.small_margin {
margin: 5px;
}
.small_padding {
padding: 5px;
}
.red {
background: #faa;
}
.blue {
background: #aaf;
}
.green {
background: #afa;
}
.small_container {
width: 500px;
display: flex;
flex-direction: row;
}
.large_container {
width: 900px;
display: flex;
flex-direction: row;
}
.image {
max-width: 100%; /* Why does this not work? If you change it to a fixed value (not a percentage) it works. */
max-height: 20em;
}
.image_holder {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
min-width: 0;
}
<div class="red large_container">
<div class="blue small_margin small_padding" style="width: 120px;">
<h1>This Works</h1>
<p>This is what I want when there is space for the full-size image (restricted to its max-height). It should be centred in the div to the right.</p>
<p>This is good.</p>
</div>
<div class="green small_margin image_holder">
<img class="image" src="http://www.gstatic.com/webp/gallery/1.jpg"/>
</div>
</div>
<br>
<div class="red small_container">
<div class="blue small_margin small_padding">
<h1>This Doesn't</h1>
<p>There is now no longer space for the image but instead of reducing its size to 100% of its parent div it just overflows.</p>
</div>
<div class="green small_margin image_holder">
<img class="image" src="http://www.gstatic.com/webp/gallery/1.jpg"/>
</div>
</div>
Then the image won't overflow the flex container. However, it won't mantain its aspect ratio.
To fix that, you can use object-fit:
.image {
object-fit: contain;
}
* {
box-sizing: border-box;
}
.small_margin {
margin: 5px;
}
.small_padding {
padding: 5px;
}
.red {
background: #faa;
}
.blue {
background: #aaf;
}
.green {
background: #afa;
}
.small_container {
width: 500px;
display: flex;
flex-direction: row;
}
.large_container {
width: 900px;
display: flex;
flex-direction: row;
}
.image {
max-width: 100%; /* Why does this not work? If you change it to a fixed value (not a percentage) it works. */
max-height: 20em;
object-fit: contain;
}
.image_holder {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
min-width: 0;
}
<div class="red large_container">
<div class="blue small_margin small_padding" style="width: 120px;">
<h1>This Works</h1>
<p>This is what I want when there is space for the full-size image (restricted to its max-height). It should be centred in the div to the right.</p>
<p>This is good.</p>
</div>
<div class="green small_margin image_holder">
<img class="image" src="http://www.gstatic.com/webp/gallery/1.jpg"/>
</div>
</div>
<br>
<div class="red small_container">
<div class="blue small_margin small_padding">
<h1>This Doesn't</h1>
<p>There is now no longer space for the image but instead of reducing its size to 100% of its parent div it just overflows.</p>
</div>
<div class="green small_margin image_holder">
<img class="image" src="http://www.gstatic.com/webp/gallery/1.jpg"/>
</div>
</div>