视区相关单位vw, vh..简介以及可实际应用场景

这篇文章发布于 2012年09月24日,星期一,01:15,归类于 CSS相关。 阅读 324970 次, 今日 8 次 39 条评论

 

一、N多的唠哩唠叨

CSS3中一些新的单位早在去年春暖花开的时候就介绍了,参见:CSS长度值及时间、频率、角度单位。显然,其中就提到了本文要感叹的单位vw, vh,见下图:
视区相关单位vh, vw截图

不过“我看见你”和“我触碰你”是不一样的。正好,机缘巧合,最近又与这两个单位想见。大致琢磨了下,貌似vh这个单位可以实现我以前曾希望实现的的整体高度自适应布局。想到这里,自己不由得小兴奋了下,于是决定抽时间研究研究(虽然最近整iPad忙得屁股尿流~~)。

然而…… //zxx: 先卖个关子,一点一点唠叨来~~

vw, vh这个可用来实现动态布局的单位到底潜力如何?我不想直接吐露;请跟随我的学习印记以及心理历程一起去寻找答案吧~~

二、需要提前知道的兼容性

vw, vh, vmin(vm)这几个视区相关单位,在2012年9月23号这天的兼容性为:Chrome 20+, IE9+ 以及Safari 6支持!

著名的CSS属性可用性查询网站caniuse给出了具体的兼容性表,点击这里查看。
视区相关单位兼容性表

因此,本文后面要展示的N个demo,就没有必要再低版本的IE浏览器上查看了~~

三、明确含义

看到上图黄色背景标示的文字(“视窗”用“视区”一词代替更恰当):

vw 相对于视窗的宽度:视窗宽度是100vw

我的第一反应是:如果视区宽度是100vm, 则1vm是视区宽度的1/100, 也就是1%,类似于width: 1%. 但是,这里多次出现的“视窗”是纳尼意思?

是浏览器内部宽度大小(window.innerWidth)?是整个浏览器的宽度大小(window.outerWidth)?还是显示器的宽度大小(screen.width)?我疑惑了!

每当我疑惑的时候,我不是去找个“我觉得应该是”的解释,而是,新建个HTML页面,像学生时代做生物实验般,多条件对比验证之。

为了便于其他同行的快速理解,测试的demo页面我特意添加了交互,您可以狠狠地点击这里:vw所谓视窗何意?demo

下图为在IE9浏览器下默认打开的效果:
vw单位所谓视区指什么的demo IE9下截图

显然,这里的“视区”不可能是浏览器外部的宽度,计算值不匹配。

我们改变浏览器的宽度,然后会看到:
浏览器宽度改变IE9浏览器下的图片宽度

至此,真相大白,“视区”所指为浏览器内部的可视区域大小,即window.innerWidth/window.innerHeight大小,不包含任务栏标题栏以及底部工具栏的浏览器区域大小。

修改vw对应宽度值,图片的尺寸大小可以进一步验证上述结论:
修改vw大小后的效果截图

注:一般情况下,Chrome浏览器浏览器内外宽度是一样的(因为浏览器左右无边框);加上浏览器大小变小时图片尺寸不渲染的bug,因此,上demo最佳测试浏览器是IE9. // zxx: 不容易啊,IE系终于勃起了一把~~

四、承上启下

视区相关单位vw, vh目前浏览器的支持算是比较弱的,因此,基本上不可能从现有的站点上找到相关的实际应用。因此,我没事的时候,脑子里就要盘算,该单位可用在何处呢?如果跟其他CSS3的属性配合使用呢?

首先,很容易想到的是,宽度的自适应布局,例如,两栏1:3的宽度自适应布局:

.sidebar {
    width: 25vw;
    float: left;
}
.main {
    width: 75vm;
    float: right;
}

但是,block水平元素本身具有自适应性,加上这里的vm相比%并没有什么优势。因此,vw单位用做宽度自适应的布局,完全是吃力不讨好得显摆!

我们需要想的是其他一些只能vw, vh才能完成的应用场景,这就是下面依次要展示的内容~~

五、场景之:元素的尺寸限制

