资讯动态

用CSS绘制国旗与艺术字:从坐标换算到clip-path实战详解

发布时间:2026/10/17 10:06:46 来源:尧图企业网站定制
画一面国旗听起来像是刚学 CSS 时才会玩的练手小项目但真正动手以后我发现它其实是把数学、盒模型、裁剪路径和文字排版揉在一起的一道综合题。尤其当你想让四颗小星严格按照标准样式“拱卫”大星时单是角度换算就够你花一个小时。这篇文章就把我这次的完整实现过程拆开揉碎写出来从坐标换算到艺术字效果顺便把踩过的坑都记录下来。如果你正准备做活动页、节日专题或者单纯想练一练 CSS 图形绘制这篇内容应该能帮你少走不少弯路。1. 核心思路与设计拆解1.1 一面国旗在视觉上由什么构成回到需求本身用 CSS 绘制国旗再添加艺术字“中国万岁”。这面旗帜的视觉信息其实非常克制一块红色矩形旗面左上角有一颗大五角星和四颗小五角星仅此而已。难点从来不是“画一个星星”而是“怎么把星星放到正确的位置、转到正确的角度”。如果你去翻官方制图说明会发现整个坐标体系非常严谨旗面长高比是 3:2大五角星外接圆直径是旗高的 3/10四颗小五角星外接圆直径是旗高的 1/10并且每颗小星都有一个角尖正对大星中心。换句话说这不是“随便摆四颗小星点缀一下”而是一个有明确几何约束的图形系统。CSS 只是最终的表现层真正决定成品是否顺眼的是前期这些常被忽略的数字。1.2 为什么用纯 CSS 而不是 SVG 或 Canvas很多人看到这种需求第一反应是用 SVG 或者 Canvas。SVG 确实擅长绘制矢量图形Canvas 也可以直接画路径但我选择纯 CSS 的原因也很简单这个需求只涉及矩形、五角星和文字CSS 完全能覆盖其次用纯 CSS 实现不需要引入额外图形库代码可以直接嵌进活动页面没有图片请求后续做动画也更方便可以直接复用 transform、opacity、filter 这些属性。更重要的是纯 CSS 方案对“前端入门到进阶”这个阶段的人来说是个很好的练习你需要自己把像素坐标算明白需要理解盒模型、定位、裁剪路径、字体效果。做一次这种小项目比照着文档抄十段样式有用得多。1.3 整体结构与模块划分我把页面拆成了三块旗面、星星、艺术字。旗面是一个固定比例的容器星星是绝对定位在旗面内部的子元素艺术字是独立在旗帜下方的一行文本。这样拆的好处是每一块都可以单独调试星星位置不对时不会影响文字文字效果不满意时也不用动旗面结构。DOM 结构大致是这样div classflag div classstar star-lg/div div classstar star-sm star-sm-1/div div classstar star-sm star-sm-2/div div classstar star-sm star-sm-3/div div classstar star-sm star-sm-4/div /div div classslogan中国万岁/div星星统一用.star类再通过额外类名区分大小和位置。这样五颗星共享同一套图形样式后续如果要调整星星颜色只改一处就够了。2. 环境与坐标准备2.1 页面骨架搭建动手前先把页面骨架搭好。我习惯用一个居中布局的页面作为“画板”让旗面和艺术字在浏览器正中间展示方便观察整体效果。页面背景用了深色这样金色星星和亮色文字会更突出。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title用 CSS 绘制国旗与“中国万岁”艺术字/title style /* 完整样式见下文 */ /style /head body !-- 结构见 1.3 -- /body /html2.2 用 CSS 变量统一色值与尺寸如果直接在样式中到处写#EE1C25、300px后面想改尺寸会非常痛苦。我习惯一开始就把关键参数抽成 CSS 变量:root { --flag-width: 300px; --flag-height: 200px; --flag-red: #EE1C25; --star-yellow: #FFDE00; --text-gold: #FFB400; }这里红色用了常见的国旗红近似值#EE1C25黄色用了偏亮丽的#FFDE00。不同设备屏幕对颜色的还原会有差异但只要不偏移太离谱视觉上都没问题。把变量放到:root里还有一个好处响应式布局时只需在小屏幕媒体查询里改变量旗帜和文字会同时缩放不用在每个元素上单独改尺寸。2.3 把官方制图法换算成像素坐标这是整个项目里最值得耐心看的部分。标准要求旗面长高比 3:2我取宽度 300px、高度 200px。根据制图说明的换算逻辑按左上四分之一区域划分网格后可以推算出各星中心坐标元素外接圆直径中心坐标相对于旗面左上角大五角星60px(50, 50)第一颗小星20px(100, 20)第二颗小星20px(120, 40)第三颗小星20px(120, 70)第四颗小星20px(100, 90)这套坐标不是估算出来的而是根据“把左上四分之一区域纵向十等分、横向十五等分”的规则换算得到。比如大星中心是纵向第五等分、横向第五等分所以纵向位置是200 / 4 / 10 * 5 25不对这里容易算错。我直接按整体旗面换算左上四分之一区域的纵向十等分每一份对应整旗高的二十分之一也就是200 / 20 10px。大星中心在纵向第五等分所以5 * 10 50px横向十五等分每一份对应300 / 30 10px大星中心在横向第五等分同样得到50px。小星坐标也一样比如第一颗小星在纵向第二等分、横向第十等分换算后就是(100, 20)。如果你拿到的是别的尺寸比如 450px 宽、300px 高只需要把上面的系数重新乘一遍即可坐标规律完全通用。3. 用 CSS 绘制国旗的完整实操3.1 绘制旗面背景旗面就是一张定好比例的红色矩形我用绝对定位当作星星的定位上下文.flag { width: var(--flag-width); height: var(--flag-height); background: var(--flag-red); position: relative; border-radius: 4px; box-shadow: 0 12px 32px rgba(0, 0, 0, 0.35); overflow: hidden; }position: relative是为了让内部的星星参照旗面左上角定位overflow: hidden可以防止子元素因为旋转或裁剪越出边界。边框圆角在这里不是必须的加一点只是为了视觉上更柔和如果你要还原真实旗帜的方正感可以去掉。3.2 用 clip-path 画五角星五角星是唯一稍微有点技术门槛的部分。我选择用clip-path的多边形坐标来画而不是用字符★因为字符在不同系统上的字体渲染差异太大无法保证尖角朝向和比例稳定。一个标准的五角星有十个顶点五个外顶点落在外接圆上五个内顶点落在内圆上。写成百分比坐标后可以复用在任意尺寸的元素上.star { position: absolute; background: var(--star-yellow); clip-path: polygon( 50% 0%, 61.8% 38.2%, 100% 38.2%, 69.1% 61.8%, 79.2% 100%, 50% 76.4%, 20.8% 100%, 30.9% 61.8%, 0% 38.2%, 38.2% 38.2% ); }这段坐标的含义是五角星的尖角朝上外顶点分布在元素边框形成的圆上内顶点按黄金比例内缩。用百分比写的好处是无论元素是 60px 还是 20px图形都会等比例缩放不用担心坐标失配。如果你对精确性有更高要求可以用一段简单的脚本生成坐标再复制到clip-path里。但就实际页面效果而言上面的坐标已经足够标准。3.3 大五角星的定位大星外接圆直径 60px所以星形元素宽度高度都设为 60px。但注意left和top指的是元素左上角的位置不是中心位置。要让星形中心落在旗面(50, 50)处必须减去元素自身尺寸的一半.star-lg { width: 60px; height: 60px; left: 20px; /* 50 - 30 */ top: 20px; /* 50 - 30 */ }这个“减去一半”的操作是最容易被忽略的。很多人写完left: 50; top: 50发现星星整体跑到了右下角其实就是忘了元素左上角不是中心点。3.4 小五角星的定位与旋转角度小星外接圆直径 20px元素宽高 20px。按照坐标表四颗小星的中心分别在(100, 20)、(120, 40)、(120, 70)、(100, 90)所以定位如下.star-sm-1 { width: 20px; height: 20px; left: 90px; /* 100 - 10 */ top: 10px; /* 20 - 10 */ transform: rotate(-121deg); } .star-sm-2 { left: 110px; /* 120 - 10 */ top: 30px; /* 40 - 10 */ transform: rotate(-98deg); } .star-sm-3 { left: 110px; top: 60px; /* 70 - 10 */ transform: rotate(-74deg); } .star-sm-4 { left: 90px; top: 80px; /* 90 - 10 */ transform: rotate(-51deg); }旋转角度是怎么来的因为默认五角星的尖角朝上也就是朝 270 度方向。要让尖角正对大星中心需要先计算当前小星指向大星的向量方向角再减去 270 度。我拿第一颗小星举例它在大星的右上方指向大星的向量是(-50, 30)用Math.atan2(30, -50)算出方向角约 149 度减去 270 度后得到约 -121 度。四颗小星的角度分别是小星指向大星的夹角实际旋转值第一颗约 149°-121deg第二颗约 172°-98deg第三颗约 196°-74deg第四颗约 219°-51deg这里我取了整数角度。如果你要做像素级复刻可以用脚本算到小数点后两位但肉眼基本看不出差别。3.5 响应式缩放固定 300px 宽的旗帜在手机上会显得偏大我用媒体查询改变 CSS 变量来做整体缩放media (max-width: 480px) { :root { --flag-width: 240px; --flag-height: 160px; } }因为所有定位都基于像素值写死这里有个更优雅的做法把整个旗帜包一层用transform: scale()统一缩放。比如在外面套一个.flag-wrapper再在媒体查询里把缩放系数设成0.8。不过我用变量方式更直观也保留了真实布局尺寸方便后续加交互。4. 艺术字“中国万岁”的实现4.1 字体选型与基础排版艺术字我用了楷体优先的字体栈STKaiti, KaiTi, SimHei, serif。楷体的笔画更有手写感配合“中国万岁”这种口号式文案比黑体多一分庄重和温度。字号我选了 56px加粗字间距 8px整体稍微旋转 -2 度让排版不那么死板。.slogan { font-family: STKaiti, KaiTi, SimHei, serif; font-size: 56px; font-weight: 900; letter-spacing: 8px; transform: rotate(-2deg); user-select: none; }如果你的系统里没有楷体会自动回退到黑体视觉上会硬朗一些但整体结构不会崩。4.2 渐变字、描边与阴影为了让文字更有“艺术字”质感我用三层效果叠加渐变填充、描边、投影。渐变填充利用background-clip: text实现把背景裁剪成文字形状同时把文字本身设为透明background: linear-gradient( 180deg, #fff6c0 0%, #ffde00 35%, #f7a400 70%, #fff2a0 100% ); -webkit-background-clip: text; background-clip: text; color: transparent;这样文字从顶部的高光浅黄过渡到中段的金色再到下部的深金黄立体感比纯色好很多。描边用-webkit-text-stroke: 2px #b8860b给文字外轮廓加一圈暗金色边避免浅色渐变在浅色背景上看不清。不过要注意这个属性在部分浏览器里只支持-webkit-前缀目前主流浏览器基本都兼容。最后加阴影text-shadow: 0 4px 0 #8b5a00, 0 8px 20px rgba(255, 180, 0, 0.35);第一层阴影做了“硬偏移”像文字底边压了一块深色垫片产生浮雕感第二层是柔和光晕模拟金色的发光效果。两层阴影组合起来比单纯一个模糊阴影更有层次。4.3 锦上添花加一个轻微浮动动画如果你要在活动页直接使用还可以给艺术字加一个缓慢浮动动画让页面更有呼吸感.slogan { animation: floatText 3s ease-in-out infinite; } keyframes floatText { 0%, 100% { transform: rotate(-2deg) translateY(0); } 50% { transform: rotate(-2deg) translateY(-8px); } }注意动画里也要带上原来的rotate(-2deg)否则文字会先跳回水平位置再运动看起来像闪了一下。5. 常见问题与排查技巧实录5.1 星星位置偏移总是往右下角跑这个绝大多数是定位基点搞错了。绝对定位的left和top是元素左上角的位置而你的坐标表里记录的是星形中心。正确做法是left: 中心X - 元素宽 / 2; top: 中心Y - 元素高 / 2;如果你总是记不住这个公式可以退而求其次把元素宽高设成奇数比如width: 61px; height: 61px然后left: 中心X - 30.5px。但最省事的还是直接写个注释把中心坐标和减去一半后的值都写在代码里。5.2 旋转后星星的角度不对先检查一件事你旋转的是整个元素默认旋转中心是元素中心这刚好也是星形中心理论上没问题。但如果你的clip-path不是标准五角星或者元素本身宽度和高度不一致旋转效果就会歪。更隐蔽的问题是 transform 顺序。如果你同时写了translate(-50%, -50%)和rotate()比如transform: translate(-50%, -50%) rotate(-121deg);这样写一般也能用因为它会先旋转还是先平移的顺序在不同浏览器里是一致的。但为了避免理解负担我更推荐直接算好left/top让 transform 只做旋转排查起来很干净。5.3 clip-path 裁剪异常或兼容性问题clip-path: polygon()在现代浏览器里已经非常稳定但如果你的项目要兼容非常老的浏览器可能要考虑降级方案给元素设置一个纯色背景方形作为 fallback或者用svg替代。另外要确认元素本身有明确的宽高如果元素内容为空且没有width/height裁剪路径可能会直接不显示。还有一个容易踩的细节clip-path的百分比坐标系是相对于元素自身的边框盒不是相对于父容器。你不需要把五角星整体坐标放到旗面坐标系里计算只需要在 60x60 或 20x20 的“局部画布”里把星形画好再通过left/top定位到目标位置。5.4 艺术字渐变不生效最常见的原因是background-clip: text需要配合color: transparent一起使用而且背景渐变要作用在同一元素上。如果你把背景写在了父元素上文字自然显示不出渐变。另一个坑是-webkit-background-clip和标准background-clip的兼容性写法建议两个都写上避免老版本 Safari 不认标准属性。如果你想保留渐变的同时又让文字可选中user-select默认是auto这没问题如果希望文字不被拖动选中可以像我一样加user-select: none。5.5 小屏幕上文字和旗帜比例失衡旗帜可以用 CSS 变量整体缩放但文字如果也直接改字号要注意字间距的等比关系。比如字号从 56px 降到 36px字间距从 8px 降到 4px视觉才会协调。如果只是临时做一个演示页也可以用transform: scale(0.7)快速缩放文字但要注意它不会自动改变文档流占位需要额外处理外边距。实操总结与一点个人体会把这个项目完整做完一遍后我最深的感受是CSS 绘制图形本身并不难真正难的是“用工程化思维去拆解一个视觉系统”。五角星坐标、角度计算、定位基准、字体效果每一环都不复杂但合在一起就是一个完整的作品。以后再做节日活动页、宣传专题时我大概率会直接复用这套模板把尺寸抽成变量、星星颜色改成品牌色就能快速产出变体。最后分享一个小技巧做这种图形类 CSS 前先在草稿纸上把坐标表列出来标清楚每个元素的中心点和尺寸再动手写代码效率会提升很多。等你多写几次就会发现自己对绝对定位、transform、clip-path 的理解完全上了一个台阶。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