响应式布局

语法:

响应式大小控制

1. clamp() —— 在一个范围里自适应

语法:

font-size: clamp(最小值, 理想值, 最大值);

📌 例子:

h1 {
  font-size: clamp(1.5rem, 2vw + 1rem, 3rem);
}
  • 最小值:1.5rem → 字体不会比这个小。
  • 理想值:2vw + 1rem → 随着视口宽度变化。
  • 最大值:3rem → 字体不会无限变大。

👉 这样可以在小屏幕不至于太小、大屏幕不至于过大,中间则平滑过渡。

2. 相对单位

(1) em —— 相对父元素的字体大小

.container {
  font-size: 16px;
}
.child {
  font-size: 1.5em; /* = 16px × 1.5 = 24px */
}

📌 特点:层层叠加,容易出现「级联放大」现象。


(2) rem —— 相对根元素 <html> 的字体大小

html {
  font-size: 16px;
}
p {
  font-size: 1.5rem; /* = 16px × 1.5 = 24px,无论父元素多大 */
}

📌 特点:避免了 em 的层层放大,更适合做全局排版。


(3) vw / vh —— 相对视口宽度/高度

  • 1vw = 视口宽度的 1%
  • 1vh = 视口高度的 1%
h1 {
  font-size: 5vw; /* 宽度的 5% */
}

📌 特点:超级自适应,但可能在超小/超大屏幕下效果不理想,所以常和 clamp() 搭配。


(4) % —— 相对父容器的(content)大小

.box {
  width: 50%; /* 父容器宽度的一半 */
}

📌 在布局中非常常见,但对 font-size 用处不大。

如果父元素的高度没明确指定(比如高度由内容撑开),那么子元素的百分比高度是 无效 的。

备注

width / height → 相对父元素 content box 的宽/高

padding / margin → 一律相对父元素content box 的宽度

定位属性 → 相对定位容器 content box 的宽/高

利用百分比

padding / margin → 一律相对父元素content box 的宽度

这样可以设置背景图片不用使用img来保持大小了,只需要使用百分比保持比例!

比如:

width:100%
height:60%
图片比例就是这个,直接设置background-img完全一样了,不用固定父元素大小!
类似于:
img{
	width:100%
}

媒体查询

现在我要再了解媒体查询语法以及媒体查询如何在断点(breakpoints)时切换风格,比如整个布局要改变。

媒体查询的形式是:

css
@media (条件) {
  /* 样式 */
}

最常用的条件是 widthheight,一般写成:

  • @media (min-width: 768px)屏幕宽度大于等于 768px 时生效
  • @media (max-width: 768px)屏幕宽度小于等于 768px 时生效
css
/* 小屏幕(手机) */
@media (max-width: 600px) {
  body {
    background: lightblue;
  }
}

/* 中等屏幕(平板) */
@media (min-width: 601px) and (max-width: 1024px) {
  body {
    background: lightgreen;
  }
}

/* 大屏幕(桌面) */
@media (min-width: 1025px) {
  body {
    background: lightpink;
  }
}

调试的时候可以打开媒体查询

image-20250912144421105

这样就可以选择不同的大小

image-20250912144529600

蓝色的是max-with

黄色的是min-width

回到正题,还可以设置布局

css
.container {
  display: flex;
  flex-direction: column;
}

@media (min-width: 768px) {
  .container {
    display: grid;
    grid-template-columns: 1fr 3fr;
  }
}
小屏幕用上下堆叠(flex),到大屏幕切换成左右分栏(grid)。

3. 常见断点(breakpoints)

没有绝对标准,但前端常用的几个区间:

设备类型宽度断点
手机max-width: 600px
平板601px ~ 1024px
桌面1025px ~ 1440px
大屏桌面min-width: 1441px

4. 移动优先(推荐写法)

通常我们写 默认样式先适配手机,然后用 min-width 一步步增强:

/* 默认:手机 */
.container {
  flex-direction: column;
}

/* 平板以上:改成行布局 */
@media (min-width: 768px) {
  .container {
    flex-direction: row;
  }
}

/* 桌面以上:加上侧边栏 */
@media (min-width: 1024px) {
  .container {
    display: grid;
    grid-template-columns: 200px 1fr;
  }
}

答疑

不是我就奇怪了,手机这种为什么要设置flex-direction: column;本来放div元素不就是从上到下吗,为什么一定要在根容器上设置为flex


1. 默认流确实是「从上到下」

