I am building a chat message and I want to fit an image inside the text bubble. The bubble has a fixed width and should scale its height depending on the image aspect ratio.
I am unable to scale the div to maintain the img aspect ratio. All of the answers found use an <img> tag, while I am using a div and none of that fixed my issue.
This is the desired outcome:
What I have achieved instead is either a very small img (size of an empty speech bubble if I do not impose any vertical or horizontal dimension) or a long img if I impose the width and keep the height dynamic.
.speech-right-wrapper {
max-width: 90%;
display: flex;
flex-direction: column;
}
speech-right-message-container {
display: flex;
justify-content: flex-end;
align-items: flex-start;
}
.speech-right-bubble {
position: relative;
background: rgb(154, 226, 255);
box-shadow: 0px 1px 2px gray;
border-radius: 15px 0 15px 15px;
display: flex;
}
.bubble-background {
width: 200px;
height: auto;
overflow: hidden;
}
.bubble-background-img {
position: absolute;
border-radius: 15px 0 15px 15px;
top: 0;
bottom: 0;
left: 0;
right: 0;
overflow: hidden;
background: no-repeat;
background-size: cover;
background-position: center;
}
<div class="speech-right-wrapper">
<div class="speech-right-message-container">
...
<div class="speech-right-bubble">
<div class="bubble-background">
<div class="bubble-background-img" v-bind:style="{ 'background-image': 'url(' + require('../assets/img/profiles/' + storyPath + bubble.bubble_background) + ')' }" v-bind:alt="bubble.bubble_background"></div>
</div>
...
</div>
...
</div>
</div>
UPDATE
For clarity, I need the <div class="bubble-background-img"> to be fix in width (say 200px) and height: auto to maintain the image aspect ratio; and I need the <div class="speech-right-bubble"> to scale to fit the image inside.
Also, unfortunately I need to use a <div> tag because v-bind:src seems not to work for local images. If I do:
<img class="bubble-background-img" v-bind:src="'../assets/img/profiles/' + storyPath + bubble.bubble_background"/>
I get this:
You should probably find a workaround for your v-bind:src issue since the correct way to display a content image is via the HTML img element.
That said, there is a solution, but it relies on using the CSS content property for element replacement, which is a fairly recent technology that's apparently still not supported in Microsoft Edge. The following CSS code is the gist of it and worked for me in testing in Firefox 68:
div { content: ('image.jpeg'); max-width: 200px; }
(In theory, a variation of this technique should also work with the more backward-compatible CSS ::before and ::after pseudo-elements, but the image inexplicably doesn't scale in my testing. I didn't spend much time experimenting though.)
I'm not a hundred percent certain what you are going for, but you could try setting the background-size as a percentage?
background-size: 100%;
background-position: center center;
Using a percentage in background size lets you scale one or more axis according to the parent container. (e.g. background-size: 100% 100%; would scale width and height, and give an effect equivalent to the contain value).
Would that work?
(Personally, I would load the image using an element as that's what they are there for, and you could use object-fit as appropriate, but obviously depends on how you've architected the view...)
Related
I'm developping an ionic application, and i want to display some images in some cards, the problem is that my images have not the some size, and i want them to look the some.
The idea is to use à css class that will solve the problem ( at least in the width )
.full-width-image {
width: 100%
}
this class will solve the problem of size and all the images will have the some width. how ever i dont know how to make a fixed height for them all. if i add to my css class a fixed height like:
.full-width-image {
width: 100%;
height: 60px;
}
some pictures will look ugly:
how it looks like
what i want is to hide the extra part of the image.
If you have a set width and height you can use object-fit: cover; for the image to fill the entire space without losing its aspect ratio.
I would recommend you to use a flex wrapper around an image.
.wrapper {
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 0 2px gray;
width: 100px;
height: 100px;
overflow: hidden;
margin: 1em;
}
.wrapper img {
border: 1px solid black;
max-width: 100%;
max-height: 100%;
}
.example {
display: flex;
}
<div class="example">
<div class="wrapper">
<img src="https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-icon.png?v=c78bd457575a">
</div>
<div class="wrapper">
<img src="https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-logo.png?v=9c558ec15d8a">
</div>
<div class="wrapper">
<img src="https://upload.wikimedia.org/wikipedia/commons/e/eb/Ash_Tree_-_geograph.org.uk_-_590710.jpg">
</div>
<div>
Using this technique you get a kind of smart image - it scales itself to fit your wrapper, its fixed size, but without distortion. Look, there are black borders around the images, so you can see that both an image with width > height and an image with a tree, where height > width, fit well the wrapper, restricting the width and the height correspondingly.
Also you can you inline-flex instead of flex in the wrapper class.
I tried many ways to achieve this but without success.
Basically, I want to have a div element (like a card) with an image and a text under the image and the goal is to make it responsive so that when the user scales down the browser or they use their phone, this whole div does not get messed up but keeps its proportions. The goal is to have multiple card-like divs setup in a 3x3 matrix. The requirement is that no matter what image is there, it just fills the container - the image should not keep its aspect ratio if its too big, it should always be a squere.
link to current state*
(*it says I am too low level to have images in my posts)
As you can see, the current problem is that the image itself does not fill in the container but, keeps the aspect ration which means the whole container div is different height and it gets pushed to another line instead of making it 3x3. That is as far as I got.
Code is here:
.box {
max-width: 120px;
max-height: 120px;
}
.card-image {
width: 100%;
height: 100%;
max-width: 90px;
max-height: 90px;
border: 1px solid black;
}
<div class="box">
<img ng-src="{{item.img}}" ng-if="item.img" class="app-image" />
<div style="font-size:80%;">{{item.name}}</div>
</div>
I am using angular to fill in the images but that should have no impact on the solution. As far as I know, setting width and height by adding "vw"s to these css parameters is not the best way because then it keeps these values fixed and it is not really responsive
So, at the end of the day, there are two ways you can help me out:
1) with the current code I have, add some css that will make the images stretch its height so that it is the same as width
2) suggest more optimal solution
Thank you
I think the easiest way, with nice browser compatibility would be something like this:
.item {
width: 30%;
height: 0;
padding-top: 30%;
display: inline-block;
background-size: cover;
background-position: center;
}
.container {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
resize: both;
overflow: auto;
}
<div class="container">
<div class="item" style="background-image: url(https://dummyimage.com/600x400/000/fff)"></div>
<div class="item" style="background-image: url(https://dummyimage.com/400x400/000/fff)"></div>
<div class="item" style="background-image: url(https://dummyimage.com/300x400/000/fff)"></div>
</div>
The image will always fill the whole container, and container will keep ratio. You will need to work a little bit on multi row layout, but still I find it the easiest way.
.card-image {
width: 100%;
height: 100%;
max-width: 90px;
max-height: 90px;
border: 1px solid black;
object-fit:fill; /* try fill,cover,contain for different results*/
}
For more info Object fit CSS tricks
I have a two column layout - fixed right column width, an scalable content in the left column.
The layout scales great with different screen sizes until I add images to the scalable column. If the container goes down to the size of the image it pushes the column too wide, squashing my 300px right column.
I set
width:100%;
on the images, which solves the responsiveness issue, but when the container is full screen again the images scale to fill it, which is not what I want because it looks rubbish. I've added
max-width:100%;
which hasn't helped.
In short, I want the image behaviour to be "Be your real size, unless the container is smaller, in which case shrink."
(I should mention that my two-column layout is done with flexbox)
Edit:
After playing around with this for ages, it turns out to be a difference in behaviour between broswers - Chrome scales the container, shrinking the image (as per max-width) but Firefox just pushes all the content out. Open this in each: https://jsfiddle.net/andyg1/sb7zefr5/
Remove width:100%; and keep max-width:100%;. This will keep images at their original size but shrink them to 100% width if the container is smaller.
Here's an example https://jsfiddle.net/v4kL409v/
You can use width: 100% and the real size if the image or the maximum size of the conainer as max-width, for example
my_image {
width: 100%;
max-width: 320px;
}
That way it will shrink with the container, but not grow above a set size.
You can use an image as a background to your flex-item.
background-image, background-repeat, background-position, and most importantly background-size
* {
margin: 0;
padding: 0;
}
body {
width: 100vw;
height: 100vh;
}
.flex {
display: flex;
justify-content: center;
width: 100%;
height: 100%;
}
.bg {
width: 50vw;
height: 50vh;
background: url(https://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png) no-repeat center;
background-size: contain;
outline: 3px dashed red;
flex: 1 0 50%;
}
.rt {
width: 300px;
height: 50vh;
outline: 3px dashed blue;
}
<div class="flex">
<figure class="bg"></figure>
<figure class="rt"></figure>
</div>
After identifying that the problem is different between Firefox and Chrome I did some research to find out that the problem can be fixed by adding:
min-width:0;
to the element containing the responsive. As discussed here: Firefox flexbox image width
Add display:block to image.
.my_image {
display:block;
max-width:100%;
height:auto;
}
I want an image to fill the 100% of its container's width, and I want it to have a max-heigth property set to it, all this keeping the aspect ratio but allowing to lose any part of the image.
img {
max-height:200px;
width:100%;
}
I know a similar thing can be done with background-size property but i want to make this to an inline <img> tag.
Any idea of how could i achieve this using CSS? or javascript?
You can try CSS3 object-fit, and see browser support tables.
CSS3 object-fit/object-position Method of specifying how an object (image or video) should fit inside
its box. object-fit options include "contain" (fit according to aspect
ratio), "fill" (stretches object to fill) and "cover" (overflows box
but maintains ratio), where object-position allows the object to be
repositioned like background-image does.
JSFIDDLE DEMO
.container {
width: 200px; /*any size*/
height: 200px; /*any size*/
}
.object-fit-cover {
width: 100%;
height: 100%;
object-fit: cover; /*magic*/
}
<div class="container">
<img class="object-fit-cover" src="https://i.stack.imgur.com/UJ3pb.jpg">
</div>
Related Info:
Exploring object-fit ★ Mozilla Hacks
Polyfill for CSS object-fit property
You can achieve this using css flex properties. Please see the code below
.img-container {
width: 150px;
height: 150px;
border: 2px solid red;
justify-content: center;
display: flex;
flex-direction: row;
overflow: hidden;
}
.img-container .img-to-fit {
flex: 1;
height: 100%;
}
<div class="img-container">
<img class="img-to-fit" src="https://images.pexels.com/photos/8633/nature-tree-green-pine.jpg" />
</div>
I have a "main-image" containing lots of small images which I "clip" into divs of fixed size by setting the background-position to some negative offsets. This works great!
Now I have a div with a size that changes during the lifetime of the web-page.
The old code had its own backgound-image with the background-size set to "contain". Something like this:
.dump {
display: inline-block;
background-image: url("/some/image.png");
background-repeat: no-repeat;
background-size: contain;
}
And that worked great too.
Now I'm trying to clip that background image from my "main-image".
E.g. My "main-image" has a size 1800px128px
The sub-image I like as background starts #1200px,10px with a size of 200px x 80px.
Is there a way to clip this rectangle and than scale to the dimensions of the containing div (which are unknown at the time of programming)
Thanks for the hint. However, I tried but can't get anything to work:
My problem is, that the div image should follow the height the containing div, so I can't tell size, or scale or zoom or whatever at the time of coding. I give an example:
<div style="width:100%; height:30%; text-align: center">
<div class="dump"></div>
</div>
Now, as I said: The image I want to appear as the background of div.dump is the 200x80px area from the main-image #origin(1200,10) AND I want that resulting image scaled to fit the hight of the container. So, I have a known translation, followed by an unknown zoom. Maybe it's just over my head.
I believe the best way to do this is using css transforms, I found this page for further reference on how to transform a background image and made this fiddle based on it.
The idea is that you will use the classes "icon" and "icon:before" to configure your sprite to fit in an element and use other classes like "smaller" and "bigger" to set the actual size of the element.
.icon
{
font-size: 2em;
text-align: center;
line-height: 3em;
border: 2px solid #666;
border-radius: 7px;
position: relative;
overflow: hidden;
}
.icon:before
{
content: "";
position: absolute;
width: 100%;
height: 100%;
left: 0%;
top: 0%;
z-index: -1;
background: url(http://blogs.sitepointstatic.com/examples/tech/background-transform/background.png) 0 0 repeat;
transform: translate(-50%, -50%) scale(1.5, 1.5);
background-repeat: no-repeat;
background-size: contain;
}
.smaller{
float:left;
width: 120px;
height: 120px;
}
.bigger{
float:left;
width: 200px;
height: 200px;
}
Because css transforms support percentage, the background will be clipped and scaled correctly, according to the size defined in "smaller" and "bigger"