面试很多常见问题都和 CSS 布局相关,比如怎么构建一个两栏布局?怎样自适应布局?这里就总结一下 CSS 两栏布局中的一些布局技巧。
两栏布局
两栏布局恐怕是最常见的一种布局方式。然而,我们常常用于两栏布局的 div 元素恰是一个块级元素,块级元素的特点是独占一行,所以当两个 div 元素在文档中挨着时,前面那个 div 实际将另外一个给“挤下去”了。这就给了我们一个思路:克服块级元素“挤占”的特性,具体怎么做呢?
<head>
<style>
* {
margin: 0;
padding: 0;
font-size: 0;
}
.wrap {
width: 100vw;
height: 100vh;
}
.left {
display: inline-block;
width: 50vw;
height: 100vh;
background-color: #f809e8;
}
.right {
display: inline-block;
width: 50vw;
height: 50vh;
background-color: #ff0000;
}
</style>
</head>
<body>
<div class="wrap">
<div class="left"></div>
<div class="right"></div>
</div>
</body>
既然块元素不允许同行,那转化成行内块行不行?谁说不行?虽然不是常见的方式,但这么做是有效的,这样做也要注意把自动的边距给去除;另外,行内块具有行内元素的特点,不同元素之间会自带间隙,这样就让两个本来占据 50% 宽度的元素超过了视口从而将一个挤了下来。
.wrap {
width: 100%;
}
.left {
width: 50%;
background-color: pink;
height: 100vh;
}
.right {
margin: -100vh 0 0 50%;
width: 50%;
background-color: lightgreen;
height: 100vh;
}
挤下去就挤下去了,那能不能通过边距重新“定位”回来?当然可以,我们设一个负 margin 值让两个元素处在同一行就实现了要求。但是这种方式实现的两栏布局会在之后的排版中出现诸多不便,比如,两栏元素中的定位变得困难了,因为设置了负 margin 值的原因,元素的定位可能需要计算,更加复杂,这些不便只能自行体会,也说明了这种解决方式在当下并不是最优的。
当然,其他正常流布局方式也是可行的。
.wrap {
display: flex;
}
.left {
flex: 1;
background-color: pink;
height: 100vh;
}
.right {
flex: 1;
background-color: blue;
height: 100vh;
}
这其中用得最多的可能就是 flex 布局,flex 布局将元素重新划分为了主轴和交叉轴,在 flex 布局上实现对齐是相当方便的,要注意这里 flex 是容器所占主轴宽度的比例。
.wrap {
display: grid;
grid-template-columns: 50% auto;
}
.left {
background-color: pink;
height: 100vh;
}
.right {
background-color: lightgreen;
height: 100vh;
}
上面 grid 布局也可以实现两栏布局,本质是将页面划分为了网格从而达到要求的,grid 布局将划分成“行”和“列”,形成单元格,可以通过网格线指定项目所在的单元格区域,因此可以轻松实现 flex 所能做的布局,但是其兼容性相比 flex 有所不足,因此使用 grid 布局需要考虑兼容性的影响。
上边的布局还在标准流范畴,下面讲脱标从而实现两栏布局的方式:
.wrap {
position: relative;
height: 100vh;
width: 100vw;
}
.left {
position: absolute;
height: 100vh;
width: 50vw;
background-color: pink;
}
.right {
margin-left: 50vw;
height: 100vh;
background-color: lightgreen;
}
第一种是定位方式实现的两栏布局,首先需要实现父元素的相对定位,然后子元素 left 绝对定位,右边则通过 margin 值挤占剩余的位置,这种方式的缺点是父元素设置了相对定位,没有那么灵活。
.wrap {
height: 100vh;
width: 100vw;
}
.left {
float: left;
height: 100vh;
width: 50vw;
background-color: pink;
}
.right {
float: left;
height: 100vh;
width: 50vw;
background-color: lightgreen;
}
还有一种双浮动的方式也可以实现两栏布局,浮动元素因为脱离了标准流从而解除了 div 的块元素布局限制,从而使得两栏布局变得十分容易,但是也有显而易见的缺点,父盒子如果没有指定高度,为了避免对后续元素的影响就需要清除浮动。
.wrap {
height: 100vh;
width: 100vw;
}
.left {
float: left;
height: 100vh;
width: 50vw;
background-color: pink;
}
.right {
margin-left: 50vw;
height: 100vh;
width: 50vw;
background-color: lightgreen;
}
同样是利用浮动,上面的解决方式是只浮动一个元素,另一个元素通过外边距定位到正确的位置,这种方式有一个子元素没有脱离标准流,因此撑开了父元素,使得后面的块级元素看起来会更“正常”一点,不失为两栏布局的一种有效方式。
讲完两栏布局,再说一下如何实现自适应布局。简单讲,假如我们需要左栏定宽(比如 100px),右边栏自适应,即保证左栏宽度的前提下随视口改变宽度,我们可以这样设置左栏的宽度:
.left {
width: calc(100%-100px);
}
这样就可以实现自适应了。这里有一个问题:假如需要右边定宽应该怎么做?除了左边元素利用 calc 计算宽度之外,对于使用 margin 实现两栏布局的方法,我们还需要计算 margin 值,或者干脆全部右浮动,参照左浮动的方式指定左边元素的宽度,这样也可以实现我们想要的自适应效果。
总之,我们需要灵活使用 CSS 特性实现我们想要的效果,除此之外,选择合适的实现方式从而避免后续布局的麻烦也是我们要重点考虑的因素。