跳到主要内容

基础概念✅

什么是CSS盒模型?​

答案

CSS盒模型用于描述文档树中元素生成的矩形框,并根据视觉格式化模型进行布局。它定义了每个元素的内容区、内边距、边框和外边距,决定了页面元素的实际显示和排列方式。 盒模型的结构如下

  1. 内容盒(Content Box)
    • 包含元素的实际内容,如文本或图像。
    • 通过 width 和 height 等属性设置。
  2. 内边距(Padding Box)
    • 包围内容盒的空间,用于增加内容与边框之间的距离。
    • 通过 padding 等属性设置。
  3. 边框(Border Box)
    • 包围内边距盒的线条,用于定义元素的边界。
    • 通过 border 等属性设置。
  4. 外边距(Margin Box)
    • 包围边框盒的空间,用于增加元素与其他元素之间的距离。
    • 通过 margin 等属性设置。
提示

参考 google css 盒模型讲解 初学者可以把盒模型理解为相框。

  1. 内容盒就是照片本身
  2. 内边距盒 照片+相框之间的空间
  3. 边框盒就是整个相框
  4. 外边距盒就是相框+其他物体之间的空间

这种关联方式就能更好地理解为什么边距可以合并,outline 不会影响盒模型的大小等概念。

可以通过 box-sizing 属性来控制盒模型的计算方式。

  1. content-box(默认):width 和 height 只包含内容区域。

  2. border-box:width 和 height 包含内容、内边距和边框。一般推荐使用这种方式,行为更可控,在代理样式重置中,会采用如下方式重置

    *,
    *::before,
    *::after {
    box-sizing: border-box;
    }

延伸阅读

什么是视觉格式化模型(View formatting model) ?​

答案

视觉格式化模型(View formatting model) 定义了用户代理(一般为浏览器)如何在可视化设备(电脑、手机、打印机等)上渲染文档树。简单理解可以认为,盒模型定义单个元素的渲染行为,视觉格式化模型则定义了整个文档树如何铺排和渲染的机制。核心概念包括

  1. 通过 display 属性控制盒模型的生成常见的盒类型包括
    1. display:block 块级盒,垂直堆叠铺排
    2. display:inline 内联盒,水平堆叠铺排
    3. display:inline-block 内容区按照块级盒处理,自身按照内联盒铺排
    4. display:flex flex 铺排
    5. display: grid 网格铺排
    6. display:table
    7. 匿名盒(anonymous block),用户代理在铺排的时候会生成匿名盒包含块级、内联两种,比如没有标签包裹的文字会生成内联匿名盒等,具体规则详见 匿名块级盒、匿名行内盒
  2. 格式化模型存在三种定位策略(position schemes) 控制元素如何铺排
    1. 正常流(Normal Flow)
      1. 块级格式化上下文(Block formatting context BFC) 内容垂直堆叠,同一个块级上下文内部的垂直 margin 会出现合并
      2. 内联格式化上下文(Inline formatting context IFC) 内容水平堆叠, 注意铺排方式还和 writing-mode 属性相关
      3. 相对定位(Relative positioning) 内容会在正常流布局的基础上发生偏移,但是原始盒模型不会改动,所以可能出现显示重叠现象
    2. 浮动布局(Float) 元素会相对正常流对应的包含块边缘对齐
    3. 绝对定位(Absolute position) 元素会脱离正常流,相对关联的包含块对齐
提示

此外视觉格式化模型会受书写方式的影响,来决定内联盒和块级盒的铺排方式,具体可以参考 Writing Modes

延伸阅读

什么是 BFC 有哪些作用?​

答案

块级格式化上下文(Block formatting context BFC) 是属于格式化模型(View formatting model) 中,正常流布局(Normal flow)的一种。

BFC 的核心特性

  1. 包含浮动元素:BFC 会包含其内部的所有浮动元素,解决高度塌陷问题
  2. 阻止外边距合并:BFC 内的外边距不会与外部元素的外边距合并
  3. 阻止文字环绕:BFC 会阻止浮动元素与 BFC 内的文字重叠
  4. 独立布局:BFC 内的元素布局不受外部影响

