htmlcssaspect-ratioobject-fit

Combining object-fit: contain and hard-coded aspect-ratio on img


I am trying to combine object-fit: contains with aspect-ratio: 1.5 /* hardcoded number */ on an img.

The image remains square, however:

// Javascript for example resizing panels only.

const leftPanel = document.querySelector('.left-panel');
const rightPanel = document.querySelector('.right-panel');
const panelHandle = document.querySelector('.panel-handle');

let isDragging = false;

panelHandle.addEventListener('mousedown', (e) => {
    isDragging = true;
    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('mouseup', onMouseUp);
});

function onMouseMove(e) {
    if (!isDragging) return;

    const containerWidth = document.body.clientWidth;
    const newLeftWidth = e.clientX;

    if (newLeftWidth < 0 || newLeftWidth > containerWidth - panelHandle.offsetWidth) return;

    const newRightWidth = containerWidth - newLeftWidth - panelHandle.offsetWidth;

    leftPanel.style.width = `${newLeftWidth}px`;
    rightPanel.style.width = `${newRightWidth}px`;
}

function onMouseUp() {
    isDragging = false;
    document.removeEventListener('mousemove', onMouseMove);
    document.removeEventListener('mouseup', onMouseUp);
}
/* img scaling */

img {
  width: 100%;
  height: 100%;
  object-fit: contain;

  /* has no effect */
  aspect-ratio: 1.5;
}

/* panel resizing */

body {
  display: flex;
  height: 100vh;
  margin: 0;
  overflow: hidden;
  user-select: none;
}

.left-panel,
.right-panel {
  height: 100%;
}

.left-panel {
  background-color: lightblue;
  width: 50%;
}

.right-panel {
  background-color: lightcoral;
  flex-grow: 1;
  text-align: center;
}

.panel-handle {
  width: 10px;
  background-color: gray;
  cursor: ew-resize;
}
<div class="left-panel">
  <img src="https://picsum.photos/400" draggable="false" />
</div>
<div class="panel-handle">
</div>
<div class="right-panel">
  <div>
    Drag the center bar to resize these panels.
  </div>
  <div>
    The image should be a 3:2 aspect ratio but is it's instrinsic square.
  </div>
</div>

I want to force the image to aspect-ratio: 1.5, and then use automatic letterboxing.

Conceptually, I want to set aspect-ratio: 1.5, and then have css choose either width: 100% or height: 100% depending on the aspect ratio of the container.

Is this possible in pure CSS? Many related questions are about maintaining an image's existing aspect ratio, which is not what I want.

X for my Y: I have an image from a server which is the wrong aspect ratio. The server is some firmware device that outputs in an aspect ratio which is twice as wide as it should be displayed (for technical reasons). I know the correct display aspect ratio and can set it directly. The <img /> is inside a dynamic container, e.g. from react-resizable-panels.

Edit:

Current behavior (image of regular grid with square aspect ratio):

enter image description here and enter image description here

Desired behavior

enter image description here and enter image description here


Solution

  • Thank you to the other answerers for their time.

    I found my answer here: https://stackoverflow.com/a/66721382/3554391

    Can't explain why it works but there ya go.

    // Javascript for example resizing panels only.
    
    const leftPanel = document.querySelector('.left-panel');
    const rightPanel = document.querySelector('.right-panel');
    const panelHandle = document.querySelector('.panel-handle');
    
    let isDragging = false;
    
    panelHandle.addEventListener('mousedown', (e) => {
      isDragging = true;
      document.addEventListener('mousemove', onMouseMove);
      document.addEventListener('mouseup', onMouseUp);
    });
    
    function onMouseMove(e) {
      if (!isDragging) return;
    
      const containerWidth = document.body.clientWidth;
      const newLeftWidth = e.clientX;
    
      if (newLeftWidth < 0 || newLeftWidth > containerWidth - panelHandle.offsetWidth) return;
    
      const newRightWidth = containerWidth - newLeftWidth - panelHandle.offsetWidth;
    
      leftPanel.style.width = `${newLeftWidth}px`;
      rightPanel.style.width = `${newRightWidth}px`;
    }
    
    function onMouseUp() {
      isDragging = false;
      document.removeEventListener('mousemove', onMouseMove);
      document.removeEventListener('mouseup', onMouseUp);
    }
    /* img scaling */
    
    .left-panel {
      position: relative;
    }
    
    .left-panel-img-wrapper {
      position: absolute;
      margin: auto;
      left: 0;
      right: 0;
      top: 0;
      bottom: 0;
      max-width: 100%;
      max-height: 100%;
      aspect-ratio: 1.5;
    }
    
    img {
      width: 100%;
      height: 100%;
      display: block;
    }
    
    /* panel resizing */
    
    body {
      display: flex;
      height: 100vh;
      margin: 0;
      overflow: hidden;
      user-select: none;
    }
    
    .left-panel,
    .right-panel {
      height: 100%;
    }
    
    .left-panel {
      background-color: lightblue;
      width: 50%;
    }
    
    .right-panel {
      background-color: lightcoral;
      flex-grow: 1;
      text-align: center;
    }
    
    .panel-handle {
      width: 10px;
      background-color: gray;
      cursor: ew-resize;
    }
    <div class="left-panel">
      <div class="left-panel-img-wrapper">
        <img class="left-panel-img" src="data:image/bmp;base64,Qk2mAAAAAAAAAD4AAAAoAAAADQAAAA0AAAABAAQAAAAAAAAAAADEDgAAxA4AAAIAAAACAAAAAAAA//////8AAAAAAAAAAAERAREBEQAAAREBEQERAAABEQERAREAAAAAAAAAAAAAAREBEQERAAABEQERAREAAAERAREBEQAAAAAAAAAAAAABEQERAREAAAERAREBEQAAAREBEQERAAAAAAAAAAAAAA==" draggable="false" />
      </div>
    </div>
    <div class="panel-handle">
    </div>
    <div class="right-panel">
      <div>
        Drag the center bar to resize these panels.
      </div>
      <div>The image to the left should be 3:2 and centered in its panel vertically and horizontally.</div>
    </div>