agentmentoragentmentor

第 05 节:让页面像页面:样式、图片、静态资源

本节 objectives:

  • 能区分全局样式和 CSS Module。
  • 能用 className 给组件加样式。
  • 能用 public/Image 放一张本地图片。

先修:会写组件、props、列表 | 上一节 << 04 | 下一节 06 >>

好看的第一步不是设计,是别让样式乱窜

初学者常把所有样式都塞进一个文件,等页面变多以后,一个 .card 到处互相影响。Next.js 支持全局 CSS,也支持 CSS Modules。官方 CSS 文档把全局样式和模块化样式分开讲,后者会把类名限定在对应组件附近,减少命名冲突1

这一节不追求高级设计。你只要学会:全站基础放全局,某个组件自己的样式放 CSS Module,图片放 public/ 或用 Image 管理。

讲解

全局 CSS 放基础规则。
例如 app/globals.css 适合放 body、链接、全站背景、基础字体。这些规则会影响很多页面,所以要克制。

CSS Module 放组件样式。
文件名通常是 Something.module.css。在组件里 import styles from "./Something.module.css",再写 className={styles.card}。这比到处写普通 .card 更不容易撞名1

JSX 用 className,不是 class
这是 React JSX 的属性规则之一2。浏览器最后仍然会得到正常的 class,只是你在 JSX 里写法不同。

图片优先用清楚的来源。
放在 public/ 里的文件可以用 /filename.png 这样的路径访问。Next.js 的 Image 组件提供尺寸、优化等能力,用它时要给出 srcaltwidthheight 等信息3

跟我做一遍(worked example)

目标:给学习卡片加一个局部样式。

  1. 新建 app/LessonCard.module.css:
css
.card {  border: 1px solid #d0d7de;  border-radius: 8px;  padding: 16px;  background: #ffffff;}
.meta {  color: #57606a;  font-size: 14px;}
  1. app/page.tsx 中使用它:
tsx
import styles from "./LessonCard.module.css";
function LessonCard({  title,  minutes,}: {  title: string;  minutes: number;}) {  return (    <article className={styles.card}>      <h2>{title}</h2>      <p className={styles.meta}>预计 {minutes} 分钟</p>    </article>  );}

为什么这样写:

  • styles.card 来自 CSS Module,只服务这张卡片。
  • className 连接 JSX 和 CSS。
  • .meta 是局部类名,不用担心别的页面也有 .meta

换你补全(faded example)

下面要给一个 ProjectCard 加 CSS Module。补全导入、类名和 JSX 属性。

tsx
import styles from "______";
function ProjectCard({ name }: { name: string }) {  return (    <article className={______}>      <h2>{name}</h2>      <p className={______}>一个练习项目</p>    </article>  );}

如果 ProjectCard.module.css 里有:

css
.card {  padding: 16px;}
.description {  color: #57606a;}

参考答案:

tsx
import styles from "./ProjectCard.module.css";
function ProjectCard({ name }: { name: string }) {  return (    <article className={styles.card}>      <h2>{name}</h2>      <p className={styles.description}>一个练习项目</p>    </article>  );}

关键判断点:导入的是整个 styles 对象;类名通过 styles.card 访问,不是字符串 "styles.card"

小结 + 通向下一节

你已经能让页面有基本结构和视觉层次。下一节进入交互,但会先问一个重要问题:这块内容真的需要在浏览器里动起来吗?

Footnotes

  1. Next.js CSS — https://nextjs.org/docs/app/getting-started/css 2

  2. React: Writing Markup with JSX — https://react.dev/learn/writing-markup-with-jsx

  3. Next.js Image Component — https://nextjs.org/docs/app/api-reference/components/image

练习

Level 1:整理全局样式。
做法:打开 app/globals.css,只保留或添加三类基础规则:bodyamain。不要把具体卡片样式放进去。

提示 1

如果规则只服务一个组件,优先放 CSS Module。

提示 2

如果规则服务全站基础排版,才放全局。 Level 2:加入一张本地图片。
做法:把一张图片放进 public/hero.png,在首页用 Image 显示它。

看参考答案
tsx
import Image from "next/image";<Image  src="/hero.png"  alt="学习桌上打开的代码编辑器"  width={800}  height={400}/>

常见错误剖析:把 alt 写成空字符串,但图片其实承载内容。只有纯装饰图片才适合空 alt;表达内容的图片要写清楚它是什么。

自评