Image in flex-row layout ignores it’s allocated height - css

I want to have a container that includes an image and a caption.
The container should always be the same size, the caption height might change.
In my mind the caption should get the auto height, depending on it’s size and the rest of the containers height will be allocated to the image.
I tried doing that with a div and i worked flawlessly. When I exchange the placeholder div with an actual image tag, the image will take the 100% height of the container, not of its allocated flex space in the container.
Why is that and how can I fix it?
Example showing the difference between div and image tag:
https://codepen.io/lkssmnt-the-lessful/pen/QWqbxNK?editors=1100
.project {
height: 500px;
width: 500px;
display: flex;
flex-direction: column;
}
.project img {
height: 100%;
width: 100%;
object-fit: cover;
}

Add overflow: hidden to the .img tag. - This has the negative effect of snipping the bottom of the image off, however.
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.wrapper {
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.project {
height: 500px;
width: 500px;
border: 5px solid red;
margin: 1rem;
display: flex;
flex-direction: column;
}
.project p {
padding: 1rem;
}
.project img {
overflow: hidden;
height: 100%;
width: 100%;
object-fit: cover;
}
.project .test {
height: 100%;
width: 100%;
background: beige;
}
<div class="wrapper">
<div class="project">
<div class="test"></div>
<p>Project 1</p>
</div>
<div class="project">
<img src="https://images.unsplash.com/photo-1518676590629-3dcbd9c5a5c9?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=987&q=80">
<p>Project 2</p>
</div>
</div>

Related

How to keep an image with flex-grow or flex-shrink (row and column)?

I have a parent container with class flex and two child containers (one with class img-container-1 and the other with img-container-2) with an image inside:
<div class="flex">
<div class="img-container-1">
<img
src="https://cdn.pixabay.com/photo/2021/06/27/14/32/raspberry-6368999_960_720.png"
alt="imagen"
>
</div>
<div class="img-container-2">
<img
src="https://cdn.pixabay.com/photo/2021/06/27/14/32/raspberry-6368999_960_720.png"
alt="imagen"
>
</div>
</div>
and in the CSS:
.flex {
display: flex;
width: 100%;
height: 100vh;
background-color: aqua;
}
.img-container-1 {
flex-grow: 1;
background-color: brown;
}
.img-container-2 {
flex-grow: 1;
background-color: burlywood;
}
img {
width: 100%;
height: 100%;
object-fit: contain;
}
I set a flex-grow of 1, to the img-container-1 / 2, as there is space available, both are filled equally, I also specify that the images occupy the entire width and height, this will take the height and width of the containers img-container-1 / 2 (right?), not the main container flex, as well as assigning an object-fit: contain, so that the aspect ratio is kept, and this is what I get (and it is what I wanted to achieve):
now I want to achieve the same, but vertically (column), therefore, to the container with the class flex I set flex-direction: column but I do not get the same result (I don't want this result):
.flex {
display: flex;
flex-direction: column; /*I set column*/
width: 100%;
height: 100vh;
background-color: aqua;
}
How can I do this:
I tried flex-grow or flex-shrink but I don't understand, I hope you can help me, (the result that you see in the last gif I achieved by placing a high of 50% to the img-container- 1 / 2, but it can be done in another way or I am forced to do it with percentages - %).
I'd suggest using the background-image instead of your current approach, that way the only thing that changes the direction is the flex-direction on your container and the images adapt since your items inside are adapting.
.flex {
display: flex;
width: 100%;
height: 100vh;
background-color: aqua;
flex-direction: column;
overflow: hidden;
}
.container-1 {
background-color: brown;
background-image: url('https://cdn.pixabay.com/photo/2021/06/27/14/32/raspberry-6368999_960_720.png');
}
.container-2 {
background-color: burlywood;
background-image: url('https://cdn.pixabay.com/photo/2021/06/27/14/32/raspberry-6368999_960_720.png');
}
.img {
background-size: contain;
background-repeat: no-repeat;
background-position: center;
height: 100%;
width: 100%;
}
<div class="flex">
<div class="img container-1">
</div>
<div class="img container-2">
</div>
</div>
.flex {
display: flex;
width: 100%;
height: 100vh;
background-color: aqua;
flex-direction: row;
overflow: hidden;
}
.container-1 {
background-color: brown;
background-image: url('https://cdn.pixabay.com/photo/2021/06/27/14/32/raspberry-6368999_960_720.png');
}
.container-2 {
background-color: burlywood;
background-image: url('https://cdn.pixabay.com/photo/2021/06/27/14/32/raspberry-6368999_960_720.png');
}
.img {
background-size: contain;
background-repeat: no-repeat;
background-position: center;
height: 100%;
width: 100%;
}
<div class="flex">
<div class="img container-1">
</div>
<div class="img container-2">
</div>
</div>

Cutting off overflowing image without overflow: hidden

I have a div with a fixed height, and inside it there is an image. This image is larger than the width and height of the containing div. I want to make the width of the image to match the width of the div, and then make the height of the image automatically generated.
HTML:
<template>
<div class="portfolio">
<div class="header">
Portfolio
</div>
<div class="projects">
<div class="project">
<img src="../assets/projects/charlotte_folke.jpg" />
</div>
</div>
<div class="overview">
</div>
</div>
</template>
SCSS:
.portfolio {
width: 100%;
height: 100%;
}
.header {
height: 10%;
display: flex;
font-size: 24px;
color: #B59762;
align-items: center;
justify-content: center;
}
.projects {
height: 80%;
display: flex;
overflow: auto;
flex-direction: column;
}
.project {
width: 100%;
height: 35%;
overflow: hidden;
img {
width: 100%;
height: auto;
}
}
The problem with this solution, is that the image element still takes up space below the containing div. I want to cut off the image completely, so it only takes up the available space specified by the containing div.
How can i achieve this?

Resize flex item based on its content

Sorry, another flexbox related question :)
I have two flex elements :
A container (red) containing a centered div (yellow)
A footer (blue) with an undefined height
The red container has a flex-grow:1 attribute, forcing it to take the remaining space on the screen
The issue happens when the yellow element is bigger than the screen size. I would like my red container to grow based on its content. Any idea of how I could do that ?
HTML:
<div class="container">
<div class="content"></div>
</div>
<div class="footer"></div>
CSS:
body,
html {
margin: 0;
height: 100%;
display: flex;
flex-direction: column;
}
.container {
flex-grow: 1;
display: flex;
align-items: center;
justify-content: center;
background: red;
}
.content {
background: yellow;
height: 2000px;
width: 100px;
}
.footer {
flex-shrink: 0;
height: 50px;
background-color: blue;
}
https://codepen.io/stepinsight/pen/roRVGQ
== EDIT ==
Andre helped me find the answer, thanks heaps !
The only thing you need to change in the code above is to replace height by min-height and the % by vh for the body/html tags 🎉
body,
html {
margin: 0;
min-height: 100vh;
display: flex;
flex-direction: column;
}
Simply remove the height property on the body element and add height: 100% to html
* { box-sizing: border-box; }
html {
height: 100%
}
body {
display: flex;
flex-direction: column;
margin: 0;
padding: 0;
}
.container {
display: flex;
align-items: center;
justify-content: center;
background: red;
}
.content {
background: yellow;
height: 2000px;
width: 100px;
}
.footer {
height: 50px;
background-color: blue;
}
Corrected: https://codepen.io/ferreirandre/pen/maoVvb
Feel free to play around with the height of .content

Sidebar with two flexbox navs top and bottom

I´m trying to align two navigations inside a sidebar –with 100% viewport height – by use of flexbox.
the red box should be placed on the top of it´s sidebar parent
the blue box on the bottom.
In case the red navigation grows and the space between both is to little the sidebar should be scrollable in y-axis. What I´ve tried is setting top and bottom margin for both without luck. Can somebody help me out ?
Thanks!
html, body {
margin: 0;
}
* {
box-sizing: border-box;
}
.sidebar {
height: 100vh;
width: 300px;
background: #ccc;
padding: 10px;
overflow-y: scroll;
}
.sidebar__top {
background: red;
height: 200px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.sidebar__bottom {
background: blue;
height: 100px;
margin-top: auto;
}
<aside class="sidebar">
<nav class="sidebar__top"></nav>
<nav class="sidebar__bottom"></nav>
</aside>
Here is my fiddle: http://jsfiddle.net/1dw7h2sp/1/
There are probably other ways to do this. In short I did the following:
Wrap your elements with a parent that is able to grow in size (.sidebar__wrapper)
Set the min-height instead of height so it can grow
Use flex-grow if you want an element to fill out the remaining space.
html, body {
margin: 0;
}
* {
box-sizing: border-box;
}
.sidebar {
height: 100vh;
width: 300px;
background: #ccc;
overflow-y: scroll;
margin: 0;
padding: 0;
}
/* set up a wrapper that can grow in size */
.sidebar__wrapper {
height: auto;
min-height: 100vh;
width: 100%;
background: #808080;
padding: 10px;
margin: 0;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.sidebar__top {
background: red;
min-height: 200px;
margin-bottom: 10px;
/* this fills up the remaining space */
flex-grow: 1;
}
.sidebar__bottom {
background: blue;
min-height: 100px;
}
<aside class="sidebar">
<div class="sidebar__wrapper">
<nav class="sidebar__top" contenteditable="true">
<p>test</p>
</nav>
<nav class="sidebar__bottom"></nav>
</div>
</aside>

Center text in 100%-screen-width div in small wrapper

I want to center a div and it's text, in a 100%-screen-width div, which is in a smaller wrapper.
.wrapper {
height: 800px;
width: 900px;
margin: auto;
background-color: #000000;
}
.box-wrapper {
width: 1000%;
position: relative;
left: -500%;
background-color: #FF6600;
}
.box {
background-color: #FF0000;
width: 600px;
position: relative;
left: 50%;
color: #00FF00;
}
span {
text-align: center;
display: block;
}
<div class="wrapper">
Random text for wrapper-div
<div class="box-wrapper">
<div class="box">
<span>ABC</span>
<span>DEF</span>
<span>GHI</span>
</div>
</div>
</div>
This code is kind of working but not perfect.
The red div should be moved a bit to the right, also the way
of doing it is not the best in my opinion.
I want a more robust and responsive solution.
To be more clear, it's for the pink division on the bottom
of this website: http://ndvibes.com
There the code is working 99% of the times and reponsive. But on some computers/screens it's 50% off. So I want a less-hacky (without transform etc) and more standard, robust way of getting that effect.
Wrapper 900px > 100%-screen-width coloured div > Centered text in that coloured div.
How can I achieve this the best as possible?
Thanks!
How about this approach, using absolute positioned pseudo elements. The outer-space div with overflow:hidden is to prevent a horizontal scroll bar appearing. I have added padding-top to the .wrapper just so you can see the snippet running in full screen mode.
body {
margin:0;
}
.outer-space {
overflow: hidden;
padding-top:80px;
}
.wrapper {
height: 800px;
width: 100%;
max-width: 900px;
margin: auto;
background-color: #000000;
}
.box {
background-color: #8904B1;
margin:0 auto;
color: #ffffff;
position: relative;
z-index: 2;
padding:10px 0;
}
.box-wrapper {
position: relative;
width:100%;
max-width: 600px;
margin:0 auto;
}
.box-wrapper:before, .box-wrapper:after {
content:"";
position: absolute;
height:100%;
width:100vw;
background-color: #8904B1;
top: 0;
z-index: 1;
}
.box-wrapper:before {
left:-100%;
}
.box-wrapper:after {
right:-100%;
}
span {
text-align: center;
display: block;
}
<div class="outer-space">
<div class="wrapper">
Random text for wrapper-div
<div class="box-wrapper">
<div class="box">
<span>Crazy full width window</span>
<span>absolute positioned pseudo elements</span>
<span>with centered content div and centered text thingy</span>
<span>all inside of a fixed width page wrapper!</span>
<br><span>““”̿ ̿ ̿ ̿ ̿’̿’̵͇̿̿з=(•̪●)=ε/̵͇̿̿/̿ ̿ ̿ ̿ ̿’““</span>
</div>
</div>
</div>
</div>
To center child element, add the following to the parent wrap will center all child.
display: flex;
align-items: center;
justify-content: center;
If you want 100% screen width, use viewport (100vw) for 100% screen width
viewport
The #viewport CSS at-rule contains a set of nested descriptors in a CSS block that is delimited by curly braces. These descriptors control viewport settings, primarily on mobile devices.
1vw = 1% of viewport width
1vh = 1% of viewport height
1vmin = 1vw or 1vh, whichever is smaller
1vmax = 1vw or 1vh, whichever is larger
REF: #viewport
REF: Viewport Sized Typography
body {
margin: 0;
}
.wrapper {
height: 800px;
width: 900px;
margin: auto;
background-color: #000000;
}
.box-wrapper {
width: 900px;
max-width: 900px;
position: relative;
background-color: #FF6600;
display: flex;
align-items: center;
justify-content: center;
}
.outer-wrapper {
width: 100vw;
display: flex;
align-items: center;
justify-content: center;
}
.box {
width: 80%;
background-color: #FF0000;
position: relative;
color: #00FF00;
}
span {
text-align: center;
display: block;
}
<div class="outer-wrapper">
<div class="wrapper">
<p>Random text for wrapper-div</p>
<div class="box-wrapper">
<div class="box">
<span>ABC</span>
<span>DEF</span>
<span>GHI</span>
</div>
</div>
</div>
</div>

Resources