浅谈图片宽度自适应解决方案

2015/10/19 · CSS,
HTML5 · 3
评论 ·
自适应

原文出处: 百码山庄   

在网页设计中,随着响应式设计的到来,各种响应式设计方案层出不穷。对于图片响应式的问题也有很多前端开发人员在进行研究。比较好的图片响应式设想便是在不同的屏幕分辨率下使用不同实际尺寸的图片,而达到在高速网络环境中使用大或超大高清图片,在低速网络或需要替用户节省流量资源的环境中使用小而清晰的图片,保证用户无论在何种环境下都能有良好的浏览体验。然而这是一个庞大而具有挑战的工作,我这里不做这个讨论,因为我目前还没有这方面很好的实践。这里我是要跟大家讨论下同一张图片在不同宽度的显示区域中的显示问题。

//SizeForLabel.h
@interface SizeForLabel : NSObject
+(CGSize)labelRectWithSize:(CGSize)size LabelText:(NSString *)labelText
Font:(UIFont *)font;
@end

首先讲的是三列布局,左右两列宽度固定,中间一列宽度自适应

 微信小程序 图片宽度自适应的实现

父元素  {
    width: 100%;
}

方法一
子元素左浮动

方法二
display: flex;

实现根据屏幕宽度变化字体大小和盒子变化,使用rem;

问题描述

我们先来看下我想要描述的问题。首先我准备了三张宽度不同的图片,让他们垂直排列在页面中,除了去除图片本身在垂直方向上产生的间距,不做其他任何样式处理,这种情况我们通常在博文中经常看到,在写博文的时候经常用到,具体效果请看:图片宽度自适应(1)。简单看下我们的页面结构:

JavaScript

<img src=”imgs/560×200.jpg” alt=””><br> <img
src=”imgs/440×200.jpg” alt=””><br> <img
src=”imgs/300×200.jpg” alt=””>

1
2
3
<img src="imgs/560×200.jpg" alt=""><br>
<img src="imgs/440×200.jpg" alt=""><br>
<img src="imgs/300×200.jpg" alt="">

为了方便查看效果,我们直接调整浏览器宽度来测试。测试效果如下gif图所示:

图片 1

我们不难发现,在我们改变窗口可视区域的时候,图片宽度并不会随之变化,以至于在小屏幕中我们只能开到图片的一部分,这是很多人所不乐见的,因为这极有可能会导致重要信息丢失。那么这个问题如何解决?

//SizeForLabel.m
//参数1:Label的大小
//参数2:Label上文字内容
//参数3:文字的字体大小
+(CGSize)labelRectWithSize:(CGSize)size LabelText:(NSString *)labelText Font:(UIFont *)font{ 
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil]; 
CGSize actualsize = [labelText boundingRectWithSize:size options:NSStringDrawingUsesLineFragmentOrigin attributes:dic       context:nil].size; return actualsize;
}  


self.label = [[UILabel alloc] init];
//Label字体大小(注意:要与自适应方法里的大小一致)
self.label.font = [UIFont systemFontOfSize:20.0f];[self addSubview:self.label];
//计算大小(我这里算的是固定宽度,计算高度;也可以固定宽度,计算高度)
CGSize digestHeight = [SizeForLabel labelRectWithSize:CGSizeMake([[UIScreen mainScreen]bounds].size.width - 20,   MAXFLOAT) LabelText:@"Label上文字内容" Font:[UIFont systemFontOfSize:20.0f]];
//给Label设置大小
self.label.frame = CGRectMake(10, 10, [[UIScreen mainScreen]bounds].size.width - 20, digestHeight);
//文字换行
self.label.numberOfLines = 0;

这个很好实现,左右两列分别左浮动和右浮动并给一个固定宽度,中间不浮动,也不设定宽度。这样基本就可以了。但为了兼容IE还必须做些工作

实例代码:

保真问题:

如果你们设计稿标准是iphone5,那么拿到设计稿的时候一定会发现,完全不能按照高保真上的标注来写css,而是将各个值取半,这是因为移动设备分辨率不一样。设计师们是在真实的iphone5机器上做的标注,而iphone5系列的分辨率是640,实际上我们在开发只需要按照320的标准来。为了节省时间,不至于每次都需要将标注取半,我们可以将整个网页缩放比例,模拟提高分辨率。这个做法很简单,为不同的设备设置不同的meta即可:

var scale = 1 / devicePixelRatio;
document.querySelector('meta[name="viewport"]').setAttribute('content', 'initial-scale=' + scale + ', maximum-scale=' + scale + ', minimum-scale=' + scale + ', user-scalable=no');
解决安卓下1px像素看起来过粗的问题

简单尝试

为了保证信息显示完整,保证图片随可视区域宽度变化而宽度自适应,我直接给图片标签设置了宽度100%,具体效果请看:图片宽度自适应(2)。

和示例一一样,我们还是手动改变可视区域宽度来观看图片的表现:

