从三栏自适应宽度布局到css布局的讨论
如何实现一个三栏自适应布局,左右各100px,中间随着浏览器宽度自适应?
第一个想到的是使用table布局,设置table的宽度为100%,三个td,第1个和第3个固定宽度为100px,那么中间那个就会自适应了,下面是一个实时的demo:
left | middle | right |
但是table布局是不推荐的,table布局是css流行之前使用的布局,有很多缺点:当table加载完之前,整个table的都是空白的,table将数据和排版参和在一起,使得页面混乱,并且table布局修改排版十分麻烦和困难。
如果不用table布局,那么第二个想到的办法是采用float,让左边的div float left,右边的div float right,如下边所示:
Action 1 先让左右两个div浮动
中间还有一个div,如果将中间的div排在第二:
<div style="float:left;">left</div>
<div>middle</div>
<div style="float:right;">right</div>
那么效果是这样的:
Action 2 右边的div浮动到了第二行
因为div默认的display为block,如果不设置width的话,块级元素会尽可能多地占用水平空间。如果设置了width: 200px,效果是这样的:
Action 3 右边的div仍然浮动到了第二行
第三个div仍然会换行,因为float right会排到当前行尽可能右边的位置,即它的容器盒的边缘或者挨着的上一个float的元素,如果当前行没有空间的话,会不断地往下移,直到有足够的空间。由于middle是一个块盒,即使设置了width,当前行的空间也会被占用,所以right只能到下一行才有空间。
同时注意到middle虽然设置了200px,但是看起来和left一样是100px宽了。这是因为float了的元素虽然在正常的文档流之内,但是只是让相邻(非float)的元素的内容围绕着它排列,它仍然占据相邻元素的background和border空间。如果给middle添加一个白色的border,那么看起来是这样的:
Action 4 浮动的元素占据了文档流相应元素的背景和边缘空间
明显看到,float left的元素占据了middle的background和border的空间,同时middle的内容围绕着left排列。理解这点很重要。
假设middle里面有个p标签,而p标签的内容比较长,那么围绕的效果是这样的:
Action 5 浮动的环绕效果
环绕的元素一旦超出float元素高度之后,会以正常的宽度显示
正如上面的注释一样,在float元素的那一行,相邻的元素的内容的宽度将会缩短,以适应float元素占去的宽度,而一旦超过float元素的区域,相邻元素的内容显示宽度就会正常。
由于默认的div会占一行,所以不能将middle放在第二个div,得放到第三个div。把第二个div和第三个div换一下顺序:
<div style="float:left;">left</div>
<div style="float:right;">right</div>
<div>middle</div>
先让float right的div渲染,再渲染middle的div。因为渲染left之后,left的那一行仍然有空间,这是由于float left之后,只会占据当前行的background和border,而当前行还有很大的空间,于是第二步渲染right时就和left同一行了,效果:
Action 6 先渲染左右两个div,再渲染中间的div
如果不设置middle的width,那么middle将围绕着left和right环绕,和left一样,right也会占用middle的空间。
Action 7 中间的div围绕着左右的div环绕
为了让middle和left/right中间有一个margin值,设置下middle的左右margin各为110px,这样就和左右和中间就各有10px的间距:
Action 8 设置中间div的margin值为100px + 10px
这种办法的优点是实现简单,支持性好。
这种自适应宽度的原理是利用了float的围绕特性,占据自然文档流的background/border位置。这个围绕特性不仅会影响当前行的内容,还会影响下一行的内容,如下说明:
<p>第一段内容,略<img src="" style="float:left;"></img></p>
<p>第二段内容,略</p>
Action 8 float元素占据了下一行的空间
第一段落围绕着图片排列
图片的float属性也影响了第二段落,也就是说float会占据自然文本流相应位置元素的背景和边框,即使和float的元素不在同一行
网上还有一种margin负值法。margin负值法的步骤是:第一步让中间的middle占100%的宽度,而middle的内容设置左右margin各为100px,这样就实现了middle居中自适应宽度的效果:
<div style="width:100%;">
<div style="margin: 0 100px;">middle</div>
</div>
接下来让left的margin-left值为-100%,由于这个比例是相对于浏览器窗口大小的,所以要是left和middle是在同一行的话,left就可以跑到middle的最左边。但是因为middle的容器盒是一个普通的div,会占据一整行,left就会排到下一行,这个时候设置margin-left为一个负数时就跑出屏幕了。所以让middle float一下,left就会排到第一行最左边,同时middle覆盖在上面:
<div style="width:100%; float:left;">
<div style="margin: 0 100px;">middle</div>
</div>
<div style="margin-left: 0">left</div>
从上面可以看到:这样实现,导致left的内容被挤出目标区域,因为正如上面所说,middle占据了left的背景空间,上面的情况是把它占满了,left内容只能overflow了。所以这样实现是有问题的,得让left也向左float一下,这样left就紧挨在middle后面了,由于middle占了100%的宽度,所以再让left向左边margin了-100%后,left就刚好在最左边了。
<div style="width:100%; float:left;">
<div style="margin: 0 100px;">middle</div>
</div>
<div style="float: left; margin-left: -100%;">left</div>
注意这里,虽然left float之后看起来也是被排到下一行了,但和默认的div独占一行是不一样的。float之后的left仍然和middle是同一行的,因为空间不足的时候,float只是把当前行盒的空间撑大,就和一个div块盒里面有很多个display为inline-block的行内级盒是同样的道理。例如:
<style>
button{ width: 150px; }
</style>
<div style="width: 300px;">
<button>按钮1</button>
<button>按钮2</button>
<button style="margin-left: -200px;">按钮3</button>
</div>
按钮3设置了一个很大的margin-left的负值后并不是跑到屏幕外了,而是在和其它两个按钮同一行的位置,显示如下:
注意,设置了float的元素并不是把display改成了 inline-block,大部份display的css计算值都变成了block,同时对原本是display: flex的没有改变:
指定值 | 计算值 |
---|---|
inline |
block |
inline-block |
block |
inline-table |
table |
table-row |
block |
table-row-group |
block |
table-column |
block |
table-column-group |
block |
table-cell |
block |
table-caption |
block |
table-header-group |
block |
table-footer-group |
block |
flex |
flex , but float has no effect on such elements |
inline-flex |
inline-flex , but float has no effect on such elements |
other | unchanged |
来自MDN
由上表可看出,一个span设置了float: left/right之后,就不需要再设置成display: block/inline-block了,直接设置宽高即可。
回归正题,left的div设置了margin-left: -100%之后就跑到左边去了,而right也是同样道理,将right的margin-left相应地设置为-100px,就跑到最右边去了:
<div style="width:100%; float:left;">
<div style="margin: 0 100px;">middle</div>
</div>
<div style="margin-left: -100%;">left</div>
<div style="margin-right: -100px;">right</div>
Action 9 margin负值法
下面讨论第三种方法,使用display: table-cell
由于table的展示拥有自适应的特点,因此把需要自适应宽度的middle的display属性设置为table-cell。
<div style="float:left;">left</div>
<div style="float:right;">right</div>
<div style="display:table-cell;">middle</div>
效果如下:
发现table-cell的宽度是根据内容自适应的,这里是要根据浏览器窗口自适应,因此给middle添加一个很大的width就可以了,例如width:2000px:
由于ie6/7不支持display: table-cell,所以如果要支持ie6/7的话,就得用display: inline-block,ie6/7的inline-block和标准不一样,它是用来触发hasLayout特性,使元素拥有布局属性。作用在行内元素,可以使得宽高等设置生效,如果作用在块元素,仅是触发布局特性,还要再设置成inline才是行内块元素,如果不设置inline效果就跟table-cell很像。不一样的地方是:设置了width:2000px,导致太长会换行,因此得用ie6/7的hack,设置*width: auto重新改会width值就可以了:
<style>
.middle{
display: table-cell;
*display: inline-block; /* _和*开头的只有ie6/7会识别 */
width: 2000px;
*width: auto;
}
</style>
<div style="float:left;">left</div>
<div style="float:right;">right</div>
<div class="middle">middle</div>
但是笔者认为:为了互联网的美好,不要再兼容ie6/7了,甚至ie8。
接下来,继续第四种方法,使用flex布局,十分简单:只需要将容器设置为display: flex,然后再设置middle的flex-grow为1即可:
<section style="display:flex;"></section>
<div>left</div> <!--宽度为100,省略-->
<div style="flex-grow: 1;">middle</div>
<div>right</div>
Action 11 使用flex-grow自适应宽度
flex-grow: 1的作用是把middle的宽度置为flex容器的剩余宽度,就达到了自适应的目的。flex的使用不作全面介绍,详情可查看CSS-Tricks: A Complete Guide to Flexbox
但是flex布局ie的支持性较差,具体查看caniuse.
最后再分析另外一个自适应的例子,某个元素的宽度要根据其它元素的宽度自适应。如下图所示,排名的位数变化可能会很大,导致最右边的文字要自适应:
根据上面的一番分析,这个例子就不难实现了,如下面的分析,p标签里的文字宽度就能自适应了:
<div style="width:320px;">
<span style="width:14px;float:left;">排名</span>
<span style="font-size:40px;float:left;">89</span>
<img style="width:44px;height:44px;float:left;" src="..."></img>
<p>你的好友会编程的银猪在土壕榜中排名89</p>
</div>
实际效果:
你的好友会编程的银猪在土壕榜中排名1
你的好友会编程的银猪在土壕榜中排名6783
使用float是最简单的,还可以尝试使用flex布局,主要用到flex-shrink属性,flex-shrink的作用是定义收缩比例,容器内的子元素的宽度和若超出容器的宽度时,将按比例收缩子元素的宽度,使得宽度和等于容器的宽度。如下所示,将前面三个span/img的flex-shrink设置为0,而p的flex-shrink设置为1,这样子使得溢出的宽度都在p标签减去,就能够达到p标签宽度自适应的效果。
<style>
span,img{ flex-shrink: 0; }
p{ flex-shrink: 1; }
</style>
<div style="display:flex;width:320px;">
<span style="width:14px;">排名</span>
<span style="font-size:40px;line-height:45px;">89</span>
<img style="width:44px;height:44px;" src="..."></img>
<p>你的好友会编程的银猪在土壕榜中排名89</p>
</div>
实时效果:
你的好友会编程的银猪在土壕榜中排名89
你的好友会编程的银猪在土壕榜中排名1890
上文综合分析了最原始的table布局,然后就是float布局、table-cell、margin负值法、以及flex布局来实现自适应宽度的实现和原理,重点讨论了float的一些特性。如果上面的分析有错误,还望指正。
个人博客: http://yincheng.site/css-layout
参考:
1. CSS Float Theory: Things You Should Know
2. CSS Tricks: All About Floats
5. 视觉格式化模型
从三栏自适应宽度布局到css布局的讨论的更多相关文章
- css实现等高布局 两栏自适应布局 三栏自适应布局
等高布局: HTML结构如下: <div class="wrapper"> <div class="box"> <h1>.. ...
- 漂亮的自适应宽度的多色彩CSS图片按钮
一.素材 二.效果 三.CSS *{padding:0;margin:0} /*----------------------------------- 自适应宽度图片按钮 ...
- 使用CSS实现三栏自适应布局(两边宽度固定,中间自适应)
来源:http://blog.csdn.net/cinderella_hou/article/details/52156333 所谓三列自适应布局指的是两边定宽,中间block宽度自适应.这道题在今年 ...
- css实现三栏自适应布局(两边固定,中间自适应)以及优缺点
方法一:绝对定位(absolute + margin) 原理:给左右两边的元素设置absolute,这样左右两边的元素脱离标准文档流的控制,中间的元素自然会上来,然后给中间的元素设置margin留出左 ...
- CSS 三栏自适应布局
CSS布局 这个很基础,方法也很多,要留意的知识点还是有一些. 比如IE6的触发layout *zoom:1 比如使用浮动后的清除浮动 clear:both 需求的延伸也会有一些: 比如三栏等高 ...
- CSS布局——左定宽度右自适应宽度并且等高布局
方法一: 别的不多说,直接上代码,或者参考在线DEMO,下面所有的DEMO都有HTML和CSS代码,感兴趣的同学自己慢慢看吧. HTML Markup <div id="contain ...
- absolute布局和css布局释疑
jqueryui也不是万能的, 有时候, 也需要自己写一些, 由 css 和jquery结合的一些东西, 如: banner中, 依次播放的div等 ## 关于jquery设计的一些思想和理念?but ...
- 【CSS】三栏/两栏宽高自适应布局大全
页面布局 注意方案多样性.各自原理.各自优缺点.如果不定高呢.兼容性如何 三栏自适应布局,左右两侧300px,中间宽度自适应 (1) 给出5种方案 方案一: float (左右浮动,中间不用给宽,设置 ...
- css 多栏自适应布局
在页面重构中,我们经常会需要实现多栏布局,例如n栏固定宽度 + m栏自适应宽度的组合,绝对布局+padding+百分比宽度是容易想到的比较暴力的解决方法,但是作为未来的"工程师", ...
随机推荐
- pt-ioprofile
pt-ioprofile是用来观察特定进程的IO信息的. 该脚本是用shell写的,有两方面的作用: pt-ioprofile does two things: ) ) is not performe ...
- OpenCV人脸识别Eigen算法源码分析
1 理论基础 学习Eigen人脸识别算法需要了解一下它用到的几个理论基础,现总结如下: 1.1 协方差矩阵 首先需要了解一下公式: 共公式可以看出:均值描述的是样本集合的平均值,而标准差描述的则是样本 ...
- PHP与API讲解(一)
了解API: 在使用与创建自己的API之前我们需要先了解什么是API! API代表应用程序编程接口,而接口指的是一个特定的服务.一个应用程序或者其他程序的公共模块. 理解SOA(面向服务的架构):SO ...
- 搭建属于自己的VIP积分系统(1)
很久没写博客了,如果有写得不好的地方,还请多多见谅. 架构设计 需求分析 这篇文章主要是介绍此VIP系统的基础架构.说实在的,我其实对 架构方面也不是很懂,我这套框架 还是拿别人的东西改过来的,并不是 ...
- AI人工智能系列随笔:syntaxnet 初探(1)
人工智能是 最近的一个比较火的名词,相信大家对于阿尔法狗都不陌生吧?其实我对人工智能以前也是非常抵触的,因为我认为机器人会取代人类,成为地球乃至宇宙的霸主,但是人工智能带给我的这种冲击,我个人感觉是欲 ...
- [原] KVM 虚拟化原理探究(6)— 块设备IO虚拟化
KVM 虚拟化原理探究(6)- 块设备IO虚拟化 标签(空格分隔): KVM [toc] 块设备IO虚拟化简介 上一篇文章讲到了网络IO虚拟化,作为另外一个重要的虚拟化资源,块设备IO的虚拟化也是同样 ...
- 内存映射文件MemoryMappedFile使用
参考资料: http://blog.csdn.net/bitfan/article/details/4438458 所谓内存映射文件,其实就是在内存中开辟出一块存放数据的专用区域,这区域往往与硬盘上特 ...
- 【转】外部应用和drools-wb6.1集成解决方案
一.手把手教你集成外部应用和drools workbench6.1 1. 首先按照官方文档安装workbench ,我用的是最完整版的jbpm6-console的平台系统,里面既包含j ...
- NV显卡Ubuntu14.04更新软件导致登录死循环,不过可以进入tty模式
注意:此方法只适用于nv显卡的电脑! 在网上寻找各种方法无果的情况下,选择重新安装显卡驱动,成功登录进入图形界面. 一.首先需要在另外一台电脑(windows系统也可以)上下载NVIDIA相应显卡驱动 ...
- Spring cookie 实战
测试环境搭建 使用Springboot构建web server, 在测试方法中打印接收的cookie. @RestController @RequestMapping("/register/ ...