资讯动态

纯CSS3模拟维基百科档案纸张:伪元素与渐变实现卷角效果

发布时间:2026/10/6 19:47:45 来源:尧图企业网站定制
简介面向网页前端开发学习者与设计爱好者该代码演示了仅借助CSS3技术实现维基百科风格档案纸张卷角效果交互集中在纸张右上角鼠标悬停时边角自然卷起赋予页面复古纸质质感与流畅细节。压缩包共5个文件包括1个可直接运行的HTML示例页、2张PNG与2张JPG辅助图片整体仅763KB结构清晰、轻量易部署。目前已有272人学习下载适合作为博客卡片、个人作品集或知识库页面的趣味视觉点缀也可嵌入文档模板或历史专题页面作为装饰元素。阅读源码可重点研究CSS3伪元素、线性渐变、圆角、阴影与过渡动画的组合运用理解不依赖JavaScript实现卷曲交互的思路对于中初级前端开发者这是一份便于拆解和二次改写的特效练习样本也可据此延伸折角、撕纸等纸质感UI效果。效果依赖现代浏览器特性建议在火狐或Chrome中打开示例以完整呈现卷角动画。1. 纯CSS3模拟维基百科档案纸张一份能直接用的视觉方案场景你正在做一个面向知识管理的 Web 项目页面里需要展示一批历史档案。设计稿上每张档案纸的右下角都有一个极薄的卷边纸张像被手指轻轻掀过带着微妙的阴影和弧度。这个效果用图片素材做不难但档案区要渲染二三十张卡片切图、压缩、适配深浅背景就全是后续成本。纯CSS3的实现方式是把每张纸的卷角直接用伪元素、渐变和 transform 渲染出来不增加一个 DOM 节点不加载一张位图颜色和尺寸全部由 CSS 变量控制。这是典型的 Web 开发源代码场景一份 HTML(CSS) 源代码资源摘出来就能用、能改、能适配。这套资源适合前端开发、页面重构和原型设计这几类人。只要你不是第一次碰 CSS跟着后面的参数调一遍基本能在半小时内把效果落到自己的项目里。我下面会把原理、完整代码、踩过的坑和一版可交互的进阶玩法一次讲透很多细节是照着官方文档未必能体会到的。2. 卷角效果的底层原理一张纸如何被两个伪元素撑起来2.1 把“纸张卷角”拆成 CSS 能表达的三个图层要用 CSS 还原纸张卷角第一件事是把视觉现象拆开。一张纸卷起右下角后你实际看到的不是一个局部圆角而是几层相互叠加的信息基底的纸面、卷起后露出的背面、角上的受光高光、落在纸面上的阴影以及纸张本身因为弯曲产生的轻微形变。如果只用一个 border-radius 去糊弄出来的效果是“圆滑的方块”不是“被掀起的纸张”。我习惯把卷角效果拆成三个绘图层来管理。第一层是纸张基底也就是内容盒子本身负责承载文字和背景色第二层是卷角本体用 ::after 伪元素实现尺寸缩小到只留下一个三角形区域负责把角落“翻”起来第三层是阴影和高光用 ::before 伪元素配合 filter 或 box-shadow 实现负责让翻起的角度产生真实的投影关系。三个图层只要两个伪元素就能全部承载不必动 HTML 结构。这类档案列表往往包含大量重复卡片每少一个真实 DOM 节点就意味着少一次布局计算和绘制合成页面在低端移动设备上的表现会更稳定。这里先记住一个关键前提伪元素定位用的是绝对定位父级必须有 position: relative。很多人第一步就把伪元素写了却忘了父级定位卷角跑到浏览器窗口边缘去回头查代码找半天。这个坑我会在第四章展开先记下结论。2.2 三种常见 CSS3 卷角形态折角、卷角和微拱角做页面效果久了就会知道CSS 里面“卷角”其实是个词根底下分三种常见形态不同业务场景选型完全不一样。形态核心实现视觉特征适用场景折角linear-gradient border 三角直线折痕边缘锐利协议、证明类严肃文档卷角radial-gradient border 三角 drop-shadow弧面过渡有纸张厚度感维基百科档案、知识库卡片微拱角box-shadow 浅线性渐变边缘微浮无明显翻折hover 反馈、轻交互组件第一种是折角也叫 dog-eared fold纸张像被硬折了一次留下锐利的对角线折痕视觉上偏硬朗。实现上可以给伪元素填充以对角线为边界的两段式 linear-gradient再在折痕位置加一条半透明细线辅助。第二种是卷角也就是这份资源要重点还原的形态。它的特征在于边缘呈弧线过渡角下能看到纸张背面的颜色或半透明阴影像手指捏着边缘轻轻拧了一下。视觉上需要用径向渐变来铺出弧面过渡再用边框三角形作为基础几何形状。维基百科档案纸张那个经典效果大多数实现都沿这个方向走。第三种是微拱角纸张边缘没有明显翻起只有一条很窄的阴影带着视觉错觉像纸因温度和湿度轻微上翘实现最简单只要 box-shadow 配合浅渐变就够。三种形态没有绝对优劣关键在于内容气质。我曾经在一个政务类项目里用了微拱角被设计否决后换成折角原因是折角跟图章式排版更贴合。参数能微调大方向不能选错。2.3 光影节奏是“纸感”的分水岭透明度与方向怎么取值很多人照着教程写完代码效果一眼假。问题不是代码写错了而是光影节奏不对。真实纸张卷起来以后角的正反两面形成两片对比区受光面被环境光照亮透明度偏高因为纸薄会透光背光面靠近纸面交界处暗下去透明度偏低。这两个区域的过渡带大约占整个卷角的 15% 到 20%太窄则生硬太宽则糊成一团。我常年用的安全参数是这样一组受光面渐变从 rgba(255,255,255,0.85) 起步收在 rgba(255,255,255,0.25)覆盖卷角弧面背光面从 rgba(0,0,0,0.12) 渐隐到 rgba(0,0,0,0.02)负责制造翻折处的暗部压力线整张纸的氛围投影用 box-shadow 承担而角的投影单独用 filter: drop-shadow 来生成这样阴影不会因为盒子的矩形边界而穿帮。需要注意渐变方向不是固定值。卷角在右下角时受光面渐变应该从右上往左下推卷角挪到左上角时方向要整体对称变换。很多人只改角的位置不改渐变方向导致光影跟翻卷方向矛盾看起来像是光从两个方向同时打过来。判断方向有一个很直接的笨办法让渐变箭头始终指向纸张中心也就是始终指向翻卷的反方向这样模拟的是环境光从纸张整体区域洒过来的效果。3. 从零搭一张档案纸DOM 结构、核心样式与参数调优3.1 从档案页抽象出的 HTML 结构写代码之前先定结构。我不会让卷角效果迁就一段随意的 markdown而是按典型档案卡片来组织把标题、正文、状态标识、日期这些业务元素放进去这样资源拿回项目里能直接替换内容使用。下面这份结构是常见的档案纸卡片写法article classpaper-doc header classpaper-doc__head span classpaper-doc__tag存档/span h2 classpaper-doc__title档案纸张组件演示/h2 time classpaper-doc__date2024-05-18/time /header div classpaper-doc__body p这是一段用于验证排版效果的示例内容。纸面底色、字号行距、段落间距都会影响整体观感所以请保留纸面区域的留白空间。/p /div footer classpaper-doc__foot span编号ARCH-2024-0518/span /footer /article结构的核心逻辑是把内容按 header、body、footer 划分卷角相关的两个伪元素都挂在最外层 article 上。这样无论内部文字如何增减卷角定位都不会受内容高度变化的影响这是组件化开发里最省心的一点。结构参数说明.paper-doc 是容器宽度、字号、内边距统一从这里控制.paper-doc__head 里的 tag 用来放“存档”“归档”之类的状态标识视觉上是一个小色块.paper-doc__body 承载主要文字行高建议设在 1.6 到 1.8 之间因为纸面效果对文字密度很敏感。如果某个卡片文字量特别大建议在 body 上设置 max-height 后配合 overflow:hidden防止内容顶破纸面的视觉边界。3.2 CSS3 核心实现从底色、双层伪元素到卷角参数接下来进入正题。先给完整样式我再逐段拆解参数.paper-doc { position: relative; width: 320px; padding: 20px 24px 16px; background: linear-gradient(145deg, #faf3e8 0%, #f5ead6 100%); border-radius: 4px; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06), 0 4px 12px rgba(0, 0, 0, 0.08); font-family: Georgia, Songti SC, serif; line-height: 1.7; color: #3a3530; } /* 卷角本体边框三角 纸张背面颜色 */ .paper-doc::after { content: ; position: absolute; right: 0; bottom: 0; width: 0; height: 0; border-width: 0 0 34px 34px; border-style: solid; border-color: transparent transparent #d9c9a7 transparent; border-radius: 0 0 0 10px; filter: drop-shadow(-3px 3px 3px rgba(0, 0, 0, 0.15)); } /* 高光层纸张翻折后的受光面 */ .paper-doc::before { content: ; position: absolute; right: 0; bottom: 0; width: 0; height: 0; border-width: 0 0 28px 28px; border-style: solid; border-color: transparent transparent rgba(255, 255, 255, 0.28) transparent; border-radius: 0 0 0 8px; }这段代码的核心在 ::after 的边框不等宽设置。border-width 取值 0 0 34px 34px意思是右边的边框宽度为 0底部为 34px左边为 34px本质上是用边框构造出一个直角三角形斜边朝向纸张中心实色部分露出档案纸的底色 #d9c9a7视觉上就是卷起的纸背。高光层 ::before 与卷角本体 ::after 错位叠加两层同向三角形大小不一致时底层露出的细小边缘自然形成弧面过渡这是“纸感”而不是“纸片感”的关键。border-radius 初看没起多大用但当你把三角形斜边预先磨出弧度就能获得非常细微的卷曲轮廓这个值建议在 8px 到 14px 之间反复调试。参数说明border-width 底部与左侧两个值控制卷角大小34px 在 320px 宽的卡片上约占总宽度的 10%肉眼看着舒展。小于 20px 会像裁切失误大于 44px 则会抢占正文阅读空间。drop-shadow 作用于三角形边界制造卷角离开纸面的悬浮感如果去掉 filter卷角会像贴纸一样平贴纸面整个效果就废了一半。3.3 两个实战适配偏黄底色与流式宽度第一个适配场景是偏黄旧纸。维基百科的档案里不少是存放了几十年的资料底色由米白变成偏黄。此时把 background 改成 linear-gradient(145deg, #e8d5a3 0%, #dccb8f 100%)同时将 ::after 的 border-color 底部值改成从底色推导出的较深一档颜色 #c9b47c::before 高光的起始透明度从 0.28 下调到 0.18防止高光过强让纸面看起来像塑料反光。第二个场景是流式宽度。如果档案卡不是定宽 320px而是跟随栅格自适应那固定 34px 的卷角在小屏上就会显得笨重。常见做法是改用 clamp 让卷角随视口缩放.paper-doc::after { border-width: 0 0 clamp(18px, 8vw, 34px) clamp(18px, 8vw, 34px); }这里的 clamp 函数把卷角尺寸约束在 18px 到 34px 之间随视口宽度线性变化。但注意 vw 单位参照的是整个视口如果组件嵌在较窄的侧边栏而非全屏内容区建议把 8vw 改成与容器宽度相关的百分比例如 10% 配合 calc 使用。现代浏览器对 calc 与 clamp 嵌套的支持已经很稳定移动端问题不大。4. 这些坑我替你踩过卷角效果常见问题与排查4.1 伪元素设置了页面上却没有卷角最常见也最挫败的排查场景。代码明明写在 ::after 里浏览器审查元素也看到伪元素存在但页面上空无一物。原因之一是遗漏了 content 属性伪元素如果没有 content:哪怕设置了 width、height、border浏览器也不会渲染任何几何形状。原因之二是父级没有 position: relative绝对定位的伪元素脱离到了最近的定位祖先上而那个祖先可能是 body 或某个外层容器卷角自然就出现在你根本看不见的位置。解决方式非常固定。第一步打开 DevTools确认 content 是否为双引号空串第二步检查选择器的定位上下文给 .paper-doc 补上 position: relative。我现在写卷角样式时永远把 content: 与 position:relative 当成一组配套写法二者缺一个效果就少一半。4.2 卷角出现了一个小缺口像是斜边被切掉这个坑常在给卡片整体设置 border-radius 之后出现。卡片设了 4px 圆角而卷角三角形正好贴在右下角父级圆角把三角形最尖的那个点切掉形成一条突兀的白色缺口。原因在于 border-radius 作用于盒子的背景裁剪而卷角伪元素三角形的绘制区域与卡片圆角的曲线相交。解决方式是把 ::after 的右下角也补上相同数值的圆角border-radius: 0 0 4px 4px让三角形贴边时刚好跟卡片圆角曲线重合。注意这里 4px 不是固定值必须与父级盒子的 border-radius 保持同步换主题时两处一起改。另一个思路是把卷角整体往内收 2px也就是 right: 2px; bottom: 2px这会让卷角避开圆角边界但它同时改变了悬浮高度需要重新调 drop-shadow 的偏移方向。我自己的项目里两种方案都用过优先推荐在三角形上补圆角实在不行再往内收。4.3 卷角像一块硬纸板完全没有柔和的弧度这种问题的最大特征是没有弧面光影只看到一块纯色三角形贴在纸角上。看似复杂原因却很直接::after 中只设置了纯色 border-color没有叠加从亮到暗的渐变过渡层。border 本身不能直接填渐变所以要么靠 ::before 的高光做出过渡要么换一种方案用 background: radial-gradient 的方式来绘制三角形后者参数更多但可控性也更强。我一般会优先用前者。当 ::before 白色半透明层从 0.28 逐级降透明再加上 border-radius 磨边弧面感立刻就会出现。这里有个判断经验如果渐变做了仍然生硬把 ::before 的 border-radius 从 8px 提升到 12px并让高光三角形比 ::after 小 4px 到 6px这个差值就是弧面的视觉宽度。差值太大阴影感不足差值太小弧面又变成一条硬线。4.4 hover 放大时卷角撕裂跟主体错开这是做交互进阶时候的典型问题。想做成 hover 时卷角变大但 transform: scale() 放大的是整个伪元素于是角的位置和朝向全乱了像一张贴纸被同时从三个方向拉扯。原因在于 transform-origin 没有同步调整。伪元素缩放必须以卡片右下角为固定原点否则放大过程会带动它向纸张中心漂移。解决方式是把 transform-origin 设置为 100% 100%并确保伪元素的 right 与 bottom 都固定在 0。另一个值得记住的细节是不要在 hover 时同时修改 border-width 和 transform两个属性一起改会跳变。正确做法是固定 border-width用 scale 动画来模拟卷角变大动画由 transition 接管。4.5 卷角挡住了文字还干扰用户选择复制当卡片内容恰好排到角落时34px 的卷角会遮挡正文。尤其在移动端手指点击角落区域时触发的是伪元素的命中区域而不是文字区域用户复制文字会发现选中范围莫名断裂。原因是伪元素虽然只画了三角形但它仍然参与布局占位并默认响应鼠标与触摸事件。解决方式是在 ::before 和 ::after 上同时加上 pointer-events: none让它们彻底退出事件命中。同时检查 .paper-doc__body 的底部留白最好给 padding-bottom 留出至少 34px 的空间。没有这层留白卷角盖住文字几乎是必然的这类问题在业务验收时往往会被当成 bug 打回来。5. 从静态到交互让卷角跟着鼠标“翻起来”5.1 用 transition 模拟纸张的物理回弹卷角做成静态后下一步通常是让它响应用户动作。最常见的目标是 hover 时卷角稍微变大表现出“手指掀纸”的感觉。这个效果不需要 JavaScript 参与。在 ::after 和 ::before 上分别添加 transition 即可.paper-doc::after, .paper-doc::before { transition: transform 0.25s ease-out, filter 0.25s ease-out; } .paper-doc:hover::after { transform: scale(1.15); filter: drop-shadow(-5px 5px 5px rgba(0, 0, 0, 0.2)); } .paper-doc:hover::before { transform: scale(1.1); }参数的逻辑在于两层伪元素的 scale 值并不同步。1.15 与 1.1 的差值让弧面宽度在放大过程中随着卷角一起扩展而不是产生重叠错位。transition 时长 0.25s 处于一个“不慢不飘”的区间ease-out 曲线让动画在开始时速度快接近结束时减速正好模拟了纸张从掀起到停顿的物理惯性。如果你想更进一步可以在 hover 时把纸面盒子的 box-shadow 也加深一档比如从 0 4px 12px 调整为 0 6px 16px这样纸角被揭开时整张纸都像跟着浮起层次感完整很多。注意这组值的过渡时间不要太长否则整张纸的“浮起”会比卷角显得迟钝。5.2 多张纸叠放用 rotate 与 z-index 构建档案堆做单张卡片容易做成一组呈现叠放效果才是业务里的常态。维基百科类的资料区往往会同时展示多份档案每份都有几乎一样的卷角这时需要靠纸张前后错开来制造景深感。常见做法是给每张卡片设置轻微的旋转角与位移偏移.paper-doc { position: relative; } .paper-doc:nth-child(1) { z-index: 3; transform: rotate(-1deg) translateY(0); } .paper-doc:nth-child(2) { z-index: 2; transform: rotate(1deg) translateY(-4px); } .paper-doc:nth-child(3) { z-index: 1; transform: rotate(-0.5deg) translateY(-6px); }参数说明rotate 的微小旋转打破了规则排列的呆板感但角度不要超过 2 度否则正文阅读会受影响。translateY 的负值让每张纸向上叠加数值越大叠放感越强。z-index 的分配要让最上层纸张的索引最高否则它的卷角阴影会被下一张纸盖住视觉上就会出现“纸叠反了”的错觉。5.3 纯 CSS 状态切换够不够用什么时候加少量 JS我经常被问到纯 CSS 的 hover 事件能不能覆盖全部交互。大多数场景可以但有两个例外。第一组件需要在点击后维持“被翻开”的状态而不是 hover 离开就立刻复原第二需要根据数据内容决定是否展示卷角比如某些档案被标记为“原件受限”时不显示翻卷效果。第一种情况可以使用 :focus-within 在纯 CSS 里模拟按压后的状态给卡片内的可交互元素加上 tabindex 后.paper-doc:focus-within::after 就能触发持续展开。但前提是卡片内部要有可聚焦元素。第二种情况必须引入少量 JS做法是给某个容器加 class再用 CSS 变量切换卷角组件的关键参数比如卷角存在时设置 --corner-opacity: 1不存在时设置为 0。视觉变化完全交给 CSS transition 处理JS 不碰绘制逻辑项目复杂度可以保持在很低的位置。6. 交付前最后一道工序用几个基准验证卷角效果6.1 像素、性能与质感的自检清单我每次做完一个纯 CSS3 组件不会急着去截效果图而是先打开三个自检维度。这一套虽然是上手活但每次都帮我拦住过问题。检查项判断方式常见问题像素在最大与最小宽度容器里分别测量卷角位置卷角尺寸在不同宽度下失衡右下角偏移性能DevTools 渲染面板查看合成层数量伪元素的 filter 动画占满合成层帧率波动质感截图放大到 200% 扫描边缘过渡渐变与背景色融合脏乱出现杂边性能这个维度最容易被忽略。卷角组件在页面里渲染 30 张卡片如果每张都因为 filter 动画占用独立合成层滚动时就会明显卡顿。我的处理方式是优先用 transform 动画替代 filter 动画把 drop-shadow 的过渡改为预置两层不同阴影的状态切换而不是每一帧都让浏览器重算阴影。质感这条我踩过真实的坑。有一次在偏黄的旧纸底上直接套白色高光渐变边缘在 200% 缩放下一圈杂边最后发现是渐变的结束色没跟底色对齐。现在每次换底色我都会重新推导一遍高光起始透明度而不是沿用米白纸张的参数。6.2 移动端 Safari 和 Chrome 各过一遍最后一个习惯是跨浏览器验证。Chrome 对 border-radius 与 drop-shadow 的像素取整和 Safari 不同桌面端正常的效果到移动端 Safari 上经常在关键位置穿帮。尤其是 drop-shadow 的偏移方向Safari 对负值处理会有细微差异卷角阴影容易多出一截。从那以后我每次交付前都会强制走一遍这套流程先把合成层调顺再做深浅背景适配最后确认卷角方向与光源一致。这套卷角的实现和参数你已经有了卡壳的地方回头翻第四五六章基本都能找到答案。希望帮到你。本文还有配套的精品资源点击获取

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

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

免费获取报价 →
↑