CSS 常用布局及解决方案

我心飞翔 分类:javascript

CSS 常用布局包括元素的水平、垂直居中,单栏布局、三栏布局等,本文分析多种情况下的布局方案。

一、居中

1. 水平居中

(1) 基于盒模型的实现

  • 子元素为行内元素
<div class="parent parent-box">
  <span class="child">子元素为行内元素</span>
</div>
 
.parent-box {
  width: 200px;
  height: 100px;
  border: 1px solid purple;
}
/* 行内元素直接设置文本居中 */
.parent {
  text-align: center;
}
 
  • 子元素为定宽块状元素
<div class="parent-box">
  <div class="child child-box">定宽子元素</div>
</div>
 
.parent-box {
  width: 200px;
  height: 100px;
  border: 1px solid purple;
}
.child-box {
  width: 100px;
  height: 20px;
}
/* 设置 margin 值,平分剩余空间 */
.child {
  margin: auto;
}
 
  • 子元素为不定宽块状元素
<div class="parent parent-box">
  <div class="child">子元素为不定宽块状元素</div>
</div>
 
.parent-box {
  width: 200px;
  height: 100px;
  border: 1px solid purple;
}
/* 子元素设置为 inline,父元素设置文本居中 */
.parent {
  text-align: center;
}
.child {
  display: inline;
}
 

(2) 基于 flex 的实现

<div class="parent parent-box">
  <div class="child">flex 布局</div>
</div>
 
.parent-box {
  width: 200px;
  height: 100px;
  border: 1px solid purple;
}
/* 使用弹性盒子,水平轴设置为居中 */
.parent {
  display: flex;
  justify-content: center;
}
 

2. 垂直居中

(1) 基于盒模型的实现

  • 父元素一定,子元素为单行内联文本
<div class="parent parent-box">
  <div class="child">父元素一定,子元素为单行内联文本</div>
</div>
 
.parent-box {
  width: 260px;
  border: 1px solid purple;
}
/* 设置一个任意行高 */
.parent {
  line-height: 100px;
}
 
  • 父元素一定,子元素为多行内联文本
<div class="parent parent-box">
  <div class="child">
    父元素一定,子元素为多行内联文本父元素一定,子元素为多行内联文本父元素一定,子元素为多行内联文本父元素一定,子元素为多行内联文本
  </div>
</div>
 
.parent-box {
  width: 300px;
  border: 1px solid;
  margin: 0 20px;
}
/* 父元素设置 line-height */
.parent {
  line-height: 300px;
}
/* 子元素设置为内联块级盒子,垂直居中,行高设置为任意一个值 */
.child {
  display: inline-block;
  line-height: 1.5;
  vertical-align: middle;
}
 
  • 父元素一定,子元素为块级元素
<div class="parent">
  <div class="child child-box"></div>
</div>
 
.parent {
  position: relative;
  width: 300px;
  height: 300px;
  border: 1px solid purple;
}
.child-box {
  width: 100px;
  height: 100px;
  border: 1px solid purple;
}
/* 原理就是 margin 平分剩余空间 */
.child {
  position: absolute;
  top: 0;
  bottom: 0;
  margin: auto;
}
 

(2) 基于 flex 的实现

<div class="parent parent-box">
  <div class="child"></div>
</div>
 
.parent-box {
  width: 300px;
  height: 300px;
  border: 1px solid purple;
}

.parent {
  display: flex;
  align-items: center;
}

.child {
  width: 100px;
  height: 100px;
  border: 1px solid purple;
}
 

二、单列布局

1. header、content、footer 为浏览器宽度

  • 方案 1:计算中间列高度
<body class="layout">
  <div class="header">头部</div>
  <div class="content">内容</div>
  <div class="footer">尾部</div>
</body>
 
.layout {
  margin: 0 auto;
  height: 100vh;
}

.header,
.footer {
  height: 40px;
  background: #009cff;
}

.content {
  height: calc(100vh - 80px);
}
 
  • 方案 2:flex 布局
.layout {
  display: flex;
  flex-direction: column;
  margin: 0 auto;
  height: 100vh;
}

.header,
.footer {
  height: 40px;
  background: #009cff;
}

.content {
  flex: 1;
}
 

2. header、footer 宽度为浏览器宽度,content 宽度小于浏览器宽度居中

<body class="layout">
  <div class="header">头部</div>
  <div class="content">内容</div>
  <div class="footer">尾部</div>
</body>
 
.layout {
  margin: 0;
  height: 100vh;
}

.header,
.footer {
  height: 40px;
  background: #009cff;
}