图片 2

现在看来图片是可以根据可视区域宽度自适应了,但是问题来了:首先,所有图片不论原始大小宽窄一律以可是区域宽度为标准了,齐刷刷的一刀切,毫无美感;其次,当较宽显示区域显示较窄图片时,图片出现严重失真,甚至失去识别度。好吧,窄屏的问题解决了,宽屏的问题有来了,不知道这是要闹哪样!但是问题出来了,我们总要想办法去解决啊,那怎么办呢?

图片自适应大小 很简单 给图片一个固定的宽度,让这个图片根据比例,适应高度,这样图片不会变形
//我先把图片设置成屏幕宽,屏幕高
UIImageView *img = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, [[UIScreen mainScreen]bounds].size.width,       [[UIScreen mainScreen]bounds].size.height)];
[self addSubview:img];
//图片会根据宽度自适应高度
img.contentMode = UIViewContentModeScaleAspectFit; 
//图片会根据高度自适应宽度
//img.contentMode = UIViewContentModeScaleAspectFill;

中间列要不要设置margin-left和margin-right ?

wxml 代码:

针对屏幕变化大小

假如用户开启了转屏设置,在网页加载之后改变了屏幕的宽度,那么监听屏幕的变化就可以做到动态切换元素样式:

window.onresize = _.debounce(function() {
      var deviceWidth = document.documentElement.clientWidth > 1300 ? 1300 : document.documentElement.clientWidth;
      document.documentElement.style.fontSize = (deviceWidth / 6.4) + 'px';
}, 50);

使用媒体查询设置根元素字体大小

优点,就是无需监听浏览器的窗口变化,它会跟随屏幕动态变化。
@media screen and (device-width: 640px) { /*iphone4/iphon5*/
      html {
        font-size: 100px;
      }
    }
@media screen and (device-width: 750px) { /*iphone6*/
      html {
        font-size: 117.188px;
      }
    }
@media screen and (device-width: 1240px) { /*iphone6s*/
      html {
        font-size: 194.063px;
      }
    }

兵来将挡,水来土掩

是问题,总有解决的办法,只是成本高低的问题。对于上面这个问题我思考了许久,刚开始我想使用width: 100%;max-width: 图片宽度; 来处理,但是,我发现图片宽度并不统一,max-width需要针对每一个宽度去设置,那根本不可行,无疑是自找麻烦,因为实际应用中,我们完全无法预知用户将使用多大宽度的图片。所以似乎单从控制图片样式已经找不到什么解决办法了,但是我开始关注 width:100%; 的问题。

我们知道,在CSS中,宽度的百分比是是相对于父级容器宽度的。如果我们能有办法控制图片标签的父容器的宽度,那问题是不是就解决了呢?

首先,为了让图片标签有可控的父元素,我们先对代码结构做一点点调整:

JavaScript

<div class=”img-wrap”> <img src=”imgs/560×200.jpg” alt=””>
</div> <div class=”img-wrap”> <img src=”imgs/440×200.jpg”
alt=””> </div> <div class=”img-wrap”> <img
src=”imgs/300×200.jpg” alt=””> </div>

1
2
3
4
5
6
7
8
9
<div class="img-wrap">
    <img src="imgs/560×200.jpg" alt="">
</div>
<div class="img-wrap">
    <img src="imgs/440×200.jpg" alt="">
</div>
<div class="img-wrap">
    <img src="imgs/300×200.jpg" alt="">
</div>

好了,接下来就是如何控制img-wrap元素的宽度的问题了。我首先想到的是浮动(float),因为我们知道浮动元素的宽度是随内容变化的,所以我先给img-wrap设置了如下样式:

JavaScript

.img-wrap {float: left;}

1
.img-wrap {float: left;}

但是,问题又来了,浮动元素会破坏原有的布局,如果不做清除浮动处理,会导致后面的内容紧跟在浮动元素之后。所以为了保证不影响其他内容,我们还得在img-wrap外面加一个容器来控制浮动与否:

JavaScript

<div class=”row”> <div class=”img-wrap”> <img
src=”imgs/560×200.jpg” alt=””> </div> </div> <div
class=”row”> <div class=”img-wrap”> <img
src=”imgs/440×200.jpg” alt=””> </div> </div> <div
class=”row”> <div class=”img-wrap”> <img
src=”imgs/300×200.jpg” alt=””> </div> </div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div class="row">
    <div class="img-wrap">
        <img src="imgs/560×200.jpg" alt="">
    </div>
</div>
<div class="row">
    <div class="img-wrap">
        <img src="imgs/440×200.jpg" alt="">
    </div>
</div>
<div class="row">
    <div class="img-wrap">
        <img src="imgs/300×200.jpg" alt="">
    </div>
</div>

好吧,现在我们在来看看,被折腾成什么样子了,图片宽度自适应(3):

图片 3

