skip to Main Content

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.

2

Answers


  1. It’s not entirely clear what you’re trying to achieve. But you can place img with object-fit: contain in a div, which will have an aspect-ratio: 1.5:

    // 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-img{
        aspect-ratio: 1.5;
        max-height:100%;
        max-width:100%;
        margin:auto;
        outline:solid 1px yellow;
    }
    
    img {
      width:100%;
      height:100%;
      object-fit: contain;
    }
    
    /* 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%;
      display:flex;
      flex-direction:column;
    }
    
    .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">
        <img src="https://picsum.photos/400" 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 should be a 3:2 aspect ratio but is it's instrinsic square.
      </div>
    </div>
    Login or Signup to reply.
  2. You want object-fit: cover. Create a container with the desired aspect ratio. Fill that with your image, styled with width and height both set to 100% and object-fit: cover. Your image will be automatically resized and cropped to cover the container. You can even use object-position to control which parts of the image will be cropped.

    // 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-img{
        aspect-ratio: 1.5;
        max-height:100%;
        max-width:100%;
        margin:auto;
        outline:solid 1px yellow;
    }
    
    img {
      width:100%;
      height:100%;
      object-fit: cover;
    }
    
    /* 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%;
      display:flex;
      flex-direction:column;
    }
    
    .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">
        <img src="https://picsum.photos/400" 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 should be a 3:2 aspect ratio but is it's instrinsic square.
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search