Squaring rectangular image with CSS/Boostrap - css

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>

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";
}

How do I create a simple title bar containing a logo, and preserve the logo's aspect ratio?

I'm trying to create a simple page with a title bar at the top, and a logo in the left of the title bar. I'm new to flexbox and grid and not great at CSS, but it seems sensible and idiomatic to use grid for the main layout, give the title bar a sensible height, and then use flexbox for the title bar itself. But I keep getting results that aren't quite right.
Attempt #1 had a huge problem with image scaling. After reading the spec the scaling seemed like a cyclic dependency caused by one </div> too many. Also I hadn't yet heard of object-fit to control the image aspect ratio.
Attempt #2 is mostly fine. The only issue is the 'letterboxing' of the image: the image content is fine but its box is too wide, due to how margins are handled. Letterboxing is exactly what object-fit: content and object-fit: scale-down are defined to do, but it's not what I want.
Attempt #3 looks just how I want it. But I only achieved that by introducing variables and explicitly setting image width and height, which I was hoping to avoid by adopting grid + flexbox. It also relies on knowing the image's aspect ratio and to sizing accordingly.
Is there a simple way to include an image in my title bar, to preserve the image's ratio, and to avoid letterboxing?
Snippets below. Thanks!
Attempt #1
* {
box-sizing: border-box;
}
.titleBar {
border: 1px solid orange;
align-items: center;
display: grid;
grid-template-rows: 150px;
height: 100%;
}
.titleBar div {
display: flex;
}
.titleBar img {
border: 5px solid lightgray;
max-height: 100%;
margin: 25px;
}
<html>
<body>
<div class="titleBar">
<div>
<img src='https://www.fillmurray.com/600/600' />
</div>
</div>
</body>
</html>
Attempt #2
* {
box-sizing: border-box;
}
body {
align-items: center;
display: grid;
grid-template-rows: 150px;
}
.titleBar {
border: 1px solid orange;
display: flex;
height: 100%;
}
.titleBar img {
border: 5px solid lightgray;
max-height: 100%;
margin: 25px;
object-fit: scale-down;
}
<html>
<body>
<div class="titleBar">
<img src='https://www.fillmurray.com/600/600' />
</div>
</body>
</html>
Attempt #3
* {
box-sizing: border-box;
font-family: 'Courier New', Courier, monospace;
--border-size: 1px;
--row-height: 150px;
--img-margin: 10px;
}
body {
display: grid;
grid-template-rows: var(--row-height);
}
.titleBar {
border: 1px solid orange;
align-items: center;
display: flex;
}
.titleBar img {
border: 5px solid lightgray;
margin: var(--img-margin);
max-height: calc(var(--row-height) - 2*var(--img-margin));
max-width: calc(var(--row-height) - 2*var(--img-margin));
object-fit: scale-down;
}
<html>
<body>
<div class="titleBar">
<img src='https://www.fillmurray.com/600/600' />
</div>
</body>
</html>
I think this is solved. There were 2 issues, one big and one little.
Issue #1 - the default align-items for flexbox is stretch. Since I'm taking up the whole height I didn't think that mattered, but deep in the W3C CSS Box Alignment Spec (section 6.1) it says this about stretch:
Note: The stretch keyword can cause elements to shrink, to fit their container.
This was causing my logo container to shrink vertically which caused letterboxing. Changing to align-items: center fixed that.
Issue #2 was less of a problem and more straightforward. E.g. I was placing an image with a 5:1 aspect ratio, a 10px border and a max-height of 100% inside a grid row with a fixed height of 100px. The layout engine calced a box of 500x100. Perfect. However, once the 10px borders were laid out, that left a content area of 480x80, and that's not 5:1. So it had no choice but to stretch, clip, or letterbox the image, depending on object-fit.
I'm not sure if my solution to Issue #2 is the best, but I decided to go with box-sizing: content-box, and to calc my height as 100% - 2*border size. Everything works, for all images of all aspect ratios, and I never have to specify width.
Snippet with 3 examples with 3 different aspect ratios:
* {
box-sizing: border-box;
}
body {
align-items: center;
border-top: 1px dotted gray;
display: grid;
grid-template-rows: 100px 100px 100px;
margin: 20px 0px 0px 0px;
;
padding: 0px;
row-gap: 25px;
}
.titleBar2 {
border: 1px solid orange;
display: flex;
height: 100%;
align-items: center;
margin: 0px;
column-gap: 25px;
}
.titleBar2 img {
box-sizing: content-box;
--border: 10px;
background-color: pink;
border: var(--border) solid lightgray;
max-height: calc(100% - 2*var(--border));
margin: 0px;
object-fit: contain;
}
<html>
<body>
<div class="titleBar2">
<img src='https://www.fillmurray.com/1200/600' />
<a href='https://www.fillmurray.com/1200/600' target='new'>https://www.fillmurray.com/1200/600</a>
</div>
<div class="titleBar2">
<img src='https://www.fillmurray.com/600/1200' />
<a href='https://www.fillmurray.com/600/1200' target='new'>https://www.fillmurray.com/600/1200</a>
</div>
<div class="titleBar2">
<img src='https://www.fillmurray.com/2000/400' />
<a href='https://www.fillmurray.com/2000/400' target='new'>https://www.fillmurray.com/2000/400</a>
</div>
</body>
</html>

