ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

纯CSS3实现纸张卷角效果:用伪元素、渐变与裁剪还原档案质感

纯CSS3实现纸张卷角效果:用伪元素、渐变与裁剪还原档案质感 简介纯CSS3实现的档案纸张卷角效果示例面向Web前端开发者与CSS特效学习者用于在页面中营造鼠标悬停时纸张右上角自然卷起的视觉互动。方案完全基于CSS3技术构建不依赖JavaScript适合为个人博客、历史档案类页面或作品集增加精致的纸质质感。压缩包内含5个文件其中1个HTML演示页承载核心效果另有2张PNG与2张JPG素材图用于纹理与背景衬托整体包大小仅763KB下载后使用Firefox或Chrome浏览器打开即可直接观察效果。目前已有272人学习浏览适合具备基础HTML/CSS知识、希望进阶掌握形变与过渡动画的开发者。通过解析源码可清晰了解卷角效果如何借助伪元素、线性渐变模拟纸张厚度以及利用transform与过渡属性触发卷起动作页面中还提供了多种素材搭配思路便于读者迁移改造到自己的项目中快速实现富有质感的纸感交互界面。1. 纯CSS3模拟维基百科档案纸张卷角效果一行JS都不用纸面细节全靠伪元素与渐变做维基百科风格的档案页面时最容易让人出戏的就是纸张角落。一篇米黄底色的扫描文段配上一个被翻阅磨卷的纸角立刻就有“馆藏资料”的味道。纯CSS3模拟维基百科档案纸张卷角效果指的是不引入任何图片与JavaScript只用渐变、阴影、裁剪与变换在普通元素上复现“纸边翘起、背面弧光、层叠厚度”三层视觉。它适合直接用在线百科词条、历史资料库、电子书预览和文档卡片里。实现成本不高但想做得不像贴纸几何拆解和图层顺序比创意更重要。这篇我按自己平时落地的方式从视觉拆解、最小代码、做旧细节、排错到进阶一次讲完。2. 卷角的视觉拆解从一条弧线到三层渐变为什么不能只画一个三角形2.1 真实纸角的几何结构缺口、耳片、弧面与投影先把右下角卷角在脑子里拆成四部分纸面本身缺掉的一个小三角、从纸面上翻起来的“耳片”、耳片与纸面之间的弧形过渡、以及耳片投在纸面上的阴影。最后一项最容易被忽略少了它卷角看起来就是贴上去的。观察旧书文件夹时会发现真正卷起来的角背面颜色和正面并不一样。耳片内侧是纸背通常更白或更浅。如果直接用正面纸张颜色立体感会明显减弱。多数卷角教程效果一般问题往往就在这耳片和纸面同一个颜色看起来只是“角被切掉了”而不是“角被翻起来了”。2.2 每个视觉层对应的CSS3能力clip-path、渐变、阴影与变换视觉层和CSS工具的对应关系大概是这样的视觉层CSS3工具关键参数纸面缺角背景渐变 / 伪元素遮罩渐变停止点放在45%至55%制造硬边翘起的耳片clip-path transform三角三顶点rotate 2deg~5deg弧形过渡radial-gradient / linear-gradient停止位置在65%至75%附近投在纸面的投影box-shadow 半透明渐变层4px~8px模糊透明度0.1至0.25渐变的优势在于可以用多个background图层严格控制颜色过渡位置阴影的优势则在于把“悬空感”交给浏览器计算。耳片的边缘也不是直线卷曲会让纸片产生拱形常见做法是在clip-path裁剪时给边上略向内凹的点或叠加radial-gradient把边缘虚化。另外“纸张卷角效果”在CSS3实现里最容易被误解的地方是有人以为必须用drop-shadow。其实卷角立体感主要靠图层遮挡与渐变filter只是锦上添花用多了反而在边缘留下难看的半透明羽边。基础版连filter都不用。2.3 为什么不用border三角和SVG很多老教程用border三角画纸角做法是写一个宽度0的元素用border-top和border-right撑出直角三角。但border三角是纯色没法往里叠加多层渐变弧面和纸背的微光完全做不出来。要追求“维基百科档案纸张卷角效果”那种旧纸感border方案可以直接排除。SVG当然能做更细腻的卷角但标题既然限定纯CSS3我一般会把SVG留作备选当项目已经有内联SVG图标体系时顺手画一个path卷角也行否则为了一个装饰角引入SVG维护成本不值。CSS伪元素方案能覆盖绝大多数页面。3. 最小化实现用两个伪元素加clip-path搭出首个右下角卷角3.1 完整HTML结构一个div装正文两个伪元素留给卷角伪元素只有两个所以结构上要把真正的内容包在卡片内部让.paper-card的::before和::after专供卷角使用。这样后面就算要加装订孔、水渍也有地方放。article classpaper-card div classpaper-meta维基百科 · 馆藏档案/div h2 classpaper-title南泉普愿禅师纪事/h2 p classpaper-text 南泉山上多古松旧志称其地“峰峦环抱泉声四出”。 元丰年间僧众依山结茅沿溪开路始有常住之形。 宣统三年所刊县境图说仍能辨认石阶与田垄的走向。 /p div classpaper-footer第 17 页 / 共 46 页/div /articleHTML本身没有玄机关键是一个原则卷角装饰必须挂在最外层的壳上正文不要直接和卡片共用同一个元素。否则后面调试层叠关系时你会被伪元素和文字互相遮挡的问题反复折腾。3.2 核心CSS阴影层、耳片层与paper背景的三步写法先做纸面色。这里选米黄深色渐变中心偏亮、四角偏暗给后续耳片的“纸背更亮”留出对比空间.paper-card { position: relative; width: min(560px, 88vw); margin: 3rem auto; padding: 2.2rem 2.8rem 3rem; background: radial-gradient(ellipse at 50% 38%, #f4edd9 0%, #eadfc4 68%, #ddcfae 100%); box-shadow: 0 1px 0 rgba(105, 82, 46, 0.12), 0 6px 14px rgba(68, 51, 24, 0.18); font-family: Georgia, Times New Roman, serif; }接着是两个伪元素。第一层::before负责缺口阴影。它盖在右下角颜色是半透明深棕渐变相当于纸面被掀开后下面那一层昏暗的空隙同时承担一部分投影.paper-card::before { content: ; position: absolute; right: -1px; bottom: -1px; width: 44px; height: 44px; background: linear-gradient( 135deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 48%, rgba(93, 76, 46, 0.35) 55%, rgba(93, 76, 46, 0.55) 100% ); transform: rotate(0.001deg); }第二层::after是耳片。先看代码.paper-card::after { content: ; position: absolute; right: -2px; bottom: -2px; width: 44px; height: 44px; background: radial-gradient(circle at 88% 88%, rgba(255, 255, 255, 0.45) 0%, rgba(0, 0, 0, 0) 42%), linear-gradient(135deg, #f9f4e6 0%, #efe5cd 52%, #c4b28b 100%); clip-path: polygon(0% 0%, 100% 0%, 100% 100%); transform: rotate(3deg); }逻辑说明right: -2px; bottom: -2px让伪元素探出纸边2px避免缩放和渲染误差时露出纸底缝隙。clip-path: polygon(0% 0%, 100% 0%, 100% 100%)从44px正方形中裁出右下角直角三角形这就是耳片轮廓。rotate(3deg)让三角形的直角边不再与纸边完全平行产生纸角被“拧着翘起来”的透视效果。背景第一层radial-gradient在右下角画一团高光模拟卷曲弧面受光第二层linear-gradient从亮到暗模拟纸背从卷根向外渐深。参数说明想让卷角更大把width和height同时改成56px到64px旋转角也要跟着加大到4deg到8deg角度不加大大耳片会显得平贴在纸面上。渐变方向135deg必须和clip-path方向一致否则耳片底色会“反着亮”一眼假。注意transform: rotate(0.001deg)不是玄学。Safari在元素的transform计算值为0度时偶尔不生成独立合成层导致伪元素和卡片主体的重叠顺序不稳定。给一个极小的角度能规避这个问题。3.3 调整尺寸与旋转角为什么大卷角需要更明显的旋转纸角卷得越大耳片翘起的视觉角度就应该越明显。一个直观的参考44px卷角用3deg适合普通卡片64px卷角至少要5deg否则大三角的硬边压过弧面感整张纸会像被裁掉一块而不是被卷起。控制旋转角度时可以盯住耳片的两条直角边。旋转后原来与卡片右侧平行的直角边会向右偏转原来与卡片底边平行的直角边会向下偏转这个偏转幅度就是人眼判断“卷起高度”的主要线索。偏转太小像“缺角”偏转太大像“折翼”3deg到5deg之间最安全。4. 把纸做旧维基百科档案纸张的米黄底色、横纹、打孔与装订细节4.1 纸面纹理叠加三层背景让米黄底不呆板前面只有一层radial-gradient做出来的纸面太平。维基百科里那些扫描档案之所以有质感是因为纸面有不均匀的纤维与使用痕迹。给.paper-card补两层背景.paper-card { background: radial-gradient(ellipse 42% 22% at 18% 18%, rgba(255, 255, 255, 0.5) 0%, rgba(0, 0, 0, 0) 70%), radial-gradient(ellipse 32% 18% at 82% 72%, rgba(186, 158, 106, 0.28) 0%, rgba(0, 0, 0, 0) 65%), repeating-linear-gradient( 0deg, rgba(0, 0, 0, 0) 0px, rgba(0, 0, 0, 0) 2px, rgba(120, 96, 56, 0.03) 2.8px, rgba(120, 96, 56, 0.03) 3px, rgba(0, 0, 0, 0) 3.8px ), linear-gradient(135deg, #f6f0df 0%, #eadfc1 68%, #dccba6 100%); }逻辑说明第一层是高光位置在左上18%处椭圆高光让纸面中心鼓起来。第二层是水渍泛黄右下82%/72%处一层很淡的黄褐色配合右下角的卷角形成“这块纸被反复捏过”的错觉。第三层是帘纹周期3px的重复线性渐变每条线只有0.2px到0.8px的宽度透明度0.03远看是纸纤维近看不扎眼。参数说明帘纹周期不要超过3px一旦大于5px就会出现明显的“条纹屏幕”感透明度0.03到0.05是安全区间再高就像扫描仪坏了。多层background的书写顺序是“越靠前越在上层”水渍层放在帘纹上层所以泛黄会盖住纹理符合真实纸张因为受潮先变色、后透出纤维的次序。4.2 打孔与装订线伪元素不够用时的替代方案卷角已占用两个伪元素装订孔就不能再用::before和::after。直接把圆形孔位写进background的多层渐变里.paper-card { background: radial-gradient(circle at 18px 48px, rgba(58, 44, 22, 0.42) 0px, rgba(58, 44, 22, 0.42) 4.5px, transparent 5.5px), radial-gradient(circle at 18px 96px, rgba(58, 44, 22, 0.42) 0px, rgba(58, 44, 22, 0.42) 4.5px, transparent 5.5px), radial-gradient(circle at 18px 144px, rgba(58, 44, 22, 0.42) 0px, rgba(58, 44, 22, 0.42) 4.5px, transparent 5.5px), radial-gradient(ellipse 42% 22% at 18% 18%, rgba(255, 255, 255, 0.5) 0%, rgba(0, 0, 0, 0) 70%), radial-gradient(ellipse 32% 18% at 82% 72%, rgba(186, 158, 106, 0.28) 0%, rgba(0, 0, 0, 0) 65%), repeating-linear-gradient(0deg, rgba(0, 0, 0, 0) 0px, rgba(0, 0, 0, 0) 2px, rgba(120, 96, 56, 0.03) 2.8px, rgba(120, 96, 56, 0.03) 3px, rgba(0, 0, 0, 0) 3.8px), linear-gradient(135deg, #f6f0df 0%, #eadfc1 68%, #dccba6 100%); }逻辑说明三个radial-gradient的三个圆孔都立在左侧18px处纵向间距分别为48px、96px、144px这是比较标准的档案打孔间距。孔的颜色用深棕而非纯黑旧纸打孔边缘会有磨损和渗墨纯黑会很突兀。参数说明孔直径4.5px到6px之间超过7px就变成“圆点贴纸”了。实际项目中如果间距要随字号缩放可以改用calc(2.5em 22px)这类混合单位但基础值建议固定像素因为打孔是物理对象不随字体变化。装订线我一般不加border而是在卡片左侧用内阴影模拟压痕.paper-card { box-shadow: inset 14px 0 0 rgba(0, 0, 0, 0.02), 0 1px 0 rgba(105, 82, 46, 0.12), 0 6px 14px rgba(68, 51, 24, 0.18); }inset 14px 0 0 rgba(0,0,0,0.02)在左边缘压出一道极淡的窄影与打孔配合后整张纸就有了“被从左边翻开”的装订感。注意阴影透明度不要超过0.04否则会变成脏边。5. 避坑与排查卷角被盖住、圆角露馅、响应式变形与打印失效5.1 伪元素被正文压住卷角只露出一半现象把代码搬进项目后卡片右下角只露出很小一块三角像被文字“吃掉了”。原因伪元素虽然用了绝对定位但没有显式建立自己的层叠上下文正文文本所在的行内盒子在最终渲染时会盖在它上方。更隐蔽的是clip-path和transform在某些浏览器下会临时让伪元素生成层叠上下文导致你把属性挪一挪、效果时灵时不灵。解决给两个伪元素都加z-index: 1并给.paper-text这类正文容器设置position: relative; z-index: 0。如果项目里卡片结构比较复杂最稳的做法是别让正文和卷角处在同一层把正文包进一个内部div卷角继续挂在最外层壳上。这样就算内部有图片、表格或覆盖层也很难压住卷角。5.2 圆角与直角打架漏底、白边、破绽现象卡片设了border-radius: 10px卷角处出现没被遮住的灰色小三角或一条白色缝隙。原因圆角让卡片右下角外轮廓变成曲线伪元素耳片仍是直角三角两段曲线和直线接不上。解决让右下角圆角保持0只在左上角做2px到3px圆角。真实的纸张卷角本来就是尖锐的右下角圆角换成0反而更接近物理形态。如果设计稿要求四角都有圆角那就把伪元素向外扩right: -4px; bottom: -4px;让耳片的直角边覆盖圆角弧线缝隙从源头消失。5.3 阴影生硬卷角像贴纸悬在纸上现象耳片下方一团黑或者完全没有阴影卷角就像是被裁掉的缺口。原因给伪元素直接压了一整块box-shadow没有模拟“从纸根到纸尖逐渐消散”的光感。解决阴影层不要用box-shadow用::before的线性渐变控制停止点从55%开始显色向100%加深。这样阴影只出现在耳片根部越往纸内越淡。真正的box-shadow只留给卡片本体避免卷角上叠加出第二条生硬轮廓。血泪经验在深色背景上看效果深色底会放大阴影层的破绽。写完卷角后把页面背景临时改成#2a2a2a如果耳片和纸面之间出现一圈亮线或贴片感说明阴影层的渐变起点太晚了把rgba(93, 76, 46, 0.35)的起点从55%提前到48%。5.4 响应式缩放固定像素的耳片一变形就翻车现象桌面端正常拖到手机宽度后卷角尺寸几乎不变占整张卡片比例严重失调。原因width: 44px; height: 44px写死了。容器宽度变了耳片比例不会跟着变。解决用clamp(28px, 7vw, 48px)控制尺寸桌面端保持48px手机端自动压到28px。同时配合容器宽度限制width: min(560px, 88vw)确保耳片不会因为卡片拉伸而显得过小。如果项目要求严格等比可以只用百分比width: 12%; aspect-ratio: 1;但百分比方案在小卡片上容易低于24px需要再加一个min-width兜底。5.5 打印导出clip-path和阴影被默认丢弃现象打印PDF时卷角消失只剩米黄底色纸面纹理也变成灰块。原因打印引擎默认不渲染clip-path、部分box-shadow和repeating-linear-gradient。解决加打印媒体查询主动降级media print { .paper-card::before, .paper-card::after { display: none; } .paper-card { background: #f4edd9 !important; box-shadow: none !important; } }打印版保留干净纸面和正文比硬还原一个半透明耳片更稳妥。导出截图时若要保留卷角记得把设备像素比设为2倍否则渐变边缘会出摩尔纹。6. 进阶技巧用CSS变量收口把卷角做进组件体系6.1 用CSS自定义属性把卷角做成开关真实项目里我一般会把卷角尺寸、颜色、旋转角度抽成CSS变量方便统一调整.paper-card { --corner-size: clamp(28px, 7vw, 48px); --corner-rotate: 3deg; --paper-bg: #f4edd9; } .paper-card::before, .paper-card::after { width: var(--corner-size); height: var(--corner-size); } .paper-card::after { transform: rotate(var(--corner-rotate)); }这样换肤时只改变量不碰伪元素逻辑也不需要在每个业务页面里复制卷角代码。做团队组件库时这段样式可以直接沉淀为一个.paper-card公共类。6.2 加一枚“已归档”印章增强语境档案感还可以用印章收尾。无需图片用border和文字就能模拟.stamp { position: absolute; right: 56px; top: 20px; padding: 4px 8px; border: 2px solid rgba(171, 41, 32, 0.72); border-radius: 3px; color: rgba(171, 41, 32, 0.78); font-size: 12px; letter-spacing: 2px; transform: rotate(-8deg); }右上角放一枚这样的半透明红章和右下角卷角形成对角线呼应整张档案纸的“被管理过”的感觉就出来了。印章不要做得太清晰透明度和旋转角度是它显得真实的关键。6.3 三条肉眼验证清单每次改完卷角我会按三张检查表过一遍放大到2倍像素看耳片边缘有无锯齿有就在clip-path里加中间点内凹放到深色背景看阴影层是否还在工作关掉::after看纸面缺角是否仍然成立如果不成立说明阴影层被错误地覆盖了。我早年写过一版很满意的卷角上线前把背景调成深色一看耳片边缘有一圈明显亮线像贴了块透明胶布。后来养成了习惯每次写完卷角先把背景调成深色检查一遍确认阴影层没有失效。这套检查流程帮我避开了很多次演示现场翻车。希望帮到你。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进