对于块级格式上下文内布局规则如下

  • 盒子从块级格式化上下文的顶层包含块从上到下垂直堆叠
  • 对于相邻的盒子,垂直 margin 会出现折叠
  • 块级格式化上下文的盒子会相对包含块左对齐(注意对于 direction: rtl 则右对齐)

如下方式会产生块级格式化上下文:

  1. 文档的根元素(<html>)
  2. display: flow-root 的元素(推荐使用)
  3. 浮动元素(float 属性不为 none 的元素)
  4. 绝对定位元素(position 属性为 absolute 或 fixed 的元素)
  5. 行内块元素(display: inline-block 的元素)
  6. 表格单元格(display: table-cell 的元素,HTML 表格单元格默认如此)
  7. 表格标题(display: table-caption 的元素,HTML 表格标题默认如此)
  8. 由 display: table、table-row、table-row-group、table-header-group、table-footer-group 或 inline-table 的元素隐式创建的匿名表格单元格
  9. overflow 属性值不是 visible 或 clip 的块级元素
  10. <button> 元素和默认 display: flow-root 的按钮类型 <input> 元素
  11. contain 属性为 layout、content 或 paint 的元素
  12. 弹性盒子项目(display: flex 或 inline-flex 的直接子元素)
  13. 网格项目(display: grid 或 inline-grid 的直接子元素)
  14. 多列容器(column-count 或 column-width 不为 auto 的元素)
  15. column-span: all 的元素

示例说明

<style>
  .box {
    background-color: #f0f0f0;
    padding: 10px;
  }

  .float-box {
    float: left;
    border: 1px solid #000;
  }

  input[type="checkbox"]:checked ~ .box {
    display: flow-root;
  }
</style>
<div class="container">
  清除浮动
  <input type="checkbox" />
  <div class="box">
    <div class="float-box">浮动元素</div>
  </div>
</div>

延伸阅读

什么是 IFC 和 BFC 有哪些区别?​

答案

内联格式化上下文(Inline Formatting Context IFC) 是视觉格式化模型中的一种布局模式,用于处理内联元素的排列。与 BFC 不同,IFC 主要处理水平方向的布局。

IFC 的核心特性:

  1. 水平排列:IFC 内的元素按照水平方向从左到右排列(在 LTR 语言环境下)
  2. 基线对齐:内联元素默认按照基线对齐,可以通过 vertical-align 属性调整
  3. 行框(Line Box):IFC 会创建行框来包含每一行的内联元素
  4. 自动换行:当内容超出容器宽度时,会自动换行创建新的行框

IFC 的布局规则:

  • 内联元素在 IFC 中水平排列,从包含块的顶部开始
  • 行框的高度由该行内最高元素的高度决定
  • 内联元素的垂直对齐通过 vertical-align 属性控制
  • 当内联元素包含块级元素时,会创建匿名块级盒

IFC 与 BFC 的主要是 IFC 主要用于文本内容的排版,如段落、标题等。 BFC 用于块级布局。

示例说明

<style>
  .container {
    border: 1px solid #ccc;
    padding: 10px;
    margin: 10px 0;
    width: 300px;
  }
  
  .normal-text {
    font-size: 16px;
    background: lightblue;
  }
  
  .tall-text {
    font-size: 32px;
    background: lightgreen;
    line-height: 1.2;
  }
  
  .image {
    width: 50px;
    height: 50px;
    background: lightcoral;
    display: inline-block;
    vertical-align: middle;
  }
  
  .highlight {
    background: yellow;
    padding: 2px;
  }
</style>

行框高度由最高元素决定:
<div class="container">
  <span class="normal-text">普通文本</span>
  <span class="tall-text">高文本</span>
  <span class="normal-text">普通文本</span>
</div>

包含图片的行框:
<div class="container">
  <span class="normal-text">文本内容</span>
  <div class="image"></div>
  <span class="normal-text">更多文本</span>
</div>

