找到
54
篇与
Web前端
相关的结果
- 第 5 页
-
HTML+CSS实现太极八卦加载动画 动画效果预览 HTML部分 <html> <head> <meta charset="utf-8"> <title>太极八卦</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="./55-太极八卦.css"> </head> <body> <div class="table"> <div class="table-cell"> <svg width="470px" height="470px" viewBox="0 0 470 470" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <defs> <filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-1"> <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> <feGaussianBlur stdDeviation="25" in="shadowOffsetOuter1" result="shadowBlurOuter1"> </feGaussianBlur> <feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.63 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1"></feColorMatrix> <feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetInner1"></feOffset> <feGaussianBlur stdDeviation="25" in="shadowOffsetInner1" result="shadowBlurInner1"> </feGaussianBlur> <feComposite in="shadowBlurInner1" in2="SourceAlpha" operator="arithmetic" k2="-1" k3="1" result="shadowInnerInner1"></feComposite> <feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0" in="shadowInnerInner1" type="matrix" result="shadowMatrixInner1"></feColorMatrix> <feMerge> <feMergeNode in="shadowMatrixOuter1"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> <feMergeNode in="shadowMatrixInner1"></feMergeNode> </feMerge> </filter> <filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-2"> <feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> <feGaussianBlur stdDeviation="22.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"> </feGaussianBlur> <feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.7 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1"></feColorMatrix> <feMerge> <feMergeNode in="shadowMatrixOuter1"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> </feMerge> </filter> <filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-3"> <feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> <feGaussianBlur stdDeviation="20" in="shadowOffsetOuter1" result="shadowBlurOuter1"> </feGaussianBlur> <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.7 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1"></feColorMatrix> <feMerge> <feMergeNode in="shadowMatrixOuter1"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> </feMerge> </filter> <filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-4"> <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> <feGaussianBlur stdDeviation="25" in="shadowOffsetOuter1" result="shadowBlurOuter1"> </feGaussianBlur> <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.63 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1"></feColorMatrix> <feMerge> <feMergeNode in="shadowMatrixOuter1"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> </feMerge> </filter> <filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-5"> <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> <feGaussianBlur stdDeviation="15" in="shadowOffsetOuter1" result="shadowBlurOuter1"> </feGaussianBlur> <feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.23 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1"></feColorMatrix> <feMerge> <feMergeNode in="shadowMatrixOuter1"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> </feMerge> </filter> <filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-6"> <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> <feGaussianBlur stdDeviation="25" in="shadowOffsetOuter1" result="shadowBlurOuter1"> </feGaussianBlur> <feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.63 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1"></feColorMatrix> <feMerge> <feMergeNode in="shadowMatrixOuter1"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> </feMerge> </filter> <filter x="-50%" y="-50%" width="200%" height="200%" filterUnits="objectBoundingBox" id="filter-7"> <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset> <feGaussianBlur stdDeviation="15" in="shadowOffsetOuter1" result="shadowBlurOuter1"> </feGaussianBlur> <feColorMatrix values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.23 0" in="shadowBlurOuter1" type="matrix" result="shadowMatrixOuter1"></feColorMatrix> <feMerge> <feMergeNode in="shadowMatrixOuter1"></feMergeNode> <feMergeNode in="SourceGraphic"></feMergeNode> </feMerge> </filter> </defs> <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> <g id="Artboard-1"> <ellipse id="Oval-1" fill="#485d51" cx="237" cy="228" rx="111" ry="111"></ellipse> <circle id="Oval" fill="#0E7CFE" filter="url(#filter-1)" cx="237" cy="228" r="39"></circle> <path d="M237.737045,228.155741 C206.543902,228.155741 181.166785,253.532859 181.166785,284.726749 C181.166785,312.174294 200.823516,335.102165 226.795386,340.215844 C169.77682,334.873529 125,286.749357 125,228.358226 C125,166.403809 175.404556,116 237.357479,116 C241.130723,116 242.479377,116.122537 242.479377,116.122537 C271.062631,118.710011 293.460007,142.732496 293.460007,171.989704 C293.460007,227.891241 237.737045,228.155741 237.737045,228.155741 L237.737045,228.155741 Z" id="Path1" fill="#FFFFFF" filter="url(#filter-2)"></path> <g id="Group" transform="translate(264.500000, 228.500000) scale(-1, -1) translate(-264.500000, -228.500000) translate(180.000000, 116.000000)" filter="url(#filter-3)" fill="#000000"> <path d="M112.737045,112.155741 C81.5439023,112.155741 56.1667848,137.532859 56.1667848,168.726749 C56.1667848,196.174294 75.8235156,219.102165 101.795386,224.215844 C44.7768195,218.873529 0,170.749357 0,112.358226 C0,50.403809 50.4045562,-2.84217094e-14 112.357479,-2.84217094e-14 C116.130723,-2.84217094e-14 117.479377,0.122537018 117.479377,0.122537018 C146.062631,2.71001075 168.460007,26.7324965 168.460007,55.9897038 C168.460007,111.891241 112.737045,112.155741 112.737045,112.155741 L112.737045,112.155741 Z" id="Path2"></path> </g> <circle id="Oval-3" fill="#000000" filter="url(#filter-4)" cx="164" cy="156" r="39"></circle> <circle id="Oval-3-2" fill="#000000" filter="url(#filter-5)" cx="187" cy="83" r="16"></circle> <circle id="Oval-4" fill="#FFFFFF" filter="url(#filter-6)" cx="309" cy="300" r="39"></circle> <circle id="Oval-4-2" fill="#FFFFFF" filter="url(#filter-7)" cx="286" cy="373" r="16"></circle> </g> </g> </svg> </div> </div> <a class="box-item" href="https://codepen.io/LOverride/" target="_blank"> </a> </body> </html>CSS部分 隐藏内容,请前往内页查看详情
-
2024 年最前沿的 5 大 CSS 功能 | 高级 CSS CSS作为Web设计的基石,一直在不断进化,以应对现代设计的挑战。2024年,CSS引入了一系列令人惊叹的新特性,大大拓展了Web设计的可能性。本文将深入探讨五个最具革命性的CSS新特性,这些特性正在彻底改变前端开发的方式。 1.CSS容器查询(Container Queries) 容器查询允许基于元素的容器大小而非视口来设置样式,这对响应式设计是一个巨大的突破。 示例: 图片 这种方法使得组件级别的响应式设计成为可能,大大提高了代码的可维护性和模块化程度。 2.CSS子网格(Subgrid) 子网格是CSS网格布局的扩展,允许网格项继承其父元素的网格定义。这对于复杂的嵌套布局特别有用。 在 subgrid 出现之前,我一直在为嵌套网格而苦苦挣扎,这往往会导致 CSS 变得复杂冗长。 子网格允许子元素与父网格无缝对齐,从而简化了这一过程。 示例: 图片 子网格简化了复杂布局的创建,减少了冗余代码,提高了网格设计的一致性。 3.@property规则定义的CSS自定义属性 @property规则允许定义具有类型检查、初始值和继承特性的自定义属性(CSS变量)。 示例: 图片 这种方法增强了CSS变量的能力,提供了更多对其行为的控制,确保了它们的正确使用。 4.CSS嵌套 CSS嵌套允许以反映HTML结构的方式嵌套CSS选择器,提高了CSS的可读性和可维护性。 示例: .card { background: white; & .title { color: black; } & .content { font-size: 0.9em; } }这种特性使CSS更加组织化,简化了样式的编写和维护过程,特别是在大型项目中。 5.CSS滚动链接动画 滚动链接动画允许创建响应用户滚动位置的动画,为网站增添了新的交互维度。 示例: @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } } #box { animation: linear fade-in; animation-timeline: scroll(); }这种动画可以使网站更加动态和吸引人,增强用户体验。 结语 2024年的这些CSS新特性为创建更具响应性、组织性和吸引力的Web设计提供了强大的工具。通过在工作流程中incorporate这些前沿特性,开发者可以显著提升项目质量并简化开发过程。 这些新特性不仅提高了开发效率,还开启了Web设计的新可能性。例如,容器查询使得真正的组件级响应式设计成为现实,而滚动链接动画则为用户交互带来了新的维度。随着这些特性的广泛采用,Web开发的未来将更加灵活、高效且富有创意。 掌握这些新特性,将有助于开发者在不断演进的Web开发世界中保持领先地位。通过实践和探索这些新工具,开发者可以创造出更加动态、响应迅速且视觉吸引的Web体验。
-
JavaScript代码的简洁之道 1、条件判断赋值布尔值 不推荐: if (a === 'a') { b = true; } else { b = false; }推荐: b = a === 'a';通过直接将条件判断的结果赋值给变量,可以简化代码,提高可读性。 2、使用三元运算符 不推荐: if (a > b) { c = a; } else { c = b; }推荐: c = a > b ? a : b;三元运算符是处理简单条件赋值的一种更简洁的方式。 3、合并重复的代码块 不推荐: function processValue(value) { if (value > 10) { console.log('Value is greater than 10'); // 其他操作 } else { console.log('Value is 10 or less'); // 其他操作 } // 重复的代码块 performAdditionalOperations(); }推荐: function processValue(value) { console.log(value > 10 ? 'Value is greater than 10' : 'Value is 10 or less'); performAdditionalOperations(); }将重复的代码块提取到条件判断之外,可以减少不必要的重复,提高代码的可读性。 4、使用数组方法代替循环 不推荐: let sum = 0; for (let i = 0; i < numbers.length; i++) { sum += numbers[i]; }推荐: let sum = numbers.reduce((acc, num) => acc + num, 0);使用数组的内置方法(如 reduce 、map 、filter 等)可以简化代码,同时提高性能,因为这些方法通常被高度优化。 5、使用模板字符串 不推荐: let greeting = 'Hello, ' + name + '!';推荐: let greeting = `Hello, ${name}!`;模板字符串(使用反引号 ` )允许嵌入变量和表达式,使字符串拼接更加简洁和直观。 6、避免不必要的全局变量 不推荐: let counter = 0; function incrementCounter() { counter++; }推荐: function createCounter() { let counter = 0; return { increment: function() { counter++; }, getValue: function() { return counter; } }; } let counterInstance = createCounter(); counterInstance.increment();通过模块或闭包来封装变量,可以避免全局命名空间的污染,提高代码的封装性和可维护性。 7、使用解构赋值 不推荐: let data = { name: 'Alice', age: 25 }; let name = data.name; let age = data.age;推荐: let { name, age } = data;解构赋值可以方便地提取对象中的属性,使代码更加简洁。 8、提前终止循环 不推荐: for (let i = 0; i < array.length; i++) { if (array[i] === target) { found = true; break; } }推荐: let found = array.includes(target);如果不需要在循环中执行其他操作,直接使用数组的内置方法(如 includes )可以提前终止搜索,提高性能。 9、使用箭头函数 不推荐: function add(a, b) { return a + b; }推荐: const add = (a, b) => a + b;箭头函数不仅语法简洁,还能避免 this 绑定的问题,使代码更加清晰。 10、避免使用 with 语句 不推荐: with (obj) { console.log(name); console.log(age); }推荐: console.log(obj.name); console.log(obj.age);with 语句会使代码难以优化,并可能导致性能问题,因此应避免使用。 11、使用 let 和 const 代替 var 不推荐: var count = 0;推荐: let count = 0; // 对于需要重新赋值的变量 const MAX_COUNT = 100; // 对于不需要重新赋值的常量let 和 const 提供了块级作用域(block scope),避免了 var 带来的函数级作用域(function scope)问题,使得代码更加清晰和可预测。 12、避免内联样式和脚本 不推荐: <div style="color: red;">This is red text</div> <script> console.log('Inline script'); </script>推荐: <link rel="stylesheet" href="styles.css"> <script src="script.js"></script>在HTML中,尽量将样式和脚本分离到外部文件,这有助于代码的组织和维护,同时也可能提高加载性能。 13、使用对象字面量进行属性赋值 不推荐: let obj = new Object(); obj.name = 'Alice'; obj.age = 25;推荐: let obj = { name: 'Alice', age: 25 };对象字面量语法更加简洁,易于阅读。 14、使用短路逻辑 不推荐: if (condition1) { doSomething(); } else if (!condition1 && condition2) { doSomethingElse(); }推荐: if (condition1) { doSomething(); } else if (condition2) { // 这里的!condition1已经被短路逻辑隐含 doSomethingElse(); }在第二个条件中,由于 else if 已经隐含了 !condition1 ,因此可以省略这部分判断,提高代码的可读性。不过,要注意这种优化仅在逻辑上确实可行时才进行。 15、避免不必要的计算 不推荐: for (let i = 0; i < array.length; i++) { // 每次循环都计算array.length console.log(array[i]); }推荐: for (let i = 0, len = array.length; i < len; i++) { console.log(array[i]); }将数组长度存储在一个变量中,避免在每次循环迭代时都重新计算它,这可以提高性能,尤其是在处理大型数组时。 16、使用 Object.assign 进行浅拷贝 不推荐: let newObj = {}; for (let key in oldObj) { if (oldObj.hasOwnProperty(key)) { newObj[key] = oldObj[key]; } }推荐: let newObj = Object.assign({}, oldObj);Object.assign 提供了一种更简洁和高效的方法来创建对象的浅拷贝。 17、使用默认参数和剩余参数 不推荐: function add(a, b) { b = b || 0; return a + b; } function sum() { let args = Array.prototype.slice.call(arguments); return args.reduce((acc, num) => acc + num, 0); }推荐: function add(a, b = 0) { return a + b; } function sum(...args) { return args.reduce((acc, num) => acc + num, 0); }默认参数和剩余参数是ES6中引入的语法糖,它们使得函数定义更加清晰和灵活。 18、避免魔法数字 不推荐: function calculateDiscount(price, discountRate) { return price * (1 - discountRate / 100); } // 调用时 let finalPrice = calculateDiscount(100, 20);推荐: const DISCOUNT_RATE_PERCENTAGE = 100; function calculateDiscount(price, discountRate) { return price * (1 - discountRate / DISCOUNT_RATE_PERCENTAGE); } // 或者使用命名参数 function calculateDiscount(price, discountPercentage) { return price * (1 - discountPercentage / DISCOUNT_RATE_PERCENTAGE); } // 调用时 let finalPrice = calculateDiscount(100, 20);通过定义常量或使用命名参数,可以避免在代码中使用难以理解的魔法数字,提高代码的可读性。 这些优化技巧可以帮助你编写出更加简洁、高效和可维护的JavaScript代码。记住,优化是一个持续的过程,随着你对语言和框架的深入理解,你会找到更多适合自己的优化方法。 我们继续深入讨论JavaScript代码优化的其他策略和最佳实践。 19、使用模板字符串 不推荐: let greeting = 'Hello, ' + name + '!';推荐: let greeting = `Hello, ${name}!`;模板字符串(Template Literals)允许你嵌入变量和表达式,使字符串拼接更加直观和易读。 20、使用解构赋值 不推荐: function getPersonInfo() { return { firstName: 'John', lastName: 'Doe' }; } let info = getPersonInfo(); let firstName = info.firstName; let lastName = info.lastName;推荐: function getPersonInfo() { return { firstName: 'John', lastName: 'Doe' }; } let { firstName, lastName } = getPersonInfo();解构赋值(Destructuring Assignment)允许你从数组或对象中提取数据,并将其赋值给不同的变量,使代码更加简洁。 21、使用箭头函数 不推荐: function add(a, b) { return a + b; } let numbers = [1, 2, 3]; let doubled = numbers.map(function(number) { return number * 2; });推荐: const add = (a, b) => a + b; let numbers = [1, 2, 3]; let doubled = numbers.map(number => number * 2);箭头函数(Arrow Functions)提供了更简洁的函数定义方式,并且没有自己的 this 绑定,这有助于避免在回调函数中常见的 this 问题。 22、使用 Promise 和 async/await 处理异步代码 不推荐: function fetchData(url, callback) { // 假设这里有一个异步的fetch操作 setTimeout(() => { callback(null, 'data'); }, 1000); } fetchData('some-url', function(err, data) { if (err) { console.error(err); } else { console.log(data); } });推荐: function fetchData(url) { return new Promise((resolve, reject) => { // 假设这里有一个异步的fetch操作 setTimeout(() => { resolve('data'); }, 1000); }); } // 使用Promise fetchData('some-url').then(data => { console.log(data); }).catch(err => { console.error(err); }); // 或者使用async/await async function getData() { try { let data = await fetchData('some-url'); console.log(data); } catch (err) { console.error(err); } } getData();Promise 和 async/await 提供了更优雅和强大的方式来处理异步代码,避免了回调地狱(Callback Hell)的问题。 23、使用 try...catch 进行错误处理 不推荐: if (someCondition) { // 可能会抛出错误的代码 } else { console.error('An error occurred'); }推荐: try { // 可能会抛出错误的代码 } catch (error) { console.error('An error occurred:', error); }try...catch 语句允许你捕获并处理在代码执行过程中抛出的错误,从而避免程序崩溃并提供更好的用户体验。 24、使用 Map 和 Set 不推荐: let obj = {}; let keys = ['a', 'b', 'c']; keys.forEach(key => { obj[key] = true; });推荐: let set = new Set(['a', 'b', 'c']);Map 和 Set 是ES6中引入的新的数据结构,它们提供了比传统对象更强大和灵活的功能,例如保持插入顺序和检测元素是否存在的时间复杂度更低。 25、避免全局变量污染 不推荐: let globalVar = 'This is a global variable';推荐: (function() { let localVar = 'This is a local variable'; // 你的代码逻辑 })();或者使用 let 和 const 在块级作用域内定义变量,以及使用模块系统(如ES6模块或CommonJS模块)来封装代码。 我们可继续探讨JavaScript代码优化的其他高级策略和最佳实践。以下是一些额外的建议: 26、使用 WeakMap 和 WeakSet WeakMap 和 WeakSet 是ES6中引入的两种新的集合类型,它们的主要特点是“弱引用”。这意味着它们不会阻止垃圾回收器回收其键(或成员)所引用的对象。这对于存储大量临时数据而不担心内存泄漏的情况非常有用。 示例: let obj = {}; let weakMap = new WeakMap(); weakMap.set(obj, 'some value'); // 当没有其他引用指向 `obj` 时,它可以被垃圾回收器回收27、使用 Symbol 类型 Symbol 是ES6中引入的一种新的原始数据类型,它表示唯一的标识符。使用 Symbol 可以避免属性名的冲突,并且可以作为对象的唯一键。 示例: let sym = Symbol('description'); let obj = {}; obj[sym] = 'value'; console.log(obj[sym]); // 输出: value28、优化循环 减少循环内的计算:将可以在循环外部计算的表达式移到外部。 使用 for...of 代替 for...in:当遍历数组时,for...of 通常比 for...in 更快,因为 for...in 还会遍历数组原型链上的属性。 使用 Array.prototype.every 、Array.prototype.some 、Array.prototype.find 等数组方法:这些方法提供了更简洁的语法,并且在某些情况下可能比传统的 for 循环更高效。 29、避免内存泄漏 清理定时器:确保在组件或页面销毁时清理所有的定时器(如 setInterval 和 setTimeout )。 取消事件监听:在不再需要时取消事件监听器。 避免全局变量:全局变量会一直存在于内存中,直到页面被关闭。尽量使用局部变量或模块作用域变量。 30、使用现代JavaScript框架和库的最佳实践 React: 使用纯函数组件和React Hooks来简化状态管理。 避免不必要的重新渲染,通过使用 React.memo 、useCallback 和 useMemo 等优化技术。 优化数据获取,使用React Query或Apollo Client等库来管理异步数据。 Vue: 使用计算属性和侦听器来优化响应式数据的处理。 避免在模板中进行复杂的计算,而是将它们放在计算属性或方法中。 使用Vuex或Pinia等状态管理库来管理全局状态。
-
-
-
纯CSS实现任意元素扫光效果的三种方式 介绍一个比较常见的动画效果。 在日常开发中,为了强调凸显某些文本或者元素,会加一些扫光动效,起到吸引眼球的效果,比如文本的 图片 或者是一个卡片容器,里面可能是图片或者文本或者任意元素 图片 除此之外,还有那种不规则的图片,比如奖品图案 图片 这些是如何实现的呢?一起看看吧 一、CSS 扫光的原理 CSS 扫光动画的原理很简单,就是一个普通的、从左到右的、无限循环的位移动画 图片 位移动画可以选择 transform 或者改变 background-position 都行。 至于扫光,我们只需要绘制一条斜向上45deg的线性渐变就可以了,示意如下 图片 用 CSS 实现就是 background: linear-gradient(45deg, rgba(255,255,255,0) 40%, rgba(255, 255, 255, 0.7), rgba(255,255,255,0) 60%);准备工作做好了,下面看 3 种不同场景的实现 二、文本扫光 首先来看文本扫光。 由于扫光在文本内部,所以需要将这个渐变作为文本的颜色。文本渐变色,可以用 backgrond-clip:text 来实现,假设 HTML 是这样的 <h1 class="shark-txt">前端侦探</h1>为了让效果看起来更加明显,我们用一个比较粗的字体 h1{ font-size: 60px; font-family: "RZGFDHDHJ"; font-weight: normal; color: #9747FF; }效果如下 图片 现在我们通过 background-clip 来添加扫光,由于是裁剪背景,所以需要将当前文本颜色设置透明,建议通过 -webkit-text-fill-color: transparent 来设置,这样可以保留文本原有颜色,好处是其他地方,比如 background-color 可以直接使用原有文本颜色 currentColor ,具体实现如下 .shark-txt{ -webkit-text-fill-color: transparent; background: linear-gradient(45deg, rgba(255,255,255,0) 40%, rgba(255, 255, 255, 0.7), rgba(255,255,255,0) 60%) -100%/50% no-repeat currentColor; -webkit-background-clip: text; }效果如下 图片 最后就是让这个扫光动起来了。 由于是在文本内部,所以这里可以通过改变background-position来实现扫光动画了,动画很简单,如下 @keyframes shark-txt { form{ background-position: -100%; } to { background-position: 200%; } }但是这样做没有动画效果,完全不会动。 这是因为背景默认尺寸是 100% ,根据背景偏移百分比的计算规则,当背景尺寸等于容器尺寸时,百分比完全失效,具体规则如下 给定背景图像位置的百分比偏移量是相对于容器的。值 0% 表示背景图像的左(或上)边界与容器的相应左(或上)边界对齐,或者说图像的 0% 标记将位于容器的 0% 标记上。值为 100% 表示背景图像的 右(或 下)边界与容器的 右(或 下)边界对齐,或者说图像的 100% 标记将位于容器的 100% 标记上。因此 50% 的值表示水平或垂直居中背景图像,因为图像的 50% 将位于容器的 50% 标记处。类似的,background-position: 25% 75% 表示图像上的左侧 25% 和顶部 75% 的位置将放置在距容器左侧 25% 和距容器顶部 75% 的容器位置。 https://developer.mozilla.org/zh-CN/docs/Web/CSS/background-position(container width - image width) * (position x%) = (x offset value) (container height - image height) * (position y%) = (y offset value)所以这种情况下,我们可以手动改小一点背景尺寸,比如 50% .shark-txt { -webkit-text-fill-color: transparent; background: linear-gradient(45deg, rgba(255, 255, 255, 0) 40%, rgba(255, 255, 255, 0.7), rgba(255, 255, 255, 0) 60%) -100% / 50% no-repeat currentColor; -webkit-background-clip: text; animation: shark-txt 2s infinite; }这样就能完美实现文本扫光效果了 图片 三、卡片容器扫光 还有一种比较常见的是容器内的扫光动效,通常是在一个圆角矩形的容器里。 像这种情况下就不能直接用背景渐变了,因为会被容器内的其他元素覆盖。所以我们需要创建一个伪元素,然后通过改变伪元素的位移来实现扫光动画了。 假设有一个容器,容器内有一张图片,HTML 如下 <div class="shark-wrap card"> <img src="https://imgservices-1252317822.image.myqcloud.com/coco/b11272023/ececa9a5.7y0amw.jpg"> </div>简单修饰一下 .card{ width: 300px; border-radius: 8px; background-color: #FFE8A3; } .card img{ display: block; width: 100%; }效果如下 图片 下面通过伪元素来创建一个扫光层,设置位移动画 .shark-wrap::after{ content: ''; position: absolute; inset: -20%; background: linear-gradient(45deg, rgba(255,255,255,0) 40%, rgba(255, 255, 255, 0.7), rgba(255,255,255,0) 60%); animation: shark-wrap 2s infinite; transform: translateX(-100%); } @keyframes shark-wrap { to { transform: translateX(100%); } }效果如下 图片 最后直接超出隐藏就行了 .shark-wrap{ overflow: hidden; }最终效果如下 图片 也适合那种圆形头像 图片 四、不规则图片扫光 其实前面两种情况已经适合大部分场景了,其实还有一种情况,就是那种不规则的图片扫光。这种图片无法直接通过 overflow:hidden 去隐藏多余部分,比如这样 图片 很明显在图片之外的地方也出现了扫光,无法做到扫光在图形的"内部"。 那么,有没有办法根据图片的外形去裁剪呢?当然也是有办法的,这里需要用到 CSS mask 遮罩。 简单来说,就是直接将该图片作为遮罩图片,这样只有形状内的部分可见,形状外的直接被裁剪了 图片 在上一种场景的情况下,只需要在此基础之上,添加一个完全相同的 mask 遮罩就行了 <div class="shark-wrap" style="-webkit-mask: url(https://imgservices-1252317822.image.myqcloud.com/coco/s09252023/3af9e8de.00uqxe.png) 0 0/100%"> <img class="logo" src="https://imgservices-1252317822.image.myqcloud.com/coco/s09252023/3af9e8de.00uqxe.png"> </div>这样就可以把扫光多余的部分裁剪掉了 图片 换张图也能很好适配 图片 五、总结一下 以上就本文的全部内容了,共介绍了3种不同的扫光场景,你学到了吗?下面总结一下重点 扫光样式本身可以直接用线性渐变绘制而成 扫光动画原理很简单,就是一个水平的位移动画 文本扫光动画需要通过改变 background-postion 实现 当背景尺寸等于容器尺寸时,设置 background-postion 百分比无效 普通容器的扫光效果需要借助伪元素实现,因为如果使用背景会被容器内的元素覆盖 普通容器的扫光动画可以直接用 transfrom 实现 使用 overflow:hidden 裁剪容器外的部分 不规则图片的扫光效果无法直接根据形状裁剪 借助 CSS mask 可以根据图片本身裁剪掉扫光多余部分 对了,这个属于常规需求,只是普通的动画效果,没有兼容性限制,放心使用,除了本文的样式,还可以根据需求改变扫光的大小,角度,颜色等,这个就看具体需求了。 六、完整案例 CSS shark animation (codepen.io):https://codepen.io/xboxyan/pen/KKLLZOE CSS shark animation (juejin.cn):https://code.juejin.cn/pen/7385810378132815882
-
使用JavaScript动态生成网站文章目录及内容滚动跟随效果 由于之前使用的文章导读插件性能过于臃肿,导致资源消耗高且难以维护,因此我决定自行开发一个轻量级的文章导读功能。参考了郄郄私语的 案例文章,我实现了以下四个主要功能: 根据文章内容自动生成目录 点击目录跳转至相应章节 滚动阅读时,目录随当前章节自动切换 目录跟随文章内容滚动 目标 本文旨在实现以下功能: 自动生成文章目录 点击目录跳转至对应章节 目录根据当前阅读章节自动高亮 目录随文章内容滚动 根据文章内容自动生成目录 实现自动生成目录的前提是文章内容须有清晰的层次结构,这需要使用 h1 至 h6 标签来定义标题。通过 JavaScript,我们可以提取这些标题来生成目录: var articleTitleList = $('.joe_detail__article').find('h1, h2, h3, h4, h5, h6'); articleTitleList.each(function() { const headingLevel = $(this).prop("tagName").toLowerCase(); const headingName = $(this).text().trim(); console.log(headingLevel, headingName); $('#catalogs').append(`<div class="catalog catalog-${headingLevel}">${headingName}</div>`); });在样式表中为目录项定义缩进样式: .catalog-h2 { margin-left: 1em; } .catalog-h3 { margin-left: 2em; } .catalog-h4 { margin-left: 3em; } .catalog-h5 { margin-left: 4em; } .catalog-h6 { margin-left: 5em; }点击目录跳转至对应章节 点击目录跳转至相应章节可以通过为每个标题添加锚点。我们将在 h1 至 h6 标签上添加 id: articleTitleList.each(function() { const headingName = $(this).text().trim(); const enHeadingName = encodeURIComponent(headingName); $(this).attr('id', `${enHeadingName}`); $('.posts-nav-lists>ul').append(`<li><a href="#${enHeadingName}">${headingName}</a></li>`); });目录自动切换至当前章节 为了让目录随着阅读位置自动切换,我们将监控用户的滚动位置并依据此更新目录的高亮条目: const catalogTrack = () => { let $currentHeading = $('h1'); articleTitleList.each(function() { const $heading = $(this); if ($heading.offset().top - $(document).scrollTop() > 20) return false; // 退出条件 $currentHeading = $heading; }); // 更新目录状态 const anchorName = $currentHeading.attr('id'); $('.posts-nav-lists>ul>li').removeClass('active'); $(`#title-${anchorName}`).parent().addClass('active'); };目录随文章内容滚动 为确保当前章节始终可见,我们控制目录区域的滚动: if ($catalog.length > 0) { $('.posts-nav-box').scrollTop($catalog[0].offsetTop - 50); // 确保可见 }性能优化 为了避免在滚动时频繁调用 catalogTrack 导致性能降低,我们可以使用函数节流技术: function throttle(fn, wait) { let lastTime = 0; return function() { const now = Date.now(); if (now - lastTime >= wait) { fn.apply(this, arguments); lastTime = now; } }; } window.addEventListener('scroll', throttle(catalogTrack, 500)); // 每500毫秒调用一次自定义跳转行为 考虑到固定导航条可能遮挡目标章节,我们可以自定义跳转行为,确保目标元素不会被遮挡: document.querySelectorAll('.posts-nav-lists>ul>li>a').forEach(link => { link.addEventListener('click', (event) => { event.preventDefault(); // 阻止默认跳转 const targetId = link.getAttribute('href').substring(1); const targetElement = document.getElementById(targetId); const headerHeight = document.querySelector('.joe_header').offsetHeight; const scrollTop = $(targetElement).offset().top - headerHeight - 10; window.scrollTo({ top: scrollTop, behavior: 'smooth' }); }); });总结 本文记录了生成和控制博客文章目录的思路与方法,针对不同需求可能会有其他解决方案。欢迎大家在评论区讨论和分享建议,感谢阅读! 完整代码示例 HTML 部分 <section class="joe_aside__item posts-nav-box"> <div class="joe_aside__item-title"><i class="fa fa-list-ul"></i><span class="text">文章目录</span><span class="line"></span></div> <div class="joe_aside__item-contain"> <div class="posts-nav-lists"><ul class="bl nav"></ul></div> </div> </section>JavaScript 部分 var articleTitleList = $('.joe_detail__article').find('h1, h2, h3, h4, h5, h6'); if (articleTitleList.length > 0) { // 目录生成及事件绑定 (function () { for (let heading of articleTitleList) { const headingLevel = heading.tagName.toUpperCase(); const $heading = $(heading); // console.log($heading); const headingName = $heading.text().trim(); const enHeadingName = encodeURIComponent(headingName); $heading.attr('id', `${enHeadingName}`); $('.posts-nav-lists>ul').append(`<li class="n-${headingLevel}"><a id="title-${enHeadingName}" href="#${enHeadingName}">${headingName}</a></li>`); // const anchorName = $heading.attr('id'); // console.log(headingLevel, headingName); } if (Joe.IS_MOBILE) { $('.joe_action').append(`<div class="joe_action_item posts-nav-switcher"><i class="fa fa-list-ul"></i></div>`) let joe_aside = $('.joe_aside .joe_aside__item.posts-nav-box .joe_aside__item-contain').html(); $('.joe_aside .joe_aside__item.posts-nav-box').remove(); let html = document.createElement('div'); html.className = 'posts-nav-box'; html.innerHTML = joe_aside; // console.log(html); $('.posts-nav-switcher').append(html); $('.joe_action_item .posts-nav-box').css({ 'position': 'absolute', 'display': 'none', 'right': '50px', 'bottom': '0px', 'padding': '15px', 'border-radius': 'var(--radius-wrap)', 'box-shadow': '0 0 10px 8px var(--main-shadow)', 'overflow': 'auto', 'max-height': '50vh', 'max-width': '80vw' }) $('.joe_action_item.posts-nav-switcher').click(() => { $('.joe_action_item.posts-nav-switcher .posts-nav-box').fadeToggle(200); }); } const catalogTrack = () => { // console.log('页面滚动标题监听'); let $currentHeading = $('h1'); for (let heading of articleTitleList) { const $heading = $(heading); if ($heading.offset().top - $(document).scrollTop() > $('.joe_header').height()) { break; } $currentHeading = $heading; const anchorName = $currentHeading.attr('id'); const $catalog = $(document.getElementById(`title-${anchorName}`)).parent(); if (!$catalog.hasClass('active')) { $('.posts-nav-lists>ul>li').removeClass('active'); $catalog.addClass('active'); } if ($catalog.length > 0) { if ($('.posts-nav-box .joe_aside__item-contain').length > 0) { $('.posts-nav-box .joe_aside__item-contain').scrollTop($catalog[0].offsetTop - 50); } else { $('.posts-nav-box').scrollTop($catalog[0].offsetTop - 50); } } else { $('.posts-nav-lists').scrollTop(0); } } }; /** * 函数节流,时间戳方案 * @param {*} fn * @param {*} wait * @returns */ function throttle(fn, wait) { var pre = Date.now(); return function () { var context = this; var args = arguments; var now = Date.now(); if (now - pre >= wait) { fn.apply(context, args); pre = Date.now(); } } } window.addEventListener('scroll', throttle(() => { catalogTrack(); }, 500)); // 监听文章目录a标签点击 document.querySelectorAll('.posts-nav-lists>ul>li>a').forEach(link => { link.addEventListener('click', (event) => { event.preventDefault(); // 阻止默认跳转行为 // 获取目标元素 ID const targetId = link.getAttribute('href').substring(1); const targetElement = document.getElementById(targetId); if (targetElement) { // 获取目标元素距离页面顶部的距离 const targetTop = $(targetElement).offset().top; // console.log(targetTop); // 获取顶栏高度,考虑动态高度变化和内部元素 const headerHeight = document.querySelector('.joe_header').offsetHeight; // 计算滚动位置 const scrollTop = (targetTop - headerHeight) - 10; // 预留10px的美观距离 window.scrollTo({ top: scrollTop, behavior: 'smooth' }); } else { console.error('目标元素未找到:', targetId); } }); }); }()) } else { $('.joe_aside__item.posts-nav-box').remove(); }通过以上修改,文章的可读性、结构性和实用性得以提升,使读者能够更好地理解和使用所提供的功能。
-
-
iFrame父子相互获取对方DOM元素 父页面获取子页面dom的方法 /* 必须用onload */ window.onload = () => { const sonWindow = document.querySelector("iframe").contentWindow; const sonDiv = sonWindow.document.querySelector(".son") console.log(sonDiv); }子页面获取父页面dom的方法 /* 必须用onload */ window.onload = () => { const parentWindow = window.parent; const parentDiv = parentWindow.document.querySelector(".parent") console.log(parentDiv); }