[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"\u002Fresource\u002Fdocument\u002Flist?undefined":3,"\u002Fresource\u002Fdocument\u002Fquery\u002F4djgk5xy1lzpiuf2?undefined":462,"\u002Fresource\u002Fadvertise\u002Flist?type=all?undefined":467},{"data":4,"status":460,"success":461},[5,148,202,291,332,370,420],{"books":6,"desc":145,"id":8,"image":146,"title":147},[7,40,63,78,93,105,117],{"cateId":8,"chapters":9,"desc":36,"id":11,"time":37,"title":38,"video":39},1,[10,15,18,21,24,27,30,33],{"bookId":11,"id":12,"indexOrder":13,"name":14},24,"8egfulw98v3h680j",0,"JavaSE 笔记（一）走进Java语言",{"bookId":11,"id":16,"indexOrder":13,"name":17},"pew6po6wrou23pk3","JavaSE 笔记（二）面向过程编程",{"bookId":11,"id":19,"indexOrder":13,"name":20},"eldst1fgrbdkmfs7","JavaSE 笔记（三）面向对象基础",{"bookId":11,"id":22,"indexOrder":13,"name":23},"48zphgkpjto8cath","JavaSE 笔记（四）面向对象高级篇",{"bookId":11,"id":25,"indexOrder":13,"name":26},"6r4llai92yc15j98","JavaSE 笔记（五）泛型程序设计",{"bookId":11,"id":28,"indexOrder":13,"name":29},"k6fmxd6qabgkwm9i","JavaSE 笔记（六）集合类与IO",{"bookId":11,"id":31,"indexOrder":13,"name":32},"qrd0xfttsz32gpqg","JavaSE 笔记（七）多线程与反射",{"bookId":11,"id":34,"indexOrder":13,"name":35},"td5tgn04nqmkrryt","JavaSE 笔记（八）GUI程序开发","基于Java25全新录制的SE课程",2025,"JavaSE 核心内容","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV163GGz2E8c",{"cateId":8,"chapters":41,"desc":59,"id":8,"time":60,"title":61,"video":62},[42,44,46,49,51,53,55,57],{"bookId":8,"id":43,"indexOrder":13,"name":14},"ibeeuwsbbi00undq",{"bookId":8,"id":45,"indexOrder":13,"name":17},"dncxjecdv4wciqcp",{"bookId":8,"id":47,"indexOrder":13,"name":48},"jviyz2hsht9ete5k","JavaSE 笔记（三）面向对象基础篇",{"bookId":8,"id":50,"indexOrder":13,"name":23},"qb9i6q9fap7bg1cc",{"bookId":8,"id":52,"indexOrder":13,"name":26},"hnkrjrkm3hjzeq6s",{"bookId":8,"id":54,"indexOrder":13,"name":29},"erpm32wduoaaqmrx",{"bookId":8,"id":56,"indexOrder":13,"name":32},"lfqtvxr7azumcwja",{"bookId":8,"id":58,"indexOrder":13,"name":35},"qs7gqok56gzc6idr","2022年制作的JavaSE版本",2022,"JavaSE 22年旧版","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1YP4y1o75f\u002F",{"cateId":8,"chapters":64,"desc":75,"id":66,"time":60,"title":76,"video":77},[65,69,72],{"bookId":66,"id":67,"indexOrder":13,"name":68},2,"g96k66kczovvbm1i","JVM 笔记（一）走进JVM",{"bookId":66,"id":70,"indexOrder":13,"name":71},"ydd7n3jg8unc3clg","JVM 笔记（二）内存管理",{"bookId":66,"id":73,"indexOrder":13,"name":74},"r9dq37de0kaeauoi","JVM 笔记（三）类与类加载","了解Java的底层运作机制","Java JVM 虚拟机","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1Er4y1r7as\u002F",{"cateId":8,"chapters":79,"desc":90,"id":81,"time":60,"title":91,"video":92},[80,84,87],{"bookId":81,"id":82,"indexOrder":13,"name":83},3,"asncyye9ya18gfar","JUC 笔记（一）再谈多线程",{"bookId":81,"id":85,"indexOrder":13,"name":86},"5tr1sm4ho6ygpt9q","JUC 笔记（二）并发编程核心",{"bookId":81,"id":88,"indexOrder":13,"name":89},"1scf51z5300mzxkh","JUC 笔记（三）并发编程进阶","你也可以成为多线程的主宰者","Java JUC 并发编程","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1JT4y1S7K8\u002F",{"cateId":8,"chapters":94,"desc":102,"id":96,"time":60,"title":103,"video":104},[95,99],{"bookId":96,"id":97,"indexOrder":13,"name":98},4,"eedesc445ygiqhil","NIO 笔记（一）基础内容",{"bookId":96,"id":100,"indexOrder":13,"name":101},"ndz9t0uunrmfmv4n","NIO 笔记（二）Netty框架专题","编写畅快的高性能网络服务器","Java NIO 网络编程","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1ar4y1J7mC\u002F",{"cateId":8,"chapters":106,"desc":114,"id":108,"time":60,"title":115,"video":116},[107,111],{"bookId":108,"id":109,"indexOrder":13,"name":110},5,"9890i8ofuadpwy2b","[扩展篇] Java 9-17新特性介绍",{"bookId":108,"id":112,"indexOrder":13,"name":113},"tsrkqvb6zpmtwh0n","[扩展篇] JavaSE关键字总结 笔记","精彩仍在继续，不要停止脚步","其他内容","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1tU4y1y7Fg\u002F",{"cateId":8,"chapters":118,"desc":141,"id":120,"time":142,"title":143,"video":144},[119,123,126,129,132,135,138],{"bookId":120,"id":121,"indexOrder":13,"name":122},6,"4db9h32opv7imszh","JavaSE 笔记（一）面向过程编程",{"bookId":120,"id":124,"indexOrder":13,"name":125},"c93u3v37br7hgn1q","JavaSE 笔记（二）面向对象基础篇",{"bookId":120,"id":127,"indexOrder":13,"name":128},"yglsjde9gi1jxkcb","JavaSE 笔记（三）泛型与集合类",{"bookId":120,"id":130,"indexOrder":13,"name":131},"ilhi987n986rmvo3","JavaSE 笔记（四）异常机制",{"bookId":120,"id":133,"indexOrder":13,"name":134},"pqv38vexmenglk4k","JavaSE 笔记（五）IO",{"bookId":120,"id":136,"indexOrder":13,"name":137},"jiq41n87i9ia7ilw","JavaSE 笔记（六）多线程",{"bookId":120,"id":139,"indexOrder":13,"name":140},"wn7x2mge9ws79zps","JavaSE 笔记（七）反射","此版本为早期录制的旧版本",2021,"JavaSE 21年旧版","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1Gv411T7pi\u002F","包含JavaSE基础路线全部教程笔记，打下坚实的基础","https:\u002F\u002Fpic2.zhimg.com\u002F80\u002Fv2-bf1a927f037a79f4d57d9ae543430a0d_1440w.webp","JavaSE 系列笔记 ☕️",{"books":149,"desc":199,"id":66,"image":200,"title":201},[150,166,178],{"cateId":66,"chapters":151,"desc":162,"id":153,"time":163,"title":164,"video":165},[152,156,159],{"bookId":153,"id":154,"indexOrder":13,"name":155},21,"iqbc2haub31bwqtz","Lombok 极速上手",{"bookId":153,"id":157,"indexOrder":13,"name":158},"ijay2hay19kn1k031","Mybatis 快速上手",{"bookId":153,"id":160,"indexOrder":13,"name":161},"ru4ogh2waocpn4jo","Maven 快速上手","JavaWeb阶段必须扩展知识点",2024,"常用知识讲解","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1gb421J7ok\u002F",{"cateId":66,"chapters":167,"desc":175,"id":169,"time":163,"title":176,"video":177},[168,172],{"bookId":169,"id":170,"indexOrder":13,"name":171},22,"ek20yvb6huhxizx7","JavaWeb 笔记（一）计算机网络基础",{"bookId":169,"id":173,"indexOrder":13,"name":174},"pgevws6w2krkffa4","JavaWeb笔记（二）Java与数据库","全面升级的JavaWeb课程","JavaWeb 网站开发","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1kS421X7rq\u002F",{"cateId":66,"chapters":179,"desc":196,"id":181,"time":142,"title":197,"video":198},[180,184,187,190,193],{"bookId":181,"id":182,"indexOrder":13,"name":183},7,"ggwwj09j2vkfftvd","JavaWeb 笔记（一）Java网络编程",{"bookId":181,"id":185,"indexOrder":13,"name":186},"sauvq105istskjaz","JavaWeb 笔记（二）数据库基础",{"bookId":181,"id":188,"indexOrder":13,"name":189},"xgbeasmvrhxx9tn4","JavaWeb 笔记（三）Java与数据库",{"bookId":181,"id":191,"indexOrder":13,"name":192},"k7dfwua3bsezvw9q","JavaWeb 笔记（四）前端基础",{"bookId":181,"id":194,"indexOrder":13,"name":195},"ycpagby2v7j4p728","JavaWeb 笔记（五）后端开发","搭建属于自己的Web网站","JavaWeb 旧版","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1CL4y1i7qR\u002F","包含JavaWeb路线全套笔记，从零开始搭建自己的网站！","https:\u002F\u002Fpic3.zhimg.com\u002F80\u002Fv2-df3b38e3012258ed70c23b586309e3f6_1440w.webp","JavaWeb 系列笔记 🚛",{"books":203,"desc":288,"id":81,"image":289,"title":290},[204,220,235,255,273],{"cateId":81,"chapters":205,"desc":216,"id":207,"time":217,"title":218,"video":219},[206,210,213],{"bookId":207,"id":208,"indexOrder":13,"name":209},8,"h7sjo5oy0l03607e","SSM笔记（一）Spring基础",{"bookId":207,"id":211,"indexOrder":13,"name":212},"eve8gq72qmdb46sg","SSM笔记（二）SpringMvc基础",{"bookId":207,"id":214,"indexOrder":13,"name":215},"63v73g0zh1qlr6fk","SSM笔记（三）SpringSecurity基础","Spring的探索之路从这里开始",2023,"JavaSSM 基础部分","[\"https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1Kv4y1x7is\u002F\", \"https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1Lh4y1M7kx\u002F\", \"https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1fV411M7aS\u002F\"]",{"cateId":81,"chapters":221,"desc":232,"id":223,"time":217,"title":233,"video":234},[222,226,229],{"bookId":223,"id":224,"indexOrder":13,"name":225},16,"0k66v5r6slsfuog4","SpringBoot笔记（一）核心内容",{"bookId":223,"id":227,"indexOrder":13,"name":228},"bqlrnc2yvkaxo8s1","SpringBoot笔记（二）数据交互",{"bookId":223,"id":230,"indexOrder":13,"name":231},"wci9lb9tgea866jt","SpringBoot笔记（三）前后端分离","SpringBoot全新重制版","SpringBoot 新版","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1xu4y1m7UP\u002F",{"cateId":81,"chapters":236,"desc":252,"id":238,"time":60,"title":253,"video":254},[237,240,243,246,249],{"bookId":238,"id":239,"indexOrder":13,"name":225},9,"e43gl1ilygps032v",{"bookId":238,"id":241,"indexOrder":13,"name":242},"emnmd8nzfdb3hr50","SpringBoot笔记（二）Git版本控制",{"bookId":238,"id":244,"indexOrder":13,"name":245},"jjlolj5igvttvyhv","SpringBoot笔记（三）Redis数据库",{"bookId":238,"id":247,"indexOrder":13,"name":248},"skgr4ivb5curdoux","SpringBoot笔记（四）其他框架介绍",{"bookId":238,"id":250,"indexOrder":13,"name":251},"le91fqhu4dqui1k4","SpringBoot笔记（五）Linux系统","逐步走向企业级开发","SpringBoot 旧版","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1UL411V7f3\u002F",{"cateId":81,"chapters":256,"desc":270,"id":258,"time":60,"title":271,"video":272},[257,261,264,267],{"bookId":258,"id":259,"indexOrder":13,"name":260},10,"oejzo0l77zeb6a7e","SpringCloud笔记（一）微服务基础",{"bookId":258,"id":262,"indexOrder":13,"name":263},"f6eya9taaelsl35p","SpringCloud笔记（二）微服务进阶",{"bookId":258,"id":265,"indexOrder":13,"name":266},"35v1hbsfcdgagdnw","SpringCloud笔记（三）微服务应用",{"bookId":258,"id":268,"indexOrder":13,"name":269},"a782u84512tyuo1m","SpringCloud笔记（四）消息队列","体验微服务架构带来的魅力","SpringCloud 进阶","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1AL4y1j7RY\u002F",{"cateId":81,"chapters":274,"desc":285,"id":276,"time":142,"title":286,"video":287},[275,278,280,282],{"bookId":276,"id":277,"indexOrder":13,"name":209},11,"efjw75u8a251qxk5",{"bookId":276,"id":279,"indexOrder":13,"name":212},"guc134xb7sl78vju",{"bookId":276,"id":281,"indexOrder":13,"name":215},"u8ekxxucowr2b1tm",{"bookId":276,"id":283,"indexOrder":13,"name":284},"vkpmw9wbej21nei6","SSM笔记（四）MySQL进阶","此教程为2021年旧版教程","JavaSSM 旧版","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1xL4y1H7Tq\u002F","包含Spring全套框架笔记，从开始到Spring Boot，以及众多运维小知识。","https:\u002F\u002Fpic4.zhimg.com\u002F80\u002Fv2-28c3144421220d7c048703281bc34f63_1440w.webp","Spring 系列笔记 🍏",{"books":292,"desc":329,"id":96,"image":330,"title":331},[293,308],{"cateId":96,"chapters":294,"desc":305,"id":296,"time":60,"title":306,"video":307},[295,299,302],{"bookId":296,"id":297,"indexOrder":13,"name":298},12,"jd3e8u5cmvx5gco6","C语言（一）计算机思维导论",{"bookId":296,"id":300,"indexOrder":13,"name":301},"lqv77apvx82nkkio","C语言（二）基础语法",{"bookId":296,"id":303,"indexOrder":13,"name":304},"xb0b9t37gyv96xns","C语言（三）高级特性","包含高等院校需要教授的全部内容","C语言程序设计","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1Cr4y137os\u002F",{"cateId":96,"chapters":309,"desc":326,"id":311,"time":60,"title":327,"video":328},[310,314,317,320,323],{"bookId":311,"id":312,"indexOrder":13,"name":313},13,"8a046ps2e4w6k4py","数据结构与算法（一）线性结构篇",{"bookId":311,"id":315,"indexOrder":13,"name":316},"3ma8db91f9zrnkja","数据结构与算法（二）树形结构篇",{"bookId":311,"id":318,"indexOrder":13,"name":319},"0lsjm59k7cgu4tpr","数据结构与算法（三）散列表篇",{"bookId":311,"id":321,"indexOrder":13,"name":322},"0qzy7bogo0g2pusa","数据结构与算法（四）图结构篇",{"bookId":311,"id":324,"indexOrder":13,"name":325},"6gmcxcikcilyxblj","数据结构与算法（五）排序算法篇","虽然很难，但是它是考研必学科目","数据结构与算法","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV13W4y127Ey\u002F","你的内心一直有一个坚定的声音在告诉你，一定要考上一名研究生，向着未来前进吧！","https:\u002F\u002Fpic2.zhimg.com\u002F80\u002Fv2-ac128404efb29ce1c9d1ccc61024f1d1_1440w.webp","C语言 系列笔记 🥬",{"books":333,"desc":367,"id":108,"image":368,"title":369},[334,349,358],{"cateId":108,"chapters":335,"desc":346,"id":337,"time":163,"title":347,"video":348},[336,340,343],{"bookId":337,"id":338,"indexOrder":13,"name":339},17,"urw2e6gg1lprv65w","Kotlin（一）基础语法",{"bookId":337,"id":341,"indexOrder":13,"name":342},"t7lnl87f74f3v1ju","Kotlin（二）类与对象",{"bookId":337,"id":344,"indexOrder":13,"name":345},"v1zzvki0knb1xvml","Kotlin（三）高级特性","包含Kotlin语言完整基础部分","Kotlin程序设计基础","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1P94y1c7tV\u002F",{"cateId":108,"chapters":350,"desc":355,"id":352,"time":163,"title":356,"video":357},[351],{"bookId":352,"id":353,"indexOrder":13,"name":354},18,"ovbzpe7065bye1st","Kotlin扩展（一）","包含Kotlin额外扩展知识","Kotlin扩展篇","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1Hg4y1m7Ca\u002F",{"cateId":108,"chapters":359,"desc":364,"id":361,"time":163,"title":365,"video":366},[360],{"bookId":361,"id":362,"indexOrder":13,"name":363},19,"3at7ybv04dmjc0wp","Gradle基础教程","Gradle配置教程（Kotlin）","Gradle教程","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1Fc411x7xF\u002F","Kotlin让JVM平台焕发新的生机，让语言的表达更加优美","https:\u002F\u002Fpic2.zhimg.com\u002F80\u002Fv2-be815568f7c79c64cdaa171b0409786d_1440w.webp","Kotlin 系列笔记 ☘️",{"books":371,"desc":418,"id":120,"title":419},[372,391,403],{"cateId":120,"chapters":373,"desc":387,"id":375,"time":388,"title":389,"video":390},[374,378,381,384],{"bookId":375,"id":376,"indexOrder":13,"name":377},26,"zjf5qapwqtqiohcn","JavaScript笔记（一）基础语法",{"bookId":375,"id":379,"indexOrder":13,"name":380},"95jc6sjyjwcp9pvp","JavaScript笔记（二）核心知识",{"bookId":375,"id":382,"indexOrder":13,"name":383},"j35cdc1qz8dzq7pn","JavaScript笔记（三）进阶知识",{"bookId":375,"id":385,"indexOrder":13,"name":386},"sdhodlihphnpcg37","JavaScript笔记（四）前端基础","包含JavaScript最新语法规范讲解",2026,"JavaScript教程","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1xq6gBgESU",{"cateId":120,"chapters":392,"desc":400,"id":394,"time":37,"title":401,"video":402},[393,397],{"bookId":394,"id":395,"indexOrder":13,"name":396},23,"bsisgazdftiz3o9c","HTML5笔记（一）基础内容",{"bookId":394,"id":398,"indexOrder":13,"name":399},"njol93fs34gfwuzf","HTML5笔记（二）高级内容","包含HTML基础内容和相关知识点","HTML5核心教程","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1BrBiYNEWg",{"cateId":120,"chapters":404,"desc":415,"id":406,"time":37,"title":416,"video":417},[405,409,412],{"bookId":406,"id":407,"indexOrder":13,"name":408},25,"jo74ciirtg8wh90y","CSS笔记（一）基础入门",{"bookId":406,"id":410,"indexOrder":13,"name":411},"ap5ixyomoejuw4ue","CSS笔记（二）盒模型和布局",{"bookId":406,"id":413,"indexOrder":13,"name":414},"4djgk5xy1lzpiuf2","CSS笔记（三）变换和过渡","包含CSS3基础内容和相关知识点","CSS3核心教程","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1sQeEzFEKi","包含Web前端学习路径全部教程笔记，打下坚实的基础","Web前端 系列笔记",{"books":421,"desc":458,"id":423,"image":368,"title":459},[422,432,450],{"cateId":423,"chapters":424,"desc":429,"id":426,"time":163,"title":430,"video":431},100,[425],{"bookId":426,"id":427,"indexOrder":13,"name":428},20,"o0ab271mkdsas87","Markdown基础语法","编写简洁而又优美的文档","Markdown教程","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1eJ4m157kC",{"cateId":423,"chapters":433,"desc":447,"id":435,"time":60,"title":448,"video":449},[434,438,441,444],{"bookId":435,"id":436,"indexOrder":13,"name":437},14,"6386mh7anqt4tzyv","设计模式（一）面向对象设计原则",{"bookId":435,"id":439,"indexOrder":13,"name":440},"8ftkb38wfn6ox0ug","设计模式（二）创建型",{"bookId":435,"id":442,"indexOrder":13,"name":443},"i1msql1k8y70etey","设计模式（三）结构型",{"bookId":435,"id":445,"indexOrder":13,"name":446},"5434a3cyyjvwhs8s","设计模式（四）行为型","使你的编码水平得到质的飞跃","设计模式系列","https:\u002F\u002Fwww.bilibili.com\u002Fvideo\u002FBV1u3411P7Na\u002F",{"cateId":423,"chapters":451,"desc":456,"id":453,"time":60,"title":457},[452],{"bookId":453,"id":454,"indexOrder":13,"name":455},15,"zj9uvg0sp3b0sok8","Docker 容器技术 笔记","这里包含其他中间件课程笔记","其他中间件笔记","我们对知识的探索从未停止，只有不断地学习，才能走向美好的未来！","其他笔记分类 🌽",200,true,{"data":463,"status":460,"success":461},{"bookId":406,"content":464,"id":413,"indexOrder":81,"introduction":465,"lastUpdate":466,"name":414},"![image-20251216143307451](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FI4SePgJ8nlLGTQE.png)\n\n# CSS3 变换和过渡\n\n上一章我们介绍了盒子模型和布局相关知识点，并且为大家扩展了更多类型的选择器，帮助我们更好地调整页面样式。这一章我们将继续深入介绍CSS3的更多内容，比如二维、三维变换、函数等。\n\n## 盒子模型进阶\n\n上一章我们介绍了盒子模型，这一章我们接着介绍盒子模型中一些更加高级的用法。\n\n### 最大宽度和最小宽度\n\n在常规的`width`和`height`之外，CSS还提供了最大\u002F最小宽度和高度的设置，这在响应式布局中非常有用，可以防止元素在不同尺寸的屏幕下变得过宽或过窄。\n\n- `max-width`: 设置元素的最大宽度。当内容或浏览器窗口宽度小于`max-width`时，元素的宽度会自适应；但当其试图超过`max-width`时，宽度将被限制在这个最大值。\n- `min-width`: 设置元素的最小宽度。即使内容很少，元素的宽度也不会低于这个值。\n- `max-height`: 设置元素的最大高度。\n- `min-height`: 设置元素的最小高度。\n\n比如我们希望盒子的宽度始终保持为父元素宽度的80%，但是最大不能超过`500px`最小不能低于`320px`，此时我们就可以使用上面提到的几个属性：\n\n```css\n.container {\n  width: 80%;         \u002F* 宽度为父元素的80% *\u002F\n  max-width: 500px;   \u002F* 但最大不超过500px *\u002F\n  min-width: 320px;   \u002F* 最小不低于320px *\u002F\n  margin: 0 auto;     \u002F* 在大屏幕上水平居中 *\u002F\n}\n```\n\n可以看到，当盒子的宽度超过设定的最大值时，就不会继续增加宽度了：\n\n![image-20251216161343395](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FlsTSopFJang4W79.png)\n\n这种用法在很多时候都是非常实用的，我们的网站内容不可能跟随页面的宽度无限增加，否则其中的内容会变形得越来越奇怪，一般常见的网站都会设置一个最大的页面宽度来保证内容不会过度变形，一旦浏览器窗口超出最大限度，页面会自动居中并留出两边的空间：\n\n![image-20251216161545744](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FmU2qkRNzFvMpEG5.png)\n\n注意，如果我们要设置盒子的固定大小，请正常使用之前的`width`和`height`属性，最大最小宽度虽然在某些情况下能够和普通的宽度效果一致，但是难免会存在特殊情况。\n\n### 盒子轮廓\n\n轮廓（outline）是绘制在元素`border`（边框）之外的一条线，用于突出元素。它与边框非常相似，但有几个关键区别：\n\n1. **不占据空间**：轮廓是在元素之上绘制的，不会影响元素的尺寸或布局，它不是盒子模型的一部分，仅仅只是装饰，因此不会增加元素的总宽度或总高度。\n2. **在盒子的边框外进行绘制**：轮廓是在盒子的边框外进行绘制，不会占用盒子内部的区域，但是可能会遮挡外部的其他元素。\n\n我们可以使用`outline`属性来控制盒子的轮廓：\n\n```css\n.container {\n  height: 100px;\n  width: 200px;\n  background-color: gray;\n  outline-style: solid;  \u002F* 轮廓采用实现绘制，可用的属性和border一样 *\u002F\n  outline-width: 2px;  \u002F* 创建一个宽度为2px的轮廓 *\u002F\n  outline-color: black;  \u002F* 边框的颜色 *\u002F\n}\n```\n\n![image-20251216162232279](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002Fp5Wrw1iSamHAVvO.png)\n\n可以看到，此时盒子的边上就出现了一圈轮廓，看起来非常像边框，但是实际上并不是边框，盒子所占据的区域依然是上面设定的宽度。\n\n同样的，如果盒子出现了圆角，那么轮廓也会按照盒子的实际形状展示：\n\n![image-20251216162548623](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002F5JQufwrRxXUGF8j.png)\n\n针对于以上三个属性，我们也可以使用边框的简写属性`outline`一步到位：\n\n```css\noutline: 2px solid black;\n```\n\n是不是感觉用起来和边框差不多，当然，轮廓也有一些比较特殊的属性，比如我们可以控制轮廓和盒子边缘的距离：\n\n```css\n.container {\n  height: 100px;\n  width: 200px;\n  background-color: gray;\n  outline: 2px solid black;\n  outline-offset: 5px;  \u002F* 表示边框距离盒子边缘的距离 *\u002F\n  border-radius: 10px;\n}\n```\n\n![image-20251216163005657](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FuLUJQb1MW4DPEp6.png)\n\n注意这个值可以是负数，负数表示轮廓往盒子里面跑：\n\n![image-20251216163247421](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FwfhLRvPgpoOtXBQ.png)\n\n实际上我们在之前的学习中，就已经遇到过出现轮廓的情况了，比如`input`标签，在默认情况下，浏览器用户代理样式会为其添加一个蓝色的轮廓：\n\n```html\n\u003Cinput type=\"text\" placeholder=\"请输入文本\">\n```\n\n\n\n![image-20251216163616691](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FP5RBLTNDt8qCj9Q.png)\n\n我们也可以通过前面学习的伪类来取消掉聚焦状态下的轮廓：\n\n```css\ninput:focus {\n  outline: none;\n}\n```\n\n### 盒子阴影\n\n使用 `box-shadow` 属性可以为元素的框添加阴影效果，这里需要用到几个属性：\n\n```css\nbox-shadow: offset-x offset-y blur-radius spread-radius color;\n```\n\n这里我们分别介绍一下这些属性有什么用：\n\n* **offset-x**  -  水平方向的偏移，默认情况下阴影在盒子的正下方。\n* **offset-y**  -  垂直方向的偏移，默认情况下阴影在盒子的正下方。\n* **(可选) blur-radius**  -  模糊半径，值越大，阴影越模糊。\n* **(可选) spread-radius**  -  扩展半径，正值使阴影扩大，负值使阴影缩小，不填等于没有阴影。\n* **color**  -  阴影的颜色。\n\n比如，下面这个例子就是：\n\n```css\n.container {\n  width: 200px;\n  height: 100px;\n  background-color: #d5d5d5;\n  box-shadow: 0 0 10px gray;   \u002F* 这里我们创建了一个模糊半径为10px的灰色阴影 *\u002F\n}\n```\n\n这里填写 `0 0 10px gray` 表示创建一个水平和垂直方向上都不偏移，扩展半径为`10px`的灰色阴影：\n\n![image-20251216171032129](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002F7Al9WIgGndxB14f.png)\n\n注意，阴影和前面介绍的轮廓一样，不会占用盒子空间，但是可能会受到父盒子尺寸的影响，比如下面这种情况：\n\n```css\n.outer-box {\n  width: 220px;\n  height: 120px;\n  overflow: hidden;  \u002F* 隐藏超出部分 *\u002F\n}\n\n.container {\n  width: 200px;\n  height: 100px;\n  background-color: #d5d5d5;\n  box-shadow: 0 0 50px gray;   \u002F* 这里我们创建了一个模糊半径为50px的灰色阴影 *\u002F\n}\n```\n\n![image-20251216172041282](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FuQT1DIlXZiY9aNf.png)\n\n当外层盒子的尺寸大小不足以容纳阴影且禁止超出部分显示时，我们的阴影会被截断，然后变得很难看。\n\n当然，除了编写一个阴影之外，我们还可以同时给盒子添加多个阴影：\n\n```css\n.container {\n  width: 200px;\n  height: 100px;\n  background-color: #d5d5d5;\n  box-shadow:   \u002F* 多个阴影可以逐行编写，但是注意需要用逗号分割 *\u002F\n      0 -4px 3px rgba(0, 42, 255, 0.12),\n      0 4px 8px rgba(255, 0, 0, 0.2);\n}\n```\n\n此外，阴影既然可以作为外阴影展示，同样的也可以在内侧展示，我们只需要添加一个`inset`即可表示这是一个内阴影：\n\n```css\n.container {\n  width: 200px;\n  height: 100px;\n  background-color: #d5d5d5;\n  box-shadow: 0 0 10px gray inset;   \u002F* 这里我们创建了一个模糊半径为10px的灰色内侧阴影 *\u002F\n}\n```\n\n![image-20251216172531895](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002F2R3MoAik18mCz4c.png)\n\n阴影和前面介绍的轮廓一样，是跟随盒子的形状进行变化的：\n\n![image-20251216173915213](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FZNpsI6lKVvfcOkM.png)\n\n除了将阴影作为一个普通的阴影使用之外，我们也可以使用阴影来解决之前遇到的边框宽度被系统缩放影响的问题。\n\n> 不同系统的 DPI \u002F 缩放比例，会导致 CSS 的“1px”并不总是等于屏幕上的 1 个物理像素。\n\n```css\n.box {\n  box-shadow: 0 0 0 1px #ccc;\n}\n```\n\n这里我们只需要创建一个扩展半径为`1px`且无模糊半径的阴影即可，它实际的展示效果等价于宽度为`1px`的边框。\n\n除了盒子可以创建阴影之外，还有一个`text-shadow`属性，它能实现文字的阴影效果：\n\n![image-20251217152453018](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002FfyjsRIN8a39dQ4H.png)\n\n可以看到它是在文字的周围增加描边阴影，用法和盒子阴影大致相同。\n\n### 行内纵向对齐\n\n经过HTML阶段的学习，我们知道，行内元素是可以任意穿插的，我们直接编写的文本内容、`a`标签、`b`标签等都算行内元素。包括一些既具有行内元素特性也具有块级元素特性的比如`img`标签，也能和文本实现穿插效果：\n\n```html\n\u003Cdiv class=\"test\">\n  带回家撒大家卡仕达手机卡三等奖哈三等奖卡仕达酱卡好的卡仕达可接受的\n  \u003Ca href=\"index.html\">点我啊\u003C\u002Fa>\n  \u003Cimg width=\"120\" src=\"https:\u002F\u002Fimg1.baidu.com\u002Fit\u002Fu=1005000719,311741344&fm=253&fmt=auto&app=138&f=JPEG\">\n\u003C\u002Fdiv>\n```\n\n![image-20250823180045333](https:\u002F\u002Fs2.loli.net\u002F2025\u002F08\u002F23\u002FhuVzcW2K7wg936O.png)\n\n不过虽然行内元素和行内块元素都可以穿插使用，但是有些时候可能并不是我们想要的效果。比如这里的图片，它展示的位置似乎并不是以文字的底部进行对齐的，看着像是有点漂移的感觉。\n\n这实际上是因为`vertical-align`属性在控制纵向对齐规则：\n\n```css\n.test img {\n  vertical-align: baseline;  \u002F* 默认情况下，行内元素的纵向对齐是baseline *\u002F\n}\n```\n\n那么什么是`baseline`呢？这里需要介绍一下`vertical-align`的几种值：\n\n![image-20250823193100171](https:\u002F\u002Fs2.loli.net\u002F2025\u002F08\u002F23\u002FRpHlVkQWg94hujT.png)\n\n这里出现了四种对齐方式，分别对应不同的标准线：\n\n* **顶线：**这一行文本行高的顶部，注意不是文字顶部，而是行高的顶部，随行高变化而变化。当行高和文字大小一致时，才是中文文字的顶部（英文文字会小一些）\n* **中线：**文字的垂直中心点，也就是小写字母`x`的中心交叉位置。\n* **基线：**英文小写`x`字母的下边缘，设置基线是为了给注入`g`、`j`这种带尾巴的字母留出空间。\n* **底线：**同顶线，只不过相反，跑到行高的底部去了。\n\n当我们修改行内或行内块元素的`vertical-align`属性时，会产生如下效果：\n\n* `baseline` - 让行内或行内块元素的底线和文本的基线对齐。\n* `top` - 让行内或行内块元素的顶线和文本的顶线对齐。\n* `bottom` - 让行内或行内块元素的底线和文本的底线对齐。\n* `middle` - 让行内或行内块元素的中线和文本的中线对齐。\n\n注意`vertical-align`只针对于行内元素或者行内块元素有效，它对于块级元素是无效的。\n\n### 精灵图\n\n精灵图（也称“雪碧图”）是一种网页图片应用处理方式。它将一个页面涉及到的所有零星图片都包含到一张大图中，然后利用 CSS 的 `background-image`、`background-position` 和 `width`、`height` 属性来显示大图中的特定部分。\n\n> **优点**：通过将多个图片合并成一张，减少了HTTP请求的数量，从而加快了页面加载速度。\n\n这种用法在计算机发展的早期，很多网页、游戏都喜欢采用，比如早期的微博：\n\n![image-20251216175230198](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FTjPdUbwgnAeVOIh.png)\n\n可以看到所有的小图标都被做到了一张图中，这样就可以反复使用同一个背景图，通过定位来选取自己需要的区域。\n\n```css\n.vip-icon {\n  display: inline-block;\n  width: 40px;\n  height: 40px;\n  background-position: -57px 0;\n  background-image: url(\"\u002Fimg\u002Fsprites.png\");\n}\n```\n\n![image-20251216175951128](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FSz14ZVTA2O6J8Ri.png)\n\n如果网站存在大量的小型图标需要展示，也可以考虑使用这种方式去节省网络资源。\n\n### 颜色渐变\n\nCSS3 渐变 (gradients) 让你可以在两个或多个指定颜色之间平稳地过渡，实现渐变色效果。渐变色需要使用 `background-image` 属性来进行设置，列举一些常用的颜色渐变函数：\n\n* **线性渐变 (Linear Gradients)**：颜色沿着一条直线过渡。\n* **径向渐变 (Radial Gradients)**：颜色从一个中心点向外辐射过渡。\n\n这里我们先来看看最简单的线性渐变：\n\n```css\n.container {\n  width: 300px;\n  height: 50px;\n  background-image: linear-gradient(red, yellow);  \u002F* 使用红色和黄色进行线性渐变 *\u002F\n}\n```\n\n默认情况下，颜色渐变方向是从上往下进行渐变：\n\n![image-20251216183331367](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002F6fhDNOjGtmsY7Bx.png)\n\n我们可以添加`to right`表示采用从左往右的线性渐变：\n\n```css\n.container {\n  width: 300px;\n  height: 50px;\n  background-image: linear-gradient(to right, red, yellow);\n}\n```\n\n![image-20251216183411565](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FqhKHGZs4TyLx2du.png)\n\n同样的，`to bottom right`还能实现从左上角斜着渐变到右下角的效果，所有的情况如下：\n\n| **写法**        | **含义**        |\n| --------------- | --------------- |\n| to bottom       | 上 → 下（默认） |\n| to top          | 下 → 上         |\n| to right        | 左 → 右         |\n| to left         | 右 → 左         |\n| to right bottom | 左上 → 右下     |\n\n针对于自定义的角度，我们也可以使用角度单位来定义：\n\n```css\nlinear-gradient(45deg, red, blue)\n```\n\n我们可以添加多种颜色让渐变看起来更丰富：\n\n```css\nbackground-image: linear-gradient(to right, red, orange, yellow, green, blue, purple);\n```\n\n![image-20251216184848190](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002F7FVE3XcMQrSGDwv.png)\n\n我们可以自行控制不同颜色占有的比例，比如我们希望红色部分更多一些再进行黄色渐变，我们可以在颜色的后面添加一个百分比，表示颜色延伸的位置：\n\n```css\nbackground-image: linear-gradient(to right, red 80%, yellow);\n```\n\n![image-20251216183729148](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FTypQvREbtWgxKuU.png)\n\n或是黄色多一些：\n\n```css\nbackground-image: linear-gradient(to right, red, yellow 20%, yellow);\n```\n\n![image-20251216184630457](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FsSx4aCMKvPgFhmk.png)\n\n虽然颜色渐变使用的也是`background-image`属性，但是这并不代表我们就无法使用图片作为背景了，我们可以使用逗号分割不同类型的背景图片：\n\n```css\nbackground:\n  linear-gradient(rgba(0,0,0,.4), rgba(0,0,0,.4)),\n  url(bg.jpg);\n```\n\n此外，我们在上一章没有提到，`background-clip`还支持在盒子模型的指定区域内展示背景图片或渐变效果，比如我们只希望在盒子的内容区域展示渐变颜色，而不作用到边框和内边距上：\n\n```css\n.container {\n  width: 300px;\n  height: 50px;\n  padding: 20px;\n  background:\n      linear-gradient(to right, red, blue) content-box;  \u002F* 表示只有内容盒子变色 *\u002F\n  border: 2px solid gray;\n}\n```\n\n![image-20251216185600589](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FiGgVfUekvQTlF8m.png)\n\n此时盒子只有内容区域是渐变色，当然，除了`content-box`之外，还有`padding-box`表示只延伸到内边距区域，或是`border-box`表示完整的整个盒子，利用这种特性，我们就能实现彩色边框：\n\n```css\n.container {\n  width: 300px;\n  height: 50px;\n  border-radius: 10px;\n  background:\n      linear-gradient(to right, white, white) padding-box,  \u002F* pading+内容区域采用白色 *\u002F\n      linear-gradient(to right, red, blue) border-box;  \u002F* border+pading+内容区域采用渐变 *\u002F\n  border: 2px solid transparent;  \u002F* 注意边框的颜色会覆盖背景，这里弄个透明的 *\u002F\n}\n```\n\n![image-20251216190415834](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002F4TKZo5q6QfcJXil.png)\n\n这样，一个好看的渐变色边框就出现了。\n\n我们接着来看径向渐变，径向渐变是由中心向外发散的渐变效果，比较适合球形盒子：\n\n```css\n.container {\n  width: 200px;\n  height: 100px;\n  background-image: radial-gradient(red, yellow);\n}\n```\n\n![image-20251216190837253](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FbJVLvqxHAYnmGoz.png)\n\n可以看到，径向渐变的颜色是有内而外，并且会以椭圆形样式适应盒子的宽高，我们还可以将渐变背景颜色直接改变为一个标准的圆形：\n\n```css\nbackground-image: radial-gradient(circle, red, yellow);\n```\n\n![image-20251216191039853](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FrJ4L3oaduMliecC.png)\n\n可以看到，现在渐变变成了标准圆形，但是由于我们的盒子并非一个正方形，导致这个渐变的圆形有一部分像是被遮挡一样，我们可以通过以下参数来调整扩散范围：\n\n| **值**          | **含义**         |\n| --------------- | ---------------- |\n| closest-side    | 到最近边         |\n| farthest-side   | 到最远边         |\n| closest-corner  | 到最近角         |\n| farthest-corner | 到最远角（默认） |\n\n比如我们希望颜色渐变以最矮的一边为准：\n\n```css\nbackground-image: radial-gradient(circle closest-side, red, yellow);\n```\n\n![image-20251216191207753](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FS1Q7N4IGZCnRgJe.png)\n\n和线性渐变一样，我们可以使用百分比来控制渐变位置：\n\n```css\nbackground-image: radial-gradient(red 5%, yellow 15%, green 60%);\n```\n\n![image-20251216191420423](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002Fhb7iwofUumDjtAz.png)\n\n我们也可以通过`at`来改变圆的中心点位置，比如我们希望从左上角开始径向渐变：\n\n```css\nbackground-image: radial-gradient(circle at left top, red, yellow);\n```\n\n![image-20251216191539862](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002F3L8GJVBS2O7CxFr.png)\n\n常见位置写法：\n\n- center\n- top \u002F bottom \u002F left \u002F right\n- x y（百分比或长度）\n\n我们可以自由编写指定的百分比来控制位置，或是固定位置。\n\n### 过滤\n\n`filter` 是 CSS 中**用于给元素添加图形处理效果**的属性，常见于图片、背景、组件状态、UI 细节增强等场景。你可以把它理解为：**在浏览器里对元素做 “PS 后期处理”**。\n\n比如现在有一个盒子：\n\n```html\n\u003Cdiv class=\"container\">\n  我是盒子里面的字，看着很漂亮很美丽\n\u003C\u002Fdiv>\n```\n\n```css\n.container {\n  color: #227fd8;\n  width: 200px;\n  height: 100px;\n  padding: 10px 15px;\n  border-radius: 10px;\n  border: 2px solid #5aa9fd;\n}\n```\n\n![image-20251216192402204](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FcpmDUA6sqBkg9oV.png)\n\n我们可以使用多种滤镜效果，来对盒子进行处理，比如高斯模糊效果，我们可以使用`blur`效果，它会使得我们的内容变模糊，我们可以自行调整模糊的强度：\n\n```css\n.container {\n  filter: blur(5px);   \u002F* 添加高斯模糊滤镜 *\u002F\n  ...\n}\n```\n\n![image-20251216192351353](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F16\u002FIHZC8DOcuWenv37.png)\n\n添加滤镜效果后，相信大家第一眼看到肯定分不清楚到底是自己近视了还是盒子问题。\n\n我们接着来看下一个滤镜，`brightness`可以控制亮度，亮度越大，盒子的颜色就会变得越亮，亮度越小，盒子的颜色就会变得越灰暗：\n\n```css\n.container {\n  filter: brightness(0.5);\n  ...\n}\n```\n\n![image-20251217145321293](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002FyQcjArZYPMmWn89.png)\n\n默认情况下，亮度为`1`，当我们调整亮度为`0.5`之后，盒子颜色会变得昏暗，就像是把蓝色调的更黑一样。\n\n我们接着来看下一个，`contrast`可以调节对比度，对比度越强，颜色展现就越鲜艳，反之颜色就越灰：\n\n![image-20251217145904706](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002FGxW52A4zgsyRwCI.png)\n\n在一些特殊日子，常常有些网站喜欢把所有内容都调整为灰白色，以纪念历史上的今天，我们可以使用`grayscale`属性来控制页面的灰度效果，当调整为`100%`表示完全变为黑白效果：\n\n![image-20251217150128544](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002Fkf21JjhEwAKgtCT.png)\n\n类似的还有`invert`滤镜，它可以使得盒子变为相反的颜色，`sepia`会为盒子添加复古棕色效果，比较适合一些老照片，柏码官网还用到了`hue-rotate`效果，它可以将某种颜色整体变换为另一种颜色，以实现多种主题的切换。\n\n此外，`drop-shadow`滤镜可以为盒子增加投影效果，这个与我们之前提到的`box-shadow`类似，但是它会根据盒子的具体绘制内容进行投影，而`box-shadow`只会按照盒子形状进行投影，我们可以对比一下两者：\n\n```css\n.container {\n  \u002F* 参数和box-shadow基本一致 *\u002F\n  filter: drop-shadow(0 0 4px gray);\n  color: #227fd8;\n  width: 200px;\n  height: 100px;\n  padding: 10px 15px;\n  border-radius: 10px;\n  border: 2px solid #5aa9fd;\n}\n```\n\n![image-20251217151723567](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002FrhgMyYBGFzfnPN1.png)\n\n![image-20251217151742426](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002FuNFdaWTY3cPrjI9.png)\n\n可以看到，普通的盒子阴影只能针对于盒子的边框产生阴影效果，而滤镜则是更细致化的，针对于所有内容的阴影效果，只要是透明背景的区域，都会产生阴影。\n\n以上介绍的滤镜并非只能使用其中一种，我们也可以将多种滤镜组合起来使用，实现更加高级的效果。\n\n有关更多滤镜效果，请参阅：https:\u002F\u002Fdeveloper.mozilla.org\u002Fzh-CN\u002Fdocs\u002FWeb\u002FCSS\u002FReference\u002FProperties\u002Ffilter\n\n### 背景过滤器\n\nbackdrop-filter 是 **CSS 中用于“模糊\u002F处理元素背后内容”** 的属性，常见于毛玻璃、半透明浮层、弹窗背景等现代 UI 设计中。它与前面介绍的`filter`效果差不多，不过，它是作用于其之后的元素，而不是盒子本身。\n\n我们可以来尝试一下：\n\n```html\n\u003Cdiv class=\"card\">我是卡片里面的文本\u003C\u002Fdiv>\n```\n\n```css\nbody {\n  background-repeat: no-repeat;\n  background-size: cover;\n  background-image: url(\"https:\u002F\u002Fimg0.baidu.com\u002Fit\u002Fu=4012604816,607436490&fm=253&app=138&f=JPEG?w=889&h=500\");\n}\n\n.card {\n  width: 150px;\n  height: 200px;\n  padding: 10px 15px;\n  border-radius: 15px;\n  background-color: #ffffff60;\n  backdrop-filter: blur(12px);  \u002F* 添加高斯模糊效果 *\u002F\n}\n```\n\n![image-20251218212937399](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F18\u002FYZsvfiQlTmre3Ah.png)\n\n可以看到，此时被盒子遮挡的背景部分，变成了高斯模糊效果。同样的，我们也可以试试看其他滤镜效果，比如灰度：\n\n![image-20251218213136272](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F18\u002Fj51Ebcv9JsWuU7k.png)\n\nbackdrop-filter 支持的函数和 filter 基本一致，这里各位可以自行尝试。\n\n## 二维和三维变换\n\n在 CSS3 中，`transform` 属性允许我们在不改变文档流的情况下，对元素进行移动、旋转、缩放和倾斜。这不仅能改变元素的外观，配合过渡和动画还能制作出丰富的交互效果。这一部分，我们就来研究一下`transform`的使用。\n\n### 二维变换\n\n二维变换（2D Transform）是指在 X 轴和 Y 轴组成的平面上进行的变换。所有的二维变换都是通过 `transform` 属性来实现的。\n\n使用 `translate()` 函数可以将元素从当前位置沿着 X 轴和 Y 轴移动：\n\n```html\n\u003Cdiv>\n  \u003Cdiv class=\"box\">\u003C\u002Fdiv>\n  \u003Cdiv>熊大，坐直升机的感觉可真舒服，就跟牢大一样\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n```\n\n```css\n.box {\n  width: 100px;\n  height: 100px;\n  background-color: red;\n  \u002F* 表示横向移动10px，纵向移动20px *\u002F\n  transform: translate(10px, 20px);\n}\n```\n\n![image-20251217154553183](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002Fm68aJiutcvSdkKB.png)\n\n可以看到，盒子在平面内发生了位置偏移，遮挡住了后续的文本，并且值得注意的是，盒子原本所占据的空间并没有发生改变，这与我们前面提到的`relative`定位布局类似，它们都能实现偏移又不脱离文档流效果。但是，`translate`的不同之处在于，它仅仅是视觉上的偏移，并非盒子本体的移动。两种情况下，使用JavaScript获取其位置时，会出现差异：\n\n![image-20251217161158891](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002Fxz2NTuEroReS7MX.png)\n\n`relative`定位相当于盒子自己发生了移动但又留着原来的位置，而`translate`则是盒子依然在原地，只是我们自己看起来像是被移动了而已。因此，`translate`更适合我们后面要介绍的动画功能，因为它仅仅是改变盒子渲染的位置，而非真正移动了盒子，我们后续介绍的所有变换效果实际上都是视觉变换，而非真正作用于盒子上。\n\n除了一次性控制盒子在横向或纵向上的移动，我们也可以单独使用：\n\n``` css\ntransform: translateX(10px);\n```\n\n我们接着来看下一个，使用 `scale()` 函数可以放大或缩小元素，同样的，它也是视觉效果，并非真的放大了盒子：\n\n```css\n.box {\n  width: 100px;\n  height: 100px;\n  background-color: red;\n  transform: scale(1.5);   \u002F* 变为原本1.5倍的大小 *\u002F\n}\n```\n\n![image-20251217161751543](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002FUD2G4XPiu7Zyx3K.png)\n\n可以看到，盒子以自己的中心位置进行放大，当然，我们也可以分别控制横向或纵向的缩放比例：\n\n```css\ntransform: scale(1.5, 2);\n```\n\n使用 `rotate()` 函数可以让元素围绕中心点进行旋转：\n\n![image-20251217162349991](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002FmstJ9qMdnNuBCSk.png)\n\n`skew()` 函数可以让元素产生倾斜变形效果，看起来像是一个平行四边形：\n\n![image-20251217162732593](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002Ffk765NGojqhABD4.png)\n\n通过这些三维变换，我们就可以实现丰富多彩的效果，结合后续的动画和过度效果，就能让网页灵动起来。\n\n### 原点变换\n\n默认情况下，所有的变换（特别是旋转和缩放）都是围绕元素的**中心点**（`center center`）进行的。我们可以通过 `transform-origin` 属性来改变这个基点。\n\n```css\n.box {\n  \u002F* 将旋转中心改为左上角 *\u002F\n  transform-origin: left top;\n  transform: rotate(45deg);\n}\n```\n\n这时候，元素就会像挂在墙上的画框歪了一样，围绕左上角的钉子旋转：\n\n![image-20251217163233941](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002FYTOFQwpfCs9lU7H.png)\n\n### 组合变换\n\n如果我们需要同时对元素进行平移、旋转和缩放，可以将这些函数写在同一个 `transform` 属性中，用空格隔开。\n\n```css\n.box {\n  \u002F* 先移动，再旋转，最后缩放 *\u002F\n  transform: translate(100px) rotate(45deg) scale(1.2);\n}\n```\n\n**注意**：变换的顺序很重要！先旋转再平移，和先平移再旋转，最终的位置可能完全不同，因为旋转会改变坐标轴的方向。\n\n比如我们这里先进行平移再旋转：\n\n![image-20251217211928289](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002Fgd3JiLzwyrkZFEP.png)\n\n但是先选择再平移：\n\n![image-20251217211949524](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002FWRHOEiMwF3XQK5q.png)\n\n原因也很简单，因为先进行了旋转操作，盒子的的移动方向也会跟着旋转，导致盒子斜着平移。\n\n### 三维变换\n\n三维变换（3D Transform）在二维的基础上引入了 **Z 轴** 的概念。Z 轴是垂直于屏幕向外的轴，通过它我们可以实现物体“近大远小”的立体效果。\n\n除了平面旋转 `rotate()`（实际上是围绕 Z 轴旋转）我们现在可以围绕 X 轴和 Y 轴旋转：\n\n```html\n\u003Cdiv class=\"inner-box\">\u003C\u002Fdiv>\n```\n\n```css\n.inner-box {\n  width: 100px;\n  height: 100px;\n  background-color: red;\n  transform: rotateY(80deg);\n}\n```\n\n当盒子围绕Y轴旋转时，随着角度的变化，盒子的宽度会变细再变宽，各位小伙伴可以拿一张A4纸模拟一下，让纸张以垂直方向为轴进行旋转，只从正面去观察是否和浏览器上的盒子选择一致：\n\n![image-20251217215138442](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002FbgWOhYuMdqxH9Xz.png)\n\n在开发者工具中，我们可以直接通过鼠标控制旋转变换的旋转角度，快速进行旋转观察。\n\n可能会有小伙伴说，这样看着好像没有那种立体的感觉，只有加上了景深，才能看到立体的翻转效果，否则`rotateY` 看起来只是单纯的变窄了。想要在平面屏幕上看到 3D 效果，首先需要开启“景深”功能，`perspective` 属性定义了观察者（人眼）距离屏幕的距离（视距）**视距越小，景深效果越强烈（近大远小越明显）视距越大，越接近平面效果。**\n\n通常我们将 `perspective` 加在**父元素**（舞台）上，这样，父元素就扩展了一个Z轴方向上的空间出来，其中的子元素就有3D变换的空间了：\n\n```html\n\u003Cdiv class=\"outer-box\">\n  \u003Cdiv class=\"inner-box\">\u003C\u002Fdiv>\n\u003C\u002Fdiv>\n```\n\n```css\n.outer-box {\n  width: 300px;\n  height: 300px;\n  border: 1px solid gray;\n  perspective: 500px;\n\n  .inner-box {\n    width: 100px;\n    height: 100px;\n    background-color: red;\n    transform: rotateY(80deg);\n  }\n}\n```\n\n![image-20251217215505138](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002FbAylBtqG6rZTcIu.png)\n\n景深效果会为盒子的观察视角添加一定的倾斜角度，此时盒子旋转看起来就有一点点的3D效果了。\n\n同样的，针对于平移效果，`translateZ()` 允许元素沿着 Z 轴移动：\n\n- **正值**：向屏幕外移动，离眼睛更近，元素看起来**更大**。\n- **负值**：向屏幕内移动，离眼睛更远，元素看起来**更小**。\n\n![image-20251217220515718](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002FWNeA1uBlmSD5rdj.png)\n\n注意必须在添加景深效果时盒子的Z轴移动才会有效果，否则无论怎么移动都看不出来效果。\n\n不过，当一个元素进行了 3D 变换，并且它内部还有子元素也进行了 3D 变换时，默认情况下，子元素会“扁平化”贴在父元素的平面上，失去自己的 3D 空间关系：\n\n```html\n\u003Cdiv class=\"outer-box\">\n  \u003Cdiv class=\"inner-box\">\n    \u003Cdiv class=\"inner-box-2\">\u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n```\n\n```css\n.outer-box {\n  width: 300px;\n  height: 300px;\n  border: 1px solid gray;\n  perspective: 500px;\n\n  .inner-box {\n    width: 100px;\n    height: 100px;\n    background-color: rgba(255, 0, 0, 0.8);\n    transform: rotateX(45deg);\n\n    .inner-box-2 {\n      width: 50px;\n      height: 50px;\n      background-color: #0080ff;\n      transform: rotateY(45deg);\n    }\n  }\n}\n```\n\n![image-20251217221656904](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002F645vub8AIlnUcpt.png)\n\n可以看到，里面的蓝色盒子又变成2D变换效果了，3D效果消失了，为了让子元素保持 3D 立体空间，我们需要在父元素上设置 `transform-style`属性：\n\n```css\ntransform-style: preserve-3d;\n```\n\n这个属性在处理复杂模型3D效果时极为有用。\n\n### 透明效果\n\n在网页设计中，透明效果非常常用，比如模态框背后的半透明遮罩、悬浮时变淡的按钮等。CSS 提供了多种方式来实现透明效果，最常见的有两种：`opacity` 属性和 Alpha 通道颜色（如 `rgba`）其中`rgba`我们在之前的学习中已经使用过，这里我们来介绍一下新朋友：`opacity`，此属性用于设置整个元素的透明度。\n\n```css\n.box {\n  background-color: red;\n  opacity: 0.5;   \u002F* 设置 50% 透明度 *\u002F\n}\n```\n\n这样，我们的盒子就会自动变成半透明状态（包括盒子的背景、文本、以及所有的内容）它会影响盒子及其子元素的整体展示效果，全部变为透明。\n\n### 过渡效果\n\n在没有使用过渡属性之前，元素的样式变化是瞬间完成的。比如我们设置一个按钮在鼠标悬停时背景色变红，它会“突变”成红色。而 CSS3 的 `transition` 属性允许我们在两个样式状态之间建立一个平滑的过渡动画，让页面交互看起来更加自然和高级。比如：\n\n```html\n\u003Cdiv class=\"simple-box\">\u003C\u002Fdiv>\n```\n\n```css\n.simple-box {\n  width: 200px;\n  height: 200px;\n  background-color: dodgerblue;\n  \n  &:hover { background-color: rebeccapurple; }\n}\n```\n\n要实现过渡效果，我们需要定义两个要素，首先是需要针对于什么属性进行过度，其次是过度需要持续多久，接着我们就可以在设置下面的CSS属性了：\n\n```css\n\u002F* 设置需要过度的属性 *\u002F\ntransition-property: background-color;\n\u002F* 过度动画的持续时间 *\u002F\ntransition-duration: .3s;\n```\n\n此时我们再将鼠标放到盒子上，就会产生背景颜色渐变的过度效果了。\n\n同样的，比如我们希望当鼠标移动到按钮上时自动放大尺寸，产生灵动效果：\n\n```css\nbutton {\n  color: white;\n  padding: 6px 12px;\n  border-radius: 6px;\n  border: none;\n  background-color: rebeccapurple;\n  \u002F* 可以直接在简写属性中一步到位 *\u002F\n  transition: transform 0.2s;\n\n  &:hover {\n    transform: scale(1.05);\n  }\n}\n```\n\n此时我们将鼠标移动到按钮上时，就会产生放大过渡效果。\n\n除了这种简单的过渡效果外，我们还可以进一步控制过渡的速度曲线，比如我们希望过渡效果一开始慢，然后逐步变快，就可以使用`transition-timing-function`属性来控制：\n\n- `linear`: 匀速（从头到尾速度一样）。\n- `ease`: （默认）慢速开始，然后变快，最后慢速结束。\n- `ease-in`: 慢速开始。\n- `ease-out`: 慢速结束。\n- `ease-in-out`: 慢速开始和结束。\n- `steps(n)`: 分步执行，像逐帧动画一样。\n\n```css\nbutton {\n  ...\n  transition: transform 0.2s ease-in;  \u002F* ease-in表示缓慢进入逐步变快 *\u002F\n\n  &:hover {\n    transform: translateX(20px);\n  }\n}\n```\n\n此外，我们还可以使用自定义速度曲线来定义更多过渡效果：\n\n```css\n\u002F* 起步稍微慢一点（斜率低），中间很快（斜率高），然后减速缓冲（斜率低），最后加速 *\u002F\ntransition: transform 0.2s cubic-bezier(0.25, 0.8, 0.25, 1);\n```\n\n当然，速度可以调整为负数，表示回放动画，从而实现回弹效果，就像果冻一样：\n\n```css\ntransition: transform 0.2s cubic-bezier(0.68, -0.55, 0.27, 1.55);\n```\n\n有些时候，我们可能还希望过渡动画存在一定的延迟，如果延迟时间结束依然满足过渡效果的条件（比如鼠标指针依然停留在按钮上）此时可以使用`transition-delay`属性来控制：\n\n```css\nbutton {\n  ...\n  transition: transform 0.2s 1s ease-in;\n\n  &:hover {\n    transform: translateX(20px);\n  }\n}\n```\n\n这样，当我们鼠标放到盒子上时，会等待1秒之后再变从初始状态过渡到`:hover`定义的CSS效果。\n\n虽然渐变效果很强大，但是有些地方存在坑点，比如高度就是一个非常难受的点，比如我们希望实现在默认情况下，盒子处于折叠状态，内容暂时被遮挡，当鼠标移动到盒子上时，再调整高度完整展示全部内容：\n\n```css\n.test-box {\n  width: 320px;\n  height: 20px;\n  padding: 5px 10px;\n  border-radius: 10px;\n  overflow: hidden;\n  border: 2px solid dodgerblue;\n  \u002F* 为高度添加过渡效果 *\u002F\n  transition: height 0.3s ease-in-out;\n\n  &:hover { height: auto; }  \u002F* 鼠标经过时，高度按照内容来决定 *\u002F\n}\n```\n\n可以看到，子盒子的高度变化确实会影响父盒子的高度，但是父盒子即使设置了高度的过渡属性，也是没有任何效果的。这是一个非常经典的坑，很多小伙伴会觉得，盒子高度变化了那不就应该触发`height`属性的过渡吗，为什么这里变化了也没用呢？\n\n> 根本原因是**浏览器无法计算“不确定值”的中间状态**，简单来说，当您告诉浏览器“在 1秒内 从 `0px` 变到 `100px`”时，浏览器是非常开心的，因为这是一道简单的数学题。但是，当您说 “从 `0px` 变到 `auto`” 时，浏览器就懵了，浏览器必须先计算布局（Reflow）才能知道 `auto` 到底等于多少像素。而在过渡开始的那一瞬间，浏览器还不知道终点在哪里，自然也就无法计算中间该怎么走。\n\n虽然这种情况确实很难处理，但是我们可以曲线救国，其中一个比较经典的做法就是使用`max-height`来解决问题，我们可以直接将初始高度设置为`max-height`属性，然后当鼠标经过时，给一个非常大的值（一定能装下内容的高度）这样，浏览器得到最大高度就能准确预测过渡终点，我们就可以实现过度效果了：\n\n```css\n.test-box {\n  ...\n  max-height: 20px;\n  transition: max-height 0.3s ease-in-out;\n\n  &:hover { max-height: 999px; }\n}\n```\n\n这样就可以解决自适应高度过渡动画的问题了。\n\n### UI设计系列（课程六）\n\n本节讲解如何利用阴影编写漂亮的按钮：\n\n![image-20251217234545216](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F17\u002F4Iizd6NwQUWVlJG.png)\n\n使用同色阴影有时候能够给人一种玻璃折射光线的感觉，会使得按钮看起来更轻更通透，当然，不仅仅是按钮，实际上页面上很多的一些卡片、选择框等都可以采用这种风格，看起来就会很高级。\n\n```html\n\u003Cdiv style=\"display: flex; gap: 20px\">\n  \u003Cbutton class=\"btn-1\">点击购买\u003C\u002Fbutton>\n  \u003Cbutton class=\"btn-2\">点击购买\u003C\u002Fbutton>\n  \u003Cbutton class=\"btn-3\">点击购买\u003C\u002Fbutton>\n  \u003Cbutton class=\"btn-4\">点击购买\u003C\u002Fbutton>\n\u003C\u002Fdiv>\n```\n\n```css\nbutton {\n  color: white;\n  padding: 10px 15px;\n  border: none;\n  border-radius: 8px;\n  cursor: pointer;\n  transition: transform 0.3s ease, box-shadow 0.5s ease;\n\n  &:hover {\n    transform: scale(1.05);\n  }\n}\n\n.btn-1 {\n  background-color: dodgerblue;\n  box-shadow: 0 0 10px rgba(0, 130, 255, 0.5);\n\n  &:hover { box-shadow: 0 0 15px rgba(0, 130, 255, 0.8); }\n}\n\n.btn-2 {\n  background-color: #ac1eff;\n  box-shadow: 0 0 10px rgba(123, 0, 255, 0.5);\n\n  &:hover { box-shadow: 0 0 15px rgba(153, 0, 255, 0.8); }\n}\n\n.btn-3 {\n  background-color: #18af2c;\n  box-shadow: 0 0 10px rgba(34, 255, 0, 0.5);\n\n  &:hover { box-shadow: 0 0 15px rgba(17, 255, 0, 0.8); }\n}\n\n.btn-4 {\n  background-color: #f88a19;\n  box-shadow: 0 0 10px rgba(255, 136, 0, 0.5);\n\n  &:hover { box-shadow: 0 0 15px rgba(255, 106, 0, 0.8); }\n}\n```\n\n### UI设计系列（课程七）\n\n本节我们将利用刚刚学到的 **3D 变换** 和 **过渡效果**，制作一个现代网站中非常常见的组件 —— **3D 翻转卡片**。\n\n这个效果的核心原理在于：我们需要两个“面”（正面和背面），它们重叠在一起，背面的初始状态是旋转了 180 度的。当鼠标悬停时，我们将整个容器旋转 180 度，这样正面转到了后面，背面转到了前面。\n\n在开始之前，我们需要补充一个专门配合 3D 旋转使用的属性：`backface-visibility`。\n\n默认情况下，当我们把一个盒子旋转 180 度背对着屏幕时，我们看到的是这个盒子正面的“镜像”或者说是它的背面。但是，如果我们设置了 `backface-visibility: hidden`，那么当盒子背对屏幕时，它就会变得不可见（透明）。利用这个特性，我们就可以把两个盒子背对背贴在一起。\n\n我们需要三层结构：\n\n1. **外部容器 (`flip-card`)**：提供透视效果（景深）。\n2. **内部容器 (`flip-card-inner`)**：这是实际进行旋转的物体，包含正面和背面。\n3. **正面和背面 (`flip-card-front`, `flip-card-back`)**：实际展示的内容。\n\n```html\n\u003Cdiv class=\"flip-card\">\n  \u003Cdiv class=\"flip-card-inner\">\n    \u003C!-- 正面 -->\n    \u003Cdiv class=\"flip-card-front\">\n      \u003Ch2>前端开发\u003C\u002Fh2>\n      \u003Cp>HTML & CSS\u003C\u002Fp>\n    \u003C\u002Fdiv>\n    \u003C!-- 背面 -->\n    \u003Cdiv class=\"flip-card-back\">\n      \u003Ch2>课程详情\u003C\u002Fh2>\n      \u003Cp>那么这一时刻又有老铁问了，羊哥羊哥，你嘚技术，到底是怎么练的。\u003C\u002Fp>\n      \u003Cbutton>立即学习\u003C\u002Fbutton>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n```\n\n```css\n\u002F* 1. 最外层容器：定义尺寸和景深 *\u002F\n.flip-card {\n  background-color: transparent;\n  width: 300px;\n  height: 200px;\n  \u002F* 开启 3D 空间感，数值越小立体感越强 *\u002F\n  perspective: 1000px; \n}\n\n\u002F* 2. 内部容器：承载正面和背面，负责旋转 *\u002F\n.flip-card-inner {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  text-align: center;\n  \u002F* 添加过渡效果，让翻转动作平滑进行 *\u002F\n  transition: transform 0.6s;\n  \u002F* 关键属性：保留子元素的 3D 空间位置，否则子元素会变扁平 *\u002F\n  transform-style: preserve-3d;\n}\n\n\u002F* 3. 鼠标悬停交互：旋转内部容器 *\u002F\n.flip-card:hover .flip-card-inner {\n  transform: rotateY(180deg);\n}\n\n\u002F* 4. 正面和背面的公共样式 *\u002F\n.flip-card-front, .flip-card-back {\n  position: absolute; \u002F* 绝对定位，让正反面重叠在一起 *\u002F\n  width: 100%;\n  height: 100%;\n  \u002F* 关键属性：隐藏背面。当面朝后时不可见 *\u002F\n  backface-visibility: hidden;\n  \n  \u002F* 一些装饰样式 *\u002F\n  border-radius: 10px;\n  display: flex;\n  flex-direction: column;\n  justify-content: center;\n  align-items: center;\n  box-shadow: 0 4px 8px rgba(0,0,0,0.2);\n}\n\n\u002F* 5. 正面特有样式 *\u002F\n.flip-card-front {\n  background: linear-gradient(to right, #4facfe, #00f2fe);\n  color: white;\n}\n\n\u002F* 6. 背面特有样式 *\u002F\n.flip-card-back {\n  background-color: #2980b9;\n  color: white;\n  \u002F* 重点：背面初始状态必须先旋转 180 度 *\u002F\n  \u002F* 这样当父容器旋转 180 度时，背面正好转回来变成 0 度（正面朝上） *\u002F\n  transform: rotateY(180deg);\n}\n\n.flip-card-back button {\n  margin-top: 10px;\n  padding: 5px 15px;\n  background: white;\n  color: #2980b9;\n  border: none;\n  border-radius: 5px;\n  cursor: pointer;\n}\n```\n\n通过这种巧妙的组合，我们就实现了一个平滑、具有原生 App 质感的 3D 翻转卡片。\n\n## 函数和变量\n\n**CSS 函数（CSS Functions）**，指的是在 CSS 属性值中使用的一种 **“带参数的表达式”**，用来完成**计算、取值、变换、颜色处理、图像生成**等工作。\n\n实际上，我们在之前的课程中已经使用过多种函数了，比如颜色函数（如 `rgb`、`rgba`、`linear-gradient`）和变换函数（如 `rotate`、`translate`）以及滤镜函数（如 `blur`、`grayscale`），通过使用这些函数，我们就可以更加灵活地配置CSS参数值。在CSS中，函数的统一形式：\n\n```css\n属性: 函数名(参数1, 参数2, …);\n```\n\n这一小节我们来认识和学习更多实用的函数。\n\n### 动态计算\n\n`calc()` 是 \"calculate\"（计算）的缩写，它允许我们在声明 CSS 属性值时执行一些数学计算。这在响应式布局中简直是神一般的存在。\n\n比如，我们希望一个侧边栏的宽度固定为 `200px`，而右侧的内容区域占据剩余的全部宽度。在以前，我们可能需要用百分比去凑。但在 CSS3 中，我们可以直接这样写：\n\n```css\n.content {\n  \u002F* 也就是：总宽度 减去 200px *\u002F\n  width: calc(100% - 200px); \n}\n```\n\n`calc()` 支持加（`+`）、减（`-`）、乘（`*`）、除（`\u002F`）四则运算。\n\n> **注意**：在使用加号和减号时，**运算符前后必须有空格**，否则无效。\n\n我们甚至可以混合不同的单位进行计算，比如百分比减去像素，或者是 `vw` 减去 `em`，浏览器会自动帮我们要处理单位换算。\n\n### 属性获取\n\n`attr()` 函数用于获取 HTML 元素上的属性值，并将其用于 CSS 中。不过目前它主要用于伪元素的 `content` 属性中。\n\n比如我们想直接获取`a`标签上的`herf`属性：\n\n```html\n\u003Ca href=\"https:\u002F\u002Fwww.baidu.com\">我是链接\u003C\u002Fa>\n```\n\n```css\na::after {\n  content: attr(href);\n  display: inline-block;\n  text-decoration: none;\n  margin-left: 5px;\n  font-size: 0.8em;\n  color: #aaa;\n}\n```\n\n![image-20251218113118184](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F18\u002FpDdbyWYKvQIXezG.png)\n\n不过这种用法，我们自己一般很少用到，在一些组件库中比较多。\n\n### 智能比较\n\n这三个函数是现代 CSS 响应式设计的利器，它们允许我们根据条件动态选择值，而无需编写繁琐的媒体查询。\n\n比如`min()` 函数接受多个值，并返回其中**最小**的那个：\n\n```css\n.container {\n  width: min(500px, 90%);\n}\n```\n\n这行代码的意思是：浏览器会比较 `500px` 和 `90%`（当前父宽度的90%），哪个小就用哪个。\n\n- 如果屏幕很宽，`90%` 超过了 `500px`，那么宽度就是 `500px`。\n- 如果屏幕很窄（比如手机），`90%` 小于 `500px`，那么宽度就是 `90%`。\n  这相当于自动实现了 `width: 90%; max-width: 500px;` 的效果。\n\n再比如`max()` 函数则相反，它返回其中**最大**的那个：\n\n```css\nwidth: max(300px, 50%);\n```\n\n这表示盒子宽度至少是 `300px`。如果 `50%` 的宽度算出来大于 `300px`，那就用更宽的那个。\n\n`clamp()` 综合了上面的两者，它接受三个参数：**最小值**、**首选值**、**最大值**：\n\n```css\nfont-size: clamp(1rem, 2.5vw, 2rem);\n```\n\n它可以实现同时控制最大和最小值，比如上面的计算方式就是：\n\n- **首选**：字体大小倾向于视口宽度的 `2.5%`（`2.5vw`），这样字体会随屏幕变大而变大（流体排版）。\n- **下限**：但是，无论屏幕多小，字体**最小**不能小于 `1rem`，防止文字太小看不清。\n- **上限**：无论屏幕多大，字体**最大**不能大于 `2rem`，防止文字大得离谱。\n\n这类函数在响应式布局中非常有效。\n\n### CSS 变量\n\n这是一个跨时代的特性，`var()` 函数允许我们使用自定义属性（也就是 CSS 变量）这使得我们可以更方便地管理网页的主题颜色、字号等重复使用的值。\n\n首先，如果需要在CSS中定义变量，变量名必须以两个连字符 `--` 开头，通常我们将变量定义在 `:root`（文档根元素）中，这样全局都可以使用：\n\n```css\n:root {\n  --primary-color: #099bf6;   \u002F* 非常适合统一定义主色调，后期可以统一在这里更改 *\u002F\n  --secondary-color: #7bbfed;\n  --text-color: #373737;\n}\n```\n\n定义好之后，我们就可以在任何地方使用 `var()` 来引用它：\n\n```css\n.main-btn {\n  border: none;\n  border-radius: 8px;\n  padding: 10px 15px;\n  color: var(--primary-color);\n  background-color: var(--secondary-color);\n}\n```\n\n![image-20251218113955836](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F18\u002FNQwad1IC7rDAJyP.png)\n\n如果我们觉得蓝色不好看，也可以改变主色调和辅色调，这样所有使用了变量的地方都可以立即切换到新的颜色：\n\n```css\n:root {\n  --primary-color: #8605ef;\n  --secondary-color: #e4caff;\n  --text-color: #373737;\n}\n```\n\n![image-20251218114710029](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F18\u002FDgzdYU4u2Kkilxr.png)\n\n这种方式非常实用，我们只需要在一个地方控制颜色和一些通用的属性。很多的一些组件库，包括柏码官网实际上就是采用这种方式进行色彩变化的：https:\u002F\u002Fwww.itbaima.cn\u002Fzh-CN\n\n此外，`var`还支持备选属性，比如当CSS中没有设置副色调，可以直接采用备选值：\n\n```css\nbackground-color: var(--secondary-color, #fff);\n```\n\n当然，除了颜色之外，基本上我们之前用到过的所有属性都可以使用变量的形式进行存储：\n\n```css\n:root {\n  --primary-color: #8605ef;\n  --secondary-color: #e4caff;\n  --font-size: 16px;\n  --line-height: 1.5;\n  --font-family: 'Roboto', sans-serif;\n}\n```\n\n注意，和CSS属性一样，我们可以通过重复定义变量来覆盖优先级更低的同名变量：\n\n```css\nbody button {\n  --primary-color: #ef0505;\n}\n```\n\n此时，由于这里的选择器优先级更高，导致`--primary-color`覆盖掉了`:root`中定义的同名变量，那么此时就会按照这个新的变量值来使用。\n\n### UI设计系列（课程八）\n\n本节我们结合 **CSS 变量** 函数，做一个简单的 **暗黑模式切换** 模拟。\n\n> **浏览器暗黑模式（Dark Mode）**，指的是浏览器或网页在显示时，整体采用**深色背景 + 浅色文字**的配色方案，用来替代传统的“白底黑字”的亮色模式。\n\n通常暗黑模式是通过给 `body` 增加一个类名（比如 `.dark-mode`）来实现的。利用 CSS 变量，我们可以轻松定义两套颜色主题。\n\n```html\n\u003Cdiv class=\"card\">\n  \u003Ch2>CSS 变量很棒\u003C\u002Fh2>\n  \u003Cp>利用变量，我们可以轻松实现主题切换。\u003C\u002Fp>\n  \u003Cbutton>切换主题\u003C\u002Fbutton>\n\u003C\u002Fdiv>\n```\n\n```css\n\u002F* 1. 定义默认主题（亮色） *\u002F\n:root {\n  --bg-color: #f5f5f5;\n  --card-bg: #ffffff;\n  --text-color: #333333;\n  --btn-bg: #3498db;\n}\n\n\u002F* 2. 定义暗色主题 *\u002F\n\u002F* 当 body 拥有 dark 类时，覆盖上面的变量 *\u002F\nbody.dark {\n  --bg-color: #2c3e50;\n  --card-bg: #34495e;\n  --text-color: #ecf0f1;\n  --btn-bg: #e74c3c;\n}\n\n\u002F* 3. 应用变量 *\u002F\nbody {\n  background-color: var(--bg-color);\n  color: var(--text-color);\n  transition: background-color 0.3s, color 0.3s; \u002F* 添加过渡让切换更丝滑 *\u002F\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  height: 100vh;\n  margin: 0;\n}\n\n.card {\n  width: 300px;\n  padding: 20px;\n  background-color: var(--card-bg); \u002F* 使用变量 *\u002F\n  border-radius: 10px;\n  box-shadow: 0 4px 6px rgba(0,0,0,0.1);\n  transition: background-color 0.3s;\n}\n\nbutton {\n  background-color: var(--btn-bg);\n  color: white;\n  border: none;\n  padding: 10px 20px;\n  border-radius: 5px;\n  cursor: pointer;\n  margin-top: 10px;\n}\n```\n\n后续只需要通过 JS 稍微切换一下 `body` 的类名，整个页面的配色就会瞬间改变，这就是 CSS 变量的魅力。\n\n## AT规则\n\n在 CSS 中，**At 规则（@规则，At-rules）** 是一类**以 @ 开头的特殊语句**，用于告诉浏览器**如何解析、加载或应用样式**，而不仅仅是“给元素设置样式”。这一节我们来认识一下不同类型的AT规则，看看如何使用它们。\n\n实际上我们之前在自定义字体时用到的`@font-face`就是一种AT规则，它可以实现远程或本地引入字体。\n\n### 媒体查询\n\nCSS **媒体查询（Media Queries）** 是用来**根据设备特性或环境条件，动态地应用不同 CSS 样式**的一种机制，是实现**响应式设计**的核心技术之一。\n\n```css\n@media 媒体类型 and (媒体特性) {\n  \u002F* 满足条件时生效的 CSS *\u002F\n}\n```\n\n默认情况下，媒体类型是可选的，我们可以不进行特别指定，常用的媒体类型有以下这些：\n\n| **类型** | **含义**                     |\n| -------- | ---------------------------- |\n| screen   | 屏幕设备（手机、平板、电脑） |\n| print    | 打印预览或打印时             |\n| all      | 所有设备（默认）             |\n\n如果不指定媒体类型，会自动采用`all`作为初始值。\n\n我们可以使用多种媒体特性来创建精确的查询条件，比如现在我们想根据当前屏幕宽度进行判断，是否采用指定样式，就可以使用媒体查询来实现，这里需要使用`screen`类型：\n\n```css\n.container {\n  width: 200px;\n  height: 50px;\n  background-color: red;\n}\n\n\u002F* 对页面尺寸进行媒体查询，当小于768px宽度时，采用下面的样式 *\u002F\n@media (max-width: 768px) {\n  .container {\n    background-color: green;\n  }\n}\n```\n\n当我们查询屏幕尺寸时，我们可以使用以下媒体特性进行判断：\n\n* `width`  -  屏幕尺寸处于指定宽度时切换样式\n* `max-width`  -  屏幕尺寸小于等于指定宽度时切换样式\n* `min-width`  -  屏幕尺寸大于等于指定宽度时切换样式\n\n这里只列举了宽度，高度也是同理的。在上面的例子中，我们用到了`max-width`来判断屏幕的最大宽度，当未达到最大宽度时，就采用其中的样式。\n\n我们也可以尝试一下在打印时产生的特殊样式，使用指定的媒体类型即可：\n\n```css\n@media print {\n  .container {\n    background-color: blue;\n  }\n}\n```\n\n![image-20251219150117931](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F19\u002FE2OVm5NwtjCrfFi.png)\n\n可以看到，当打印时，盒子的颜色会变成蓝色。\n\n此外，还有一些常用的媒体查询特性，比如`orientation`可以检查当前是否处于横屏或是竖屏状态，`resolution`可以检测当前屏幕的分辨率和缩放等。有关更多媒体特性请参阅：[媒体查询](https:\u002F\u002Fdeveloper.mozilla.org\u002Fzh-CN\u002Fdocs\u002FWeb\u002FCSS\u002FReference\u002FAt-rules\u002F@media#媒体特性)\n\n需要注意的是，AT规则虽然看着像是嵌套了一层CSS选择器，但是其本身并不参与任何优先级判断，在比较优先级时，依然是其中编写的选择器在进行判断，因此，为了能够保证样式在特定情况下准确覆盖，建议大家把媒体查询卸载后面，以保证同优先级下样式不会被覆盖。\n\n### 深色模式\n\n`@media` 还可以检测用户的系统偏好，例如是否开启了深色模式，深色模式是现在很多网站都会使用的颜色主题，因为深色模式在夜间能有效降低屏幕的亮度，保护眼睛，同时深色模式有着非常完美的对比度，很多颜色都能搭配。\n\n我们可以使用 `prefers-color-scheme` 这个媒体特性来为网站提供深色模式的样式：\n\n```css\n@media (prefers-color-scheme: dark) {\n  body {\n    background-color: #121212;\n    color: #eeeeee;\n  }\n}\n```\n\n切换深色模式可以尝试在系统设置中选择：\n\n![image-20251219152100832](https:\u002F\u002Fs2.loli.net\u002F2025\u002F12\u002F19\u002FzqLw7pa1yiPoCYZ.png)\n\n这样，浏览器也会自动采用深色模式，我们可以观察一下深色模式下会有什么变化。\n\n配合我们之前介绍的深色模式适配样式，就可以实现根据用户系统设置来自动切换浅色或是深色效果了。\n\n### 动画\n\n前面我们介绍了CSS过渡（`transition`）虽然过渡效果能带来非常平滑的动画切换，但它只能实现从一个状态到另一个状态的简单变化。如果我们想创建更复杂的、多步骤的动画，比如让一个元素来回移动、闪烁或者改变多次颜色，就需要使用CSS动画（`animation`）\n\n动画的核心是 `@keyframes` 规则，它用来定义动画的各个关键帧（即动画过程中的关键状态）首先，我们需要使用 `@keyframes` 创建一个动画，你可以为它指定一个名字，然后在内部定义动画的起始状态（`from` 或 `0%`）、中间状态（任意百分比）和结束状态（`to` 或 `100%`）\n\n比如现在我们想创建一个盒子左右移动的动画：\n\n```css\n@keyframes Test {\n  0% { transform: translateX(0px) }\n  50% { transform: translateX(100px) }\n  100% { transform: translateX(0px) }  \u002F* 最终状态为不移动 *\u002F\n}\n```\n\n这里我们写了个3个关键帧，来表示在动画进行到不同的进度时所具有的三种状态，这样浏览器就可以自动推算出中间的过渡动画了。\n\n这样，我们就定义好了在不同进度下的样式，当动画播放时，会自动从一个阶段过渡到另一个阶段的样式。我们需要使用`animation-name`属性来指定盒子要采用的动画效果名称，然后再使用`animation-duration`指定动画的播放时间，使用`animation-delay`控制动画播放延迟：\n\n```css\n.container {\n  width: 100px;\n  height: 100px;\n  background-color: red;\n  animation-name: Test;  \u002F* 动画名称要和刚刚创建的保持一致 *\u002F\n  animation-duration: 3s;  \u002F* 动画持续时间越长，播放越慢 *\u002F\n  animation-delay: 0s;  \u002F* 播放延迟 *\u002F\n}\n```\n\n接着，我们就可以在盒子中看到动画自动播放了。和之前一样，我们可以控制动画的速度曲线：\n\n```css\nanimation-timing-function: ease-out;\n```\n\n此时动画的每一个关键帧就是先快后慢地播放。\n\n默认情况下，动画只会在页面加载时播放一次，我们也可以控制播放次数，只需设置`animation-iteration-count`属性即可控制：\n\n```css\nanimation-iteration-count: 3;\n```\n\n如果我们希望动画永远播放下去，也可以直接设置为`infinite`，表示无限次数播放。\n\n我们还可以控制动画的播放方向，默认情况下是按照正常的方向在进行，也可以让其反着来：\n\n| **值**            | **说明**     |\n| ----------------- | ------------ |\n| normal            | 正向（默认） |\n| reverse           | 反向         |\n| alternate         | 正 → 反 → 正 |\n| alternate-reverse | 反 → 正      |\n\n```css\nanimation-direction: reverse;\n```\n\n最后这里还有一个比较重要的属性，它可以决定动画开始前或是结束后，元素保持什么样的状态，使用`animation-fill-mode`来控制：\n\n| **值**    | **效果**                      |\n| --------- | ----------------------------- |\n| none      | 不保留（默认）                |\n| forwards  | 停在最后一帧                  |\n| backwards | 立即应用第一帧                |\n| both      | 同时具备 forwards + backwards |\n\n注意，使用停留最后或第一帧之前，一定要关闭动画的循环播放效果，否则动画重复播放结束之后才会使用这里的状态。\n\n除了让动画正常播放外，我们还可以让它定格在某一个进度下，比如我们希望鼠标移动到盒子上时自动暂停动画播放，鼠标移开时自动恢复动画播放，`animation-play-state`属性可以直接控制：\n\n```css\n.container {\n  ...\n\n  &:hover { animation-play-state: paused; }\n}\n```\n\n除了设置一个动画外，我们也可以同时增加多个动画，让它们叠加展示，比如：\n\n```css\n@keyframes Test2 {\n  0% { background-color: red; }\n  50% { background-color: blue; }\n  100% { background-color: yellow; }\n}\n```\n\n```css\n.container {\n  ...\n  animation-name: Test, Test2;\n  animation-duration: 3s, 2s;\n  animation-timing-function: ease-in;\n  animation-fill-mode: forwards;\n\n  &:hover { animation-play-state: paused; }\n}\n```\n\n注意，当我们使用多个动画时，上面提到的这些属性也可以通过逗号分隔来分别控制不同动画的时间、速度曲线、填充模式等，如果只写一个表示所有动画采用一样的设置。\n\n针对于以上属性，我们可以使用`animation`简写属性，一步到位：\n\n```css\nanimation: name duration timing-function delay iteration-count direction fill-mode play-state;\n```\n\n比如：\n\n```css\nanimation: move 1s ease-in-out 0.3s infinite alternate forwards;\n```\n\n表示使用名字为`move`的动画，持续时间1秒钟，先慢后快再慢结束，延迟0.3s播放，无限循环播放，动画方向先正后反，保留最后一帧状态。\n\n### 层叠优先级控制\n\n`@layer` 是 **CSS Cascade Layers（层叠层）** 相关的 AT 规则，用来**显式控制样式在层叠中的优先级顺序**，解决“样式越来越多、权重越来越乱”的问题。简单来说就是：@layer 用来给 CSS 规则分层，并决定“哪一层的样式优先级更高”\n\n在没有 @layer 之前：\n\n- 后加载的 CSS 通常会覆盖先加载的\n- 为了覆盖样式，不断提高选择器权重\n- 为了提高优先级导致出现大量 `!important`\n- 第三方样式（如组件库）很难控制优先级\n\n我们可以通过`@layer`创建多个层，写得越靠后的层，优先级越高，比如：\n\n```css\n@layer reset, base, components, utilities;\n```\n\n这里我们一共定义了4个层，其中`utilities`的优先级最高，`reset`的优先级最低。\n\n那么定义好之后如何使用呢？我们可以使用`@layer`指定需要使用的层，并在其中编写样式：\n\n```css\n@layer utilities {\n  .container { background-color: dodgerblue; }\n}\n\n@layer base {\n  .container { background-color: red; }\n}\n```\n\n可以看到，虽然这里的两个选择器的内容完全一样，并且背景颜色为红色排在后面，但是实际上，最终生效的是上面的蓝色，因为它和下面的样式不在同一个层级上，由于`utilities`的优先级更高一些，它就更能覆盖其他的样式。\n\n同样的，即使较前层级的优先级更高，靠后的层级也能实现覆盖：\n\n```css\n@layer utilities {\n  .container { background-color: dodgerblue; }\n}\n\n@layer base {\n  div.container { background-color: red; }\n}\n```\n\n这类似于我们前面提到的“层叠上下文”概念，优先级的比较只存在于同一个层级中，跨越层级时会直接按照更高优先级的层级样式进行展示。\n\n不过，如果我们使用了`!important`，它就会使得样式跨越层级，变为最高优先级：\n\n```css\n@layer utilities {\n  .container { background-color: dodgerblue; }\n}\n\n@layer base {\n  .container { background-color: red !important; }  \u002F* 此时虽然层级不如上面，但是被强制提高优先级 *\u002F\n}\n```\n\n比较有趣的是，如果大家都使用了`!important`的话，它会反转层的优先级顺序：\n\n```css\n@layer utilities {\n  .container { background-color: dodgerblue !important; }\n}\n\n@layer base {\n  .container { background-color: red !important; }\n}\n```\n\n可以看到，此时生效的是下面的红色盒子，这也是为了保证最低层级的CSS使用`!important`来覆盖其他样式。\n\n那如果是没有采用分层的样式呢？比如我们直接编写的选择器：\n\n```css\n@layer utilities {\n  .container { background-color: dodgerblue; }\n}\n\n.container { background-color: red; }\n```\n\n综上，完整优先级排序结果如下：\n\n| 优先级   | 类型                                     |\n| -------- | ---------------------------------------- |\n| 1 (最低) | 先声明的 `@layer` 中的普通样式           |\n| 2        | 后声明的 `@layer` 中的普通样式           |\n| 3        | 未分层的普通样式                         |\n| 4        | 未分层的  `!important` 样式              |\n| 5        | 后声明的 `@layer` 中的 `!important` 样式 |\n| 6 (最高) | 先声明的 `@layer` 中的 `!important` 样   |\n\n可以看到，如果存在未分层的样式，那么浏览器会直接采用它，因为未使用`@layer`的样式默认处于最顶层。所以，要让元素实现分层管理，必须采用`@layer`进行编写，否则就会失去意义。因为比较麻烦，所以这种方式不推荐小型或个人项目使用。\n\n### 其他常用AT规则\n\n这一节我们接着来介绍一些常用的AT规则，首先是`@import`，它可以实现在CSS文件中引入其他CSS文件：\n\n```css\n@import \"css\u002Fnormalize.css\";\n```\n\n当我们使用后，只要页面引入了此CSS就会自动将其中所有`@import`所关联的CSS样式一并引入。同时，在引入CSS时，我们可以直接指定此CSS文件内定义内容的层级：\n\n```css\n@import url(\"reset.css\") layer(reset);\n@import url(\"components.css\") layer(components);\n```\n\n不过我们还是更推荐大家选择`link`标签进行CSS引入，因为这种方式会阻塞渲染，加载完一个CSS之后才去加载另一个，而`link`标签可以实现并行加载，不阻塞。\n\n针对于页面上的一些CSS属性，可能在老旧浏览器中尚不支持，我们可以使用`@supports`来进行判断，只有在支持的情况下才启用其中的样式：\n\n```css\n@supports (backdrop-filter: blur(10px)) {\n  .card {\n    backdrop-filter: blur(10px);\n  }\n}\n```\n\n这样浏览器就会进行判断，不支持则不生效此样式。\n\n前面我们介绍了`@media`能够根据浏览器窗口尺寸进行判断，同样的，我们也可以根据父元素的窗口尺寸进行判断。使用`@container`进行容器查询：\n\n```css\n@container (min-width: 400px) {\n  .item {\n    font-size: 18px;\n  }\n}\n```\n\n根据父容器的尺寸进行查询，满足条件则生效里面的样式。\n\n### UI设计系列（课程九）\n\n这一节我们来编写一个自定义的浏览器弹窗，弹窗包含背景和窗口部分。\n\n```html\n\u003Cdiv class=\"dialog-modal\">\n  \u003Cdiv class=\"dialog-card\">\n    \u003Cdiv class=\"dialog-card__header\">\n      \u003Ch4>重要通知\u003C\u002Fh4>\n    \u003C\u002Fdiv>\n    \u003Cdiv class=\"dialog-card__content\">\n      柏码将于2025年12月32日免费赠送各位学员一套\n      小米17Pro手机 + 钢化膜套装，请于当天早上9点到群内\n      领取，过时不候\n    \u003C\u002Fdiv>\n    \u003Cdiv class=\"dialog-card__footer\">\n      \u003Cbutton disabled>领取\u003C\u002Fbutton>\n      \u003Cbutton>不领取\u003C\u002Fbutton>\n    \u003C\u002Fdiv>\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n```\n\n```css\n.dialog-modal {\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  background-color: rgba(0, 0, 0, 0.5);\n\n  .dialog-card {\n    display: flex;\n    flex-direction: column;\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    transform: translate(-50%, -50%);\n    width: 300px;\n    height: 350px;\n    background-color: white;\n    border-radius: 10px;\n\n    .dialog-card__header {\n      padding: 10px 15px;\n      border-bottom: 1px solid #eaeaea;\n    }\n\n    .dialog-card__content {\n      flex: 1;\n      font-size: 14px;\n      padding: 10px 15px;\n    }\n\n    .dialog-card__footer {\n      padding: 10px 15px;\n      border-top: 1px solid #eaeaea;\n      text-align: center;\n    }\n  }\n}\n\nh1, h2, h3, h4, h5, h6 {\n  margin: 0;\n}\n```\n\n### UI设计系列（课程十）\n\n这一节我们根据前面讲解的媒体查询对前面编写的苹果官网做一个移动端适配，同时修复之前的背景图片定位问题。\n\n### UI设计系列（课程十一）\n\n这一节我们来实现一下苹果官网的顶部导航栏下拉菜单效果。\n\n## 其他内容\n\n随着CSS的课程来到尾声，我们也将和大家说再见了，在课程的最后时光里，我们继续来介绍一些CSS中比较常见但又不容易和前面串联的知识点，希望在这最后的时光里大家也能好好享受CSS带来的快乐。\n\n### 表格样式\n\n针对于我们前面学习的表格`table`标签，CSS也有很多属性可以控制其样式，我们来研究一下。\n\n其中最常见的需求是给表格加上边框，让它看起来更清晰，在HTML阶段，我们并不推荐大家使用标签属性来控制边框，因为CSS里面控制会更加灵活：\n\n```css\ntable, th, td {\n  border: 1px solid #ccc;\n}\n```\n\n在默认情况下，你会发现表格的边框是双线的，看起来有点老式。这是因为每个单元格（`td`, `th`）都有自己的边框。我们可以使用 `border-collapse` 属性将这些边框合并起来：\n\n```css\ntable {\n  width: 100%;\n  border-collapse: collapse; \u002F* 合并边框 *\u002F\n}\n```\n\n`border-collapse` 有两个值：\n\n- `collapse`：将相邻的边框合并为一条。\n- `separate`：边框分离（默认值）。当使用此值时，还可以用 `border-spacing` 属性来设置边框之间的距离。\n\n为了让表格内容不那么拥挤，我们可以给单元格添加一些内边距（`padding`），并设置文本对齐方式：\n\n```css\nth, td {\n  padding: 10px;\n  text-align: left; \u002F* 标题和数据向左对齐 *\u002F\n}\n```\n\n为了提高可读性，有些网站经常会制作“斑马条纹”表格，即奇数行和偶数行背景色不同。这可以通过我们前面学习的 `:nth-child` 伪类轻松实现：\n\n```css\ntr:nth-child(even) {\n  background-color: #f2f2f2; \u002F* 偶数行背景变灰 *\u002F\n}\n```\n\n这样，一个美观、易读的现代风格表格就完成了。\n\n### 比例尺寸\n\n在响应式设计中，我们经常需要让一个元素（比如视频或图片容器）保持固定的宽高比，例如 16:9。在过去，这需要一些复杂的 “padding-top hack” 技巧。但现在，CSS 提供了一个非常简单的属性：`aspect-ratio`\n\n`aspect-ratio` 允许你直接定义一个元素的宽高比，比如这里我们插入视频的CSS：\n\n```html\n\u003Cdiv class=\"video-container\">\n  \u003Ciframe src=\"\u002F\u002Fplayer.bilibili.com\u002Fplayer.html?isOutside=true&aid=115083162161828&bvid=BV1sQeEzFEKi&cid=31912692890&p=1\" scrolling=\"no\" border=\"0\" frameborder=\"no\" framespacing=\"0\" allowfullscreen=\"true\">\u003C\u002Fiframe>\n\u003C\u002Fdiv>\n```\n\n```css\n.video-container {\n  width: 80%; \u002F* 宽度自适应 *\u002F\n  aspect-ratio: 16 \u002F 9; \u002F* 宽高比设置为 16:9 *\u002F\n  background-color: #f0f0f0;\n}\n```\n\n这样，无论 `.video-container` 的宽度如何变化，它的高度都会被浏览器自动计算，以始终保持 16:9 的比例。这对于嵌入的视频、图片画廊、产品展示卡片等都非常有用。\n\n你也可以用它来创建正方形：\n\n```css\n.profile-pic {\n  width: 150px;\n  aspect-ratio: 1 \u002F 1; \u002F* 宽高比 1:1，即正方形 *\u002F\n}\n```\n\n只需设置一样的比例即可成为正方形状态。\n\n### 滚动穿透\n\n“滚动穿透”（Scroll Chaining）是一个常见的用户体验问题。想象一个场景：你在一个弹窗（Modal）内部滚动内容，当你滚动到顶部或底部时，如果你继续滚动，背后整个页面的 `\u003Cbody>`也会跟着滚动。这通常不是我们想要的效果。\n\n比如现在我们在页面上创建了一个弹窗：\n\n```html\n\u003Cdiv class=\"dialog-modal\">\n  \u003Cdiv class=\"dialog-card\">\n    沙井啊手动滑稽阿斯加德看哈手机扩大\n    萨达好贱啊圣诞节阿是打卡机阿萨达\n  \u003C\u002Fdiv>\n\u003C\u002Fdiv>\n\u003Cdiv style=\"height: 2000px\">\u003C\u002Fdiv>\n```\n\n```css\n.dialog-modal {\n  position: fixed;\n  top: 0;\n  left: 0;\n  right: 0;\n  bottom: 0;\n  background-color: rgba(0, 0, 0, 0.5);\n\n  .dialog-card {\n    writing-mode: vertical-lr;\n    white-space: nowrap;\n    position: absolute;\n    top: 50%;\n    left: 50%;\n    transform: translate(-50%, -50%);\n    width: 300px;\n    height: 350px;\n    background-color: white;\n    border-radius: 10px;\n    overflow: auto;\n  }\n}\n```\n\n我们会发现，弹窗里面的内容滚动到底部之后，如果继续使用鼠标滚轮，会导致其后面的元素也进行滚动。CSS 提供了 `overscroll-behavior` 属性来解决这个问题，它可以控制当滚动到达内容边界时的行为：\n\n```css\noverscroll-behavior: contain;\n```\n\n`overscroll-behavior` 主要有三个值：\n\n- `auto`：（默认值）滚动会“穿透”到父级元素。\n- `contain`：阻止滚动穿透，将滚动限制在本元素内。\n- `none`：和 `contain` 效果类似，但它还会阻止在边界处的默认滚动效果（如回弹）。\n\n通过在需要独立滚动的容器上设置 `overscroll-behavior: contain;`，你就可以轻松地优化滚动体验，防止页面出现意外的滚动。不过，这种方式并不完美，因为实际上我们在`modal`处滚动式依然可以发生滚动，最好的办法还是利用JS来阻止滚动事件。\n\n### 用户选择\n\n`user-select` 属性用于控制用户是否能够选择（即用鼠标拖蓝高亮）页面上的文本。\n\n在某些场景下，禁用文本选择是很有用的：\n\n- **按钮和图标**：用户点击按钮是为了触发操作，而不是复制按钮上的文字。\n- **自定义UI组件**：在拖拽等交互中，不希望意外选中文本。\n\n`user-select` 的常用值：\n\n- `none`：元素及其子元素内的文本都不能被选择。\n- `auto`：（默认值）浏览器根据情况决定，通常文本内容是可选择的。\n- `text`：用户可以自由选择文本。\n- `all`：只需单击一次，即可选中整个元素的所有内容，而不是像平常一样只选中一个词或一个字母。这在代码块等场景中非常方便。\n\n例如，你可以给代码块设置 `user-select: all;`，让用户可以一键复制全部代码。\n\n### 浏览器私有前缀\n\n我们在编写CSS样式时，经常看到诸如 -webkit-、-moz- 这类前缀，实际上这种写法叫做 **浏览器私有前缀（Vendor Prefix）**主要用于 **CSS 属性、值或函数在标准尚未完全确定时**，让不同浏览器先行实现和测试新特性。不同的浏览器有不同的私有前缀：\n\n| **前缀** | **对应浏览器内核 \u002F 浏览器**                           |\n| -------- | ----------------------------------------------------- |\n| -webkit- | WebKit \u002F Blink：Chrome、Safari、新版 Edge、iOS 浏览器 |\n| -moz-    | Gecko：Firefox                                        |\n| -ms-     | Trident \u002F EdgeHTML：IE、老版 Edge                     |\n| -o-      | Presto：老版 Opera（已淘汰）                          |\n\n浏览器在规范稳定前，会用前缀避免将来 API 变动造成破坏，比如有些属性可以像这样写：\n\n```css\n.box {\n  -webkit-user-select: none;\n  -moz-user-select: none;\n  user-select: none;\n}\n```\n\n这在一些老旧的浏览器中非常有效，因为某些特性可能还尚未正式添加，需要添加特殊前缀才能正确启用，老版本浏览器只识别带前缀的写法。\n\n不过，随着前端技术的不断完善，到目前来说已经不需要大家手动去添加这些前缀了，我们后续会学习的一些CSS处理器会在编译时自动帮我们添加对应带前缀的属性。\n\n### 性能优化\n\n`will-change` 属性可以提前告知浏览器，某个元素将要发生什么样的变化，这样浏览器就可以在元素真正发生变化之前，提前做好优化准备。当变化实际发生时，整个过程会更加流畅、快速，从而提升页面的渲染性能。这非常适合页面中存在一些过渡动画的情况。\n\n简单来说，当你对一个元素使用了 `will-change`，浏览器会为这个元素创建一个独立的渲染层（也称为“合成层”）。之后，涉及这个元素的变化（如 `transform`, `opacity`）将在这个独立的层上进行，而不会影响或重绘页面上的其他部分。这个过程通常由GPU（图形处理器）来加速，因此效率非常高。\n\n以下是一些适合使用 `will-change` 的场景：\n\n| 场景               | 示例代码                                                | 说明                                                         |\n| ------------------ | ------------------------------------------------------- | ------------------------------------------------------------ |\n| **鼠标悬停效果**   | `.element:hover { will-change: transform; }`            | 当鼠标悬停在一个元素上，准备触发一个transform动画时，可以提前通知浏览器。 |\n| **动态变化的元素** | `.sliding-element { will-change: transform, opacity; }` | 对于即将通过JavaScript进行位移或透明度变化的元素，比如一个轮播图的滑动项。 |\n| **动画状态**       | `.element.animating { will-change: transform; }`        | 当通过添加一个class来启动CSS动画时，可以在该class中加入 `will-change`。 |\n\n`will-change` 虽好，但不能滥用，过度使用会消耗过多内存，反而可能导致页面变慢甚至崩溃。\n\n你可以指定一个或多个你期望变化的CSS属性：\n\n- `transform`: 表示元素的几何变换即将发生。\n- `opacity`: 表示元素的透明度即将发生变化。\n- `scroll-position`: 表示元素的滚动位置即将发生变化（常用于可滚动容器）。\n- `contents`: 表示元素的内容即将发生变化。\n- `auto`: 这是默认值，表示浏览器不进行任何特殊的提前优化\n\n总而言之，`will-change` 是一个强大的性能优化工具，但需要像手术刀一样精确地使用。\n\n## 本章练习\n\n### 选择题\n\n**1. 关于 `max-width` 和 `min-width` 属性，下列说法错误的是？**\nA. `max-width` 用于设置元素的最大宽度，当浏览器窗口小于该值时，元素宽度会自适应缩小。\nB. `min-width` 用于设置元素的最小宽度，即使内容很少，宽度也不会低于此值。\nC. 如果同时设置了 `width: 80%` 和 `max-width: 500px`，当父容器宽度为 1000px 时，该元素宽度为 800px。\nD. 这些属性常用于响应式布局，防止元素在不同屏幕尺寸下过度变形。\n\n**2. 关于 CSS 轮廓（outline）与边框（border）的区别，描述正确的是？**\nA. `outline` 会占据盒子的空间，从而影响由于布局。\nB. `outline` 总是绘制在 `border` 的内部。\nC. `outline` 不占据空间，绘制在边框之外，可能会遮挡外部其他元素。\nD. `outline` 不能像 `border` 一样设置颜色和样式。\n\n**3. 在使用 `box-shadow` 设置阴影时，如果希望阴影显示在盒子内部（内阴影），需要添加哪个关键字？**\nA. `inside`\nB. `inset`\nC. `inner`\nD. `internal`\n\n**4. 行内元素的 `vertical-align` 属性默认对齐方式是？**\nA. `top` (顶线对齐)\nB. `middle` (中线对齐)\nC. `bottom` (底线对齐)\nD. `baseline` (基线对齐)\n\n**5. 下列关于“精灵图（Sprites）”的优点，描述最准确的是？**\nA. 可以让图片在网页上自动旋转和缩放。\nB. 通过将多张小图合并为一张大图，减少 HTTP 请求数量，加快页面加载速度。\nC. 可以直接在 CSS 中修改图片的颜色和分辨率。\nD. 是为了让图片具有 3D 效果。\n\n**6. 若要实现一个从左到右的红色到黄色的线性渐变背景，正确的写法是？**\nA. `background-image: linear-gradient(to right, red, yellow);`\nB. `background-image: linear-gradient(to left, red, yellow);`\nC. `background-image: linear-gradient(red, yellow);`\nD. `background-image: radial-gradient(circle, red, yellow);`\n\n**7. 想要给一个透明背景的 PNG 图片添加符合其不规则形状的投影，应该使用哪个属性？**\nA. `box-shadow`\nB. `filter: blur()`\nC. `filter: drop-shadow()`\nD. `text-shadow`\n\n**8. 关于 CSS3 的二维变换 `transform: translate(10px, 20px)`，下列说法正确的是？**\nA. 元素会在文档流中真正移动，原本的位置会被其他元素占据。\nB. 元素只是视觉上发生了偏移，原本占据的空间依然保留，不脱离文档流。\nC. 该属性只能用于块级元素，行内元素无效。\nD. 它是通过修改 `margin` 值来实现移动的。\n\n**9. 在制作 3D 翻转卡片时，为了让子元素在旋转时保持其 3D 立体空间（而不是扁平化贴在父元素上），需要在父元素上设置什么属性？**\nA. `perspective: 1000px;`\nB. `transform: rotateY(180deg);`\nC. `transform-style: preserve-3d;`\nD. `backface-visibility: hidden;`\n\n**10. 为什么给元素的 `height` 属性设置 `transition` 过渡效果时，从 `0px` 变到 `auto` 不会产生动画？**\nA. 因为 `height` 属性不支持过渡效果。\nB. 因为 `auto` 是一个不确定的计算值，浏览器无法计算中间状态。\nC. 因为必须配合 `width` 属性一起变化。\nD. 因为过渡时间设置得太短了。\n\n**11. 使用 `calc()` 函数进行计算时，下列写法正确的是？**\nA. `width: calc(100%-20px);`\nB. `width: calc(100% - 20px);`\nC. `width: calc(100% +20px);`\nD. `width: calc(100%* 20px);`\n\n**12. 在 CSS 中定义变量（自定义属性）时，变量名必须以什么开头？**\nA. `$` (例如 `$main-color`)\nB. `@` (例如 `@main-color`)\nC. `--` (例如 `--main-color`)\nD. `var-` (例如 `var-main-color`)\n\n**13. 如果希望一个 CSS 动画无限次循环播放，应该将 `animation-iteration-count` 属性设置为哪个值？**\nA. `loop`\nB. `always`\nC. `infinite`\nD. `100%`\n\n**14. 为了检测用户系统是否开启了深色模式（Dark Mode），应该使用哪个媒体查询特性？**\nA. `(theme: dark)`\nB. `(prefers-color-scheme: dark)`\nC. `(display-mode: dark)`\nD. `(system-color: dark)`\n\n**15. 如何使用 `aspect-ratio` 属性创建一个宽高比为 4:3 的容器？**\nA. `aspect-ratio: 4 by 3;`\nB. `aspect-ratio: 4, 3;`\nC. `aspect-ratio: 4:3;`\nD. `aspect-ratio: 4 \u002F 3;`\n\n**16. 根据 CSS 层叠层（`@layer`）的优先级规则，在不使用 `!important` 的情况下，下列哪个样式的优先级最高？**\nA. 先声明的 `@layer` 中的样式。\nB. 后声明的 `@layer` 中的样式。\nC. 未分层的普通样式。\nD. `:root` 中定义的样式。\n\n**17. 为了防止在一个弹窗内部滚动到底部时，导致整个页面背景跟着滚动（即“滚动穿透”），可以在该弹窗容器上使用哪个 CSS 属性？**\nA. `overflow: hidden;`\nB. `scroll-snap-type: y mandatory;`\nC. `overscroll-behavior: contain;`\nD. `user-select: none;`","上一章我们介绍了盒子模型和布局相关知识点，并且为大家扩展了更多类型的选择器，帮助我们更好地调整页面样式。这一章我们将继续深入介绍CSS3的更多内容，比如二维、三维变换、函数等。","2025-12-19 23:11:58",{"data":468,"status":460,"success":461},[469,474],{"id":8,"image":470,"link":471,"name":472,"type":473},"\u002Fimage\u002Fadv\u002Frainyun-2025-06.webp","https:\u002F\u002Fwww.rainyun.com\u002Fitbaima_","雨云优惠购","cloud",{"id":66,"image":475,"link":476,"name":477,"type":478},"\u002Fimage\u002Fadv\u002Fsimcard-2025-11.webp","https:\u002F\u002Fmall.itbaima.cn","号卡优惠","simcard"]