首页
/ freeCodeCamp 课程实战:用 box-shadow 与 border-radius 纯 CSS 绘制新月图形

freeCodeCamp 课程实战:用 box-shadow 与 border-radius 纯 CSS 绘制新月图形

2026-09-06 13:57:26作者:明树来

本文围绕 freeCodeCamp「Applied Visual Design」课程中的挑战 Create a Graphic Using CSS 展开,讲解如何用 box-shadowborder-radiustransparent 背景三个属性,仅靠一个空 <div> 就"借"出一个月牙形图形。读完你能掌握 CSS 阴影五段式语法的精确用法、border-radius: 50% 的成圆原理,以及理解该挑战在课程中如何被正则测试断言验证。

挑战在课程中的位置

这个挑战位于 Applied Visual Design 模块的 Transform 小节后、复杂图形小节前,挑战 ID 为 587d78a6367417b2b2512add。从 模块结构文件 中的 challengeOrder 数组可以看到,它紧跟在两个 skew 变换挑战之后,紧接着就是 "Create a More Complex Shape Using CSS and HTML"(用 ::before/::after 伪元素画爱心):

{
  "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"
},
{
  "id": "587d78a6367417b2b2512ade",
  "title": "Create a More Complex Shape Using CSS and HTML"
}

这个排布并非随意:前置挑战 Add a box-shadow to a Card-like Element 刚刚讲过 box-shadow 的完整语法,本挑战要求你复用这套语法做一个"阴影即图形"的反转练习;后续挑战 Create a More Complex Shape Using CSS and HTML 则在此基础上引入伪元素拼装多部件图形。

核心原理:阴影才是你看到的月亮

挑战文档(description 部分)给出的思路是:

你其实要做的,是创建一个圆形、透明的物体,并给它一个略微偏移的清晰阴影——你最终看到的月亮形状,其实是那个阴影本身。

拆解这句话,就是一次"视觉欺骗"的三步构造:

  1. 本体外壳border-radius: 50% 把一个 100×100 的方形元素变成正圆;
  2. 本体隐藏background-color: transparent 让本体完全不占视觉;
  3. 阴影登场box-shadowblur-radiusspread-radius 都设为 0,得到边缘锐利(crisp)的阴影;offset-x/offset-y 把它推开 25px/10px,于是阴影与"隐形本体"的圆形轮廓错开,重叠部分被本体"遮住",露出的那一段弧形就是月牙。

这里的关键直觉是:阴影是画在元素盒子外围/旁边的,它的形状跟随元素的边框圆角。当本体圆是透明的、阴影圆是不透明的,且两者圆心错开时,阴影被本体区域遮挡后剩下的部分,恰好就是弦切圆弧——即月牙。

box-shadow 语法回顾与参数逐项解析

文档提示读者回忆早前挑战中的 box-shadow 语法。结合前置挑战 587d781b367417b2b2512abe.md 的描述,box-shadow 按顺序接受以下值:

参数 含义 必填 本挑战取值
offset-x 阴影相对元素水平方向的偏移量 25px
offset-y 阴影相对元素垂直方向的偏移量 10px
blur-radius 阴影模糊半径,越大越柔和 0(要锐利边缘,需显式写 0)
spread-radius 阴影扩展半径,正值放大负值缩小 0(需显式写 0,否则默认 0 但会改变后面 color 的位置)
color 阴影颜色 blue

两个"可选"参数是本挑战的易错点:blur-radiusspread-radius 虽然可选,但由于 color 排在它们之后,若想让颜色生效在第四位之后,就必须把两个半径显式写成 0,否则写法 25px 10px blue 会被解析为"偏移 25px/10px + 颜色 blue、默认模糊"——效果上仍是柔和阴影而非清晰月牙。文档中给的 box-shadow 正则断言(见后文测试部分)中 (px)? 是可选的,说明 00px 两种写法都通过,但顺序和空格不可乱。

前置挑战中还提到:多组阴影可以用逗号分隔叠加,例如:

box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);

本挑战只用单组阴影,但理解多阴影叠加后,你可以进一步用第二组阴影模拟"月晕"。

操作步骤:从种子代码到新月

种子代码

挑战的初始(seed)代码如下,一个绝对定位居中、100×100 的蓝色方块,带着一组"错误"的阴影参数:

<style>
  .center {
    position: absolute;
    margin: auto;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    width: 100px;
    height: 100px;
    background-color: blue;
    border-radius: 0px;
    box-shadow: 25px 10px 10px 10px green;
  }

</style>
<div class="center"></div>