我们应该都做过或见过这样的交互:点击下图,弹框查看原始大图;或者一屏内(不能有滚动条)大图幻灯片浏览。这类需求让人头疼的地方之一就是原始大图的尺寸限制问题——因为很有可能图片过大,尼玛一屏显示器区域不够放,我们需要对其进行缩放处理。例如:点击这里查看(无论浏览器尺寸多小,图片永远在一屏内显示)。
图片永远在一屏内显示

这类限制的实现,在当下,需要获得图片的原始大小,以及浏览器内部尺寸,算大小,算比例等,算是比较折腾的。

但是,vw, vh等单位本身就是浏览器视区大小相关单位,直接使用其做限制,岂不省了N多JS代码??

img { max-height: 90vh; }

您可以狠狠地点击这里:vw, vh与图片的尺寸限制demo

例如,在暂未支持vh单位的FireFox 15浏览器下,点击缩略图,会看到高高的图片完全溢出在屏幕之外(没有被限制住 – 父容器没有固定高度值,因此90%打酱油):
FireFox 15.0.1下点击图片缩略图
弹框大图片使用vh限制高度无效的模样

连弹框一起被废掉了

而支持vh单位的IE9浏览器呢~~当当当当,见下面截图:
IE9浏览器下使用vh高度限制成功截图 张鑫旭-鑫空间-鑫生活

IE浏览器这回终于是“媳妇熬成婆”了,不容易,大家鼓掌……

相关图片限制CSS如下:

.vw_vh_img {
    max-width: 90vw;
    max-height: 90vh;
}

注:demo页面使用的弹框脚本就是之前“seajs使用示例及spm合并压缩工具”一文中展示的最终脚本。

六、视区覆盖以及边界定位

既然vw, vh是视区相关单位,我就想到是不是可以利用这个特性实现精确的视区大小覆盖以及视区边界的定位。

拿视区覆盖举例,如果我定义一个元素的高宽如下:

.element {
    width: 100vw;
    height: 100vh;
}

然后,再将其定位到视区左上角,岂不是可以实现视区的完整覆盖;我立马想到了弹出框的半透明覆盖层。您可以狠狠地点击这里:vw, vh视区完全覆盖与纯CSS弹框

建议在Chrome20+浏览器下查看效果(因为有range控件),点击demo页面按钮,则半透明覆盖层显现了——完整覆盖:

半透明覆盖层的完整覆盖

吐槽:

  1. 如果您在FireFox浏览器下查看本demo,会发现,FireFox浏览器下的黑色半透明也是完整覆盖的(图略~),为何?其目前是不支持vw, vh单位的啊!?
    原因就在于,覆盖层为固定定位(fixed)元素(绝对定位(absolute)元素也如此)。本demo中,其高宽100%的效果就跟设置width: 100vw; height: 100vh;是一模一样的。I am a little disappointed!
  2. OK,看上面demo标题可以发现,本demo最重要的知识点其实并不在于vw, vh这两个单位的介绍;而是展示了如果使用纯CSS实现弹框的水平与垂直居中效果(IE6也是可以支持的,不过写法需要变变~以后有机会详细介绍)。拖动range控件,可以看到图片尺寸无论怎样变,弹框总是居中的——纯CSS实现,没有JavaScript的计算与定位,您有兴趣可以研究研究的~~
    拖动滑块
    图片尺寸变大但是弹框一直水平垂直居中对齐

正如上面所提到的,某些情况下,vw, vh所产生的效果与百分比%单位无异,尤其对于absolute/fixed定位属性的元素,例如下面这个边界定位的例子:

您可以狠狠地点击这里:vh, vw等同百分比单位测试demo

//zxx: 我这里更多地是为了演示,其实要实现效果,最简单就是bottom:0.

关键CSS代码如下:

{
    height: 30px;
    margin-top: -30px;

    position: fixed;
    top: 100%;
    top: 100vh;
    left: 5%;
    left: 5vw;
    right: 5%;
    right: 5vw;
}

代码含义很简单,支持vh, vw单位的使用之(因为在后面声明);不支持的就是要百分比%单位。

然后各个浏览器测试发现,效果是一模一样的(不支持position: fixed的IE6就当它不存在吧),固定在视区底部,不随滚动条滚动的空白工具栏:
IE7浏览器下底部工具条固定效果

说实话,原本第一眼看到单位vw, vh的时候,觉得这个单位,说不定会引发目前布局方式的大变革——水平方向流体布局!!

