Make an image shrink to available height without expanding its parent - css

I'm trying to create a two-column section where:
Columns have same width (responsive)
The height of block is defined by the height of image contained in left column after it stretches to 100% of it's parent.
In the right column there are several elements one of which is a link containing image.
I want that link with image from last paragraph to shrink it's height containing original image aspect ratio without stretching the it's container when the image has portrait orientation.
Not sure it its possible with plain CSS. Tried with flexbox and grid layout but I must be missing something.
I prepared a fiddle: https://jsfiddle.net/Kuznets/8u6c70ku/3/
* { box-sizing: border-box }
.wrap { max-width: 80%; margin: 0 auto; }
.container { display: flex; }
.left, .right {
flex: 0 0 50%;
border: 1px solid black;
}
.left {
position: relative;
display: flex;
align-items: flex-end;
}
.left div.left-text {
position: absolute;
color: white;
padding: 1em;
font-size: 200%;
}
.should-set-height {
width: 100%;
}
.right {
display: flex;
flex-direction: column;
align-items: center;
justify-content:space-between;
}
<div class="wrap">
<div class="container">
<div class="left">
<img class="should-set-height" src="https://dummyimage.com/200x240/aaaaaa/ffffff" alt="">
<div class="left-text">
This is a beautiful slogan
</div>
</div><!--/.left-->
<div class="right">
<header>Product title</header>
<a class="fit-height" href="javascript:void(0)">
<img class="should-shrink" src="https://dummyimage.com/200x400/aaaaaa/ffffff">
</a>
<div class="price">$ 19.99</div>
<button class="button-black">Add to basket</button>
</div><!--/.right-->
</div><!--/.containter-->
</div><!--/.wrap-->

One way you could accomplish this would be to have the left image set to have width: 100%, height: auto; then use a background image for the right container.
Here's a quick demo on CodePen: https://codepen.io/patriziosotgiu/pen/NaBmZe?editors=1100
You could also add extra rules, like for instance a min-width for the left column, or have those columns fit in one column for mobile.
Note: I assumed the left image to be larger than 200x240px

Related

CSS: Element in flexbox container won't appear unless it or the container are assigned a specific height

I'm trying to create a vertical line inside a flexbox container div, and am finding that unless I give either the line or the container a specific height (like 100px instead of a percentage), the line won't show. Examination with devtools shows that the line has 0 height, even though the container has a non-zero height. I'm guessing that maybe the rendering engine somehow doesn't know about the container's height at the time it's rendering the line? I'd like to find a way to make this work with percentages in order to make the container and line responsive.
jsfiddle: [https://jsfiddle.net/jjorsett/d0852yhx/25/][1] Set .line's height units to px and it will show up.
css and html:
<div class="container">
<img class="image" src="http://via.placeholder.com/100x250"/>
<div class="line">
</div>
</div>
.container {
background: yellow;
display: flex;
height: auto;
justify-content: space-around;
align-items: center;
}
.line {
border-left: .25em solid #f60;
height: 50%;
}
.image {
object-fit: contain;
width: 25%;
}
[1]: https://jsfiddle.net/jjorsett/d0852yhx/25/
Just remove align-items: center; from your container and height: 50% from your child and see the magic.
.container {
background: yellow;
display: flex;
height: auto;
justify-content: space-around;
}
.line {
border-left: .25em solid #f60;
}
.image {
object-fit: contain;
width: 25%;
}
<div class="container">
<img class="image" src="http://via.placeholder.com/100x250"/>
<div class="line">
</div>
</div>
When you align your item in the center it will automatically shrink your child container according to the children of your child div.
For the benefit of anyone else coming across this, I got the behavior I wanted by using javascript as follows (fiddle here: https://jsfiddle.net/jjorsett/d0852yhx/62/)
<div class="container">
<img class="image" src="http://via.placeholder.com/100x250"/>
<div id="line">
</div>
</div>
.container {
background: yellow;
display: flex;
height: auto;
justify-content: space-around;
align-items: center;
}
#line {
border-left: .25em solid #f60;
height: 50%;
}
.image {
object-fit: contain;
width: 25%;
}
window.onresize = adjustLineSize;
window.onload = adjustLineSize;
function adjustLineSize() {
var line = document.getElementById("line");
var desiredLineHeight = line.parentElement.clientHeight/2;
line.style.height= desiredLineHeight + "px";
}

Container wrapping around tallest child in CSS Grid

I think I might be having the wrong approach with this design problem. Here is a codepen with a reproduction of the issue and a Stack Snippet :
Codepen
body {
display: flex;
justify-content: center;
}
.main-container {
background-color: grey;
width: 1000px;
display: grid;
grid-template-areas: "img description" "share share";
grid-template-columns: 271px 1fr;
}
.img-meta {
grid-area: img;
width: 272px;
align-self: center;
position: relative;
}
.red {
width: 272px;
height: 380px;
background-color: red;
}
.green {
background-color: green;
height: 150px;
align-self: center;
}
.blue {
background-color: blue;
position: absolute;
padding-top: 10px;
height: 100px;
width: 272px;
}
<div class="main-container">
<div class="img-meta">
<div class="red"></div>
<div class="blue"></div>
</div>
<div class="green"></div>
</div>
Problem is immediately apparent: the blue container is out of the parent grid container. The green container contains text and expands depending on the quantity of said text, which is what is wanted. The red container has fixed dimensions and contains an image which needs to position itself at the center of the green container at all times. Blue container needs to be just under the red container regardless of position of red container.
When the text is longer than the img-meta container, design is as expected.
But when the text is shorter than img-meta, the design appears as shown in the snippet: because the blue container is relatively positioned, it escapes the flow of the document and the grey grid container doesn't wrap around it.
I understand this is normal behaviour for a relatively positioned container, but I am out of ideas to get the expected design.
I have tried to design this with flexboxes initially, before picking a grid.
I tried to use min-height on the text container to force it to always have the height of the of the img-meta container but no luck because it will create a lot of empty space at the top.
I have also tried to have the blue container out of its parent and remove its positioning in order to get the grid to wrap around it, but this will leave a space between the red and the blue container!
Maybe the grid direction is wrong for that type of design, and I'm looking forward to see your ideas!
I'd go with
.blue { 
position: absolute;
width: 100%;
height: 100%;
}
.grey {
position: relative;
display: flex;
align-items: center;
}

Two rows div layout. Building flexible layout that should adapt to different screen sizes

I'm trying to build a flexible layout that should adapt to different screen sizes as the following pictures show.
It's basically two div rows, occupying each 50% of the vertical size of the screen.
Top div is a container to hold pictures and bottom div will display a leaflet map.
I'd like the Image div to keep aspect ratio so image is not deformed, ans Map div to adapt horizontally.
So far, my code is basic and looks like this :
<div id="container">
<div id="Top div">
<div id='image'>Image</div>
</div>
<div id="Bottom div">
<div id='map'>Map</div>
</div>
</div>
Any idea of the CSS style I should add to each div to achieve this layout ?
Image layout desktop
Image layout smartphone
You could use Flexbox to achieve this layout. Refer to my CSS below and check out the attached Codepen.
#container {
display: flex;
flex-flow: row wrap;
}
#Top {
display: flex;
flex: 1 1 100%;
padding-bottom: 1rem;
}
#image {
flex: 0 1 50%;
margin: auto;
padding: 3rem;
background-color: #ccc;
text-align: center;
}
#Bottom {
flex: 1 1 100%;
}
#map {
padding: 5rem;
background-color: green;
text-align: center;
}
If, for some reason you cannot use flexbox you can achieve this easily. The main trick is to add an element to act as a wrapper to the image, set a height/width to this element and then set the max-width/max-height on the image to 100%. This way it will scale without deforming.
To achieve occupying each 50% of the vertical size of the screen you can set the height to 50vh.
#map {
background-color: green;
height: 100%;
}
.section {
height: 50vh;
}
.img-container {
width: 100%;
text-align: center;
}
.sample-img {
max-width: 100%;
max-height: 100%;
}
<div id="container">
<div id="Top div" class="section img-container">
<img class="sample-img" src="https://via.placeholder.com/180" alt="image" />
</div>
<div id="Bottom div" class="section">
<div id='map'>Map</div>
</div>
</div>

