如何实现左边固定宽度,右边自适应?
前言
这是今天(8月29号)在美团面试中遇到的一个问题,这个问题其实很经典,我在准备面试的时候看到这题总是很自然的略过了,因为我之前有在项目中实现过一次,所以很自信。
然而在面试中却暴露出了问题,对清除浮动概念掌握不准确,对float布局的应用不够了解,对flex布局了解不详细。导致我的回答比较糟糕。面试回来后反复在网上搜了几篇介绍这个问题的博客(质量不一),然后自己实现,测试了一下,做个梳理。
解决思路
首先来分析一下问题:左边固定宽度,右边自适应。
我觉得这个问题的关键点在于右边自适应,在CSS布局中,什么情况下可以实现宽度(在一行中)自适应?答案是:
- 动态地计算宽度
- 或者
display:block
+width: auto
动态地计算宽度,然后让两个子元素float,设置父元素清除浮动,这样就可以实现,但是这样需要多一次计算操作,每次页面重流影响到该元素时都会计算一次,所以性能不好,但还是放上实现代码供参考:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.wrapper {
background-color: blueviolet;
overflow: hidden;
}
.left {
background-color: crimson;
width: 300px;
float: left;
}
.right {
background-color: blue;
width: calc(100% - 300px);
float: left;
}
.footer {
background-color: aqua;
height: 200px;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="left">
<div style="height: 300px"></div>
</div>
<div class="right">
<div style="height: 200px"></div>
</div>
</div>
</div>
<div class="footer"></div>
</body>
</html>
如果是使用块级元素自适应,需要考虑一个问题:题目的要求是右边的自适应只占据一部分宽度,而不是整整一行,怎么实现?其实问题很简单,就是在左边留出来一块非内容区,当然,你可以用margin留,也可以用padding留,但是逻辑上来讲,我们想要的其实是右边的盒子宽度等于窗口宽度 - 左边固定宽度。所以margin从逻辑上更能表现这一点,在某些情况下,padding更像是属于盒子内部。
留出来足够的空间后,左边如何设置呢?
首先左边肯定是要在右边之上的,即脱离了右边所在的文档流,脱离当前文档流的方式:float,绝对定位。
然么基本思路确定了就来分别看看两种处理方式:
float + margin-left:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.wrapper {
background-color: blueviolet;
overflow: hidden;
}
.left {
background-color: crimson;
float: left;
width: 300px;
}
.right {
background-color: blue;
margin-left: 300px;
}
.footer {
background-color: aqua;
height: 200px;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="left">
<div style="height: 300px"></div>
</div>
<div class="right">
<div style="height: 200px"></div>
</div>
</div>
</div>
<div class="footer"></div>
</body>
</html>
解释一下这段代码:
左边设置固定宽度,浮动,右边用margin-left留出相应的距离,另外为了防止浮动元素高于块级元素,溢出容器,我们可以对父容器设置清除浮动,我这里就使用了overflow设为hidden,创建一个BFC,然后清除浮动的方式。
absoulte+margin-left:
这个就不写代码了,这种方式的缺点在于,你不能向浮动那样写clearfix让左右内容高度相同,除非你给左边设置固定高度限制。
flex方法
flex布局中,flex项(item)有flex-grow属性,这个属性是item放大的比例系数,具体的含义可以看这篇关于flex的文章Flex-弹性布局原来如此简单!!
实现思路是,我们设置左边固定宽度的item,然后设置它不放大也不缩小,右边设置一个放大系数flex-grow属性,这样只有右边的放大了,于是就占满了所有的剩余空间。
实现代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
.wrapper {
display: flex;
background-color: blueviolet;
}
.left {
background-color: crimson;
flex: 0 0 300px;
}
.right {
background-color: blue;
flex-grow: 1;
}
.footer {
background-color: aqua;
height: 200px;
}
</style>
</head>
<body>
<div class="wrapper">
<div class="left">
<div style="height: 300px"></div>
</div>
<div class="right">
<div style="height: 200px"></div>
</div>
</div>
</div>
<div class="footer"></div>
</body>
</html>
本文的例子都可以复制新建一个html文件,然后查看结果。