注意种子代码里有三处"故意的错误"待修正:background-color: blue(本体不透明)、border-radius: 0px(还是方块)、box-shadow: 25px 10px 10px 10px green(模糊半径和扩展半径都是 10,且颜色是 green——阴影又软又绿,看不出月牙)。

其中 position: absolute + 四个方向 0 + margin: auto 是经典绝对居中写法,保持不变即可。

三步修改

按文档 instructions 的顺序执行:

  1. 隐藏本体:将 background-colorblue 改为 transparent
  2. 变成正圆:将 border-radius0px 改为 50%。对一个宽高相等的方形盒子,50% 的圆角等于各角内切半圆,四角拼成一个正圆;
  3. 重写阴影:将 box-shadow 改为 25px 10px 0 0 blue——offset-x 25px、offset-y 10px、blur-radius 0、spread-radius 0、颜色 blue

最终解法

<style>
  .center {
    position: absolute;
    margin: auto;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    width: 100px;
    height: 100px;
    background-color: transparent;
    border-radius: 50%;
    box-shadow: 25px 10px 0 0 blue;
  }
</style>
<div class="center"></div>

渲染结果:屏幕上没有蓝色方块,只有右下方移出一个蓝色月牙。

参数微调实验

理解了"阴影即图形"后,可以安全地做以下变体来巩固手感:

  • offset-x25px 减小到 10px:月牙变宽(本体与阴影更多重叠);
  • blur-radius0 改为 5px:月牙边缘变柔和,更像真实月光;
  • spread-radius 改为 -10px:阴影整体缩小,月牙变细;
  • box-shadow 里追加第二组:box-shadow: 25px 10px 0 0 blue, 28px 13px 15px 0 rgba(0,0,0,0.3);,可叠出带柔光晕的效果(多阴影语法见 前置挑战)。

测试如何验证你的答案

该挑战的 --hints-- 部分内置了三条正则断言,这也是课程"边学边测"机制的落点。三条断言分别对应三步修改:

// 断言 1:背景必须透明
assert.match(code,/background-color:\s*?transparent;/gi);

// 断言 2:圆角必须是 50%
assert.match(code,/border-radius:\s*?50%;/gi);

// 断言 3:box-shadow 五段式,0 可以省略 px 单位
assert.match(code,/box-shadow:\s*?25px\s+?10px\s+?0(px)?\s+?0(px)?\s+?blue\s*?;/gi);

从正则本身能读出几个容错细节:\s*? 允许属性名与冒号间任意空白,/gi 忽略大小写(TransparentBLUE 均可),0(px)? 表示 blur-radius/spread-radius00px 都通过——与上一节"顺序不可乱、单位可省"的结论一致。

这些断言是怎么跑起来的?从客户端源码结构看,经典挑战页面由 classic/show.tsx 挂载,它在预览 iframe 之外另建一个隐藏的测试 iframe:utils/frame.tscreateFrame 通过 frame.srcdoc = createContent(id, frameContext)srcdoc 属性把挑战代码直接写进 iframe,而 runTestsInTestFrame 则调用 window.FCCTestRunner.getRunner(type).runAllTests(tests, timeout) 执行上述断言。也就是说,你的 CSS 会先在 fcc-main-frame 里真实渲染给你看效果,再由测试 runner 对源码字符串做正则匹配来判断是否通过——这也是为什么断言检查的是 code 文本而非计算样式:正则只能验证"你写了什么",无法验证浏览器最终算出的像素。

与后续挑战的衔接

本挑战证明了"一个盒子 + 一组阴影"就能独立成图。下一个挑战 Create a More Complex Shape Using CSS and HTML 把同一思想推广到多个部件:用 .heart 本体加 ::before/::after 两个伪圆,再配合 transform: rotate(-45deg) 拼出爱心。两者合起来构成该模块的图形构造套路——先用 border-radius/transform 摆出部件,再用颜色与透明度决定"哪些部件是可见的",月牙是"本体不可见、阴影可见",爱心则是"本体与伪元素同色、旋转错位"。

小结

  • 月牙图形的本质:transparent 圆形本体 + blur-radius: 0 的偏移阴影,让阴影在错位处露出弧形;
  • box-shadow 五段式 offset-x offset-y blur-radius spread-radius color 中,blur-radius/spread-radius 想为 0 时建议显式写出,既保证 color 位置正确,也符合课程断言的要求;
  • 该挑战源码位于 587d78a6367417b2b2512add.md,模块顺序定义在 applied-visual-design.json,测试执行链可从 frame.tsrunTestsInTestFrame 追起。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391