freeCodeCamp 课程实战:用 CSS Transform 的 skewY() 沿 Y 轴倾斜元素
本文基于 freeCodeCamp 课程中 "Applied Visual Design"(应用视觉设计)板块的一道编辑器挑战题展开。该题目要求使用 transform 属性的 skewY() 函数将元素沿垂直(Y)轴倾斜 -10 度。读完本文,你将理解剪切(skew)变换的几何原理、skewX()/skewY() 的差异与角度正负号的视觉效果,并完整掌握这道题的初始代码、标准答案,以及 freeCodeCamp 是如何用断言测试来验证你的代码的。
一、这道题在课程中的位置
该挑战题的源文件是 curriculum/challenges/english/blocks/applied-visual-design/587d78a6367417b2b2512adc.md,其标题为 "Use the CSS Transform Property skewY to Skew an Element Along the Y-Axis"(使用 CSS Transform 属性 skewY 沿 Y 轴倾斜元素)。
从课程结构文件 applied-visual-design.json 可以看到该题在板块中的精确顺序:
{
"id": "587d78a6367417b2b2512adb",
"title": "Use the CSS Transform Property skewX to Skew an Element Along the X-Axis"
},
{
"id": "587d78a6367417b2b2512adc",
"title": "Use the CSS Transform Property skewY to Skew an Element Along the Y-Axis"
},
{
"id": "587d78a6367417b2b2512add",
"title": "Create a Graphic Using CSS"
}
也就是说,它紧跟在 skewX() 练习之后——课程先用 X 轴倾斜建立直觉,再过渡到 Y 轴倾斜,随后就进入"用 CSS 制作图形"的综合性练习。该板块属于 applied-visual-design(helpCategory 为 HTML-CSS),隶属于 Responsive Web Design 认证,这一点可以从 responsive-web-design.json 的结构中确认。
二、skewY():沿垂直轴的剪切变换
原题目的描述(description)部分写道:既然 skewX() 会沿 X 轴倾斜元素,那么 skewY() 就是沿 Y(垂直)轴倾斜元素。
两者的几何含义是:
| 函数 | 作用轴 | 视觉表现 |
|---|---|---|
skewX(angle) |
水平(X)轴 | 上下两条水平边保持原位,左右两侧向相反方向水平错位,元素被"横着压扁" |
skewY(angle) |
垂直(Y)轴 | 左右两条垂直边保持原位,上下两侧向相反方向垂直错位,元素被"竖着压扁" |
从源码结构看,skew 类变换属于 CSS 的剪切(shear)变换:变换只移动每个像素点,移动量与该点到变换原点(transform-origin)在垂直于剪切轴方向上的距离成正比,即位移 = tan(角度) × 距离。因此:
- 角度绝对值越大,错位越明显;
skewY(90deg)在数学上已经是奇异状态(tan 趋于无穷),实际角度通常取 ±45° 以内的较小值; - 正负号决定倾斜方向:
skewY(-10deg)会让元素上方向右、下方向左倾斜(以默认的transform-origin: 50% 50%计),而skewY(10deg)则方向相反; - 变换不改变元素在文档流中占据的布局盒大小,只改变渲染结果——这和
scale()、rotate()一样,是纯视觉变换。
CSS 还提供了一个双参数简写 skew(a, b),第一个参数作用于 X 轴,第二个作用于 Y 轴,例如 skew(0deg, -10deg) 与 skewY(-10deg) 效果等价。
三、题目任务与初始代码(seed)
任务要求(instructions)原文:使用 transform 属性,将 id 为 top 的元素沿 Y 轴倾斜 -10 度。
题目的初始编辑器代码(seed-contents)如下:
<style>
div {
width: 70%;
height: 100px;
margin: 50px auto;
}
#top {
background-color: red;
}
#bottom {
background-color: blue;
transform: skewX(24deg);
}
</style>
<div id="top"></div>
<div id="bottom"></div>
初始代码中有几个值得注意的铺垫:
- 公共样式:两个
div都是width: 70%、height: 100px,并用margin: 50px auto水平居中,保证对比效果清晰; #bottom已经写好了transform: skewX(24deg);——这是上一道 skewX 挑战题 的答案,在此作为参照物保留;#top只有背景色、没有 transform(注意其花括号内有一个空行),这正是你需要补上transform: skewY(-10deg);的位置。
四、完整答案与逐行解析
题目的标准答案(solutions)完整代码如下:
<style>
div {
width: 70%;
height: 100px;
margin: 50px auto;
}
#top {
background-color: red;
transform: skewY(-10deg);
}
#bottom {
background-color: blue;
transform: skewX(24deg);
}
</style>
<div id="top"></div>
<div id="bottom"></div>
相对初始代码,唯一的变化就是在 #top 规则中加入了一行:
transform: skewY(-10deg);
渲染后,红色的 #top 矩形会被沿垂直轴轻微"歪斜",与下方被横向剪切 24 度的蓝色 #bottom 矩形形成对照,直观展示了两种剪切方向的区别。
几个易错点:
- 必须写在
#top的选择器内,且属性名是transform(不能写成已废弃的-webkit-transform或skewY:之类的属性); - 角度必须精确为
-10deg,缺少负号(写成skewY(10deg))或单位(写成skewY(-10))都会被判定为不满足要求; transform是"整体替换"语义:如果在同一选择器里再写另一个transform,后写的会覆盖前面的,多个变换应写在同一声明里,如transform: skewY(-10deg) rotate(5deg);(从右向左依次应用)。
五、测试如何验证你的答案:hints 中的断言正则
题目 hints 部分给出了一条断言:
assert.match(code, /#top\s*?{\s*?.*?\s*?transform:\s*?skewY\(-10deg\);/g);
这条正则精确刻画了通过判定:
#top\s*?{—— 匹配#top选择器及其开始花括号(\s*?是非贪婪空白匹配,容忍任意排版空格);.*?—— 允许中间存在其他声明(如background-color: red;);transform:\s*?skewY\(-10deg\);—— 关键部分:transform属性后必须紧跟skewY(-10deg),括号与连字符在正则中都做了转义(\(、-10deg)。
这也解释了为什么答案里 #top 必须先保留 background-color 再追加 transform——断言允许两者之间的任意内容,但顺序必须是选择器 → 若干声明 → transform: skewY(-10deg);。
六、挑战题的数据结构:从 Markdown 到编辑器
这道题的文件本身就是一份带 frontmatter 的 Markdown,其字段与课程模式 challenge-schema.js 中的 Joi 校验相对应:
---
id: 587d78a6367417b2b2512adc
title: Use the CSS Transform Property skewY to Skew an Element Along the Y-Axis
challengeType: 0
dashedName: use-the-css-transform-property-skewy-to-skew-an-element-along-the-y-axis
forumTopicId: 301075
---
各字段含义:
id:与文件名一致,同时出现在 applied-visual-design.json 的challengeOrder中,用于把题目挂到板块顺序里;challengeType: 0:编辑器挑战题。从 challenge-schema.js 可见challengeType被限定为 0 到 33 的整数(Joi.number().min(0).max(33)),不同类型对应不同的题目形态(编辑器题、视频、多选、填空等);dashedName:由标题生成的 URL 友好 slug,必须匹配小写字母数字与连字符(slugRE = /^[a-z0-9-]+$/)。
正文部分由约定标记的区段组成:# --description--(讲解)、# --instructions--(任务)、# --hints--(提示与断言)、## --seed-contents--(初始代码)、# --solutions--(参考答案)。课程构建管线会解析这些区段生成挑战数据,--seed-contents-- 中的代码即渲染进在线编辑器的初始内容,--hints-- 中的断言即提交时的判题逻辑。
七、skew 在后续课程中的进阶应用
skew 并不只出现在这一道练习题里。在仓库课程中,"Learn CSS Transforms by Building a Penguin" 项目(learn-css-transforms-by-building-a-penguin 板块)以及 "Flappy Penguin" 工作坊的几十个挑战文件里都大量使用了 transform: skew 与 rotate、scale 的组合来塑造图形——可以推断,skewY 这类剪切变换是后续 CSS 图形项目的常规工具。
理解 skewY(-10deg) 时的建议路径:
- 先跑通本题:在
#top中补上transform: skewY(-10deg);,对照红蓝两个矩形的倾斜方向; - 改动角度与正负号:试试
skewY(10deg)、skewY(-30deg),观察倾斜方向与程度如何变化; - 加入
transform-origin:例如transform-origin: 0 0;,观察剪切锚点变化对整体位移的影响; - 组合多个变换:
transform: skewY(-10deg) rotate(90deg);,体会变换函数的作用顺序。
小结
本文以 freeCodeCamp "Applied Visual Design" 板块中的 skewY 挑战题为线索,覆盖了:skewX()/skewY() 的几何原理与角度、正负号语义;题目完整的初始代码与标准答案(在 #top 规则中补写 transform: skewY(-10deg););判题断言正则 /#top\s*?{\s*?.*?\s*?transform:\s*?skewY\(-10deg\);/g 的匹配逻辑;以及题目背后的 Markdown 挑战文件结构(id、challengeType、dashedName 等字段与 Joi 模式校验)。掌握这些内容后,你既能独立通过这道课程题,也能把 skew 剪切变换用到自己的 CSS 图形与视觉设计实践中。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00