多行文本的行框:
<div class="container">
  <span class="normal-text">第一行文本</span>
  <span class="tall-text">第二行高文本</span>
  <span class="normal-text">第三行文本</span>
  <span class="highlight">高亮文本</span>
</div>

延伸阅读

什么是 Cascade?​

答案

层叠(cascade) 用来处理一个元素的 css 属性上匹配多条规则时,如何计算最终的属性值。这最终通过层叠计算出来的属性值叫做层叠值(cascaded value)。

核心规则如下

  1. 默认顺序,从低到高
    1. 用户代理设置的默认样式
    2. 用户设置的默认样式,通过插件或者配置实现
    3. @layer 规则
    4. 开发者设置的样式
      1. 内联样式 > ID 选择器 > 类属性选择器 > 标签选择器 > 通配符
      2. 选择器优先级相同,则后面的样式覆盖前面的
  2. 如果设置了 !important 会导致优先级权重提升,但是和默认顺序相反即从低到高依次为
    1. !important 开发者设置样式
    2. !important @layer 规则
    3. !important 用户设置样式
    4. !important 代理设置样式

延伸阅读

什么是层叠上下文(Stacking Context)?​

答案

层叠上下文(Stacking Contexts) 决定了文档树中的元素在可视化设备上的叠放规则,可以类比为 PhotoShop 中图层堆叠的概念。默认层叠上下文的核心包括

  1. 正常流布局中,同级元素层叠优先级,靠后的元素高于靠前的元素,不同级的子元素层叠规则由最终同级的父元素决定。这也是为什么单纯设置某个子元素的 z-index 不生效的原因,因为同级的父元素可能层叠靠前导致无法覆盖后面的元素
  2. 对于 position 不等于 static 值的定位元素, z-index 的值越大层叠越靠上。注意对于 flex、grid 这些容器的子元素不依赖 position 限制,可以直接设置 z-index 控制层叠
  3. 如下方式会创建层叠上下文
    1. 文档根元素 <html>
    2. position 值为 absolute(绝对定位)或 relative(相对定位)且 z-index 值不为 auto 的元素;
    3. position 值为 fixed(固定定位)或 sticky(粘滞定位)的元素(沾滞定位适配所有移动设备上的浏览器,但老的桌面浏览器不支持);
    4. flex (flex) 容器的子元素,且 z-index 值不为 auto;
    5. grid (grid) 容器的子元素,且 z-index 值不为 auto;
    6. opacity 属性值小于 1 的元素(参见 the specification for opacity);
    7. mix-blend-mode 属性值不为 normal 的元素;
    8. 以下任意属性值不为 none 的元素:
      • transform
      • filter
      • backdrop-filter
      • perspective
      • clip-path
      • mask / mask-image / mask-border
      • isolation 属性值为 isolate 的元素;
    9. will-change 值设定了任一属性而该属性在 non-initial 值时会创建层叠上下文的元素(参考这篇文章);
    10. contain 属性值为 layout、paint 或包含它们其中之一的合成值(比如 contain: strict、contain: content)的元素。

延伸阅读

什么是逻辑属性和逻辑值?​

答案

CSS 利用 逻辑属性 解决由于书写方向和模式改变,导致的非预期的渲染错误。

浏览器在实际布局(Layout)和绘制(Painting) 阶段依赖坐标系确认布局位置和绘制顺序,参考 Coordinate Spaces chromium 对坐标体系的说明

  • 物理坐标(Physical coordinates):对应于输出设备的物理方向(如屏幕、打印页面)。通常用于绘制,因此布局逻辑在传递给绘制阶段时可能会产生这种空间的值。CSS 属性如 top、right、bottom、left 就属于物理坐标空间。
  • 逻辑坐标(Logical coordinates):用于布局,支持根据 writing-mode 和 direction CSS 属性的不同值进行通用定位。以 before、after、start 或 end 命名的属性属于逻辑坐标空间。
  • 不考虑内联方向翻转的逻辑坐标:即“逻辑块坐标(logical block coordinates)”,不考虑文本方向。比如 “LogicalLeft” 和 “LogicalRight” 就是这类坐标的例子。

