Viewport那些事(四)


meta viewport

     

     为了更好地方便网页作者在移动浏览器上设置合适自己网页的viewport,Apple在meta标签中引入了viewport属性,相关的介绍可以看这里:《Using the viewport》

     http://developer.apple.com/library/ios/#documentation/AppleApplications/Reference/SafariWebContent/UsingtheViewport/UsingtheViewport.html

     

scale

     这里缩放比例指的是设备像素和CSS像素之间的比例,即可以认为是device-width/height和visual viewport(可以通过window.innerWidth/Height获取)之间的比例。

旋转屏幕

     Safari旋转屏幕是保持visual viewport的宽度不变,除非超出最大/最小缩放比例,所以旋转屏幕后缩放比例会发生变化。


Viewport的默认值(IOS)

     首先来看看width的默认值,前面和Apple的文档中都有提到viewport的默认值中width为980px,但是当initial-scale被设置为1.0的时候,Safari会认为width的值为device-width。所以如你想设置initial-scale为1.0并且viewport的宽度为980px时,你需要同时设置这两个属性,详见《Using the viewport》。

     其他属性的默认值文档中虽然没有提到,但是很容易试验出来。

     minimum-scale,它的值是根据排版出来的document大小来计算,Safari会取参考值0.25,device-width/document.width和device-height/document.heght的最大值,可以看出Safari的设计是想保证visual viewport刚好包含文档的整个宽度或者刚好包含文档的整个高度。

     maxmum-scale,如果没有指定,Safari会取maxmum-scale为5。

     initial-scale,如果没有指定,Safari会取initial-scale = minimum-scale。


     基于以上这些结论,可以比较容易地知道不同网页在不同meta viewport设置下的layout viewport和初始的visual viewport,我们还是以(三)中的那个页面为例来说明,没有设置viewport属性并且文档高度足够大,如果页面中存在比较大的overflow元素,例如width:2000px,那么文档的宽度document.width就是2000,Safari Mobile根据以上规则计算出的minimum-scale和initial-scale就是document.width/device-width,所以初始打开页面会是这样:

     

     如果没有overflow元素,document.width就是viewport的大小980,初始打开页面就会是这样:


    如果 网页通过javascript动态调整页面的宽度或高度,那么就有可能导致Safari Mobile打开页面后计算出的minimum-scale和initial-scale不断变化而发生抖动,在用户进行了一次缩放或者旋屏之后抖动停止。


initial-scale对width的影响

     如果没有设置width而设置了initial-scale,那么width = device-width / initial-scale

     如果设置了width并且设置了initial-scale,那么width为device-width / initial-scale和设置的width间的最大值 


document大小对minimum-scale的影响

     即使网页作者指定了minimum-scale的值,它也会根据排版出来的document大小来调整,最终的值为minimum-scale,document.width/device-width和document.heght/device-height三者之间的最大值。


Safari中Viewport的处理流程


viewport相关的数据结构

     viewport参数在Document中保存的结构如下所示:

struct ViewportArguments {
    enum {
        ValueAuto = -1,
        ValueDeviceWidth = -2,
        ValueDeviceHeight = -3,
        ValuePortrait = -4,
        ValueLandscape = -5
    };

    float width;
    float minWidth;
    float maxWidth;
    float height;
    float minHeight;
    float maxHeight;
    float zoom;
    float minZoom;
    float maxZoom;
    float userZoom;
    float orientation;
};

   结构中每一个值都对应这meta标签中viewport的属性值,默认值都是ValueAuto(-1)。


触发Viewport更新的时机

     在WebKit源码中,触发viewport更新的时机只有两处,分别是在加载第一次接收到数据并且Document创建之后和Meta标签处理时解析到viewport属性时,相应的函数调用关系图如下:


     


     在Document创建之后更新viewport时ViewportArguments为默认值ValueAuto。


viewportArguments的处理

     线程分工

     在对Viewport的处理中,内核线程仅完成viewport的解析步骤就将viewport参数抛给主线程来处理。

     主线程会完成viewport的计算和处理工作。除了内核线程抛转来的viewport消息,一些其它情况也会触发主线程中viewport的计算步骤。


     在WebKit源码中,WebCore只解析viewport的属性并不处理ViewportArguments(通过Document::processArguments函数解析Viewport参数),而是将其交给ChromeClient来处理,对应的函数调用关系图如下:

     

     


     在Safari的ChromeClientIOS::dispatchViewportPropertiesDidChange函数中会调用Frame::dictionaryForViewportArguments函数将Viewport参数封装成NSDictionary的形式传递给主线程来处理。

NSDictionary* Frame::dictionaryForViewportArguments(const ViewportArguments& arguments) const
{
    return [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:NSFloatValue(arguments.initialScale), NSFloatValue(arguments.minimumScale),
                                                NSFloatValue(arguments.maximumScale), NSFloatValue(arguments.userScalable),
                                                NSFloatValue(arguments.width), NSFloatValue(arguments.height), nil]
                                       forKeys:[NSArray arrayWithObjects:@"initial-scale", @"minimum-scale", @"maximum-scale", @"user-scalable", @"width", @"height", nil]];
}


     主线程在收到消息后会调用UIWebDocumentView的viewportConfigurationsDidChange函数来处理viewport参数。


     


     根据前面的讨论,viewport中最小缩放比例会根据document的大小进行调整,而document的大小在动态网页中经常会发生变化,这是viewport就需要重新计算。所以主线程处理Viewport参数的函数viewportConfigurationsDidChange除了被内核线程Document::updateViewportArguments抛转的消息触发外,还有可能在文档大小发生变化时被调用。


     


     另外,观察Safari中Viewport计算函数的调用栈,还有如下一些情况也可能会触发viewport的重新计算。


    


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值