I have a container with a background image. I would like it to:
It seems like what I need is contain
on the width, but not height, but then I'm not sure how to do the minimum offset from the top.
See my attempts here:
background-size: 100% auto;
background-position: left 20px;
/* works when the height is shorter than the image
------------------
| |
| |
|................|
|. .|
|. .|
|. .|
|. .bg .|
|. .|
|. .|
|. .|
------------------
. . <- this is clipped off, that is fine.
................
*/
/*
does not work when the height is larger than the image
------------------
| |
| |
|................|
|. .|
|. .|
|. .|
|. .bg .|
|. .|
|. .|
|. .|
|. .|
|. .|
|................| <- I want this to be stuck to the bottom
| |
| |
------------------
*/
background-size: 100% auto;
background-position: left bottom;
/* works when the height is taller than the image
------------------
| |
| |
| |
|................|
|. .|
|. .|
|. .|
|. .bg .|
|. .|
|. .|
|. .|
|. .|
|................| <- stuck to the bottom, good!
------------------
*/
/*
does not work when the height is shorter than the image
................
. .
. .
. .
. .bg .
. . <- This is clipped off
------------------
|. .|
|. .|
|. .|
|................|
------------------
*/
background-size: cover;
background-position: left 20px;
/* works when the width is wider than the image (scales it up)
------------------
| |
| |
|................|
|. .|
|. .|
|. .|
|. .bg .|
|. .|
|. .|
|. .|
------------------
. . <- this is clipped off, that is fine.
................
*/
/*
does not work when the width is narrower than the image, and the height is taller
------------------
| |
| |
|................|.....
|. | . <- I do not want the width to overflow
|. | .
|. | .
|. .bg | .
|. | .
|. | .
|. | .
|. | .
|. | .
|................|.....
------------------
*/
What I want:
/* if the container is shorter than the image
------------------
| |
| |
|................| <- 20px offset from the top, full width of the container
|. .|
|. .|
|. .|
|. .bg .|
|. .|
|. .|
|. .|
------------------
. . <- this is clipped off, that is fine.
................
*/
/*
if the container is larger than the image
------------------
| |
| |
| |
| |
|................| <- full width of the container
|. .|
|. .|
|. .|
|. .bg .|
|. .|
|. .|
|. .|
|. .|
|. .|
|................| <- stuck to the bottom
------------------
*/
Snippet for testing:
/* width/heights are for illustrative purposes - actual width-heights are unknown */
div {
background-size: cover;
background-position: left 20px;
background-repeat: no-repeat;
margin-bottom: 50px;
border: 1px solid red;
width: 200px;
height: 300px;
}
.taller {
height: 500px;
}
.shorter {
height: 100px;
}
.wider {
width: 400px;
}
.narrower {
width: 200px;
}
<!-- this image size and the container size are variable depending on author input - these are included as test cases, but I do not know the sizes -->
<strong>Same Size</strong>
<div style="background-image: url('https://picsum.photos/200/300');"></div>
<strong>Taller</strong>
<div class="taller" style="background-image: url('https://picsum.photos/200/300');"></div>
<strong>Wider</strong>
<div class="wider" style="background-image: url('https://picsum.photos/200/300');"></div>
<strong>Narrower</strong>
<div class="narrower" style="background-image: url('https://picsum.photos/200/300');"></div>
<strong>Shorter</strong>
<div class="shorter" style="background-image: url('https://picsum.photos/200/300');"></div>
<strong>Taller & Wider</strong>
<div class="taller wider" style="background-image: url('https://picsum.photos/200/300');"></div>
<strong>Taller & Narrower</strong>
<div class="taller narrower" style="background-image: url('https://picsum.photos/200/300');"></div>
<strong>Shorter & Wider</strong>
<div class="shorter wider" style="background-image: url('https://picsum.photos/200/300');"></div>
<strong>Shorter & Narrower</strong>
<div class="shorter narrower" style="background-image: url('https://picsum.photos/200/300');"></div>
It is possible using just CSS, but you need to change a little bit your markup, by adding container div. I made an container resizable to simplify testing of this solution.
.container {
resize: both;
overflow: auto;
position: relative;
width: 200px;
height: 200px;
padding-top: 20px;
display: flex;
justify-content: flex-end;
}
.image {
margin-top: auto;
width: 100%;
height: 0;
padding-top: 150%;
background-size: contain;
background-repeat: no-repeat;
}
<div class="container">
<div class="image" style="background-image: url('https://picsum.photos/200/300');"></div>
</div>
How it works:
.container
has:
display: flex
, it is important to allow a "margin magic" to work,
justify-content: flex-end
to push the div with image to bottom;
padding-top: 20px
to always keep the empty space you wanted
.image
has:
width: 100%
to fill space horizontaly,
height: 0
and padding-top: 150%
to keep the image proportions ratio,
background-repeat: no-repeat
so image is used just once, and with contain
it fill div horizontally,
margin-top: auto
with display: flex
of parent allows vertical move of div, but constrained by parent padding,
EDIT in response to OP comment
It seems, that you still can use this method even if you don't know the image width and height, and therefore cannot calculate ratio - if you modify it a little bit. It actually make it even simpler
.container {
resize: both;
overflow: auto;
position: relative;
width: 200px;
height: 200px;
padding-top: 20px;
display: flex;
justify-content: flex-end;
}
.image {
margin-top: auto;
width: 100%;
height: auto;
}
<div class="container">
<img class="image" src='https://picsum.photos/200/300'></div>
</div>