在制作高宽限制demo的时候,我还觉得,应该是可以的。尼玛,当我做覆盖以及定位这两个demo的时候,心一下子凉下去了

  1. vw, vh用在宽度自适应上没有价值——%可以实现之~~
  2. 现在又:vw, vh用在absolute/fixed定位属性元素上没有价值——%可以实现之~~

vw, vh这两个视区相关动态单位似乎应用前景一下子黯淡了很多,潜力似乎也就那样——想来想去,得出一个结论:vw, vh视区大小相关单位只适用于非定位元素高度相关属性上! //zxx: 高度相关属性如 – height/min-height/max-height/line-height/padding-top/padding-bottom等

于是,我下面所设想的应用场景就会脱离宽度,脱离绝对定位元素,会是什么呢??

七、场景之:Office Word效果

我们可以把web页面做得像Office文档那样,一屏正好一页;拖动滚动条,我们可以一直往下看到最后一页。

如果只借助CSS,这种效果绝对定位是实现不了的。因为其top值是动态的(100%, 200%, 300% …),必须借助JavaScript才能实现。而使用vh单位,既能捕获浏览器可视区域高度,又不脱离文档流,真是实现Office Word效果最佳利器!

您可以狠狠地点击这里:vh单位模拟office word效果demo

建议使用Chrome20+浏览器查看demo,IE9浏览器下背景图片的vh单位定位似乎有bug!

您会看到大致如下的效果(下图为手动改小浏览器高度后的效果,实际效果更佳):
高度vh模拟office word的界面效果

相关CSS代码如下:

page {
    display: block;
    height: 98vh;
    width: 69.3vh;
    margin: 1vh auto;
    padding: 12vh;
    border: 1px solid #646464;
    box-shadow: 0 0 15px rgba(0,0,0,.75);
    box-sizing: border-box;
    background: url(office/bl.png) no-repeat 8vh 88vh,
                url(office/br.png) no-repeat 59vh 88vh,
                url(office/tl.png) no-repeat 8vh 8vh,
                url(office/tr.png) no-repeat 59vh 8vh;
    background-color: white;
    position: relative;
}
page:after {
    content: attr(data-page);
    color: graytext;
    font-size: 12px;
    text-align: center;
    bottom: 4vh;
    position: absolute;
    left: 10vh;
    right: 10vh;
}

HTML代码如下:

<page></page>
<page></page>
<page></page>

JavaScript代码为创建data-page属性值,如下:

var elePages = document.querySelectorAll("page"), lenPage = elePages.length;
for (var i=0; i<lenPage; i+=1) {
    elePages[i].setAttribute("data-page", "第 "+ (i+1) +" 页,共 "+ lenPage +" 页");    
} 

说明:

  1. 本demo应用诸多CSS3属性,部分HTML特性,以及高级点的JavaScript API, 因此,一些老的浏览器显然是不支持的,应用在对外的实际项目是不切实际的。不过,用来做个演示文档,或是分享展示工具之类,还是很OK的!
  2. demo页面的宽高按照标准纸张的21:29.7的比例制定,因此,所有单位值都是使用的vh单位。
  3. 本demo <page>元素还可以设置float:leftinline-block两端/居中对齐等,让一屏的水平方向显示多个page页面,就如实际的office word一样。

八、场景之:水平时间轴

水平方向上的流体布局,正在琢磨折腾中,有不少技术难点,稍等几天……

下图为demo雏形截图,其中,左上角第一个已经成型的垂直布局显然要调整成水平方向型的,具体如何操作,请等我再好好想想,您也可以一同思考!
水平时间轴上的水平布局实现雏形

补充于2016年8月8日

  1. vw可用来解决滚动条出现页面晃动的问题
  2. 可以实现等比例图形;
  3. 配合font-size可以实现基于vw的自动缩放式网页布局;

九、结语

视区相关单位除了文章多次提到的vw, vh,还有个vmin(vm – 据说有的浏览器font-size: vm支持),表示视区宽度或高度较小的那个。由于我实在想不出可以使用vmin的场景,因此,未具体介绍。

补充:
@Zearlin vm:…个人觉的很重要,特别是移动平台,可以实现Orientation后内容自动auto-fit的效果,如iBook阅读PDF。