常规属性均采用物理坐标系,这会导致在在通过 writing-mode 等改变书写模式后影响常规元素的铺排示例如下

<style>
  .container {
    display: flex;
    gap: 10px;
  }
  .parent {
    width: 200px;
    height: 200px;
    display: flex;
    background: cadetblue;
    justify-content: center;
    align-items: center;
    position: relative;
  }
  .child {
    height: 30px;
    position: absolute;
    top: 30px;
    left: 30px;
    background: coral;
  }

  .block-size {
    /* 采用 block-size 设置逻辑高度,不受物理坐标系影响 */
    block-size: 30px;
    /* 注意必须重置 height, 不然最终还是覆盖 block-size */
    height: unset;
  }
  
  #toggle:checked ~ .container .parent {
    writing-mode: vertical-rl;
  }
</style>
开启 write-mode: vertical-rtl
<input type="checkbox" id="toggle" />
<div class="container">
  <div class="parent">
    parent
    <div class="child">children</div>
  </div>
  <div class="parent">
    parent
    <div class="child block-size">children</div>
  </div>
</div>

延伸阅读

什么是书写模式(writing-mode),有什么作用?​

答案

默认浏览器采用由上到下、从左到右的书写模式(writing-mode),但是对于一些语言如阿拉伯语、日语等,书写模式会有所不同。所以浏览器定义了 Writing Modes Level 规范来处理不同书写模式的问题。核心的属性包括

  • writing-mode:定义书写模式,决定了块级元素的排列方式,常用值,支持 horizontal-tb(水平从上到下)、vertical-rl(垂直从右到左)
  • direction:定义文本方向,决定了内联块的排列顺序,常用值,支持 ltr(从左到右)、rtl(从右到左)

例如如下配置

  • writing-mode: vertical-rl 决定了块的铺排是垂直方向从右到左
  • direction: ltr 决定了内联盒的排列是从左到右
writing-mode: vertical-rl; direction: ltr:

'top' / 'start' side

block-flow direction
<------------------------------------ |
------------------------------------- |
| c | s | |
'left' | o | o | | inline 'right'
/ | n | m | | direction /
'after' | t | e | | 'before'
side | e | | | side
| n | | |
| t | | |
------------------------------------- v

'bottom' / 'end' side

什么是响应式设计?如何实现?​

答案

核心概念

响应式设计是一种网页设计方法,使网站能够自动适应不同设备和屏幕尺寸,提供最佳的用户体验。其核心思想是"一套代码,多端适配"。

实现方法

  1. 媒体查询(Media Queries)

    • 根据设备特性应用不同的样式
    • 常用的断点:手机(<768px)、平板(768px-1024px)、桌面(>1024px)
  2. 弹性布局(Flexbox/Grid)

    • 使用相对单位而非固定像素
    • 容器能够根据内容自动调整
  3. 相对单位

    • 使用 rem、em、%、vw/vh 等相对单位
    • 避免使用固定像素值
  4. 图片适配

    • 使用 max-width: 100% 确保图片不溢出容器
    • 使用 srcset 和 sizes 属性提供不同尺寸的图片

