如上图,需求如下:
一个未知宽高的容器,要被均分为四个相同大小格子(即四个容器),且格子间有10px间距(即十字型空隙),有哪些方法可以解决呢?
分析问题
一般实现布局,用的多的是CSS的几大属性display
float
position
flex
。
其中display
的应用很灵活,用的最多的是table
和table-cell
;float
实现浮动排列,多行可以每行套个容器,也可以不套而是在每行第一个元素前生成用于清除浮动的隐藏内容(::before
display:block
clear:both;
height:0;
line-height:0;
overflow:hidden;
visibility:hidden;
);
flex
就不用多说了,专为布局而生;
position
实现布局需要考虑精确位移,可能需要用到top
right
bottom
left
transform:translate()
calc()
。要注意的是设置position:absolute;
的元素是也可以通过设置margin
(这个之前记错了,以为设置定位的元素不能使用margin
)的来实现定位。(仅CSS而言,暂时想不到其他实现精确位移的方式了)
结构设定
统一CSS设置:
/*CSS Reset*/
.container, .container * { padding: 0; margin: 0; line-height: 0; }
.cell>div { width: 100px; height: 100px; background-color: #598; }
主要HTML结构:
<div class="container">
<div>
<div class="cell no1">
<div></div>
</div>
<div class="cell no2">
<div></div>
</div>
</div>
<div>
<div class="cell no3">
<div></div>
</div>
<div class="cell no4">
<div></div>
</div>
</div>
</div>
解决方案
以下是目前可想到的解决方案
/* 方案一 ———— table*/
.container {
display: table;
}
.cell {
display: table-cell;
}
.cell>div {
margin: 5px;
}
优点:简单、简洁,松散耦合
缺点:table
和table-cell
在IE6/7中可能有兼容性问题
/*方案二 ———— flex*/
.container {
display: flex;
flex-flow: column;
}
.container>div {
display: flex;
margin: 5px 0;
}
.cell>div {
margin: 0 5px;
}
优点:简单,松散耦合,布局灵活性大
缺点:flex
的兼容性问题
/*方案三 ———— float + clear:both*/
.container>div::before {
/*主要是清除第二个框前面的浮动*/
content: '.';
display: block;
clear: both;
height: 0;
width: 0;
line-height: 0;
overflow: hidden;
visibility: hidden;
}
.cell {
float: left;
}
.cell>div {
margin: 5px;
}
/*方案三·改 —— 将清除浮动改为overflow: hidden;*/
.container>div {
overflow: hidden;
}
优点:兼容性良好;“方案三·改”也可以让代码简洁
缺点:代码量大,并且后面紧跟的页面元素还需要先清除浮动才能保证不影响页面;“方案三·改”在IE6/7可能有兼容性问题
/*方案四 ———— translate + calc()
*calc()方法 参考自:http://ued.ctrip.com/blog/translation-css-layout-math-read-calc.html
*/
.container {
position: relative;
}
.container>:last-child {
transform: translateY(10px);
}
.cell {
position: absolute;
}
.container>:first-child>.cell:last-child {
transform: translate(calc(100% + 10px),0);
}
.container>:last-child>.cell:first-child {
transform: translate(0, 100%);
}
.container>:last-child>.cell:last-child {
transform: translate(calc(100% + 10px), 100%);
}
优点:不对页面其他元素构成影响
缺点:transform
和calc
会有兼容性问题。
----割----
之前搞错了position
元素使用margin
的特性,今天看其他代码时,才发现记错了。所以又想出个方案
/* 方案五 ———— position:relative + margin */
.container {
/* 用于修正整个四宫格区域对后面页面的影响 */
overflow: hidden;
width: 210px;
height: 210px;
}
.container>:last-child {
position: relative;
top: -90px;
}
.cell {
position: relative;/* 利用相对定位可以位移的特性 */
}
.container .cell:last-child{
top: -100px;
left: 110px;
}
/* 方案五·改————可以将top:-90px;部分替换成下面这个 */
.container>:last-child {
margin-top: -90px;
}
优点:兼容性良好
缺点:因为relative
的元素任然会在文档中占用位置,所以会影响四宫格后面的页面内容的布局。不过还好可以对整个四宫格的区域设置固定宽高并且overflow:hidden
来解决。可是宽高又是强耦合了。
-----割-----
今天看其他同学引用其他同学的代码(绕得有点...),看到可以实现三列布局效果,但是就是看不明白原理,然后决定一步一步注释了看效果。花了不少时间,但是加深了,对float
、position
、relative
、absolute
、margin
的理解。因此又想出了一个方案。
/* 方案六 ———— position */
.container {
/* 用于解决不占用文档位置而影响后面布局的问题 */
width: 210px;
height: 210px;
}
.container>div {
position: relative;
}
.container>div:last-child {
top: 110px;
}
.cell {
position: absolute;/* 所有.container>div高度都会变为0 */
}
.cell:last-child {
left: 110px;
}
优点:绝对兼容
缺点:因为每个格子使用的绝对定位,而且它们的容器(.container>div
)以及容器的容器(.container
)的高度都未设置也就是默认的跟随内容的auto
,所以整个四宫格区域不会占用页面位置,从而后面的页面元素会跑到四宫格下面去。可以通过方案五的方式,给.container
设置固定宽高来解决,但是不需要overflow:hidden;
。
关于CSS方法calc
的使用可以看看这篇文章:
【译】CSS的布局数学:读懂calc – 携程设计委员会
以上
欢迎交流。