面试官 🤔:那用 CSS 实现圣杯布局你总该会吧……

1,202 阅读3分钟

Screen Recording 2024-07-07 at 00.12.54.gif

圣杯布局是个什么布局

圣杯布局(Holy Grail Layout)是一种经典的网页布局,通常包括一个头部、一个底部、一个主要内容区域和左右两个侧栏。实现这种布局的方式有很多

使用 Flex 实现

  1. 首先,利用垂直方向(flex-direction: column;)的 flex 实现上、中、下的布局;
  2. 再对中间部分使用 flex 实现左、中、右的布局;
  3. 中间的内容区域使用 flex: 1; 来撑满剩余空间;
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>圣杯布局</title>
    <style>
        body {
            margin: 0;
            display: flex;
            flex-direction: column; /* 垂直方向的 flex 布局 */
            min-height: 100vh;   /* 高度为视图高度 */
        }

        header, footer {
            background: #ccc;
            padding: 10px;
            text-align: center;
        }

        .container {
            display: flex;
            flex: 1;  /* 撑满剩余空间 */
        }

        main {
            flex: 1;
            order: 2; /* 通过 order 控制元素的顺序 */
            background: #f4f4f4;
            padding: 10px;
        }

        aside {
            flex: 0 0 200px;
            background: #ddd;
            padding: 10px;
        }

        .left {
            order: 1; /* 左侧栏 */
        }

        .right {
            order: 3; /* 右侧栏 */
        }
    </style>
</head>
<body>
    <header>头部</header>
    <div class="container">
        <aside class="left">左侧栏</aside>
        <main>主要内容</main>
        <aside class="right">右侧栏</aside>
    </div>
    <footer>底部</footer>
</body>
</html>

image.png

使用 Grid 实现

  1. 和 flex 布局思路类似,先处理垂直方向水平方向
  2. 通过 grid-template-rows grid-template-columns 来控制某一方向下元素对空间的占用;
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>圣杯布局</title>
    <style>
        body {
            margin: 0;
            display: grid;
            grid-template-rows: auto 1fr auto;  /* 垂直方向(上、中、下)三个元素的排列 */
            min-height: 100vh;
        }

        header, footer {
            background: #ccc;
            padding: 10px;
            text-align: center;
        }

        .container {
            display: grid;
            grid-template-columns: 200px 1fr 200px; /* 水平方向(左、中、右)三个元素的排列 */
        }

        main {
            background: #f4f4f4;
            padding: 10px;
        }

        aside {
            background: #ddd;
            padding: 10px;
        }

        .left {
            grid-column: 1;
        }

        .main {
            grid-column: 2;
        }

        .right {
            grid-column: 3;
        }
    </style>
</head>
<body>
    <header>Grid 布局</header>
    <div class="container">
        <aside class="left">左侧栏</aside>
        <main class="main">主要内容</main>
        <aside class="right">右侧栏</aside>
    </div>
    <footer>底部</footer>
</body>
</html>

image.png

其他方式

利用 flex 和 grid 去实现布局,是比较主流的方式。也有一些其他方法可以实现圣杯布局的效果

float
  1. 让中间的三个元素(左侧边、内容区、右侧边)向某一方向浮动
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<title>圣杯布局示例</title>
		<style>
			/* 重置默认的margin和padding */
			* {
				margin: 0;
				padding: 0;
				box-sizing: border-box;
			}

			/* 头部和底部居中 */
			.header,
			.footer {
				background-color: #f2f2f2;
				text-align: center;
				padding: 1em;
				width: 100%;
				height: 50px;
			}

			/* 中间三列布局 */
			.container {
				width: 100%;
			}

			.sidebar {
				float: left; /* 或者使用 float: right; */
				width: 150px; /* 侧边栏宽度 */
				background-color: #ccc;
				height: calc(100vh - 100px); /* 侧边栏高度 */
			}

			.content {
				float: left;
				width: calc(100% - 300px);
				background-color: #ddd;
				height: calc(100vh - 100px); /* 主内容高度 */
			}

			.footer {
				clear: both; /* 清除浮动 */
			}
		</style>
	</head>
	<body>
		<div class="header">Header</div>
		<div class="container">
			<div class="sidebar">Left Sidebar</div>
			<div class="content">Main Content</div>
			<div class="sidebar">Right Sidebar</div>
		</div>
		<div class="footer">Footer</div>
	</body>
</html>

image.png

  • display: table
  1. 使用 display: table; 使得元素的行为类似于 table 元素,从而实现多列的布局效果;
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>圣杯布局</title>
		<style>
			body {
				margin: 0;
				padding: 0;
				display: table;
				width: 100%;
				height: 100vh;
			}

			header,
			footer {
				/* display: table-row; */
				display: block;
				width: 100%;
				background: #ccc;
				text-align: center;
				height: 50px;
			}

			.container {
				display: table;
				height: calc(100% - 100px);
				width: 100%;
			}
			.container .row {
				display: table-row;
				width: 100%;
			}

			.main {
				width: calc(100% - 400px);
				display: table-cell;
				background: #f4f4f4;
				padding: 10px;
			}

			.aside {
				display: table-cell;
				width: 200px;
				background: #ddd;
				padding: 10px;
			}
		</style>
	</head>
	<body>
		<header>头部</header>
		<div class="container">
			<div class="row">
				<div class="aside left">左侧栏</div>
				<div class="main">主要内容</div>
				<div class="aside right">右侧栏</div>
			</div>
		</div>
		<footer>底部</footer>
	</body>
</html>

image.png

  • 使用绝对定位
  1. 使用 position: absolute; 之后将元素的位置固定到左侧或右侧
<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
		<title>圣杯布局</title>
		<style>
			body {
				margin: 0;
				padding: 0;
				position: relative;
			}

			header,
			footer {
				background: #ccc;
				text-align: center;
				height: 40px;
			}

			.container {
				position: relative;
				padding: 0 200px;
				min-height: calc(100vh - 80px);
			}

			main {
				position: absolute;
				left: 200px;
				right: 200px;
				height: 100%;
				background: #f4f4f4;
				padding: 10px;
				box-sizing: border-box;
			}

			.left {
				position: absolute;
				left: 0;
				top: 0;
				bottom: 0;
				width: 200px;
				background: #ddd;
			}

			.right {
				position: absolute;
				right: 0;
				top: 0;
				bottom: 0;
				width: 200px;
				background: #ddd;
			}
		</style>
	</head>
	<body>
		<header>头部</header>
		<div class="container">
			<aside class="left">左侧栏</aside>
			<main>主要内容</main>
			<aside class="right">右侧栏</aside>
		</div>
		<footer>底部</footer>
	</body>
</html>

image.png


以上是一些实现圣杯布局的方法(Flex, Grid, Float, Table, Position),利用它们各自的机制实现我们想要的效果