一个网页是由众多HTML元素在一定的规则下进行组织排版的产物。因此使用HTML进行应用开发,完成满足用户需求的应用,需要对引擎的排版机制进行一定的了解,这样才能够如指臂使得灵活操纵各个元素,使网页能以需要的效果进行呈现。
为了简化排版逻辑,我们在下面的介绍中统一使用div作为排版控制标签,一起研究如何控制div完成页面的布局。
DIV标签可以把文档分割为独立的、不同的部分。它可以用作严格的组织工具。(W3CSCHOOL)
在AppCan应用开发平台中,默认的UI框架就是依赖于div的各种布局组合,来实现界面的定制。
HTML引擎排版时,可以认为所有网页元素都是包含在body中按照流方式进行排布的,如下图顺序所示。
所有元素都忽略 top, bottom, left, right 或者 z-index 声明。DIV元素作为块元素,默认是自动的开始新一行,所以多个div进行布局时,每一个DIV都占用独立一行。
如下事例代码,我们建立了多个div,观察它的效果。
- <body style="background:#FFFFFF">
- <div>a</div><div>b</div><div>c</div><div>d</div><div>e</div><div>f</div>
- </body>
可以看到每一个div占用了手机屏幕的一整行。BODY被六个div元素撑高。
我们看到div元素内容实际并不需要占用一行,如果希望多个元素根据宽度自动横排适配,可以进行如下调整。
- <body style="background:#FFFFFF">
- <div style="display:inline-block">a</div>
- <div style="display:inline-block">b</div>
- <div>c</div><div>d</div><div>e</div><div>f</div>
- </body>
当为a和b的div指定了inline-block属性后,这两个div元素不再占用一整行,他根据内容自动撑开为8x18的矩形,并在一行内显示。我们扩充b-div元素的内容,使其变长
- <body style="background:#FFFFFF">
- <div style="display:inline-block">a</div>
- <div style="display:inline-block">bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb</div>
- <div>c</div><div>d</div><div>e</div><div>f</div>
- </body>
如上图所示,b-div自动在第二行显示,因此可以看到inline-block属性是串行安排元素,如果不超过一行,则在一行内显示,超过一行,则进行换行。
我们再调整一下代码,把inline-block改为inline
- <body style="background:#FFFFFF">
- <div style="display:inline">a</div>
- <div style="display:inline">bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb</div>
- <div>c</div><div>d</div><div>e</div><div>f</div>
- </body>
看到a b在一行显示,inline和inline-block的区别就是,inline强制元素在一行,而inline-block则是不超过一行在一行内显示,否则换行。
如上是我们常用的div 显示控制。参考w3cSchool整理的display属性表格如下
上面我们讲解了div元素在默认浏览器流式布局的情况下,body中元素布局的情况,而实际上,每一个div元素内部也可以包含其它元素,而这些子元素也是一样按照流方式进行布局。请参看如下代码和效果图。
- <body style="background:#FFFFFF">
- <div style="display:inline">a</div>
- <div style="display:inline">
- <div style="display:inline">A</div>
- <div style="display:inline">B</div>
- <div>C</div>
- </div>
- <div>c</div><div>d</div><div>e</div><div>f</div>
- </body>
从上述事例图中可以看到,包含在div中的子div也遵循之前的流式方式进行排版,并且由于父DIV是由子div支撑起来的,因此子div的布局也会影响到父div在父流中的布局。
但很多情况下,总会有一些捣乱分子存在,他们不希望按照固定的流来安置自己而是更希望自己能够有个性一点。他们使用float和position属性来实现这个目的。float常用的属性如下
loat这个CSS属性比较难于控制,使用的好,那么你可以把布局做的很眩,使用的不好,界面会乱的一塌糊涂。如下是摘录的float的用法分析,它已经对float进行了***的说明。
#p#
CSS浮动属性Float详解
什么是CSS Float?
float 是 css 的定位属性。在传统的印刷布局中,文本可以按照需要围绕图片。一般把这种方式称为“文本环绕”。在网页设计中,应用了CSS的float属性的页面元素就像在印刷布局里面的被文字包围的图片一样。浮动的元素仍然是网页流的一部分。这与使用绝对定位的页面元素相比是一个明显的不同。绝对定位的页面元素被从网页流里面移除了,就像印刷布局里面的文本框被设置为无视页面环绕一样。绝对定位的元素不会 影响其它元素,其它元素也不会影响它,无论它是否和其它元素挨着。
像这样在一个元素上用CSS设置浮动:
- #sidebar { float: right; }
fload属性有四个可用的值:Left 和Right 分别浮动元素到各自的方向,None (默认的) 使元素不浮动,Inherit 将会从父级元素获取float值。
Float的用处
除了简单的在图片周围包围文字,浮动可用于创建全部网页布局。
Float对小型的布局同样有用。例如页面中的这个小区域。如果我们在我们的小头像图片上使用Float,当调整图片大小的时候,盒子里面的文字也将自动调整位置:
同样的布局可以通过在外容器使用相对定位,然后在头像上使用绝对定位来实现。这种方式中,文本不会受头像图片大小的影响,不会随头像图片的大小而有相应变化。
清除Float
清除(clear)是浮动(float)的相关属性.一个设置了清除Float的元素不会如浮动所设置的一样,向上移动到Float元素的边界,而是会忽视浮动向下移动。如下,一图顶千言。
范例代码和事例截图
- <div style="float:left" >aaaa<br>aaaaa<br>aaaaaa<br>aaaaaa<br></div>
- <div style="float:right" >bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb<br>
- bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb</div>
- <div>cccccc</div>
上例中,侧栏向右浮动,并且短于主内容区域。页脚(footer)于是按浮动所要求的向上跳到了可能的空间。要解决这个问题,可以在页脚(footer)上清除浮动,以使页脚(footer)待在浮动元素的下面。
- #footer { clear: both; }
- <div style="float:left" >aaaa<br>aaaaa<br>aaaaaa<br>aaaaaa<br></div>
- <div style="float:right" >bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb<br>
- bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb</div>
- <div style="clear:both">cccccc</div>
清除(clear)也有4个可能值。最常用的是 both,清楚左右两边的浮动。left 和 right 只能清楚一个方向的浮动。none 是默认值,只在需要移除已指定的清除值时用到。inherit 应该时第五个值,不过很奇怪的是 IE 不支持(这个不奇怪吧,IE 从来都这么特立独行吧 -糖伴西红柿注)。只清除左边或右边的浮动,实际中很少见,不过绝对有他们的用处。
#p#
伟大的塌陷
使用浮动(float)的一个比较疑惑的事情是他们怎么影响包含他们的父元素的。如果父元素只包含浮动元素,那么它的高度就会塌缩为零。如果父元素不包含任何的可见背景,这个问题会很难被注意到,但是这是一个很重要的问题。
塌陷的直观对立面更不好,看看下面的情况:
当上面的块级元素自动扩展以适应浮动元素时,段落间的文本流中会出现非自然的空白换行,而且没有有效的方法来修正这个问题。对于这种情况,设计师的抱怨会更甚于对塌陷的抱怨(没理解,不是设计完成之后才会进行页面编码吗?-糖伴西红柿)。
为了防止怪异的布局和跨浏览器的问题,塌陷问题几乎总是被要处理的。我们在容器中的浮动元素之后,容器结束之前来清除浮动。
清除浮动的技术
如果你很明确的知道接下来的元素会是什么,可以使用 clear:both; 来清除浮动。这个方法很不错,它不需要 hack,不添加额外的元素也使得它有良好的语义性。当然事情并不是都可以这样解决的,工具箱中还是需要另外几个清除浮动的工具。
◆ 空div方法从字面来看,是一个空的 div。
有时可能会用
或者一些其他元素,但是 div 是最常用的,因为它没有浏览器默认样式;没有特殊功能,而且一般不会被 css 样式化。这个方法因为只是为了表现,对页面没有上下文涵义而被纯语义论者嘲笑。诚然,从严格的角度来说他们是对的,但是这个方法有效而且没有任何伤害。
◆ overflow 方法在父元素上设置 overflow 这个 css 属性。如果父元素的这个属性设置为 auto 或者 hidden,父元素就会扩展以包含浮动。这个方法有着较好的语义性,因为他不需要额外元素。但是,如果需要增加一个新的 div 来使用这个方法,其实就和空 div 方法一样没有语义了。而且要记住,overflow 属性不是为了清除浮动而定义的。要小心不要覆盖住内容或者触发了不需要的滚动条。
◆ 简单清除方法使用了一个聪明的 css 伪选择符(:after)来清除浮动。比起在父元素上设置 overflow,只需要给它增加一个额外的类似于”clearfix”的类。这个类使用如下 css:
- .clearfix:after {
- content: ".";
- visibility: hidden;
- display: block;
- height: 0;
- clear: both;
这会在清除浮动的父元素之后应用一点看不见的内容。这不是全部内容,还需要一些额外的代码来适应那些老旧的浏览器。
不同的情况需要不同的浮动清除方法。以一个具有不同样式块的网格为例。
为了从视觉上较好的把相似的块联系起来,需要在必要的地方开启新行,这里是颜色改变的地方。如果每个颜色组都有一个父元素的话,我们可以使用 overflow 或者 简单清除方法。或者,在每组之间用一个空div方法。额外的 div 之前并不存在,可以自己试试来看看哪个方法好。
#p#
浮动的问题
浮动因脆弱而饱受诟病。大多数的脆弱性来自于 IE6 及其一系列的浮动相关 bug。因为越来越多的设计师不再支持 IE6 了,你也可以不关注它了。不过对于那些要关注的人来说,这里有些大概。
◆ 推倒是浮动元素内的元素(大多是图片)比浮动元素本身宽造成的现象。大多数的浏览器会在浮动之外渲染图片,但是不会有伸出来的部分影响其他布局。IE 会扩展浮动来包含图片,精彩大幅度地影响布局。一个普遍的例子是突破伸出主内容之外把侧栏推到下面。
◆ 快速修正:确保不是图片造成这种情况,使用 overflow:hidden 来切除多余的部分。
◆ 双倍边距bug处理 IE6 时,另一个需要记住的事情是,如果在和浮动方向相同的方向上设置外边距(margin),会引发双倍边距。快速修正:给浮动设置 display:inline; 而且不用担心,它依然是块级元素。
◆ 3像素间距是指挨着浮动元素的文本会神奇的被踢出去3像素,好像浮动元素的周围有一个奇怪的力场一样。快速修正:在受影响的文本上设置宽度或高度。
◆ IE7 中,底边距 bug是当浮动父元素有浮动子元素时,这些子元素的底边距会被父元素忽略掉。快速修正:用父元素的底内补白(padding)代替。
接着我们继续说明其他用于定位的元素
position常用的属性如下(static为默认属性)
其中absolute和fixed都会使元素不再遵循流的布局方式。而relative还会使元素继续遵循流的方式,只是使其定位于相对于其在流中的位置的相对位置上。我们先看一下relative的效果。
- <body style="background:#FFFFFF">
- <div style="display:inline">a</div>
- <div style="display:inline">
- <div style="display:inline;position:relative;left:30px">A</div>
- <div style="display:inline">B</div>
- <div>C</div>
- </div>
- <div>c</div><div>d</div><div>e</div><div>f</div>
- </body>
上述代码中,我们指定了A元素在其流中位置向右30px,这个变化并不会影响到B元素在流中的布局。
好后面我们关键介绍absolute和fixed属性。
absolute属性
我们用一段代码和截图来直观的体验一下
- <div>a</div>
- <div style="position:absolute;left:50px">b</div>
- <div>c</div>
- <div>d</div>
- <div>e</div>
从上图看到,我们为b元素定义了position为absolute,并指定其离左边50px(这个50px是距离屏幕边界,如何相对于其父元素定位,后面有详细介绍)。由于指定了absolute属性,则b元素已经不再从属于流,因此流按照acde的方式进行排列。
上述代码中有一个疑问,我们指定了b元素为absolute,但并没有指定b的top坐标,那为什么b元素显示在目前这个位置呢?这个可以这样理解,每一个元素可以使用top left right bottom四个位置进行定位,b元素在流中的时候,浏览器为其计算了top left right bottom四个位置值,当我们指定了absolute和left属性时,引擎直接修改了left和right属性,但top和bottom还使用了之前流中的位置,因此b元素会在目前屏幕中这个位置显示。如果我们再为b元素指定top或bottom属性,则b元素将会变更位置,按照指定位置显示。left和bottom、top和bottom是一组属性,当我们指定了left,则right自定按照width-left获得,如果指定了right,则left按照width-right获得,当同时指定了left和right则按照left处理。top和bottom同理。
absolute属性会使元素根据相对于 static 定位以外的***个父元素进行定位。这段话如何理解呢?请参看如下代码,了解子元素使用absolute的效果
- <div>a</div>
- <div style="position:absolute;right:20px;">b</div>
- <div>c<div style="position:absolute;left:20px;">ccc</div></div>
- <div>d</div>
- <div>e</div>
上述代码中我们在c元素内指定了元素ccc,ccc元素使用absolute定位,指定了其left=20px。但从上述截图中我们看到ccc元素指定的20px并不是距离c元素左边界20px而是距离整个屏幕边界,也就是body的边界20px。这就是由于c元素默认position属性为static,body默认的position属性也是static,因此ccc元素并没有依据c的位置也没有根据body进行定位而是根据屏幕位置进行了定位。好,我们修改一下c元素的posiiton属性看看效果。
- <div>a</div>
- <div style="position:absolute;right:20px;">b</div>
- <div style="position:relative">c
- <div style="position:absolute;left:20px;">ccc</div></div>
- <div>d</div>
- <div>e</div>
上述代码中,我们指定了c元素的定位属性为relative,这时,ccc元素属性为absolute时,就根据了c元素的边界进行了定位。那如果c元素也是absolute定位该是什么效果呢?
- <div>a</div>
- <div style="position:absolute;right:20px;">b</div>
- <div style="position:absolute;left:80px">c
- <div style="position:absolute;left:20px;">ccc</div>
- </div>
- <div>d</div>
- <div>e</div>
上述代码中我们修改了c元素为absolute定位,左边距80px,可以看到ccc元素根据c元素定位后的位置进行了相对定位。
#p#
fixed属性
生成绝对定位的元素,相对于浏览器窗口进行定位。
元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。
这个属性可以控制元素在硬件屏幕上的指定位置显示,它不再从属于流,也不再使元素从属于其父元素属性进行定位,而是直接根据硬件屏幕进行定位。这个属性主要用于超出浏览器窗口的网页时,保持某些元素永远浮动于屏幕的制定位置。我们举一个事例来看他的效果。
- <div>111</div>
- <div>222</div>
- <div>333</div>
- <div>444</div>
- <div>555</div>
- <div>111</div>
- <div>222</div>
- <div>333</div>
- ... ... ... ... ... ...
- <div>444</div>
- <div>555</div>
- <div style="position:fixed;left:50px;top:90px">I am fixed</div>
我们建立多个div条目使其超出屏幕容纳范围,然后加入一个fixed的元素,并指定其位置。然后滚动屏幕,可以看到不论网页怎么滚动,fixed元素始终在屏幕指定的物理位置。从上面看出,fixed属性在界面设计中是非常关键的功能,但遗憾的是在android2.2以下和iOS5.0以下平台都不支持这个属性。在AppCan平台,我们提供了几种机制来实现相关的类似功能。具体可以参考我们相关的网站。
通过上面的讲述,我们已经知道了比较常见的几种用于布局的属性,来实现元素的定位。但这些属性还不能够完成我们对界面的布局要求,还要与其他相关定位属性进行结合。下面我们就对这些属性进行分析。
之前的事例中我们发现,div元素本身的大小,完全根据其子元素的高宽来支撑的,但实际情况是我们希望为d iv元素本身设定一个大小高宽位置,然后在其中排布子元素。下面是几种方案
在流中的div元素会完全忽略top, bottom, left, right,width,height这些属性,因此无法为流中的div元素指定大小位置等信息。在这种情况下如果需要调整div的高宽值,我们可以使用padding属性、min-height、max-height、min-width、max-width来处理。我们一一进行介绍
padding 属性是用来指定一个元素的内边距。一个元素的宽度可以认为是"
宽度=左边框宽度+左侧内边距+内容宽度+右侧内边距+右边框宽度",就如下图所示。下图中的margin属性是元素与其他元素间的间隔也就是外边距。
padding属性的衍生属性有padding-top padding-bottom padding-right padding-left,分别制定四个边距。
那么我们如何使用padding 来调整div的高宽呢,很简单直接为Padding指定数值即可。从上面的公式可以看出,如果希望宽度固定,再指定了边框宽度和边距宽度后,内容宽度也就必须是定值。因此,使用padding来调整高宽时,常用在固定高宽的场景中。下面举一个事例。
- <div style="position:relative;padding:80px;border:1px solid #000">111
- <img style="position:absolute;left:0px;top:5px;"
- width="70px" height="30px" src="http://www.google.com.hk/intl/zh-CN/images/logo_cn.png">
- </img>
- </div>
上面事例中我们看到,我们设定了padding属性为80px,也就是说111元素外围四个边内边距都为80px,这时我们为img子元素指定了绝对定位left:0px top:5px。介绍一个定位的小技巧,上面的google图片我们希望他居于左侧并且纵向居中,该如何做呢?
- <div style="position:relative;padding:80px;border:1px solid #000">111
- <img style="position:absolute;left:0px;top:50%;margin-top:-15px" width="70px" height="30px" src="http://www.google.com.hk/intl/zh-CN/images/logo_cn.png">
- </img>
- </div>
上面的代码中,我们为图片指定了top位置为其父元素的50%位置(父元素Position要设定为非static),但这指定了图片的左上角位置在50%,图片还是不居中,这时我们为图片指定了上外边距为-15px,也就是图片高度的一半,图片会再上移15点,达到居中的效果。其实公式很简单 positionY=divHeight*50%-imgHeight*50%
下面是一个padding复杂应用效果的范例截图
上面我们使用padding来控制元素的高宽,但在元素包含内容会出现变化的情况下,想固定高宽,padding已经不能够胜任。这时我们会用到min-width、max-width、min-height和max-height属性。我们看下面的min-height事例,来了解其使用效果。
- <div style="position:relative;padding-left:80px;border:1px solid #000;min-height:100px">
- 111<br>222<br>
- <img style="position:absolute;left:0px;top:50%;margin-top:-15px" width="70px" height="30px"
- src="http://www.google.com.hk/intl/zh-CN/images/logo_cn.png">
- </img>
- </div>
上述的范例中,我们为div制定了左侧内边距80px用于容纳图片,高度指定了最小高度100px,这时我们可以看到,即使内容高度发生了变化,div高度还是100px。但这个范例里只加入了111 222两个内容部分,如果内容部分高度超过了100px,会出现什么情况呢?
div被撑开,如何避免这种问题呢?看如下代码
- <div style="position:relative;padding-left:80px;border:1px solid #000;min-height:100px; max-height:100px;overflow:hidden>
- 111<br>222<br>
- <img style="position:absolute;left:0px;top:50%;margin-top:-15px" width="70px" height="30px"
- src="http://www.google.com.hk/intl/zh-CN/images/logo_cn.png">
- </img>
- </div>
与之前代码相比,我们为div指定了max-height属性,来控制其***高度,避免内容超出区域时撑大div,同时指定了overflow属性,避免显示到div外侧(overflow属性在不同的手机平台上和平台的不同版本中,支持度也是不同的,auto和scroll属性基本都不会被支持。因此,如果希望在div内部实现滚动效果,目前浏览器原始功能还是不能够实现的)
上边的事例中我们都使用的是px作为长度高度单位,但是在手机应用研发中,面对的手机硬件屏幕尺寸、分辨率等类别非常多,如果使用px作为度量单位,会造成在低分辨率手机显示正常的元素,在高分辨率上显示的非常小而无法让用户操作,或者在高分辨率手机的屏幕上显示正常,但在低分辨率屏幕上又过大无法完全展示。对于这种情况,我们推荐,在手机应用研发中,网页内部的度量单位都使用em。什么是em呢?假如当前网页的默认字体是12px,那么0.5em就是6px,如果字体是32px那么0.5em就是16px。em是当前字体大小相对单位。这样,我们只需要为页面在不同分辨率的手机指定不同的字体大小,而页面内部元素都指定em为单位,即可做到在不同分辨率上保持相近的效果。那如何来为每个页面指定字体呢,我们使用media query属性。下面代码摘录于AppCan UI框架包
- @media all and (min-width:340px) and (min-height:620px),(min-width:620px) and (min-height:340px)
- {
- html
- {
- font-size:20px;
- }
- .ui-block-auto
- {
- width:33.333%
- }
- }
- @media all and (min-width:420px) and (min-height:760px) and (max-height:900px),
- (min-width:760px) and (max-width:900px) and (min-height:420px)
- {
- html
- {
- font-size:24px;
- }
- .ui-block-auto
- {
- width:33.333%
- }
- }
- @media all and (min-width:1000px) and (min-height:740px),(min-width:740px) and (min-height:1000px)
- {
- html
- {
- font-size:20px;
- }
- .ui-block-auto
- {
- width:20%
- }
- }
从上述代码中,我们可以看到如何为不同分辨率的屏幕指定字体的。但这又衍生出了另一个问题,当手机进行横竖屏进行切换时,手机认为分辨率发生了变化,这时会造成上述media适配出现适配到其他分辨率的情况,有可能手机竖屏时布局正常变成横屏时,真个布局发生了放大或缩小,字体也出现了变化。如何解决这种问题呢?有几种方法
1.如果软件只需要在竖屏使用,AppCan平台为应用提供了配置选项,只需要在调整一下配置即可使应用不再转屏。
2.如果应用需要转屏支持,可以在网页中加入下述代码
- document.body.style.fontSize=window.getComputedStyle(document.body,null).fontSize;
上述代码的作用是为body的style指定字体,而字体是由浏览器计算得来的。由于style属性优先级高于CSS类,因此,可以使手机旋转时的适配无效,保证手机界面不管横竖屏始终保持一种字体。
3.如果应用需要支持旋转屏,并且确认软件只运行于指定的手机分辨率上,可以调整media query,使其对横竖屏情况进行分别适配。
到此,我们已经基本介绍了在手机HTML应用研发中,如何通过css属性对手机的元素进行定位的。希望能对大家使用HTML进行手机应用研发有所帮助,谢谢。
AppCan移动应用开发平台的开发环境和指导帮助可以参考我们的网站 www.appcan.cn
作者:AppCan.cn
*为尊重作者劳动成果,转载请注明出处*