How to shrink a responsive image within a flex container with fixed height

I want to display some divs containing an image and two divs with text in it in a flexbox container with a fixed height.
These divs represent tracks with an album cover, the song name and the artists name.
Like this:
<div class="flex-container">
<div class="track">
<img class="track--image" src="http://lorempixel.com/400/400/">
<div class="track--artist-name">Artist</div>
<div class="track--track-name">Song</div>
</div>
<div class="track">
.
.
.
</div>
The CSS:
.flex-container {
display: flex;
width: 100%;
height: 100px;
background-color: lightblue;
}
.track {
border: 1px solid black;
text-align: center;
max-width: 9rem;
color: black;
}
.track--image {
width: 100%;
border-radius: 50%;
}
.track--name,
.track--artist-name {
width: 100%;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
The problem is that the image has a width of 100% to fit into its parent div. But this also implies that it overflows its parent. And also the two divs within the track div get pushed outside its parents.
How do I prevent the image from beeing too big for its parent div so that either the image and the two divs fit inside the parent?
I also prepared a codepen to better describe the problem: https://codepen.io/anon/pen/YBQGRb
EDIT:
My expectation looks something like this:
As you can see the light grey container is my flex-container within I want to have my track divs. The image and those two texts should fit within even if the height of the flex-container changes.
If you edit your image class like this it works.
.track {
border: 1px solid black;
text-align: center;
width: 9rem;
color: black;
.track--image {
border-radius: 50%;
height:100%;
}
}
https://codepen.io/anon/pen/XOadGO
Does switching height to auto in your .flex-container give you the desired outcome,
.flex-container {
display: flex;
width: 100%;
height: auto;
background-color: lightblue;
}
After comment
All I've done below is add a small amount of padding to the track container to get the image off the top border and forced the image to fit within the fluid-container by control the width.
.track .track--image {
width: 35%;
height: auto;
border-radius: 50%;
}
.track {
border: 1px solid black;
padding: 5px;
text-align: center;
max-width: 9rem;
color: black;
}
I fixed my problem now like this:
.track--image {
height: 66%;
border-radius: 50%;
}
This works not for every height of the flex-container but is okay in my case.

Scale image to maximum size to fit the container

I have a wrapper of fixed sizes with the image inside of it:
.wrapper {
background: yellowgreen;
width: 8em;
height: 8em;
display: flex;
align-items: center;
justify-content: center;
border-radius: calc(11em / 12);
}
.wrapper img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
border: calc(1em / 12) solid black;
border-radius: calc(11em / 12);
}
This is ok:<br>
<div class="wrapper"><img src="https://audiophilesoft.ru/ASIO4ALL/asio4all.png" alt=""></div><br>
This is not ok:<br>
<div class="wrapper"><img src="https://audiophilesoft.ru/design/icons/go.png" alt=""></div>
I need any image to fit the wrapper - with maximum size available, keeping proportions, without cut, and I need the image border to always stick to the image contour (without any gaps between the image and the border). Now it works only for images which sizes are >= wrapper sizes, small images just don't scale.
If I specify width/height instead of max-*, the border becomes fixed and doesn't stick to images contour (there is a vertical or horizontal gap between the border and the image).
How to achieve this? Maybe some CSS tricks, additional wrappers? Actually object-fit works as I need, I just need the border that will stick to image.
Change width and height to max-width and max-height, respectively, in .wrapper:
And do the inverse in .wrapper img selector:
.wrapper {
max-width: 8em;
max-height: 8em;
display: flex;
align-items: center;
justify-content: center;
}
.wrapper img {
width: 100%;
height: 100%;
object-fit: contain;
border: calc(1em / 12) solid black;
border-radius: calc(11em / 12);
}
<div class="wrapper"><img src="https://images.tcdn.com.br/img/arquivos/355878/images/icons/us-flag.png?v=c4a83628611cc4338b8d08bee8d670ae" alt=""></div>
The original image is 32x16: link
As pointed out, my previous solution wasn't what OP actually sought for, so I've updated the answer below with what I believe is a solution. This also works with display:flex.
I've added an extra div called .inner-wrap to make sure that the border exactly surrounds the image at all times and doesn't overflow the container.
.wrapper {
background: yellowgreen;
width: 8em;
height: 8em;
display: flex;
align-items: center;
justify-content: center;
border-radius: calc(11em / 12);
overflow:hidden;
box-sizing:border-box;
}
.wrapper img {
max-height:100%;
width:100%;
display:block;
}
.inner-wrap{
width: 100%;
max-height: 100%;
border:2px solid red;
border-radius: calc(11em / 12);
box-sizing:border-box;
overflow:hidden;
}
This is ok:<br>
<div class="wrapper"><div class="inner-wrap"><img src="https://audiophilesoft.ru/ASIO4ALL/asio4all.png" alt=""></div></div><br>
This is ok?<br>
<div class="wrapper"><div class="inner-wrap"><img src="https://audiophilesoft.ru/design/icons/go.png" alt=""></div></div>
This is ok?<br>
<div class="wrapper"><div class="inner-wrap">
<img src="https://s-media-cache-ak0.pinimg.com/originals/aa/ca/3d/aaca3dc87cede5635530a8448dd39a58.jpg" alt=""></div></div>

Scale an image to maximally fit available space and center it

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)')

Resources