最近有個需求,要求按照最小邊展現圖片,而且要求同一張圖片,在客戶端側和前端側展現的圖片樣式徹底相同。
這就要求前端跟客戶端的圖片大小要徹底一致,而且雙方協商好按照同一方式進行展現。css
固然,咱們能夠直接用background-size:cover;
來解決,可是,background是畢竟不是img,若是想寬度固定,高度自適應仍是比較難的,而直接用img,那麼只能使用object-fit:cover;object-position:center;
的方法,可是這種方法兼容性較差。 html
object-fit 兼容性前端
因此,這裏咱們探討一些其餘的方法。git
咱們可讓div套住img,經過div限制大小,經過獲取img的尺寸自適應div。github
<div class="img_box">
<img class="img" />
</div>
複製代碼
以下圖所示,左側空白正方形爲一個box,右側矩形爲圖片。canvas
let imgLoader = new Image();
let img = document.querySelector('.img'), box = document.querySelector('.img_box');
let imgSrc = './pic1.jpg';
imgLoader.onload = () => {
let width = imgLoader.width, height = imgLoader.height;
}
imgLoader.src = imgSrc;
複製代碼
注意:要把imgLoader掛載src的地方放在onload之後,以防止有緩存的狀況下onload事件不執行。api
<style>
.img_box{
width: 300px;
height: 200px;
background: black;
position: relative;
overflow: hidden;
}
.img{
position: absolute;
}
</style>
<script>
let imgLoader = new Image();
let img = document.querySelector('.img'), box = document.querySelector('.img_box');
let imgSrc = './pic1.jpg';
imgLoader.onload = () => {
let width = imgLoader.width, height = imgLoader.height;
if(width > height){
img.style.height = '100%';
img.style.left = '50%';
img.style.transform = 'translateX(-50%)';
}else if(width < height){
img.style.width = '100%';
img.style.top = '50%';
img.style.transform = 'translateY(-50%)';
}
img.src = imgSrc;
}
imgLoader.src = imgSrc;
</script>
複製代碼
let imgLoader = new Image();
let img = document.querySelector('.img'), box = document.querySelector('.img_box');
let imgSrc = './pic1.jpg', style = 'cover';
imgLoader.onload = () => {
let width = imgLoader.width, height = imgLoader.height;
if(width > height || (width == height && box.offsetWidth < box.offsetHeight)){
img.style.height = '100%';
img.style.left = '50%';
img.style.transform = 'translateX(-50%)';
}else if(width < height || (width == height && box.offsetWidth > box.offsetHeight)){
img.style.width = '100%';
img.style.top = '50%';
img.style.transform = 'translateY(-50%)';
}
img.src = imgSrc;
}
imgLoader.src = imgSrc;
複製代碼
一樣的道理,若是以最大邊做爲展現的依據,則把兩個規則調轉一下便可,並增長一個選項。瀏覽器
let imgLoader = new Image();
let img = document.querySelector('.img'),box = document.querySelector('.img_box');
let imgSrc = './pic2.jpg',style = 'cover';
imgLoader.onload = () => {
let width = imgLoader.width, height = imgLoader.height;
if(style == 'cover'){
if(width > height || (width == height && box.offsetWidth < box.offsetHeight)){
img.style.height = '100%';
img.style.left = '50%';
img.style.transform = 'translateX(-50%)';
}else if(width < height || (width == height && box.offsetWidth > box.offsetHeight)){
img.style.width = '100%';
img.style.top = '50%';
img.style.transform = 'translateY(-50%)';
}else{
img.style.width = '100%';
img.style.height = '100%';
}
}else if(style == 'contain'){
if(width > height || (width == height && box.offsetWidth < box.offsetHeight)){
img.style.width = '100%';
img.style.top = '50%';
img.style.transform = 'translateY(-50%)';
}else if(width < height || (width == height && box.offsetWidth > box.offsetHeight)){
img.style.height = '100%';
img.style.left = '50%';
img.style.transform = 'translateX(-50%)';
}else{
img.style.width = '100%';
img.style.height = '100%';
}
}
img.src = imgSrc;
}
imgLoader.src = imgSrc;
複製代碼
這裏按照background-size
的方法,增長style
參數,若是style='cover'
,表示按最小邊展現,若是style='cover'
,表示按最大邊展現。緩存
let imgLoader = new Image();
let img = document.querySelector('.img'),box = document.querySelector('.img_box');
let imgSrc = './pic2.jpg',style = 'cover';
imgLoader.onload = () => {
let width = imgLoader.width, height = imgLoader.height;
if(style == 'cover'){
if(width/height > box.offsetWidth/box.offsetHeight){
img.style.height = '100%';
img.style.left = '50%';
img.style.transform = 'translateX(-50%)';
}else if(width/height < box.offsetWidth/box.offsetHeight){
img.style.width = '100%';
img.style.top = '50%';
img.style.transform = 'translateY(-50%)';
}else{
img.style.width = '100%';
img.style.height = '100%';
}
}else if(style == 'contain'){
if(width/height > box.offsetWidth/box.offsetHeight){
img.style.width = '100%';
img.style.top = '50%';
img.style.transform = 'translateY(-50%)';
}else if(width/height < box.offsetWidth/box.offsetHeight){
img.style.height = '100%';
img.style.left = '50%';
img.style.transform = 'translateX(-50%)';
}else{
img.style.width = '100%';
img.style.height = '100%';
}
}
img.src = imgSrc;
}
imgLoader.src = imgSrc;
複製代碼
img寬>img高 bash
可是上面的方法本質上是在加載過一次圖片後,獲取了寬高再進行調整。
雖然一般狀況下,瀏覽器的資源緩存機制會使圖像會只加載一次並在整個會話中使用,可是new Image()
這種方法一般用做預加載,在此處咱們不須要進行預加載,所以咱們能夠作這樣的修改。
let img = box.getElementsByTagName('img')[0];
img.onload = () =>{
let width = img.offsetWidth, height = img.offsetHeight;
if(type == 'cover'){
if(width > height || (width == height && box.offsetWidth < box.offsetHeight)){
img.style.height = '100%';
img.style.left = '50%';
img.style.transform = 'translateX(-50%)';
}else if(width < height || (width == height && box.offsetWidth > box.offsetHeight)){
img.style.width = '100%';
img.style.top = '50%';
img.style.transform = 'translateY(-50%)';
}else{
img.style.width = '100%';
img.style.height = '100%';
}
}else if(type == 'contain'){
if(width > height || (width == height && box.offsetWidth < box.offsetHeight)){
img.style.width = '100%';
img.style.top = '50%';
img.style.transform = 'translateY(-50%)';
}else if(width < height || (width == height && box.offsetWidth > box.offsetHeight)){
img.style.height = '100%';
img.style.left = '50%';
img.style.transform = 'translateX(-50%)';
}else{
img.style.width = '100%';
img.style.height = '100%';
}
}
}
複製代碼
上面這種方式經過直接加載圖片,而後獲取圖片的尺寸,再根據尺寸動態的進行修改圖片的 展現。一樣,也能夠建立一次實例而後利用canvas加載圖像的方法來展現。
let canvas =document.getElementById("canvas"),width = 300,height = 180,imgSrc = './pic2.jpg',style = 'contain';
// 設置寬高經過js來控制,不要用css
canvas.width = width;
canvas.height = height;
let ctx = canvas.getContext("2d");
ctx.fillStyle = '#000000';
ctx.fillRect(0, 0, width, height);
let img = new Image();
img.onload = ()=>{
let {startX, startY, lengthWidth, lengthHeight} = setSize(style,width,height,img.width,img.height);
ctx.drawImage(img, startX, startY, lengthWidth, lengthHeight, 0, 0, width, height);
}
img.src = imgSrc;
/*
* 設置圖片的展現方式
* @param {Number} style 肯定取最小邊仍是最長邊, box_width 固定盒子的寬, box_height 固定盒子的高
* @param {Number} source_width 原圖片的寬, source_height 原圖片的高
* @return {Object} {截取的圖片信息},對應drawImage(imageResource, startX, startY, lengthWidth, lengthHeight, dx, dy, dWidth, dHeight)參數
*/
function setSize(style,box_width, box_height, source_width, source_height){
let startX = 0,startY = 0,lengthWidth = source_width,lengthHeight = source_height;
if(style == 'cover'){
if(source_width > source_height || (source_width == source_height && box_width < box_height)){
lengthWidth = box_width*lengthHeight/box_height;
startX = (source_width - lengthWidth)/2;
}else if(source_width < source_height || (source_width == source_height && box_width > box_height)){
lengthHeight = box_height*lengthWidth/box_width;
startY = (source_height-lengthHeight)/2;
}else{
lengthWidth = box_width;
lengthWidth = box_height;
}
}else if(style == "contain"){
if(source_width > source_height || (source_width == source_height && box_width < box_height)){
lengthHeight = box_height*lengthWidth/box_width;
startY = (source_height-lengthHeight)/2;
}else if(source_width < source_height || (source_width == source_height && box_width > box_height)){
lengthWidth = box_width*lengthHeight/box_height;
startX = (source_width - lengthWidth)/2;
}else{
lengthWidth = box_width;
lengthWidth = box_height;
}
}
return {startX,startY,lengthWidth,lengthHeight}
}
複製代碼
在寫canvas時請注意,canvas的寬高請使用js來調整,而不要修改css。
簡單理解,canvas原理就是一個畫畫的原理,canvas這個標籤是畫板,而在canvas中展現的東西是在畫布上的。在渲染canvas時,初始化畫板爲300*150,一樣畫布也是300*150。當經過改變canvas的style進行寬高的修改時,其實僅僅是修改畫板的寬高,而當畫板與畫紙尺寸不統一時,畫紙內的圖像就會趨向於與畫板的尺寸相同,必然會致使圖像的拉伸或者壓縮。
這裏能夠參考該文章。
所以,在修改尺寸的時候,要同步修改畫板與畫紙,這裏能夠直接使用用HTML 5 canvas 的api動態控制。
以上三種方法,均可以獲得與background-size:cover;background-position:center;
和object-fit:cover;object-position:center;
相同的效果。各位也能夠根據本身的須要調整max-height
或transform
等屬性。
這裏提供下demo,地址可見:github.com/tingchow/se…
若有問題,歡迎提出修改。