正文
1、背景
在网页展示图片是一个很常见的需求,大多数情况下,展示区域的大小是固定的,原图片的大小也是固定的
如果展示区域的宽高和原图片的宽高不等比例,那么在默认情况下很可能会压缩或拉伸图片以适应区域大小
下面我们用两张图片做一个对比实验,假设展示区域的宽高都是 300px
横向图片的宽高分别是 722px 和 88px,纵向图片的宽高分别是 80px 和 525px
<!DOCTYPE html> <html> <head> <style> .image { width: 300px; height: 300px; } </style> </head> <body> <img class="image" src="test.png"> </body> </html>
2、设置 CSS
很显然,这并不是我们想要的,因为它会导致图片变形压缩,我们需要找到一种办法,能让图片等比例缩放
最简单的方法莫过于设置 CSS,使得图片可以自动适应展示区域的大小,代码非常简单
<!DOCTYPE html> <html> <head> <style> .image-box { width: 300px; height: 300px; } .image { width: auto; height: auto; max-width: 100%; max-height: 100%; } </style> </head> <body> <div class="image-box"> <img class="image" src="test.png"> </div> </body> </html>
3、使用 canvas
设置 CSS 样式之后,图片会按照最小边进行等比例缩放,这种解决办法已经可以满足大多数的使用场景
但有时候我们会希望展示区域被占满,鱼和熊掌不可兼得,这时我们不得不裁剪图片能够等比例缩放的最大区域
实际上就是用一个与展示区域等比例的矩形截取图片,并要求截取出来的图片尽可能大且位于原图片的中心位置
<!DOCTYPE html> <html> <head> <script> window.onload = function() { let cvs = document.querySelector('#image') let ctx = cvs.getContext('2d') let img = new Image() img.src = 'test.png' img.onload = () => { let adaptedImage = adaptImage(0, 0, img.width, img.height, 0, 0, cvs.width, cvs.height) ctx.drawImage(img, ...adaptedImage) } } function adaptImage(imgX, imgY, imgW, imgH, cvsX, cvsY, cvsW, cvsH) { let idealW = imgW let idealH = cvsH + (imgW - cvsW) * (cvsH / cvsW) if (idealH <= imgH) { return [0, imgH / 2 - idealH / 2, idealW, idealH, cvsX, cvsY, cvsW, cvsH] } else { idealH = imgH idealW = cvsW + (imgH - cvsH) * (cvsW / cvsH) return [imgW / 2 - idealW / 2, 0, idealW, idealH, cvsX, cvsY, cvsW, cvsH] } } </script> </head> <body> <canvas id="image" width="300" height="300"> </body> </html>