I am building a single page application. In one of the views I want to show an image which must take as much available space as possible:
most important: it must keep the aspect ratio
it must not be cropped
it must be stretched horizontally and/or vertically (without changing aspect ratio) to cover the maximum possible space
the size of the image and viewport are not known
it must be centered
no js must be used
the element must be an img element and no background must be used - I already have a background (in the container)
For example, let's say that the image is 100px x 100px, and that we have a container of 500px x 300px. The image would then be stretched to 300px x 300px, and be horizontally centered so that 100px are left as padding on both sides.
Is this possible?
Here is my non-finished code of what I am trying to accomplish.
.container1 {
width: 500px;
height: 300px;
border: 2px;
border-color: red;
border-style: solid;
}
.container2 {
width: 300px;
height: 500px;
border: 2px;
border-color: blue;
border-style: solid
}
.fill-vertical {
border: 2px;
border-style: solid;
border-color: green;
display: block;
max-width: 100%;
}
.fill-horizontal {
width: 100%;
border: 2px;
border-style: solid;
border-color: green;
}
<h1>Container 1, 500px x 300px, not filled</h1>
<div class="container1">
<img src="https://dummyimage.com/100x100/000/fff">
</div>
<h1>Container 1, filled vertically (should be horizontally centered)</h1>
<div class="container1">
<img class="fill-vertical" src="https://dummyimage.com/100x100/000/fff">
</div>
<h1>Container 300px x 500px, not filled</h1>
<div class="container2">
<img class="fillIt" src="https://dummyimage.com/100x100/000/fff">
</div>
<h1>Container 300px x 500px, filled horizontally, should be vertically centered</h1>
<div class="container2">
<img class="fill-horizontal" src="https://dummyimage.com/100x100/000/fff">
</div>
In that code I am forced to use a different class for the image depending on whether I want to stretch vertically or horizontally, but actually I want CSS to do this automatically: just one stretch class must be defined.
In short what I want CSS to do is: stretch width and/or height to fit available space, keeping aspect ratio
#This can be achieved in CSS with a few changes#
The required changes are:
Create a new .centerImage css rule. overflow: hidden; ensures that the image does not spill out of the container. position: relative; is required as the child img will need to be positioned absolutely relative to the container.
Create a new .centerImage img css rule. max-height: 100%; and max-width: 100% ensures the aspect ratio is kept intact. Setting bottom, left, right and top to 0 and margin: auto; centers the image.
Add the centerImage class to the containing divs.
Change .fill-vertical to height: 100%; which will make the img fill the vertical space.
Change .fill-horizontal to width: 100%; which will make the img fill the horizontal space.
.container1 {
border: 2px;
border-color: red;
border-style: solid;
height: 300px;
width: 500px;
}
.container2 {
border: 2px;
border-color: blue;
border-style: solid;
height: 500px;
width: 300px;
}
.fill-vertical {
height: 100%;
}
.fill-horizontal {
width: 100%;
}
.centerImage {
display: block;
overflow: hidden;
position: relative;
text-align: center;
}
.centerImage img {
bottom: 0;
left: 0;
margin: auto;
max-height: 100%;
max-width: 100%;
position: absolute;
right: 0;
top: 0;
}
<h1>Container 1, 500px x 300px, not filled</h1>
<div class="container1 centerImage">
<img src="https://picsum.photos/500/500">
</div>
<h1>Container 1, filled vertically (should be horizontally centered)</h1>
<div class="container1 centerImage">
<img class="fill-vertical" src="https://picsum.photos/500/500">
</div>
<h1>Container 300px x 500px, not filled</h1>
<div class="container2 centerImage">
<img src="https://picsum.photos/500/500">
</div>
<h1>Container 300px x 500px, filled horizontally, should be vertically centered</h1>
<div class="container2 centerImage">
<img class="fill-horizontal" src="https://picsum.photos/500/500">
</div>
http://jsbin.com/bupuwohica/2/
#Further to the above changes, it is possible to achieve this with the CSS property object-fit#
To do this you need to:
Add object-fit: contain; to the image
Set height and width to 100%
The only caveat to this is browser support as while Firefox, Chrome, Safari and Opera have supported this for some time IE and Edge do not and will require either a polyfill or fallback.
.container {
border: 2px solid red;
height: 200px;
overflow: hidden;
resize: both;
width: 300px;
}
img {
object-fit: contain;
height: 100%;
width: 100%;
}
<p>The below div is resizable, drag the bottom right corner to see how the image scales</p>
<div class="container">
<img alt="" src="https://picsum.photos/500/500" />
</div>
https://jsfiddle.net/efyey801/
Here's one way to do it, relying on background-size. This does use img tags, as required, but the visible graphic is loaded as background to take advantage of available css rules.
.container {
background-color: #edc;
position: relative;
margin: 2em;
}
.container img {
display: block;
width: 100%;
height: 100%;
background-image: url(http://www.clipartbest.com/cliparts/yck/eXb/yckeXboMi.png);
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
#c1 {
width: 400px;
height: 100px;
}
#c2 {
width: 400px;
height: 600px;
}
<div id="c1" class="container">
<img src="">
</div>
<div id="c2" class="container">
<img src="">
</div>
Here's some more information on background-size: https://developer.mozilla.org/en-US/docs/Web/CSS/background-size
Yes it's entirely possible. You just need to make sure you have "Bounds" or limits on your possible max size for X or horizontal and Y or vertical limits. Once you know the max dimensions then you can make those constants to compare to. The easiest method i know of is to compare X and Y as Vectors so you can see their change. To get it centered is also easy at this point:
(((horizontalScreenLimit - widthOfImage)/2), ((verticalScreenLimit - heightOfImage)/2)')
Related
Let's say i have rectangular image with dimensions of 1400px(height)x700px(width). I want to square it in the way that the image would keep its original stretch and the sides would be white. I do not want to crop the image - want it to fully fit into square.
Do you know how it can be achieved over CSS/Bootsrap?
You can use CSS flexbox on your container to center your image, and then use max-width and max-height to confine the image to your container proportionally.
body {
background-color: #f7f7f7;
}
.square-img-container {
float: left;
display: flex;
align-items: center;
justify-content: center;
width: 160px;
height: 160px;
background-color: white;
border: 1px solid #eee;
margin: 10px;
}
.square-img-container img {
max-height: 100%;
max-width: 100%;
}
<div class="square-img-container">
<img src="https://via.placeholder.com/700x1400.png" alt="">
</div>
<div class="square-img-container">
<img src="https://via.placeholder.com/1400x700.png" alt="">
</div>
Goal is to render an object without letterboxing, as long as the aspect ratio is within given limits, such as between 16:9 and 4:3.
For example, when the available width of a 16:9 image is reduced below 16:9 aspect ratio, we want to clip the left and right side of the image. If the width is further reduced below 4:3 aspect ratio, we want to keep that aspect ratio and start scaling down.
In this example, you can see how the object scales. The problem with this approach is that scaling happens immediately, as soon as the available space is even one pixel off.
.iframe {
border: 1px solid black;
width: 350px;
height: 350px;
resize: both;
overflow: auto;
}
.wrapper {
background-color: #c05046;
height: 100%;
display: flex;
}
.image {
margin: 0 auto;
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
<div class="iframe">
<div class="wrapper">
<img class="image" src="https://i.ytimg.com/vi/PX-0Nrg4Yhw/maxresdefault.jpg">
</div>
</div>
[An iframe is simulated in the examples and you can change its size for changing the available space.]
The fluid-ratio trick as explained at https://voormedia.com/blog/2012/11/responsive-background-images-with-fixed-or-fluid-aspect-ratios can somehow achieve scaling between 2 ratios, but has several shortcomings:
It works with a fixed height and only scales width, which makes it work horizontally, but not vertically.
The object is not an arbitrary object but rather a background-image, which means this trick probably won't work with video and other objects.
.iframe {
background-color: #c05046;
border: 1px solid black;
width: 350px;
height: 350px;
resize: both;
overflow: auto;
}
.column {
max-width: 640px;
}
figure.fluidratio {
margin: 0;
padding-top: 15%; /* slope */
height: 240px; /* start height */
background-image: url(https://i.ytimg.com/vi/PX-0Nrg4Yhw/maxresdefault.jpg);
background-size: cover;
-moz-background-size: cover; /* Firefox 3.6 */
background-position: center; /* Internet Explorer 7/8 */
}
<div class="iframe">
<div class="column">
<figure class="fluidratio"></figure>
</div>
</div>
I saw somebody suggest using embedded SVG, but didn't get the examples to work.
Any feedback appreciated.
If I understood the problem right, you want to achieve something like this:
.iframe {
border: 1px solid black;
width: 100%;
height: 100%;
}
.container {
width: 100%;
max-width: 130vh;
position: relative;
margin: 0 auto;
}
.wrapper {
background-color: #c05046;
height: 0;
padding-top: 75%;
position: relative;
width: 75%;
left: 50%;
transform: translateX(-50%);
max-width: 640px;
}
.image {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
height: 100%;
}
<div class="iframe">
<div class="container">
<div class="wrapper">
<img class="image" src="https://i.ytimg.com/vi/PX-0Nrg4Yhw/maxresdefault.jpg">
</div>
</div>
</div>
*the resizing is disabled here, please check in full screen with responsive mode.
Using inner .wrapper, it keeps the part with ratio of 4/3 always visible, but it allows the content to overflow it boundaries. By max-height: 130vh its height keeps scaling also. As it is not based on background-image, it can be used with video as well as image.
The main disadvantage is using a vh unit what keeps it relative to view port size, to parent container height. -> see comment
In this picture, I have a HTML content "div#container". It may contain a lot of things like images, forms and other HTML tags.
I want to resize this div and put it inside other container(s). The new containers may have different widht/height so I have to resize the div#container. It's a bit like to resize an image - I need to keep the width/height ratio. And I need to place the div#container in the center of the new container.
Is it to do so with pure CSS?
Thanks
Here's how you can do it using height: 100% and width: 100% on div#container and padding on div#dash-container:
.container {
background: lightgray;
position: relative;
height: 100%;
width: 100%;
}
.dash-container-1,
.dash-container-2 {
box-sizing: border-box;
border: dashed 2px;
}
.dash-container-1 {
height: 500px; /*whatever sizes you want*/
width: 300px;
padding: 100px 0;
}
.dash-container-2 {
height: 300px;
width: 500px;
padding: 0 5%; //you can use px, %, em, ...
}
<div class="dash-container-1">
<div class="container"></div>
</div>
<div class="dash-container-2">
<div class="container"></div>
</div>
I have few thumbnail image of users and their image can be portrait or wide.
I wish the thumbnails to be in a circle without lose the aspect ratio of it.
So I created a container for each image like that:
<div class='container'>
<img src='' ... />
</div>
With this css:
.container {
border-radius: 50%;
overflow: hidden;
position: relative;
width: 50px;
height: 50px;
img {
width: inherit;
}
}
it works fine with portrait images because the image width inherit from the container.
The problem now is to adapt the same to wide images... I should replace the width with height in order to let in work as expected.
There is a better solution of mine?
Or there is a way with Less to achieve at this?
You should leave the width/height unset and set the max-width/max-height to 100%.
img {
max-width: 100%;
max-height: 100%;
}
This will only downscale images though, not upscale.
width: fit-content; height: fit-content;
.container{
width: 50px;
height: 50px;
border: 1px solid black;
border-radius: 50%;
overflow: hidden;
}
.container > img{
object-fit: cover;
width: 100%;
height: 100%;
}
<div class='container'>
<img src='http://searchengineland.com/figz/wp-content/seloads/2015/12/duckduckgo-logo-wordmark4-1920.png' alt='duck power'>
</div>
So I have a page where the header image can be wider than the width of the content. Say, the content is always 960px wide, but the header image could 1200px wide.
So in order to keep the header image centred I'm using the left: +/-50% trick.
<div class="page">
<header>
<div class="image"><img /></div>
</header>
<article>lots of text...</article>
<div>
div.page {
width: 200px;
background: blue;
margin: 0 auto;
height: 400px;
}
header {
height: 75px;
}
div.image {
position: absolute;
left: 50%;
border: 1px red solid;
}
img {
position: relative;
left: -50%;
height: 50px;
width: 500px;
background: green;
}
article {
background: yellow;
}
So as in this fiddle http://jsfiddle.net/P7F7j/ you can see that horizontal scroll bars display because div.image is off screen, and the same would happen if img is off screen too. Is there any way to remove these elements from the flow so they don't trigger horizontal scrolling?
Make the header min-width: 960px; width: 100%; and set the image as a background-image with style no-repeat center top
That way the header will always be at least 960px and will be filled with your image. Overflowing is handled automatically with background-images.