user541686
user541686

Reputation: 210455

How to set <img> max-height: width; without repercussions?

Here's what I'm trying to accomplish in pure CSS:

  1. I'm given an arbitrary div. I know nothing about its layout except that its height can be sufficiently large to contain the content I will put in it.
    In particular, to be absolutely explicit, this means I don't know its positioning, padding, margins, width, etc. and hence nothing in the solution should depend on their particular values.

  2. I'm given an image file with arbitrary dimensions to place inside the div (directly or indirectly).

  3. CSS should scale down the image to ensure its width does not exceed that of its parent.

  4. CSS should then crop the image to a circle.

In the end, then, I should see a circular image fit into the div without any aspect distortion, neither of whose dimensions exceed that of the original.

Here's what this would look like in my ideal world:

<!DOCTYPE html>
<head>
	<style type="text/css">
		img {
			max-width: 100%;
			max-height: width;  /* I wish this was a thing... */
			border-radius: 50%;
			object-fit: cover;
		}
	</style>
</head>
<body>
	Arbitrary content...
	<div style="width: 25%; margin-left: 10px; top: 1em;"> <!-- arbitrary -->
		<img src="https://i.sstatic.net/8mNMb.png"/>
	</div>
	Arbitrary content...
</body>
</html>

Now obviously that doesn't work, because you can't do height: width.

But what can I do instead? I've tried every trick in the book I could find, but they all end up failing spectacularly in some way or the other. Here's an example with the height: 0; padding-bottom: 100%; trick:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
	<style type="text/css">
		.square {
			height: 0px;
			padding-bottom: 100%;
		}
		.circle {
			position: absolute;
			max-width: 100%;
			height: 100%;  /* not really sure what to put here */
			border-radius: 0%;
			object-fit: cover;
		}
	</style>
</head>
<body>
	Arbitrary content...
	<div style="width: 25%; margin-left: 50px; top: 1em;">
		<div class="square">
			<img class="circle" src="https://i.sstatic.net/8mNMb.png"/>
		</div>
	</div>
	Arbitrary content...
</body>
</html>

How do I achieve this?

Upvotes: 0

Views: 579

Answers (2)

JasonB
JasonB

Reputation: 6368

Your second snippet was close. You need position:relative; on the square container so you can set the circle's height and with to 100% of that square container. Using object-fit: scale-down; on the img tag seems to do it.

.circle {
  height: 0px;
  padding-bottom: 100%;
  position: relative;
  border-radius: 50%;
  overflow: hidden;
}

.circle img {
  position: absolute;
  width: 100%;
  height: 100%;
  object-fit: scale-down;
}
Arbitrary content...
<div style="width: 25%; margin-left: 50px; top: 1em;">
  <div class="circle">
    <img src="https://i.sstatic.net/8mNMb.png" />
  </div>
</div>
Arbitrary content...
<div style="width: 250px;">
  <div class="circle">
    <img src="https://picsum.photos/68/50" />
  </div>
</div>
Arbitrary content...
<div style="width: 250px;">
  <div class="circle">
    <img src="https://picsum.photos/200/300" />
  </div>
</div>
Arbitrary content...
<div style="width: 250px;">
  <div class="circle">
    <img src="https://picsum.photos/300/200" />
  </div>
</div>
Arbitrary content...
<div style="width: 250px;">
  <div class="circle">
    <img src="https://picsum.photos/400/400" />
  </div>
</div>

Upvotes: 1

connexo
connexo

Reputation: 56754

You can capitalize on the fact that percentage-based paddings always refer to the width of the parent element, even if applied to padding-top and/or padding-bottom. So you could work with a height: 0; and padding: 50% 0; to get a square div at all times.

Examples:

div div {
  background: #ccc;
  border-radius: 50%;
  height: 0;
  padding: 50% 0;
}

.a {
  width: 20px;
}

.b {
  width: 80px;
}
<div class="a">
  <div></div>
</div>

<div class="b">
  <div></div>
</div>

Now you can simply apply the background-image of your choice to div div.

Upvotes: 0

Related Questions