没错,<div> 默认就是 块级元素,会在标准文档流里从上到下排布。 👉 所以 在最简单的手机布局场景 下,确实不用特意加 flex-direction: column;


2. 为什么很多教程还写了 flex-direction: column;

主要有这几个原因:

(1) 为了和「大屏布局」对齐思路

很多时候设计是这样的:

  • 手机:上下堆叠
  • 平板:两列
  • 桌面:三列

flex/grid 的好处是,你只要在不同断点切换容器属性就行:

.container {
  display: flex;
  flex-direction: column; /* 手机:上下 */
}

@media (min-width: 768px) {
  .container {
    flex-direction: row; /* 平板:左右 */
  }
}

👉 这样写比较「语义对称」:一开始就是 flex 布局,然后只改方向,而不是从 blockflex


(2) 方便做水平/垂直对齐

如果只是标准流:

  • 元素之间要平均分布?难。
  • 垂直方向要居中?得写很多额外样式。

但 flex 自带:

.container {
  display: flex;
  flex-direction: column;
  justify-content: center; /* 垂直居中 */
  align-items: center;     /* 水平居中 */
}

👉 如果一开始就用 flex,布局调整和对齐会很方便。


(3) 未来可能要拓展

产品迭代时,设计师经常说:

  • 「手机还是一列,但想要某些卡片在中间对齐」
  • 「间距要平均」
  • 「底部加个自适应的按钮栏」

如果容器已经是 flex,就能直接用 justify-content / align-items / gap,不需要大改。


3. 总结

  • 手机上一列 确实不需要 flex,默认文档流就能搞定。
  • 但很多团队会 一开始就用 flex/grid,因为:
    1. 方便和大屏布局保持一致(只改方向,不改 display)。
    2. 带来了更灵活的对齐、分布能力。
    3. 提前为未来需求留余地。

所以教程里写 flex-direction: column; 更多是 布局习惯和可扩展性考虑,而不是说“必须这么写”。

布局思路CSS 语义/性能差别


1. 100vw / 100vh

.full {
  width: 100vw;
  height: 100vh;
}
  • vw/vh:视口宽度/高度的百分比,1vw = 视口宽度的 1%,1vh = 视口高度的 1%。
  • 这种写法的意思是:元素的尺寸始终等于视口大小
  • 它本质是一个「尺寸设定」,不会影响元素的定位方式(还是正常文档流)。

📌 用途:全屏背景、全屏容器、轮播图一屏占满。


2. position: fixed; top:0; right:0; bottom:0; left:0;

.full {
  position: fixed;
  top: 0; right: 0; bottom: 0; left: 0;
}
  • 固定定位,锚定在视口上,大小等于视口。
  • 不管页面滚动到哪里,它都会 固定不动
  • 本质是「定位方式」,而不是「尺寸设置」。

📌 用途:固定导航栏、浮层、模态框、遮罩。

100vw 在有滚动条时会 包含滚动条宽度,容易导致出现横向滚动条(比如 PC 浏览器)。

  • 解决办法:可以用 width: 100%; 替代,或者 calc(100vw - var(--scrollbar-width))

100vh 在移动端 Safari 上会因为地址栏的显示/隐藏而变化,导致「跳动」。

  • 新标准有 svh, lvh, dvh 可以解决。

标准流间隙问题

1. 为什么会超出

  • 标准流 + inline-block:元素之间的空格(HTML 里的空格/换行)会占宽度。
  • 标准流 + float:50% + 50% = 100%,但如果再加 margin,总宽度就 > 100%。
  • 标准流 + box-sizing: content-box(默认):width 只算内容,不算 padding/border,加了 padding 也会超出。

原来那些空格是来自HTML 里的空格/换行,我把格式改为这样

html
<body>
  <div class="container">
    <div class="box1"></div><div class="box2"></div>
  </div>
</body>

效果:

image-20250912151357463

还原回去:

html
<body>
  <div class="container">
    <div class="box1"></div>
    <div class="box2"></div>
  </div>
</body>

效果:

image-20250912151530010

提示

当元素是 inlineinline-block 时,HTML 源码里的空格/换行 会被浏览器当成 一个空白字符(whitespace) 渲染出来。

2. 如何避免这种“神秘间隔”?

方法 1:去掉换行/空格

<div style="display:inline-block;width:50%">A</div><div style="display:inline-block;width:50%">B</div>

但这很丑,不好维护。

方法 2:父容器 font-size:0

.parent {
  font-size: 0;
}
.parent > div {
  font-size: 16px; /* 还原内容文字大小 */
}

