Published on

CSS布局

Authors
  • avatar
    Name
    青雲
    Twitter

CSS布局是前端开发中不可或缺的一部分,它决定了网页的结构和内容的排版。随着Web技术的发展,CSS布局也在不断进化。今天,我们将探讨一些常用的CSS布局技术。 image.png

水平垂直居中

在传统网页布局中,经常会遇到需要将元素水平和垂直居中的情况。实现这一布局效果,CSS提供了多种方式。

使用margin: auto;

最简单的居中方式是对块级元素设置margin: auto,这可以实现水平居中。对于垂直居中,这种方式有限制,因为它需要固定高度和position属性。

.center {
  width: 50%;
  margin: auto;
  position: relative;
  top: 50%;
  transform: translateY(-50%);
}

使用绝对定位和transform

使用position: absolute可以让元素摆脱文档流,配合transform可以实现精确的居中对齐。

.center {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

使用flexbox的align-itemsjustify-content属性

当容器设置为display: flex时,通过align-itemsjustify-content属性可以轻松实现水平和垂直居中。

.flex-container {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 200px; /* 需要设置高度 */
}

使用grid

CSS Grid提供了一个更为整洁和现代的方法,只需要一行代码即可实现水平垂直居中。

/* 使用 place-items 属性 */
.container {
  display: grid;
  place-items: center;
}

/* 等效的分开设置方式 */
.container {
  display: grid;
  align-items: center;
  justify-content: center;
}

左侧固定、右侧自适应

在许多布局中,需要一个侧边菜单固定宽度,而主内容区域则根据视口大小自适应变化。

使用float和margin

通过为侧边栏浮动并设置固定宽度,主内容区通过设置margin-left来实现自适应。需要注意清除浮动带来的影响。

.sidebar {
 float: left;
 width: 200px; /* 固定宽度 */
}
.main-content {
 margin-left: 200px; /* 与sidebar宽度相同 */
}

使用Flexbox

在Flex布局中设置侧边栏宽度固定,并使用flex: 1让主内容区域自适应。

.flex-container {
 display: flex;
}
.sidebar {
 flex: 0 0 200px; /* 固定宽度 */
}
.main-content {
 flex: 1; /* 自适应剩余空间 */
}

使用Grid

Grid布局简化了这一布局实现,只需要定义列模板,侧边栏固定宽度,主内容区自适应即可。

.grid-container {
 display: grid;
 grid-template-columns: 200px auto;
}

.grid-container {
  display: grid;
  grid-template-columns: 200px 1fr;
}

两种方式有细微的差别:

  • 1fr表示“fractional unit”,即剩余空间的一份。这意味着在页面布局中,.grid-container的第一列宽度被固定为200px,而第二列则会占据剩下的空间。fr单位将可用空间分配给列或行,能动态地调整它的大小来填充额外的空间。
  • 使用auto关键字会导致第一列同样固定为200px宽度,但第二列的宽度则根据其子元素的内容来决定。在不超出.grid-container容器的宽度范围内,第二列的宽度会自动增长或缩小,以适应内容的大小。不过,它不会像使用1fr那样去占据所有剩余空间,如果内容不足以填充整个容器,后者可能显得更空旷。

双飞翼/圣杯布局

双飞翼和圣杯布局是早期解决三栏布局中,中间栏内容优先加载并保持自适应的布局技巧。

圣杯布局

圣杯布局 的特点在于利用padding和负margin来调节两侧栏的位置。它的主要步骤如下:

  1. 三个div分别代表左边栏、中间栏和右边栏,都放在容器内。
  2. 容器设置padding-left和padding-right为侧边栏的宽度,以留出两侧的空间。
  3. 中间栏宽度设置为100%,先渲染保证填满整个容器。
  4. 左右边栏使用position: relative;和负的margin值拉回到容器两侧的适当位置。
<!DOCTYPE html>
<html>
  <head>
    <style>
      .container {
        padding-left: 200px; /* 左侧栏的宽度 */
        padding-right: 150px; /* 右侧栏的宽度 */
      }
      .main {
        width: 100%;
        height: 400px;
        float: left;
        background-color: aquamarine;
      }
      .left {
        width: 200px;
        height: 400px;
        position: relative;
        float: left;
        margin-left: -100%;
        left: -200px;
        background-color: pink;
      }
      .right {
        width: 150px;
        height: 400px;
        position: relative;
        float: left;
        margin-left: -150px;
        right: -150px;
        background-color: yellow;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="main">Main content here...</div>
      <div class="left">Left sidebar...</div>
      <div class="right">Right sidebar...</div>
    </div>
  </body>
</html>

image.png

双飞翼布局

双飞翼布局 的步骤类似,但它在中间栏内部增加了一个子div,用来控制中间栏的实际内容宽度。步骤如下:

  1. 三个div分别代表左边栏、中间栏和右边栏。
  2. 中间栏宽度设置为100%,首先渲染,并在其内部再创建一个div,用于包含实际内容。
  3. 左右边栏使用margin-left和margin-right占据适当的位置。
  4. 左右边栏使用float属性向两侧浮动,中间栏内容通过内div的margin来调整,保证不被两侧栏覆盖。
<!DOCTYPE html>
<html>
  <head>
    <style>
      .container {
        overflow: hidden; /* 清除浮动 */
      }
      .main-wrap {
        float: left;
        width: 100%;
        height: 500px;
        background-color: antiquewhite;
      }
      .main {
        margin-left: 200px; /* 左侧栏的宽度 */
        margin-right: 150px; /* 右侧栏的宽度 */
        background-color: aquamarine;
        height: 400px;
      }
      .left {
        float: left;
        width: 200px;
        margin-left: -100%;
        background-color: pink;
        height: 400px;
      }
      .right {
        float: left;
        width: 150px;
        margin-left: -150px;
        background-color: yellow;
        height: 400px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <div class="main-wrap">
        <div class="main">Main content here...</div>
      </div>
      <div class="left">Left sidebar...</div>
      <div class="right">Right sidebar...</div>
    </div>
  </body>
</html>

image.png 区别在于圣杯布局通过对容器设置左右内边距并使用负margin调整两侧栏位置,而双飞翼布局则是通过中间栏内的子div调整宽度和通过外边距负值(margin)直接调整两侧栏位置。两者实现结果类似,但双飞翼布局由于多了一层main-wrap,可能DOM结构更复杂,而圣杯布局需要父元素明确的宽度。 不过这两种布局在Flexbox和Grid出现之前非常流行,但现在已经被更现代的布局方法所替代。

Flex布局

flex 布局的基本概念 - CSS:层叠样式表 | MDN

Flex布局主要用于1维布局,即在一个方向(水平或垂直)上进行布局设计。Flexbox使得在不同的屏幕尺寸和显示设备上对复杂的布局进行适配变得容易。

核心概念

  1. 容器(Flex Container):使用display: flex;display: inline-flex;声明的元素。
  2. 项目(Flex Item):容器中的子元素会成为布局项目。
  3. 主轴(Main Axis):Flex项目的排列方向。

image.png

  1. 交叉轴(Cross Axis):与主轴垂直的方向。

image.png

主要属性

  • 容器属性:
    • display: 设置为 flex 或 inline-flex 来定义一个flex容器。
    • flex-direction: 决定项目的排列方向(row 或 column 等)。
    • justify-content: 设置项目在主轴上的对齐方式。
    • align-items: 设置项目在交叉轴上如何对齐。
    • flex-wrap: 设置项目是否换行。
    • align-content: 当项目换行时,定义交叉轴上的对齐方式。
  • 项目属性:
    • flex-grow: 定义项目的放大比例。
    • flex-shrink: 定义项目的缩小比例。
    • flex-basis: 定义项目分配剩余空间前的默认大小。
    • flex: 是flex-grow, flex-shrink和flex-basis的简写。
    • align-self: 允许单独的项目有不同于容器的对齐方式。

Grid布局

网格布局的基本概念 - CSS:层叠样式表 | MDN

Grid布局用于2维布局,即同时在水平和垂直方向上设计布局。Grid 引入了网格的概念,允许我们不仅可以对行进行布局,还可以对列进行布局。 image.png

核心概念

  • 容器(Grid Container):使用display: grid;display: inline-grid;声明的元素。
  • 项目(Grid Item):容器直接子元素自动成为网格项目。
  • 行(Rows)、列(Columns):构成网格结构的单元格排列方式。
  • 网格线(Grid Line):网格的分隔线,可以是水平的或垂直的。

常用属性

  • 容器属性:
    • display: 设置为 gridinline-grid 来定义一个grid容器。
    • grid-template-columns, grid-template-rows: 定义行和列的尺寸。
    • grid-template-areas: 定义区域模板,为网格中的区域指定自定义名称。
    • grid-gap, grid-row-gap, grid-column-gap: 设置行与行、列与列之间的间距。
  • 项目属性:
    • grid-column-start, grid-column-endgrid-row-start, grid-row-end: 定义项目的位置和大小,指定项目跨越的网格线。
    • grid-column, grid-row: start 和 end 的简写。
    • grid-area: 用来指定项目放在哪一块区域。

面试实战

面试题1: 解释Flexbox如何工作以及常用的属性有哪些?

答案:

Flexbox是一种布局模型,为一维布局提供了更灵活的方式。在一个flex容器内部,子元素可以方便地在主轴或交叉轴上进行对齐、排列和分布空间。常用Flexbox属性包括: 对于容器:

  • display: flex; 定义一个flex容器。
  • flex-direction 控制子元素排列方向(例如:row、column)。
  • justify-content 在主轴上如何对齐子元素(例如:flex-start、flex-end、center、space-between)。
  • align-items 在交叉轴上如何对齐子元素(例如:flex-start、flex-end、center、baseline、stretch)。
  • flex-wrap 控制子元素是否换行。

对于子元素:

  • flex-grow 定义子元素如何分配多余空间。
  • flex-shrink 定义子元素如何收缩以适应容器。
  • flex-basis 定义子元素在分配多余空间前的默认大小。
  • order 控制子元素的排列顺序。

面试题2: 解释Grid布局和Flex布局的区别?

答案:

虽然Flex布局和Grid布局都是用来创建复杂布局的CSS技术,但它们各有侧重点。 Flex布局侧重于1维的布局(水平或垂直),适合于元素集合的线性布局,如导航栏或列表项,更加灵活于单方向布局。 Grid布局侧重于2维的布局(水平和垂直同时进行),适合于复杂的页面布局,像是整个页面或复杂组件,它允许我们在两个方向上进行布局。

面试题 3:解释CSS中的定位(positioning)以及它包含的值。

答案:

CSS的定位(positioning)功能允许你控制元素的位置,并且可以是相对于它们正常的流位置(默认布局),或相对于其父元素、其它元素,或视口本身。定位的属性值包括: static:默认值,元素正常出现在流中。 relative:相对于其正常位置进行定位。 absolute:相对于最近的已定位祖先元素进行定位,如果没有已定位的祖先元素,则相对于初始包含块。 fixed:相对于视口进行定位,即使页面滚动,元素也会保持在相同的位置。 sticky:元素根据用户的滚动位置在relative和fixed定位之间切换。

面试题 4:CSS中的z-index是什么,如何工作?

答案:

z-index是一个CSS属性,它可以设置元素在堆叠上下文中的垂直叠加顺序。元素可以有正数、负数或零的z-index值。值较高的元素会覆盖值较低的元素显示。默认的z-index是自动的,元素按照它们出现在文档流中的顺序进行堆叠。只有定位元素(position设为非static)的z-index才会生效。

面试题5: 什么是响应式设计,如何使用CSS实现它?

答案:

响应式设计是一种网页设计方法论,目的是让网页能够快速适应不同大小的设备,如手机、平板和桌面。实现响应式设计主要通过以下三个方面:

  1. 流动网格布局:使用百分比而非固定单位,允许布局随着屏幕大小的变化而变化。
  2. 媒体查询(Media Queries):CSS技术,可以根据不同的屏幕尺寸和特性应用不同的样式规则。
  3. 弹性图片:设置图片的max-width为100%,使其在容器内自适应大小。

CSS代码示例使用媒体查询:

/* Base styles */
body {
  font-family: 'Arial', sans-serif;
}
img {
  max-width: 100%;
  height: auto;
}

/* Medium devices (tablets, 768px and up) */
@media (min-width: 768px) {
  .container {
    width: 750px;
  }
}

/* Large devices (desktops, 992px and up) */
@media (min-width: 992px) {
  .container {
    width: 970px;
  }
}

/* Extra large devices (large desktops, 1200px and up) */
@media (min-width: 1200px) {
  .container {
    width: 1170px;
  }
}