自从上次写了关于CSS学习瓶颈的文章后,还是有不少人询问我,说自己确实觉得有问题,需要突破,不知该从何下手?

以我个人,以本文的内容举例:
照理讲,视区相关单位vw, vh完全是个新东西,兼容性又不好,而且就是个单位,含义不难理解,应该捣鼓不出什么值得学习的东西。实际上,就我个人而言,学到了很多东西,都有哪些呢?

  1. vw, vh的精确含义
  2. 兼容性
  3. 与百分比宽度关系
  4. 与绝对定位元素关系
  5. 应在在何种元素上更有价值
  6. Chrome浏览器下浏览器窗体改变可能的不渲染bug
  7. IE9下vh单位的定位错误bug
  8. vh高度值的内部元素不支持百分比%高度
  9. 温故了CSS3的一些新属性,尤其CSS3 background相关的
  10. 想到并实践了纯CSS下的弹框屏幕水平垂直居中对齐
  11. 实践了使用vh实现水平流体布局的可能性
  12. 学到了列表水平中轴线对齐技术
  13. 以及接下来可能学到的东西~~

多花点功夫,多些想法(感性认知,如果这样……或者那样……),多实践实践(制作demo),多总结总结(写作),再深入延伸延伸(水平方向流体布局 → 水平时间轴);久而久之,水平自然大幅提升,瓶颈自然会突破。

对于技术文章,技术本身有时候是次要的;反而是一些想法,观点会给人以更长远以及持久的积极影响。

本文尽量从我自己,以第一人称来叙述,从前到后,基本上就是自己平时学习新东西的套路。本文的内容从技术层面讲,确实是薄纸一张;但是,希望自己平时的学习套路,思考方式,实际做法等能够为初入前端的新人们一些启示。

文章最后提到的,水平时间轴实现,如果最近实践效果不错,我可能会新开一篇文章,重点介绍,因为我觉得应该会比较有趣!

已经凌晨1点了,我必须撤了。感谢阅读,如有错误,欢迎指正,共同进步!

(本篇完)

分享到:


发表评论(目前39 条评论)

  1. 小秀春子说道:

    最近在刘海屏的iphone发现vh出现不符合的情况,大神,有没有后续更新

  2. chang说道:

    vm 单位提出就是用来解决网页自适应的问题的

  3. 冰箱说道:

    vw,vh在移动端自适应字体大小DIV大小间距坐标什么的,要省掉多少适配分辨率的CSS啊(尤其是万恶的rem定义),实在是爽到不行的一个特性,从此以后我就走在vw vh的不归路上了,随便你用什么移动设备查看网页,效果都是保持一致的

  4. Andy Chen说道:

    vh vw还是和%有很大区别的,%是相对于父元素,会出现级联反应,而且很多时候parent可能是没有宽度和高度的

  5. happylich说道:

    在chrome里做了一个实验,觉得vw的百分比是相对于document.documentElement.clientWidth来计算的,下面是我的代码:

    TO-DO

    html {
    width: 100%;
    background: #f35;
    }
    h1 {
    width: 1000px;
    background-color: #d91;
    }
    h2 {
    width: 50vw;
    background-color: #a3a;
    }

    <h1>Hello world!</h1>
    <h2>你好世界!<h2>

  6. Tiesida说道:

    张大牛,文章中第三点–(我的第一反应是:如果视区宽度是100vm, 则1vm是视区宽度的1/100)这里的单位应该是vw吧。

  7. clfeng说道:

    表达点个人看法哈。觉得其实很多场景的话直接使用%都能实现,就提到的图片的等比例缩放而言,只设置宽度或只设置高度的就可以了,并不涉及大量的js
    另者感觉从rem跟em对比到%和vh,vw可以更好的理解这个东西,rem相对于html的font-size,其解决的问题是em是根据父容器em来计算当多层嵌套后大小计算会变得很复杂,而rem则简单多了。相对比者,如果我有元素我想设置的其宽度就是占屏幕的宽度的50%,那么如果这个元素的父容器的width就是屏幕的width,这样直接50%就够了,但是如果不是的话就只能1.设置fixed或者absolute(当存在一个问题当这样需求的元素多了,页面就会有很多的绝对定位,感觉不是很理想)2.就是使用vh,vw,因为其天然的针对屏幕大小所以可以很直接得达到目的

  8. 后台是用什么写的啊说道:

    哈哈~~大神教我怎么进修哇

  9. 不悔说道:

    公司之前做一个适配手机的页面,我用到了rem单位,发现在华为一款手机下的UC浏览器里面有问题,后来try了又try,决定用VW, 后来后来发现VW也不支持。最后我老大让我放弃了这个浏览器。。。。。。本以为手机里面没有了业界毒瘤的祸害,没想到还有个UC等着我去折腾,还是太年轻啊。

  10. a说道:

    这张图片里的女生到底是谁。。

  11. sadkilo说道:

    一个那么简单的单位,博主都可以捣鼓出那么多东西,厉害厉害

  12. wl说道:

    vh好是好,移动端偏偏UC Browser for Android不支持,麻蛋。

  13. zhoou说道:

    为什么会居中?期初我也不明白,但是看到下面的代码我就知道了,这是博主曾经写过一个水平垂直居中的技巧,就是利用空白标签实现这个效果,只不过这里换成了伪类元素。点赞
    .dialog_container:after {
    display: inline-block;
    content: ”;
    width: 0;
    height: 100%;
    vertical-align: middle;
    }

  14. xuchenhui说道:

    楼主,vw vh其实并非和window.innerWidth/window.innerHeight大小相关,你可以用手机或平板打开你的例子然后手工缩放,你会发现这两个值会随着屏幕虚拟视窗变化但用vm vh 的图片不会变化。在移动端window.innerWidth/window.innerHeight这两个值为visual viewport,会随着屏幕层缩放而变化。因此在移动端vh vw真正的基准度量是layout viewport,也就是meta标签中viewport属性定义的值,默认980px。可以用document.document Element.clientWidth来获取

    • james说道:

      如果把CSS放到JS中,可以直接使用JS来动态计算vw, vh, calc等。
      可以看下这个类库:https://github.com/cssobj/cssobj

  15. 死兔比说道:

    so nice nice nice nice!

  16. 小猿大圣说道:

    原文:于是,我下面所设想的应用场景就会脱离宽度,脱离绝对定位元素,会是什么呢??

    vw vh 这个单位,应该是新布局flex而生的吧?

  17. 雨打浮萍说道:

    求助大神,安卓UC浏览器,vw存在兼容性,怎么解决

  18. 说道:

    vw vh 主要是实现了动态高度百分比布局,比如宽高比不固定的图片,vw很轻易的实现正方形图片缩略图~ 感谢张大神

  19. 石櫻燈籠说道:

    因為有一次要在移動頁面上放一個很長的提示信息,就在移動端用過一次vw,希望能將內容控制在整兩行。
    給了字體3.7vw,測試的幾個手機屏幕寬度都是360px。按理說字體應該就是13.32px或左右。實機測試了一下。多數手機都沒有問題,但遇到個華為榮耀6,直接幹到36px。眼睛直接就瞎了。

  20. moli说道:

    vw,vh在控制字体大小上面不好用!

    • 龙四龙五龙六说道:

      那如果是vw,vh,加上calc,加上百分数呢,我们就用vw和vh控制html根元素的字体大小,其他还是用em,rem。

  21. 很得了说道:

    自己使用过程中发现一个问题
    视窗宽度是算上scroll的,也就是说用100vw的时候当Yscroll出现时就会出现根本不需要的Xscroll,解决方法是fixed或者calc

  22. 一汀烟雨说道:

    vw所谓视窗何意?这个页面的链接错了 打不开
    把域名改成你博客地址就能打开了

  23. 高杰说道:

    .div{
    text-align:center;
    }
    .div.after{
    display: inline-block;
    width: 0;
    height: 100%;
    vertical-align: middle;
    content: ”;
    }
    .div .div-child{
    vertical-align: middle;
    }
    为什么这样能实现垂直居中?

  24. 大猫说道:

    楼主的这个捐赠用微信的转账多方便

  25. 罗小黑学代码说道:

    图片全都坏掉了 真可惜 楼主还会补么

  26. HACK21说道:

    文章不错~ 捐赠共勉~

  27. lys说道:

    沙发一个
    看到你写到“ ’视区‘所指为浏览器内部的可视区域大小”的时候产生了很多想法,,但在往下看的时候心逐渐哇凉哇凉的~~
    期待更多的分享