示例说明

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>响应式设计演示</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }
        
        body {
            font-family: Arial, sans-serif;
            line-height: 1.6;
            color: #333;
        }
        
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 0 20px;
        }
        
        /* 响应式导航栏 */
        .navbar {
            background: #007bff;
            color: white;
            padding: 1rem 0;
        }
        
        .nav-content {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        
        .logo {
            font-size: 1.5rem;
            font-weight: bold;
        }
        
        .nav-menu {
            display: flex;
            list-style: none;
            gap: 2rem;
        }
        
        .nav-menu a {
            color: white;
            text-decoration: none;
            transition: opacity 0.3s;
        }
        
        .nav-menu a:hover {
            opacity: 0.8;
        }
        
        .hamburger {
            display: none;
            flex-direction: column;
            cursor: pointer;
        }
        
        .hamburger span {
            width: 25px;
            height: 3px;
            background: white;
            margin: 3px 0;
            transition: 0.3s;
        }
        
        /* 响应式网格布局 */
        .grid-demo {
            margin: 2rem 0;
        }
        
        .grid-container {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
            gap: 2rem;
            margin: 2rem 0;
        }
        
        .grid-item {
            background: #f8f9fa;
            padding: 1.5rem;
            border-radius: 8px;
            border: 1px solid #dee2e6;
        }
        
        .grid-item h3 {
            color: #007bff;
            margin-bottom: 1rem;
        }
        
        /* 响应式图片 */
        .image-demo {
            margin: 2rem 0;
        }
        
        .responsive-image {
            width: 100%;
            height: auto;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        
        /* 响应式表格 */
        .table-demo {
            margin: 2rem 0;
            overflow-x: auto;
        }
        
        .responsive-table {
            width: 100%;
            border-collapse: collapse;
            margin: 1rem 0;
        }
        
        .responsive-table th,
        .responsive-table td {
            border: 1px solid #dee2e6;
            padding: 0.75rem;
            text-align: left;
        }
        
        .responsive-table th {
            background: #f8f9fa;
            font-weight: bold;
        }
        
        /* 响应式文本 */
        .text-demo {
            margin: 2rem 0;
        }
        
        .responsive-text {
            font-size: clamp(1rem, 2.5vw, 1.5rem);
            line-height: 1.6;
        }
        
        /* 响应式按钮 */
        .button-demo {
            margin: 2rem 0;
        }
        
        .responsive-button {
            display: inline-block;
            padding: clamp(0.5rem, 2vw, 1rem) clamp(1rem, 4vw, 2rem);
            background: #007bff;
            color: white;
            text-decoration: none;
            border-radius: 4px;
            transition: background 0.3s;
            font-size: clamp(0.875rem, 2vw, 1rem);
        }
        
        .responsive-button:hover {
            background: #0056b3;
        }
        
        /* 媒体查询断点 */
        @media (max-width: 768px) {
            .nav-menu {
                display: none;
            }
            
            .hamburger {
                display: flex;
            }
            
            .grid-container {
                grid-template-columns: 1fr;
                gap: 1rem;
            }
            
            .container {
                padding: 0 15px;
            }
        }
        
        @media (max-width: 480px) {
            .container {
                padding: 0 10px;
            }
            
            .grid-item {
                padding: 1rem;
            }
        }
        
        /* 设备信息显示 */
        .device-info {
            background: #e9ecef;
            padding: 1rem;
            border-radius: 4px;
            margin: 1rem 0;
            font-family: monospace;
        }
        
        .demo-section {
            margin: 3rem 0;
            padding: 2rem;
            background: white;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }
        
        .demo-section h2 {
            color: #495057;
            margin-bottom: 1rem;
            border-bottom: 2px solid #007bff;
            padding-bottom: 0.5rem;
        }
        
        .code-example {
            background: #f8f9fa;
            border: 1px solid #e9ecef;
            border-radius: 4px;
            padding: 1rem;
            margin: 1rem 0;
            font-family: 'Courier New', monospace;
            font-size: 14px;
            overflow-x: auto;
        }
    </style>
</head>
<body>
    <!-- 响应式导航栏 -->
    <nav class="navbar">
        <div class="container">
            <div class="nav-content">
                <div class="logo">响应式设计演示</div>
                <ul class="nav-menu">
                    <li><a href="#grid">网格布局</a></li>
                    <li><a href="#images">响应式图片</a></li>
                    <li><a href="#table">响应式表格</a></li>
                    <li><a href="#text">响应式文本</a></li>
                </ul>
                <div class="hamburger">
                    <span></span>
                    <span></span>
                    <span></span>
                </div>
            </div>
        </div>
    </nav>
    
    <div class="container">
        <!-- 设备信息 -->
        <div class="device-info">
            <strong>当前视口宽度:</strong><span id="viewport-width"></span>px<br>
            <strong>设备类型:</strong><span id="device-type"></span>
        </div>
        
        <!-- 网格布局演示 -->
        <section class="demo-section" id="grid">
            <h2>响应式网格布局</h2>
            <p>使用 CSS Grid 的 auto-fit 和 minmax 实现响应式网格:</p>
            
            <div class="grid-container">
                <div class="grid-item">
                    <h3>网格项目 1</h3>
                    <p>这是一个响应式网格项目,会根据屏幕宽度自动调整列数。</p>
                </div>
                <div class="grid-item">
                    <h3>网格项目 2</h3>
                    <p>在桌面端显示多列,在移动端自动变为单列布局。</p>
                </div>
                <div class="grid-item">
                    <h3>网格项目 3</h3>
                    <p>使用 CSS Grid 的 auto-fit 功能实现自适应列数。</p>
                </div>
            </div>
            
            <div class="code-example">
.grid-container {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 2rem;
}
            </div>
        </section>
        
        <!-- 响应式图片演示 -->
        <section class="demo-section" id="images">
            <h2>响应式图片</h2>
            <p>图片会根据容器宽度自动缩放,保持宽高比:</p>
            
            <img src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwMCIgaGVpZ2h0PSI2MDAiIHZpZXdCb3g9IjAgMCAxMDAwIDYwMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjEwMDAiIGhlaWdodD0iNjAwIiBmaWxsPSIjMDA3YmZmIi8+Cjx0ZXh0IHg9IjUwMCIgeT0iMzAwIiBmb250LWZhbWlseT0iQXJpYWwiIGZvbnQtc2l6ZT0iNDgiIGZpbGw9IndoaXRlIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBkeT0iLjNlbSI+5Y2g5L2N5p2h5Lu2PC90ZXh0Pgo8L3N2Zz4K" 
                 alt="响应式图片演示" 
                 class="responsive-image">
            
            <div class="code-example">
.responsive-image {
  width: 100%;
  height: auto;
  max-width: 100%;
}
            </div>
        </section>
        
        <!-- 响应式表格演示 -->
        <section class="demo-section" id="table">
            <h2>响应式表格</h2>
            <p>表格在小屏幕上可以水平滚动:</p>
            
            <div class="table-demo">
                <table class="responsive-table">
                    <thead>
                        <tr>
                            <th>设备类型</th>
                            <th>屏幕宽度</th>
                            <th>布局方式</th>
                            <th>特点</th>
                        </tr>
                    </thead>
                    <tbody>
                        <tr>
                            <td>手机</td>
                            <td>&lt; 768px</td>
                            <td>单列布局</td>
                            <td>垂直堆叠,触摸友好</td>
                        </tr>
                        <tr>
                            <td>平板</td>
                            <td>768px - 1024px</td>
                            <td>双列布局</td>
                            <td>中等屏幕优化</td>
                        </tr>
                        <tr>
                            <td>桌面</td>
                            <td>&gt; 1024px</td>
                            <td>多列布局</td>
                            <td>充分利用屏幕空间</td>
                        </tr>
                    </tbody>
                </table>
            </div>
            
            <div class="code-example">
.table-demo {
  overflow-x: auto;
}

.responsive-table {
  width: 100%;
  min-width: 600px;
}
            </div>
        </section>
        
        <!-- 响应式文本演示 -->
        <section class="demo-section" id="text">
            <h2>响应式文本</h2>
            <p>使用 clamp() 函数实现响应式字体大小:</p>
            
            <p class="responsive-text">
                这是一段响应式文本,字体大小会根据视口宽度自动调整。
                在桌面端显示较大字体,在移动端显示较小字体,确保良好的可读性。
            </p>
            
            <div class="code-example">
.responsive-text {
  font-size: clamp(1rem, 2.5vw, 1.5rem);
  line-height: 1.6;
}
            </div>
        </section>
        
        <!-- 响应式按钮演示 -->
        <section class="demo-section">
            <h2>响应式按钮</h2>
            <p>按钮的内边距会根据屏幕大小自动调整:</p>
            
            <div class="button-demo">
                <a href="#" class="responsive-button">响应式按钮</a>
                <a href="#" class="responsive-button">另一个按钮</a>
            </div>
            
            <div class="code-example">
.responsive-button {
  padding: clamp(0.5rem, 2vw, 1rem) clamp(1rem, 4vw, 2rem);
  font-size: clamp(0.875rem, 2vw, 1rem);
}
            </div>
        </section>
        
        <!-- 媒体查询演示 -->
        <section class="demo-section">
            <h2>媒体查询断点</h2>
            <p>常用的响应式断点设置:</p>
            
            <div class="code-example">
/* 手机端 */
@media (max-width: 768px) {
  .nav-menu { display: none; }
  .grid-container { grid-template-columns: 1fr; }
}

/* 小屏手机 */
@media (max-width: 480px) {
  .container { padding: 0 10px; }
}

/* 平板端 */
@media (min-width: 769px) and (max-width: 1024px) {
  .grid-container { grid-template-columns: repeat(2, 1fr); }
}

/* 桌面端 */
@media (min-width: 1025px) {
  .grid-container { grid-template-columns: repeat(3, 1fr); }
}
            </div>
        </section>
    </div>
    
    <script>
        // 更新设备信息
        function updateDeviceInfo() {
            const width = window.innerWidth;
            const height = window.innerHeight;
            
            document.getElementById('viewport-width').textContent = width;
            
            let deviceType = '桌面端';
            if (width <= 480) {
                deviceType = '小屏手机';
            } else if (width <= 768) {
                deviceType = '手机';
            } else if (width <= 1024) {
                deviceType = '平板';
            }
            
            document.getElementById('device-type').textContent = deviceType;
        }
        
        // 初始化
        updateDeviceInfo();
        
        // 监听窗口大小变化
        window.addEventListener('resize', updateDeviceInfo);
        
        // 汉堡菜单交互
        document.querySelector('.hamburger').addEventListener('click', function() {
            const navMenu = document.querySelector('.nav-menu');
            navMenu.style.display = navMenu.style.display === 'flex' ? 'none' : 'flex';
        });
        
        // 平滑滚动
        document.querySelectorAll('a[href^="#"]').forEach(anchor => {
            anchor.addEventListener('click', function (e) {
                e.preventDefault();
                const target = document.querySelector(this.getAttribute('href'));
                if (target) {
                    target.scrollIntoView({
                        behavior: 'smooth'
                    });
                }
            });
        });
    </script>
</body>
</html>

Open browser consoleTests

延伸阅读

什么是视口(Viewport)?如何设置?​

答案

核心概念

视口是浏览器中用于显示网页的区域。在移动设备上,视口的概念尤为重要,因为移动设备的屏幕尺寸与桌面不同,需要特殊的处理来确保网页正确显示。

视口类型

  1. 布局视口(Layout Viewport)

    • 浏览器默认的视口大小
    • 通常是 980px 宽度(桌面浏览器标准)
  2. 视觉视口(Visual Viewport)

    • 用户实际看到的视口区域
    • 会随着用户缩放而改变
  3. 理想视口(Ideal Viewport)

    • 设备屏幕的物理像素宽度
    • 通过 meta viewport 标签设置

设置方法

<!-- 基本设置 -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- 详细设置 -->
<meta name="viewport" content="
width=device-width,
initial-scale=1.0,
minimum-scale=1.0,
maximum-scale=5.0,
user-scalable=yes
">

参数说明

参数说明示例
width视口宽度device-width(设备宽度)
initial-scale初始缩放比例1.0(不缩放)
minimum-scale最小缩放比例0.5
maximum-scale最大缩放比例5.0
user-scalable是否允许用户缩放yes/no

常见问题

  1. 移动端字体过小

    /* 设置最小字体大小 */
    body {
    font-size: 16px;
    }
  2. 触摸目标过小

    /* 确保触摸目标足够大 */
    .button {
    min-height: 44px;
    min-width: 44px;
    }
  3. 横屏适配

    @media (orientation: landscape) {
    .container {
    flex-direction: row;
    }
    }

延伸阅读