哈哈,好像是我想要的效果了。但是,作为一个有点强迫症的开发者,虽然达到了我想要的效果,但加了那么多层嵌套标签,总让我感觉不舒服。于是,我继续折腾,终于我恍然大悟, display:inline-block 的元素宽度也是随内容变化的,而且图片默认样式恰巧也表现为inline-block的效果,是否可以从这里下手呢?

JavaScript

<div class=”img-wrap”> <img src=”imgs/560×200.jpg” alt=””>
</div> <div class=”img-wrap”> <img src=”imgs/440×200.jpg”
alt=””> </div> <div class=”img-wrap”> <img
src=”imgs/300×200.jpg” alt=””> </div>

1
2
3
4
5
6
7
8
9
<div class="img-wrap">
    <img src="imgs/560×200.jpg" alt="">
</div>
<div class="img-wrap">
    <img src="imgs/440×200.jpg" alt="">
</div>
<div class="img-wrap">
    <img src="imgs/300×200.jpg" alt="">
</div>

结构再度回归到只有一层嵌套,然而css样式却需要调整一下:

JavaScript

.img-wrap {display: inline-block;}

1
.img-wrap {display: inline-block;}

当我,再次进行测试的时候,心情舒畅多了,你们感受下:图片宽度自适应(4)。

最后,补上完整的css代码:

CSS

JavaScript

.img-wrap { display: inline-block; } .img-wrap img { width: 100%;
vertical-align: middle; }

1
2
3
4
5
6
7
.img-wrap {
  display: inline-block;
}
.img-wrap img {
    width: 100%;
    vertical-align: middle;
}

2 赞 10 收藏 3
评论

图片 4

注意,中间那列需要把左右两个外边距分别设为左右两列的宽度,否则会有些问题。如下:

<swiper indicator-dots="{{indicatorDots}}" autoplay="{{autoplay}}" interval="{{interval}}" duration="{{duration}}"> 
  <block wx:for="{{imgUrls}}" wx:key="image"> 
   <swiper-item> 
     <image src="{{item.image}}" model="aspectFit" style="width: {{imageWidth}}px;" bindload="imageLoad" /> 
   </swiper-item> 
  </block> 
</swiper> 

在谷歌、火狐等标准浏览器下是这样的(包括IE8+):

  JS 代码:

中间那列子元素的margin-left或margin-right的起点是不一致的,在IE6、IE7中,即使不给中间列设定margin-left和margin-right,它的子元素的左右外边距的起点仍然是在左右两列宽的的基础上的,就像是有margin-left和margin-right一样。所以为了各浏览器保持一致,中间那列还是设一个margin-left和margin-right为好。

imageLoad: function () { 
  this.setData({ 
   imageWidth: wx.getSystemInfoSync().windowWidth,//图片宽度 

   imgUrls: [ 
     { image: "http://img02.tooopen.com/images/20150928/tooopen_sy_143912755726.jpg" }, 
   { image: "http://img06.tooopen.com/images/20160818/tooopen_sy_175866434296.jpg" }, 
   { image: "http://img06.tooopen.com/images/20160818/tooopen_sy_175833047715.jpg" }], 
   indicatorDots: false,//是否显示圆点 
  autoplay: true,//自动播放 
  interval: 2000,//间隔时间 
  duration: 1000//监听滚动和点击事件 
 }) 
} 

IE6中的3px间隙bug

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

在上图的ie6截图中,我们看到各列之间有一条3px的间隔,这是只有IE6才有的问题。

您可能感兴趣的文章:

  • 微信小程序
    Image组件实例详解
  • 微信小程序
    image组件binderror使用例子与js中的onerror区别
  • 微信小程序使用image组件显示图片的方法【附源码下载】
  • 微信小程序
    图片等比例缩放(图片自适应屏幕)
  • 微信小程序实现图片自适应(支持多图)
  • 微信小程序
    图片宽高自适应详解
  • 微信小程序图片自适应支持多图实例详解
  • 微信小程序实现image组件图片自适应宽度比例显示的方法

如果中间那列的margin-left和margin-right都为0的话,则只要把左列的margin-right设为-3px,右列的margin-left设为-3px就行了。

但如果把中间列的margin-left和margin-right分别为左右两列的宽度时(上面已经说了,这也是必须这样做的),即使把左列的margin-right设为-3px,右列的margin-left设为-3px也还是没有效果。这时候还得把中间列的margin-left设为左列宽度-3px,margin-right设为右列宽度-3px才行。如下:

最终的代码

   body, div {

       margin:0;

       padding:0;

   }

   div {

       height:200px;

       color:#F00;

   }

   .left {

       float:left;

       width:100px;

       background:#00f;

       _margin-right:-3px;

   }

   .right {

       float:right;

       width:100px;

       background:#0f0;

       _margin-left:-3px;

   }

   .center {

       background:#333;

       margin:0 100px;

       _margin:0 97px;

   }

我是left

我是right

我是center

两列布局,一列宽度固定,另一列自适应布局也是这个道理的。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图