Four column div with 3 regular columns and 1 rotated vertically

I am trying to make a div that contains 4 columns.
The first one should be rotated vertically. Text in it should be centered vertically and horizontally. It also should have a background and width 10%.
The rest columns (2, 3, 4) should have width 30%.
What is the best approach to do this?
P.S. Of course the div should be responsive and should look good at any resolution.
Remember, you will need to add min-height or height if the other divs with(30% width has too little content). in my case i added 300px;
.flex {
display: flex;
}
.flex-center-all {
display: flex;
justify-content: center;
align-items: center;
width: 10%;
background: green;
min-height: 300px;
}
.rotate {
transform: rotate(90deg);
}
.container {
width: 100%;
}
.container > div:not(.flex-center-all) {
width: 30%;
}
<div class="flex container">
<div class="flex-center-all">
<div class="rotate">rotate</div>
</div>
<div>text <br> txt</div>
<div>text</div>
<div>text</div>
</div>

Flexbox - can't keep divs in content area from overlapping footer

I have a web page using a column flexbox, with fixed size header and footer, and a content area which takes up the remaining space. This works fine.
The content area is a row flexbox, and I have 2 square divs side by side. I am making them square by using padding-bottom. This works fine, unless the window is >2x the content area height. Then my squares start bleeding into the footer, because padding is based on element width.
I would like the squares to never overlap the footer. I'm ok with there just being dead space to the right of the squares. I would like to stick with flexbox and avoid floats if possible. Only modern browsers need be supported.
Is this possible with only CSS? Or is this a job for JS.
Fiddle
html, body {
height: 100%;
margin: 0;
padding: 0;
}
#box {
display: flex;
flex-flow: column;
height: 100%;
}
div {
border: 1px solid tomato;
box-sizing: border-box;
margin: 0;
padding: 2px;
}
#header {
flex: 0 0 5em;
}
#footer {
flex: 0 0 5em;
}
#content {
background: blue;
display: flex;
flex: 1 1 auto;
flex-flow: row wrap;
min-height: 30%;
}
#content > div {
background: tomato;
border-color: black;
flex: 1 0 auto;
max-height: 50%;
padding-bottom: 50%;
}
<div id="box">
<div id="header">
<p><b>header</b>
</p>
</div>
<div id="content">
<div id='am'></div>
<div id='pm'></div>
</div>
<div id="footer">
<p><b>footer</b>
</p>
</div>
</div>
TIA!
Simple soluton:
#box
{
display: flex;
flex-flow: column;
min-height: 100%; /* this*/
}
JSfiddle Demo
Note: This assumes you want the page to overflow...but I didn't see any reference to containing the page height to the viewport.

Resources