https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics
https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Box_model
https://developer.mozilla.org/en-US/docs/Web/CSS/Cascade
https://developer.mozilla.org/en-US/docs/Web/CSS/Reference
https://web.dev/learn/css

1. Important Points#

CSS 学习顺序:
    box model:
        元素本身有多大

    cascade / specificity:
        为什么最后生效的是这条规则

    layout:
        元素之间如何排列

    responsive:
        屏幕变化时布局如何变化

    visual polish:
        color / typography / spacing / state / animation
CSS 不是背属性:
    先判断元素属于哪个 layout context
    再判断尺寸来自 content / parent / viewport / constraint
    再判断样式来自哪条 cascade rule
    最后才调具体属性

Demo 使用方法:

每个 demo 都可以复制成一个 index.html
用浏览器打开
修改数值观察变化
重点看 layout / size / cascade 的变化

2. Box Model#

一句话:每个元素都是一个盒子,尺寸由 content + padding + border + margin 共同影响。

demo: content-box vs border-box#

<!doctype html>
<html>
<head>
  <style>
    .box {
      width: 200px;
      padding: 24px;
      border: 6px solid #2563eb;
      margin: 12px;
      background: #dbeafe;
    }

    .content-box {
      box-sizing: content-box;
    }

    .border-box {
      box-sizing: border-box;
    }
  </style>
</head>
<body>
  <div class="box content-box">content-box: visual width > 200px</div>
  <div class="box border-box">border-box: visual width = 200px</div>
</body>
</html>
观察:
    content-box 的 width 只算 content
    border-box 的 width 包含 padding 和 border

项目默认:
    * { box-sizing: border-box; }

3. Selectors And Cascade#

一句话:CSS 先匹配 selector,再按 cascade order 决定谁赢。

常见优先级:
    inline style
        highest

    #id
        high specificity

    .class / [attr] / :hover
        normal project style

    element / ::before
        low specificity

同优先级:
    later rule wins

demo: specificity#

<!doctype html>
<html>
<head>
  <style>
    button {
      color: white;
      background: #64748b;
    }

    .primary {
      background: #16a34a;
    }

    #saveButton {
      background: #dc2626;
    }
  </style>
</head>
<body>
  <button id="saveButton" class="primary">Save</button>
</body>
</html>
观察:
    button selector 会输给 .primary
    .primary 会输给 #saveButton

实践:
    业务组件尽量用 class
    少用 id 写样式
    避免 !important

4. Units#

一句话:单位决定尺寸跟谁绑定。

Unit Meaning Use
px fixed CSS pixel border, icon, exact spacing
% relative to parent fluid width
rem relative to root font size typography and spacing scale
em relative to current font size component-local spacing
vw / vh viewport width / height full screen section
fr grid free space fraction CSS Grid columns
ch width of 0 character readable text line length

demo: readable width#

<!doctype html>
<html>
<head>
  <style>
    body {
      font-family: system-ui, sans-serif;
      line-height: 1.6;
    }

    article {
      max-width: 68ch;
      margin-inline: auto;
      padding: 24px;
    }
  </style>
</head>
<body>
  <article>
    <h1>Readable Article</h1>
    <p>
      max-width: 68ch keeps long text readable because the line length
      follows character count, not the viewport width.
    </p>
  </article>
</body>
</html>

5. Custom Properties#

一句话:CSS variables 让颜色、间距、尺寸变成可复用的 design token。

demo: theme token#

<!doctype html>
<html>
<head>
  <style>
    :root {
      --color-bg: #f8fafc;
      --color-panel: #ffffff;
      --color-brand: #2563eb;
      --space-4: 16px;
      --radius-2: 8px;
    }

    body {
      margin: 0;
      padding: var(--space-4);
      background: var(--color-bg);
      font-family: system-ui, sans-serif;
    }

    .card {
      padding: var(--space-4);
      border-radius: var(--radius-2);
      background: var(--color-panel);
      border: 1px solid #e2e8f0;
    }

    .button {
      padding: 8px 12px;
      border: 0;
      border-radius: var(--radius-2);
      color: white;
      background: var(--color-brand);
    }
  </style>
</head>
<body>
  <div class="card">
    <p>Change --color-brand once, the button theme changes.</p>
    <button class="button">Action</button>
  </div>
</body>
</html>
实践:
    colors / spacing / radius / shadow 用变量
    component 内部变量可以被外部覆盖
    不要把所有属性都变量化,只抽重复且有语义的值

6. Typography#

一句话:好看的 UI 不是只靠颜色,字体大小、行高、段落宽度和层级更重要。

demo: type scale#

<!doctype html>
<html>
<head>
  <style>
    body {
      font-family: system-ui, sans-serif;
      color: #111827;
    }

    .panel {
      max-width: 56ch;
      margin: 32px auto;
      padding: 24px;
      border: 1px solid #e5e7eb;
    }

    h1 {
      margin: 0 0 8px;
      font-size: 2rem;
      line-height: 1.15;
    }

    p {
      margin: 0;
      font-size: 1rem;
      line-height: 1.7;
      color: #4b5563;
    }
  </style>
</head>
<body>
  <section class="panel">
    <h1>Clear Type Hierarchy</h1>
    <p>Heading is compact. Body text is comfortable. Line length is controlled.</p>
  </section>
</body>
</html>

7. State#

一句话:CSS 不只画静态页面,也表达用户操作状态。

demo: hover / focus-visible#

<!doctype html>
<html>
<head>
  <style>
    button {
      padding: 10px 14px;
      border: 1px solid #cbd5e1;
      border-radius: 8px;
      background: white;
      color: #0f172a;
      cursor: pointer;
    }

    button:hover {
      background: #f1f5f9;
    }

    button:focus-visible {
      outline: 3px solid #93c5fd;
      outline-offset: 2px;
    }

    button:disabled {
      cursor: not-allowed;
      opacity: 0.5;
    }
  </style>
</head>
<body>
  <button>Focusable Button</button>
  <button disabled>Disabled Button</button>
</body>
</html>
重点:
    hover 表示鼠标状态
    focus-visible 表示键盘可访问性
    disabled 表示不可操作状态

8. Transition#

一句话:transition 只适合小范围状态变化,不适合修复布局问题。

demo: smooth state#

<!doctype html>
<html>
<head>
  <style>
    .chip {
      display: inline-block;
      padding: 8px 12px;
      border-radius: 999px;
      background: #e0f2fe;
      color: #075985;
      transition: background-color 160ms ease, transform 160ms ease;
    }

    .chip:hover {
      background: #bae6fd;
      transform: translateY(-2px);
    }
  </style>
</head>
<body>
  <span class="chip">Hover me</span>
</body>
</html>
实践:
    transition color / background-color / opacity / transform
    避免频繁 transition width / height / top / left
    动画必须服务于状态反馈