十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

HTML+CSS+JS创意交互:视觉错觉按钮与聚光灯解密实现

HTML+CSS+JS创意交互:视觉错觉按钮与聚光灯解密实现 1. 项目概述从“好玩”的代码中重新认识HTML最近在整理旧项目时翻出了两个我早年写的、现在看来依然觉得挺有意思的HTML代码片段。它们不是什么复杂的框架应用也没有用到高深的算法就是纯粹的、朴素的HTML加上一点点CSS和JavaScript的“魔法”。我之所以想分享出来是因为我觉得在当下这个前端框架百花齐放的时代我们偶尔也需要回归到最基础的Web三剑客HTML、CSS、JS本身去看看它们能玩出什么花样。这两个例子一个关乎视觉呈现的“障眼法”另一个则是与用户交互的“小机关”它们能很好地说明即使是最基础的语法只要思路打开也能创造出令人会心一笑的效果。很多人对HTML的印象可能还停留在“标签语言”、“结构骨架”上觉得它枯燥、刻板。但事实上HTML是承载Web内容的画布CSS是画笔和颜料而JavaScript则是让画作动起来的灵魂。三者结合其表现力远超想象。今天分享的这两个“好玩”的代码正是这种结合的小小体现。它们适合所有对Web前端感兴趣的朋友无论是刚入门的新手想找点乐子激发兴趣还是有一定经验的开发者想重温基础技术的魅力都能从中获得一些启发。接下来我们就直接进入正题看看这两个小玩意儿到底是什么以及它们是如何工作的。2. 第一个好玩的代码视觉错觉之“永远点不到的按钮”这个例子我称之为“视觉错觉按钮”。它的效果是页面上有一个看起来非常普通的按钮上面写着“点我试试”。但无论你怎么移动鼠标去点击按钮总会“狡猾”地躲开你的光标让你永远无法真正点到它。这听起来有点无厘头但实现原理却非常简单主要利用了CSS的:hover伪类和一点JavaScript的动态计算。2.1 核心思路与原理拆解这个效果的核心在于“预判”。它不是让按钮在鼠标点击的瞬间才闪避那样需要极高的响应速度且不自然。我们的策略是让按钮实时感知鼠标的接近并在鼠标进入其“危险范围”时就提前向反方向移动。监听鼠标移动通过JavaScript监听整个文档document或按钮容器区域的mousemove事件实时获取鼠标当前的坐标(clientX, clientY)。计算“威胁”方向将按钮视为一个矩形计算出其中心点坐标。比较鼠标坐标和按钮中心点坐标就能得到一个从中心指向鼠标的向量。这个向量的方向就是鼠标“威胁”来袭的方向。反向位移既然知道了威胁来自哪个方向我们就让按钮朝相反方向移动一段距离。这个移动通过动态修改按钮元素的CSStransform: translate(x, y)属性来实现。设置安全距离我们还需要定义一个“激活半径”。只有当鼠标与按钮中心的距离小于这个半径时按钮才开始逃跑。否则按钮应保持在原位避免过度敏感。这里的关键在于移动的计算需要平滑且带有一定的“惯性”或“随机性”让躲避动作看起来更自然、更像一个调皮的生物而不是一个生硬的机械运动。2.2 完整代码实现与逐行解析下面就是完整的HTML文件代码你可以直接复制保存为一个.html文件用浏览器打开体验。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title永远点不到的按钮/title style body { margin: 0; height: 100vh; display: flex; justify-content: center; align-items: center; background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); font-family: Segoe UI, Tahoma, Geneva, Verdana, sans-serif; overflow: hidden; /* 防止按钮跑出视口导致滚动条出现 */ } #escapeButton { padding: 20px 40px; font-size: 1.5rem; color: white; background: linear-gradient(to right, #ff416c, #ff4b2b); border: none; border-radius: 50px; cursor: pointer; /* 虽然点不到但样子要做足 */ box-shadow: 0 10px 20px rgba(255, 65, 108, 0.3); transition: transform 0.2s ease-out; /* 给移动加上平滑过渡 */ position: absolute; /* 使用绝对定位以便于通过transform移动 */ user-select: none; /* 防止文字被选中 */ } #message { position: absolute; bottom: 20%; color: #666; font-size: 0.9rem; } /style /head body button idescapeButton点我试试/button div idmessage提示试着快速移动鼠标或者从角落突击/div script const button document.getElementById(escapeButton); const message document.getElementById(message); // 定义按钮的“敏感半径”单位像素。鼠标进入此范围按钮开始逃跑。 const runAwayRadius 150; // 定义按钮每次逃跑的基础距离 const baseRunDistance 50; // 获取视口浏览器可视区域的宽高 const viewportWidth window.innerWidth; const viewportHeight window.innerHeight; // 初始将按钮放置在视口中央 button.style.left 50%; button.style.top 50%; button.style.transform translate(-50%, -50%); // 监听整个文档的鼠标移动事件 document.addEventListener(mousemove, (e) { // 获取按钮当前的视觉位置考虑transform后的位置 const buttonRect button.getBoundingClientRect(); const buttonCenterX buttonRect.left buttonRect.width / 2; const buttonCenterY buttonRect.top buttonRect.height / 2; // 计算鼠标与按钮中心的距离 const deltaX e.clientX - buttonCenterX; const deltaY e.clientY - buttonCenterY; const distance Math.sqrt(deltaX * deltaX deltaY * deltaY); // 如果鼠标在敏感半径之外按钮不动 if (distance runAwayRadius) { // 可以添加一个缓慢回归原位的效果这里为了简单先不做 return; } // 鼠标进入危险区域计算逃跑方向与鼠标方向相反 // 计算单位向量方向 const dirX deltaX / distance; const dirY deltaY / distance; // 逃跑方向取反 const runDirX -dirX; const runDirY -dirY; // 计算逃跑距离距离越近跑得越远增加紧张感并加上一点随机扰动 const runDistance baseRunDistance * (1 (runAwayRadius - distance) / runAwayRadius) Math.random() * 10; // 计算目标位移 const targetTranslateX runDirX * runDistance; const targetTranslateY runDirY * runDistance; // 应用位移。注意我们是在按钮初始位置视口中心的基础上进行transform移动。 // 因此新的位置是相对于其初始定位点left:50%, top:50%的偏移。 button.style.transform translate(calc(-50% ${targetTranslateX}px), calc(-50% ${targetTranslateY}px)); // 动态更新提示信息增加趣味性 const taunts [ “哈哈差一点”, “你追不上我的~”, “左边不对是右边”, “我的身法如何”, “要不要放弃” ]; message.textContent taunts[Math.floor(Math.random() * taunts.length)]; }); // 给按钮一个“万一”被点到的反应虽然很难 button.addEventListener(click, () { button.textContent “怎么可能”; button.style.background “linear-gradient(to right, #00b09b, #96c93d)”; message.textContent “恭喜你这需要极大的运气和极快的速度”; // 移除鼠标移动监听让按钮停下来 document.removeEventListener(mousemove, arguments.callee); }); /script /body /html代码关键点解析CSS部分 (style)body样式设置了全屏居中布局和渐变背景营造一个干净的舞台。#escapeButton的样式精心设计使其看起来像一个诱人的、可点击的按钮圆角、渐变、阴影。position: absolute和transition: transform 0.2s ease-out是实现动态移动的关键。绝对定位使其脱离文档流方便用transform自由移动过渡属性让移动过程平滑。overflow: hidden是为了防止按钮跑出屏幕外导致出现滚动条破坏体验。JavaScript部分 (script)getBoundingClientRect()这个方法返回元素的大小及其相对于视口的位置。这是我们获取按钮实时屏幕坐标的核心API。距离计算Math.sqrt(deltaX * deltaX deltaY * deltaY)是计算两点间直线距离的公式勾股定理。向量与单位向量(deltaX, deltaY)是从按钮中心指向鼠标的向量。将其除以长度distance得到的就是单位向量(dirX, dirY)它只表示方向长度为1。反向单位向量(-dirX, -dirY)就是逃跑方向。动态逃跑距离baseRunDistance * (1 (runAwayRadius - distance) / runAwayRadius)这个公式确保了鼠标离按钮越近按钮就跑得越远紧张感和趣味性更强。Math.random() * 10增加了一点不可预测性。Transform的应用translate(calc(-50% ${targetTranslateX}px), calc(-50% ${targetTranslateY}px))是精髓。-50%是为了抵消按钮自身left:50%; top:50%带来的偏移使其中心点对准定位点后面的px值则是我们计算出的逃跑偏移量。事件监听器的移除在按钮的click事件中我们移除了mousemove的事件监听示例中用了arguments.callee在实际开发中更推荐使用函数名引用让按钮在被“捕获”后停止逃跑。2.3 优化技巧与扩展思路这个基础版本已经很有趣了但你还可以让它更好玩边界检测与反弹目前按钮可能会“卡”在视口边缘。你可以添加逻辑当按钮预测的新位置超出视口边界时让它朝反方向或随机方向逃跑模拟“碰壁回头”的效果。移动轨迹算法现在的逃跑是直线远离。可以引入更复杂的算法比如让按钮像游戏里的AI一样进行“之”字形移动加入垂直于威胁方向的位移或者有“体力”设定逃跑一段时间后会减速。多人“围捕”模式这是一个更高级的扩展。想象一下页面上有多个代表不同玩家的光标可以通过WebSocket实现多端同步按钮需要同时躲避所有光标的接近其移动策略会变成一个有趣的算法问题如朝着威胁合力最小的方向移动。视觉反馈增强当鼠标靠近时按钮可以变大紧张、变色警告或者留下残影增强动态效果。注意这个效果非常消耗性能因为它需要在鼠标每一次移动事件触发频率极高时进行大量的计算距离、向量、样式更新。在实际网站中应谨慎使用或加入防抖debounce逻辑限制计算频率。但作为一个“好玩”的演示它完美地展示了DOM操作和基础数学的结合。3. 第二个好玩的代码交互叙事之“密室解密纸条”第二个例子偏向交互叙事。它模拟了一个经典的密室逃脱或侦探游戏中的场景你得到一张经过处理的“加密”纸条比如被涂黑、被火烧过一部分你需要与它互动比如在上面移动鼠标作为“灯光”照射或者用“化学药水”涂抹来揭示隐藏的信息。这里我们实现一个鼠标作为聚光灯照亮隐藏文字的效果。3.1 核心思路与原理拆解这个效果的核心是蒙版Mask和混合模式Blend Mode的运用。视觉结构我们需要两层内容。底层是完整的、清晰的“解密后”的文字或图像。上层是一张看起来被污损、涂黑的“加密”图层这个图层完全遮盖了底层。交互揭示我们在上层“加密”图层上创建一个“窥视孔”。这个孔的位置跟随鼠标移动。透过这个孔用户就能看到下层的清晰内容。技术实现实现“窥视孔”有多种CSS方案方案ACSS径向渐变蒙版将上层的background-image设置为一个巨大的径向渐变从中心透明到边缘黑色。然后通过JavaScript动态更新这个渐变的中心点位置为鼠标坐标。这是性能较好、代码较简洁的方案。方案BCanvas动态绘制将上层内容画到Canvas上通过globalCompositeOperation设置混合模式并清除一个圆形区域的像素来显示下层。这种方式更灵活可以做出非圆形的、甚至笔刷效果的揭示但代码更复杂。方案CSVG蒙版使用SVG的mask元素里面包含一个跟随鼠标移动的circle。这是最符合语义且矢量无损的方案。这里我们选择方案ACSS径向渐变蒙版因为它足够实现效果且易于理解和实现与HTML集成度最高。3.2 完整代码实现与逐行解析同样这是一个完整的HTML文件。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title密室解密纸条聚光灯效果/title style body { margin: 0; height: 100vh; display: flex; justify-content: center; align-items: center; background-color: #2c3e50; /* 深色背景模拟昏暗环境 */ font-family: ‘Georgia’, ‘SimSun’, serif; /* 使用衬线字体增加复古感 */ cursor: none; /* 隐藏默认鼠标指针增强沉浸感 */ } .decryption-note { position: relative; width: 80vw; max-width: 600px; height: 60vh; border-radius: 8px; overflow: hidden; /* 确保内部元素不溢出 */ box-shadow: 0 15px 35px rgba(0, 0, 0, 0.5); } /* 下层解密后的清晰内容 */ .revealed-content { position: absolute; width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 40px; box-sizing: border-box; background-color: #ecf0f1; /* 羊皮纸或旧纸张的颜色 */ color: #2c3e50; text-align: center; z-index: 1; } .revealed-content h1 { font-size: 2.2rem; margin-bottom: 20px; border-bottom: 2px solid #8e44ad; padding-bottom: 10px; } .revealed-content p { font-size: 1.2rem; line-height: 1.8; margin-bottom: 15px; } /* 上层被污损的加密层 */ .obscured-layer { position: absolute; width: 100%; height: 100%; /* 关键背景是黑色但中心有一个圆形透明区域作为“聚光灯” */ /* 初始聚光灯在中心半径为80px */ background: radial-gradient(circle 80px at center, transparent 0%, rgba(0, 0, 0, 0.95) 100%); /* 添加一些纹理模拟烧焦、污渍效果 */ background-image: radial-gradient(circle at 20% 30%, rgba(139, 69, 19, 0.4) 2px, transparent 3px), radial-gradient(circle at 70% 80%, rgba(128, 128, 128, 0.3) 1px, transparent 2px); background-size: 200px 200px, 150px 150px; z-index: 2; pointer-events: none; /* 让鼠标事件穿透此层直接作用于底层文档以便监听document的mousemove */ } /* 自定义的聚光灯光标 */ .spotlight-cursor { position: absolute; width: 160px; /* 与渐变中圆形直径匹配 */ height: 160px; border: 2px solid rgba(255, 255, 255, 0.7); border-radius: 50%; box-shadow: 0 0 20px 5px rgba(255, 215, 0, 0.7); /* 金色光晕 */ pointer-events: none; z-index: 3; transform: translate(-50%, -50%); /* 使光标中心对准鼠标位置 */ transition: transform 0.05s ease-out; /* 轻微的跟随延迟模拟真实灯光惯性 */ } .instructions { position: absolute; bottom: 20px; width: 100%; text-align: center; color: #bdc3c7; font-size: 0.9rem; z-index: 4; } /style /head body div class“decryption-note” div class“revealed-content” h1藏宝图的秘密/h1 p当月光照亮第三座石像的左眼/p p影子指向的橡树下/p p往东走七步再向北三步。/p p记住真正的财富不是金银/p p而是你一路追寻的勇气与智慧。/p p—— 探险家“夜风” 留/p /div div class“obscured-layer” id“obscuredLayer”/div div class“spotlight-cursor” id“spotlightCursor”/div div class“instructions”移动鼠标用“聚光灯”照亮隐藏的信息.../div /div script const obscuredLayer document.getElementById(‘obscuredLayer’); const spotlightCursor document.getElementById(‘spotlightCursor’); const noteElement document.querySelector(‘.decryption-note’); // 聚光灯半径 const spotlightRadius 80; // 获取纸条元素的位置信息用于坐标转换 const noteRect noteElement.getBoundingClientRect(); // 监听鼠标在纸条区域上的移动 noteElement.addEventListener(‘mousemove’, (e) { // 计算鼠标相对于纸条左上角的坐标 const x e.clientX - noteRect.left; const y e.clientY - noteRect.top; // 1. 更新污损层的渐变中心点 // 语法radial-gradient(circle [半径] at [x] [y], ...) obscuredLayer.style.background radial-gradient(circle ${spotlightRadius}px at ${x}px ${y}px, transparent 0%, rgba(0, 0, 0, 0.95) 80%), radial-gradient(circle at 20% 30%, rgba(139, 69, 19, 0.4) 2px, transparent 3px), radial-gradient(circle at 70% 80%, rgba(128, 128, 128, 0.3) 1px, transparent 2px) ; // 2. 更新自定义光标位置 spotlightCursor.style.left ${x}px; spotlightCursor.style.top ${y}px; }); // 当鼠标移出纸条区域将聚光灯重置到中心或隐藏 noteElement.addEventListener(‘mouseleave’, () { const centerX noteRect.width / 2; const centerY noteRect.height / 2; obscuredLayer.style.background radial-gradient(circle ${spotlightRadius}px at ${centerX}px ${centerY}px, transparent 0%, rgba(0, 0, 0, 0.95) 80%), radial-gradient(circle at 20% 30%, rgba(139, 69, 19, 0.4) 2px, transparent 3px), radial-gradient(circle at 70% 80%, rgba(128, 128, 128, 0.3) 1px, transparent 2px) ; spotlightCursor.style.left ${centerX}px; spotlightCursor.style.top ${centerY}px; }); // 窗口大小变化时重新获取纸条的位置信息 window.addEventListener(‘resize’, () { const newRect noteElement.getBoundingClientRect(); noteRect newRect; // 注意这里直接修改了const变量在实际复杂项目中应避免。此处为简化。 }); /script /body /html代码关键点解析CSS部分.obscured-layer的background属性是核心。我们使用了多重背景。第一层是一个径向渐变radial-gradient(circle 80px at center, transparent 0%, rgba(0,0,0,0.95) 100%)它定义了一个中心透明、边缘黑色的圆形区域这就是“聚光灯”的光斑。at center定义了中心点位置这个值将通过JS动态更新。后面两个径向渐变是叠加的静态纹理模拟污渍。pointer-events: none让污损层不拦截鼠标事件这样mousemove事件才能被下层的.decryption-note或document捕获到。.spotlight-cursor是一个自定义的光标通过绝对定位和transform: translate(-50%, -50%)使其中心点与鼠标对齐并添加了光晕效果增强视觉反馈。JavaScript部分getBoundingClientRect()再次出场用于获取纸条容器相对于视口的精确位置。坐标转换e.clientX和e.clientY是鼠标相对于整个浏览器视口的坐标。我们需要将其转换为相对于纸条容器左上角的坐标计算方法是clientX - elementRect.left。动态更新背景通过JS修改obscuredLayer.style.background我们实时重写了径向渐变的at ${x}px ${y}px部分让透明中心点跟随鼠标移动。多重背景的维护在更新时我们必须完整地重写整个background属性包括后面模拟污渍的静态渐变层否则它们会被覆盖掉。这就是为什么我们在JS中拼接字符串时把三层渐变都写上了。3.3 优化技巧与扩展思路这个聚光灯效果本身已经很有沉浸感了但还有巨大的扩展空间多种解密工具不仅仅是聚光灯。可以模拟“显影药水”点击后被点击的区域会永久性地、缓慢地显现文字通过改变该区域污损层的透明度。或者模拟“火烤”文字会从鼠标位置像被火燎过一样逐渐显现。Canvas高级效果使用Canvas可以实现更炫酷的效果。比如聚光灯的光斑边缘可以是毛茸茸的、不均匀的揭示区域可以不是圆形而是像真正的手电筒一样有光束形状甚至可以实现“刮刮乐”效果鼠标按下拖动时像刮涂层一样显示下方内容。叙事结合将这个小工具嵌入一个完整的互动故事中。例如玩家需要在房间里找到“电池”才能打开这个“紫外线灯”聚光灯或者需要收集“化学试剂”来调配显影药水。解密出的文字是推动剧情的关键线索。移动端适配在手机上可以将交互方式从鼠标移动改为触摸移动。但需要注意触摸事件没有“悬停”状态需要处理touchmove事件并可能需要在解密区域周围添加操作指引。性能优化频繁更新CSS的background属性尤其是复杂的渐变可能引发重绘。如果感觉卡顿可以尝试使用requestAnimationFrame来节流更新或者探索使用CSS自定义属性--mouse-x,--mouse-y配合property注册让浏览器更高效地处理动画。注意这个效果的关键在于坐标系的转换一定要准确。如果发现聚光灯位置偏移十有八九是坐标计算出了问题。务必分清clientX/Y、pageX/Y、offsetX/Y的区别并清楚getBoundingClientRect()返回的是相对于视口的位置。4. 从“好玩”到“好用”代码背后的通用技术与思考分享了两个具体的例子我们不妨跳出来看看它们背后共通的、可以复用到其他正经开发中的技术和思路。4.1 核心技术点提炼DOM元素位置与几何学两个例子都重度依赖getBoundingClientRect()和鼠标事件坐标。这是实现任何与视图位置相关交互的基础。你必须熟练掌握视口坐标、文档坐标、元素自身坐标之间的转换关系。CSS Transform 与性能第一个例子用transform: translate()来移动按钮。为什么不用top/left因为transform的变更通常由浏览器的合成器线程处理不一定会触发重排Layout和重绘Paint性能更好。在实现动画和频繁位置更新时这是首选方案。CSS 渐变与混合模式的创意应用第二个例子展示了如何用radial-gradient动态创建视觉孔洞。CSS渐变不仅仅是背景色过渡它可以用来生成复杂的图案、纹理和遮罩。结合mix-blend-mode、background-blend-mode还能创造出更惊艳的视觉效果。事件驱动编程mousemove、click、mouseleave等事件是交互的源泉。写好事件处理函数注意性能防抖/节流、注意内存及时移除无用监听器、注意事件冒泡与委托是前端工程师的基本功。状态管理与视觉反馈好的交互一定有即时的、清晰的视觉反馈。按钮逃跑时的平滑移动、聚光灯的跟随光晕都是反馈。在更复杂的应用中你需要管理好UI状态如“正在解密”、“已解密”并让每个状态都有对应的视觉呈现。4.2 如何构思你自己的“好玩”项目如果你也想创作类似的有趣小项目可以遵循这个思路找到一个简单的“梗”或“概念”比如“会躲的按钮”、“聚光灯解密”、“永远对不准的滑块”、“会吃掉你光标的小怪物”。这个点子要足够简单一句话就能说清。拆解核心交互用户做什么移动鼠标、点击界面如何反应元素移动、样式变化用流程图或伪代码把主逻辑画出来。选择最合适的技术方案用CSS动画还是JS控制用DOM还是Canvas/SVG优先选择你熟悉的、能最快实现原型的技术。第一个版本越简单越好。实现与调试埋头敲代码解决遇到的具体问题比如坐标计算不准、动画卡顿、边界情况处理。打磨与润色加上好看的样式、平滑的过渡、有趣的文案、声音效果如果需要。这是让项目从“能用”到“好玩”的关键一步。分享与获取反馈把它放到网上看看别人的反应。你可能会发现你没想到的玩法或bug。4.3 常见问题与排查技巧在制作这类动态交互效果时你肯定会遇到一些典型问题问题现象可能原因排查与解决思路元素移动卡顿、不跟手1.mousemove事件触发太频繁计算或DOM操作过重。2. 使用了top/left而非transform。3. 浏览器被其他任务阻塞。1. 使用requestAnimationFrame对更新函数进行节流。2. 确保位移使用transform。3. 简化计算或使用 Web Worker 处理复杂运算。4. 用 Chrome DevTools 的 Performance 面板分析性能瓶颈。坐标计算偏移元素位置不对1. 错误理解了坐标系统clientXvspageXvsoffsetX。2. 没有考虑元素边框、内边距或父级元素的定位。1. 统一使用getBoundingClientRect()获取元素位置使用clientX/Y获取鼠标位置并在同一坐标系视口坐标系下计算。2. 在计算相对位置时务必减去父级容器的offsetLeft/Top或getBoundingClientRect().left/top。聚光灯或遮罩边缘有锯齿、不清晰1. CSS渐变在极端情况下可能产生锯齿。2. Canvas绘制时没有平滑处理。1. 对于CSS可以尝试稍微增加渐变半径或使用-webkit-backface-visibility: hidden;等技巧因浏览器而异。2. 对于Canvas设置context.imageSmoothingEnabled true。移动端触摸无效只监听了mousemove事件未监听touchmove事件。同时监听touchmove事件并从e.touches[0].clientX获取触摸点坐标。注意调用e.preventDefault()防止页面滚动。效果在滚动后错位使用了clientX/Y但页面发生了滚动元素的实际视口位置已变而计算逻辑未更新。1. 在scroll事件中重新获取元素的位置信息getBoundingClientRect。2. 或者考虑使用pageX/Y相对于文档的坐标进行计算但这需要与元素的文档坐标进行匹配。最后我想说的是前端开发不仅仅是构建表单、列表和弹窗。它是一片充满创意的沃土。这些“好玩”的代码就像是工作之余的小练习它们能帮你保持对技术的热情锻炼你解决具体问题的能力甚至可能在未来某个正经的项目中这些看似“玩具”的技术会以意想不到的方式派上用场。希望这两个例子和背后的分析能给你带来一些灵感。不妨现在就打开编辑器基于这些思路创造一个属于你自己的、好玩的HTML代码片段吧。
返回列表