What's the math behind CSS's background-size:cover

前端 未结 4 1334
长发绾君心
长发绾君心 2021-01-30 13:57

I\'m creating an \"image generator\" where users can upload an image and add text and/or draw on it. The outputted image is a fixed size (698x450).

On the client side,

相关标签:
4条回答
  • 2021-01-30 14:41

    Thanks to mdi for pointing me in the right direction, but that didn't seem quite right. This is the solution that worked for me:

        $imgRatio = $imageHeight / $imageWidth;
        $canvasRatio = $canvasHeight / $canvasWidth;
    
        if ($canvasRatio > $imgRatio) {
            $finalHeight = $canvasHeight;
            $scale = $finalHeight / $imageHeight;
            $finalWidth = round($imageWidth * $scale , 0);
        } else {
            $finalWidth = $canvasWidth;
            $scale = $finalWidth / $imageWidth;
            $finalHeight = round($imageHeight * $scale , 0);
        }
    
    0 讨论(0)
  • 2021-01-30 14:42

    Here's a logic behind cover calculations.

    You have four base values :

    imgWidth // your original img width
    imgHeight
    
    containerWidth // your container  width (here 698px)
    containerHeight
    

    Two ratios derived from these values :

    imgRatio = (imgHeight / imgWidth)       // original img ratio
    containerRatio = (containerHeight / containerWidth)     // container ratio
    

    You want to find two new values :

    finalWidth // the scaled img width
    finalHeight
    

    So :

    if (containerRatio > imgRatio) 
    {
        finalHeight = containerHeight
        finalWidth = (containerHeight / imgRatio)
    } 
    else 
    {
        finalWidth = containerWidth 
        finalHeight = (containerWidth / imgRatio)
    }
    

    ... and you have the equivalent of a background-size : cover.

    0 讨论(0)
  • 2021-01-30 14:45

    I know this is a very old question, but the answer I wrote is actually cleaner by using max and mins on the ratios between the images instead of each image with itself:

    var originalRatios = {
      width: containerWidth / imageNaturalWidth,
      height: containerHeight / imageNaturalHeight
    };
    
    // formula for cover:
    var coverRatio = Math.max(originalRatios.width, originalRatios.height); 
    
    // result:
    var newImageWidth = imageNaturalWidth * coverRatio;
    var newImageHeight = imageNaturalHeight * coverRatio;
    

    I like this approach because it is very systematic — maybe it's the wrong word —. What I mean is you can get rid of the if statements and make it work in a more "math formula" kind of way (input = output, if that makes sense):

    var ratios = {
      cover: function(wRatio, hRatio) {
        return Math.max(wRatio, hRatio);
      },
    
      contain: function(wRatio, hRatio) {
        return Math.min(wRatio, hRatio);
      },
    
      // original size
      "auto": function() {
        return 1;
      },
    
      // stretch
      "100% 100%": function(wRatio, hRatio) {
        return { width:wRatio, height:hRatio };
      }
    };
    
    function getImageSize(options) {
      if(!ratios[options.size]) {
        throw new Error(options.size + " not found in ratios");
      }
    
      var r = ratios[options.size](
        options.container.width / options.image.width,
        options.container.height / options.image.height
      );
    
      return {
        width: options.image.width * (r.width || r),
        height: options.image.height * (r.height || r)
      };
    }
    

    I created a jsbin here if you want to take a look at what I mean with systematic (it also has a scale method that I thought was not needed in this answer but very useful for something other than the usual).

    0 讨论(0)
  • 2021-01-30 14:51

    When using background-size: cover, it is scaled to the smallest size that covers the entire background.

    So, where it is thinner than it is tall, scale it until its width is the same as the area. Where it is taller than it is thin, scale it until its height is the same as the area.

    When it is larger than the area to cover, scale it down until it fits (if there is less overflow in height, scale until the same height, if there is less overflow in width, scale until the same width).

    0 讨论(0)
提交回复
热议问题