.content {
  width: 80%;
  height: calc(100vh - 80px);
  background: #eee;
  margin: 0 auto;
}
 

另一种方案参考上一个 demo

三、三列布局

1. 基于盒模型的实现

  • float + margin

左右两列先写,中间列最后写,左右列分别设置一个宽度左右浮动,中间列 margin 左右分别设置为左右列的宽度。

<body class="layout">
  <div class="sub">sub</div>
  <div class="extra">extra</div>
  <div class="main">main</div>
</body>
 
.layout {
  height: 100vh;
  margin: 0;
}

.sub {
  float: left;
  width: 20%;
  height: 100px;
  background: #009cff;
}

.extra {
  float: right;
  width: 10%;
  height: 200px;
  background: #009cff;
}

.main {
  margin-left: 20%;
  margin-right: 10%;
  height: 100%;
  background: #dff;
}
 
  • position + margin

左右元素绝对定位,中间元素的 margin-left、margin-right 对应左右元素的宽度。

<body class="layout">
  <div class="sub">left</div>
  <div class="main">main</div>
  <div class="extra">right</div>
</body>
 
.layout {
  min-height: 100vh;
  margin: 0;
}

.sub,
.extra {
  position: absolute;
  top: 0;
  height: 100%;
  background: rgb(56, 165, 238);
}
.sub {
  left: 0;
  width: 10%;
}

.extra {
  right: 0;
  width: 20%;
}

.main {
  margin-left: 10%;
  margin-right: 20%;
}
 

以上实现都是中间列要么写在中间,要么写在最后面,不利于主要内容的 seo 和优先渲染,那若是我们想优先渲染主要内容该怎么办呢?DOM Tree 是从上往下解析的,所以我们需要把 main 提到前面,于是就有了下面的布局方案。

2. 基于盒模型的三列布局增强版

  • 双飞翼布局

双飞翼布局也是用 float+margin 进行布局,不同的是 main 被提到了最前面,里面加了个子元素。该布局方案的精髓在于左列和中间列左浮动,右列右浮动,左列设置 margin: -100%,把该列拉回原本的位置,右列设置 margin 为负的自身宽度,回到上一行。main 的宽度设置为容器宽度,子元素 margin 的左右设置为左右列的宽度。

<body class="layout">
  <div class="main">
    <div class="content"></div>
  </div>
  <div class="left"></div>
  <div class="right"></div>
</body>
 
.layout {
  min-height: 100vh;
  margin: 0;
}
.left {
  float: left;
  width: 200px;
  height: 100vh;
  margin-left: -100%;
  background-color: antiquewhite;
}
.right {
  float: right;
  width: 200px;
  height: 200px;
  margin-left: -200px;
  background-color: aquamarine;
}
.main {
  width: 100%;
  float: left;
}
.content {
  height: 100vh;
  margin-left: 200px;
  margin-right: 200px;
  background-color: bisque;
}
 
  • 圣杯布局

圣杯布局比双飞翼布局相比,元素嵌套没这么深,主要精髓在于,所有列设置左浮动,左右列设置 position: relative,分别设置对应方向的偏移值。父元素设置左右 margin 分别为左右列的宽度。

<body class="layout">
  <div class="main">content</div>
  <div class="left">left</div>
  <div class="right">right</div>
</body>
 
.layout {
  min-height: 100vh;
  margin: 0;
  margin-left: 300px;
  margin-right: 200px;
}
.left {
  float: left;
  position: relative;
  margin-left: -100%;
  left: -300px;
  width: 300px;
  height: 100vh;
  background-color: antiquewhite;
}
.right {
  float: left;
  position: relative;
  right: -200px;
  width: 200px;
  height: 200px;
  margin-left: -200px;
  background-color: aquamarine;
}
.main {
  float: left;
  width: 100%;
  height: 100vh;
  background-color: bisque;
}
 

3. 基于 flex 实现三栏布局

<body class="layout">
  <div class="main">主内容栏宽度自适应</div>
  <aside class="left">侧边栏宽度固定</aside>
  <aside class="right">侧边栏宽度固定</aside>
</body>
 
.layout {
  display: flex;
  height: 100vh;
  margin: 0;
}

.main {
  flex: 1;
  background: #aaa;
}

.left,
.right {
  height: 100%;
}
.left {
  order: -1;
  width: 10%;
  background: #009cff;
}

.right {
  width: 20%;
  background: orange;
}
 

原创文章,首发于个人博客,转载请注明出处

回复

我来回复
  • 暂无回复内容