👉 因为空格宽度依赖 font-size,设成 0 就没有空隙了。

方法 3:负 margin

.left {
  display: inline-block;
  width: 50%;
  margin-right: -4px;
}

(丑陋 hack,不推荐 🙈)(导致左边元素大小被右边元素占用,左边元素变小)

方法 4:不用 inline-block,改用 flex / grid

这是最推荐的现代方案:

.parent {
  display: flex;
}
.child {
  flex: 1;
}

👉 完全没有空隙问题,而且还能用 gap 控制间距。

body

body元素自带margin:8px;,需要去除才能完全拥有浏览器界面

margin为什么合并

html
<style>
    .box1 {
        height: 200px;
        background-color: lightpink;
        margin-bottom: 20px;
    }
    .box2 {
        height: 200px;
        background-color: lightblue;
        margin-top: 30px;
    }
</style>
</head>
<body>
    <div class="box1"></div>
    <div class="box2"></div>
</body>

最终合并为30px:

image-20250918200600318

之前在浮动里面演示了浮动是不会触发margin合并的,现在探究合并的根本原因

margin 合并只发生在垂直方向(上下 margin),不会发生在水平方向。

合并规则是取最大值,而不是相加。

媒体查询示例

媒体查询有一套编写顺序,如果使用min-width,就是从最小的屏幕样式开始不断向大的写,如果是max-with就是从pc端样式不断向移动端过渡

两种风格

1. Mobile First(推荐,现代主流)

  • 基础样式默认给 最小屏幕(移动端)

  • 媒体查询使用 min-width,随着屏幕变大不断“增强”样式。

  • 写法示例:

    css
    /* 默认:移动端样式 */
    body {
      font-size: 14px;
    }
    
    /* 平板及以上 */
    @media (min-width: 768px) {
      body {
        font-size: 16px;
      }
    }
    
    /* 桌面端及以上 */
    @media (min-width: 1200px) {
      body {
        font-size: 18px;
      }
    }

2. Desktop First(传统思路)

  • 基础样式默认给 PC 端

  • 媒体查询使用 max-width,屏幕变小的时候不断“覆盖”成适合小屏的样式。

  • 写法示例:

    css
    /* 默认:桌面端样式 */
    body {
      font-size: 18px;
    }
    
    /* 平板及以下 */
    @media (max-width: 1200px) {
      body {
        font-size: 16px;
      }
    }
    
    /* 手机及以下 */
    @media (max-width: 768px) {
      body {
        font-size: 14px;
      }
    }

✅ 总结:

  • min-width → Mobile First,从小到大。
  • max-width → Desktop First,从大到小。

现在大多数团队和框架(Bootstrap、Tailwind 等)都是 Mobile First,所以更常用 min-width

示例

现在开始讲述max-width类型转变关键!

PC隐藏移动端组件:

css
/* 移动端隐藏元素 */
.mobile-nav,
.mobile-main {
    display: none;
}

平板

css
/* 平板端媒体查询 (768px - 1024px) */
@media (max-width: 1024px) {
    .features {
        grid-template-columns: repeat(2, 1fr);
    }

    .desktop-main {
        grid-template-columns: 1fr;
    }

    .sidebar {
        order: -1;
    }
}

移动端:

css
/* 移动端媒体查询 (小于768px) - 完全不同的框架 */
@media (max-width: 768px) {
    /* 隐藏桌面端元素 */
    .desktop-nav,
    .desktop-main,
    .features {
        display: none;
    }

    /* 显示移动端元素 */
    .mobile-nav,
    .mobile-main {
        display: block;
    }
    /* 移动端导航 - 垂直卡片式 */
    /*导航以及导航的子元素都定义在这边*/
    .mobile-nav {
		...
    }
    /* 移动端主要内容 - 垂直卡片堆叠 */
    /*主题内容以及主题内容子元素都放在这个媒体查询里面*/
    .mobile-main {
        ...
    }
}

超级小屏幕

css
/* 超小屏幕 (小于480px) */
@media (max-width: 480px) {
    .mobile-nav-buttons {
        justify-content: center;
    }

    .mobile-nav-btn {
        flex: 1;
        min-width: 80px;
    }

    .mobile-stats {
        grid-template-columns: 1fr;
    }

    .mobile-hero h1 {
        font-size: 1.5rem;
    }
}

amfe-flexible

特别好用,在html上设置font-size,不管屏幕大小怎么变化,font-size相应变化,使用rem作为大小单位可维持相对大小比例不变!

评论

评论加载中……