当前位置: 首页 > news >正文

wordpress变404seo优化好做吗

wordpress变404,seo优化好做吗,南京网站维护,1040视频app前言 最近在做复图标库功能时,感觉这个功能在使用上有些“生硬”。如随机删除一个图标,后面的元素在视觉上是“瞬间移动”过来补位的。想着做个小优化,简单加个动画效果吧。 看起来确实“花里胡哨”了,实现也很简单, …

前言

最近在做复图标库功能时,感觉这个功能在使用上有些“生硬”。如随机删除一个图标,后面的元素在视觉上是“瞬间移动”过来补位的。想着做个小优化,简单加个动画效果吧。

在这里插入图片描述

看起来确实“花里胡哨”了,实现也很简单,

<ul><transition-group appear tag="ul"><!--图片循环--></transition-group>
</ul>

为什么简单的设置几个样式规则,元素就可以平滑的移动到对应的位置?如果我们手写这个功能,应该如何考量和设计?

插播

先简单回顾几个基本知识点(更细节的内容这里不展开讨论)。

浏览器的渲染流程

虽然不同的浏览器内核在渲染流程上稍有不同,但大体上是一致的,主要步骤如下:

  • DOM树构建:解析HTML,生成DOM树
  • CSSOM树构建:解析CSS,生成CSSOM树
  • 渲染树构建:将DOM树和CSSOM树结合,生成渲染树(Render Tree)
  • 布局:根据渲染树,计算元素的的几何信息(位置,大小)
  • 绘制:根据布局信息,把每一个图层转换为像素,渲染在屏幕上

简单示意图如下

在这里插入图片描述

由图可知:

  • CSS解析不会阻塞DOM解析,但会阻塞DOM渲染
  • JavaScript会阻塞DOM解析,进而阻塞DOM渲染
  • 浏览器碰到script标签(没有defer/async属性时)就会触发页面渲染。如果前面的CSS资源尚未加载完毕,浏览器会等待它加载完毕后再执行脚本

FPS

简单来说,FPS是浏览器的每秒的渲染帧数,大多数设备的刷新率是60FPS,一般来说FPS越低页面就会越卡顿。

像素管道

标准上每一帧约为16.7ms。但浏览器需要花费时间将新帧绘制到屏幕上,大约只有10ms执行代码。如果无法满足这个要求,帧率会降低,出现卡顿。

先看一张经典图:

在这里插入图片描述

  • JavaScript(代码执行)。一般的纯前端阻塞都是来自JS,JS线程的运行本身就会阻塞UI线程(除WebWorker外)。所以执行长时间的同步代码会占用每帧的渲染时间。
  • Style(样式计算)。利用CSS匹配器计算元素的最终样式。
  • Layout(布局)。当样式规则应用后,浏览器开始计算元素在屏幕上显示的大小及位置,这个过程中一个元素的变动可能会影响到另一个元素,从而引起回流。
  • Paint(绘制)。绘制就是简单的像素填充,包括文本、颜色、图片、边框、阴影等可视部分。因为网页样式是层级结构,所以绘制操作会在每一层进行。
  • Composite(合成)。合成操作会按照正确的层级顺序绘制到屏幕上,以保证渲染的正确性。层级错误的话会导致样式错乱,如底层的元素显示到上层等。

上述过程为理论标准过程,但实际上并非每一帧都会完整执行这五个步骤,不管我们通过JS或者css动画去完成一些动作,本质上都与【回流】(重排)和【重绘】两个概念相关。所以通常对于指定帧有3种运行方式。

  • 修改元素的"layout"属性(几何属性,如宽、高、位置等),浏览器会自动重排页面,受到影响的元素都需要重新绘制,且最终绘制的元素需要进行合成。重排经过了管道的每一步,对性能影响比较大。

    在这里插入图片描述

  • 修改元素的"paint only"属性(外观属性,,如颜色、阴影等),不影响页面布局,此时浏览器会跳过布局,但仍执行绘制。

    在这里插入图片描述

  • 修改元素的一个不需要布局和重绘的属性(如透明度、transform变形等),浏览器只执行合成,性能较好。

    在这里插入图片描述

由上可知,JavaScript、Style和Composite三个阶段是无法避开的。而执行的阶段越少,耗时就越短,每秒渲染的帧数就越高。

简单优化

布局的过程实际上就是回流的过程,这一步几乎会对整个页面重新计算排版,性能开销较大。而绘制是像素填充的过程,是管道中运行时间最长的任务。所以针对JS动画,通常我们可以采用如下优化方法

  • 使用requestAnimationFrame来代替定时器
  • 大量计算任务可以使用Web Worker执行
  • 更改DOM时使用微任务
  • 降低CSS选择器的复杂度
  • 避免强制同步布局
  • 合理设计z-index层数
  • 频繁修改属性的元素,可使其脱离文档流
  • 渲染层提升为合成层,利用GPU加速绘制

下面简单介绍其中的两点(后面会用到)

requestAnimationFrame

上面提到了,每一帧必须保证JS运行时间小于10ms,才能给样式计算、布局、绘制留出充足的时间。那么,是否我们满足了这个条件,且保证每一帧耗时都在16.7ms之内,就能保证不丢帧呢?

其实不必然,这取决于JS执行方式,如使用定时器(setTimeout/setInterval)来实现。因为定时器无法保证回调函数的真正执行时机,它可能在某一帧的开始、中间、结束时执行,有可能导致丢帧。

在这里插入图片描述

使用requestAnimationFrame,会使浏览器在下一次重绘之前调用传入的动画函数,回调函数执行次数通常与浏览器屏幕刷新次数相匹配。

在这里插入图片描述

如下图所示,我们分别使用setTimeout和requestAnimationFrame把元素平移800像素,差异还是很明显的。

在这里插入图片描述

避免强制同步布局(FSL)

在上面的浏览器的渲染流程中提到,浏览器中的页面的渲染过程可以分为计算布局和绘制两个阶段。布局是指浏览器根据DOM树、CSS样式和其他因素来确定每个元素在页面中的大小和位置等相关属性。绘制是指将计算好的布局信息转化为可视元素显示在屏幕上。

通常情况下,浏览器会对布局操作进行优化,例如使用异步方式进行布局(也称为增量布局或延迟布局)。这意味着当对DOM进行修改时,浏览器不会立即触发布局,而是等待一段时间,将多个连续的布局操作合并在一起进行。这样可以提高性能和响应速度。

然而,有些情况下,我们需要在修改DOM后立即获得最新的布局信息。这时我们可以使用强制同步布局的方法来实现。强制同步布局的方式往往是通过触发获取某些属性值的操作,例如读取元素的位置、大小、滚动等属性,或者通过访问offsetTopoffsetWidthoffsetHeight属性来实现。这样会迫使浏览器立即执行布局阶段,以确保获取的属性值是最新的。

当然,单个FSL影响不大,如果触发了布局抖动,会导致严重的性能问题。举个简单的例子,批量修改元素宽度

// 把子元素的宽设置成与外部容器一样
const container = document.querySelector('.container');
const items = document.querySelectorAll('.item');
// 遍历所有子节点,重新设置width
for (var i = 0; i < items.length; i++) {const width = container.offsetWidth;items[i].style.width = width + 'px';
}

实际上,每次更改样式,都会导致刚刚执行的布局失效。因为更改了新的样式,下一次读取宽度时,浏览器需要重新布局,直到循环结束,循环期间的布局实际上都是“无效”的。

我们可以在谷歌性能在线测试网站(https://googlechrome.github.io/devtools-samples/jank/)进行测试。观察性能面板,可以看到给出了警告提示:强制回流可能是性能瓶颈。定位到相关代码可以看到正是获取元素位置信息造成的。

在这里插入图片描述

在这里插入图片描述

FLIP

进入正题。严格来说,FLIP并不是特定的代码实现或者框架,而是一种思路。FLIP技术以一种高效的方式来动态的改变DOM元素的位置和尺寸,而无需关注布局是如何计算或渲染的。在改变的过程中赋予一定的动效,从而达到动画的目的。

##核心思想

FLIP由四个单词组成:First, Last, Invert, Play。

First:

元素的初始状态。

Last

元素的最终状态。

Invert

反转。计算初始状态和最终状态的属性差异,如宽高、位置、透明度等,设置对应的规则进行反转,使其看起来还在初始状态(这点比较绕,下面有具体示例介绍)。

Play

执行。移除对应规则,使其平滑变化到最终状态。

具体实现

下面来看一个简单示例:把第一个元素移动到最后一个位置(原生写法)。
在这里插入图片描述

按照FLIP的设计原则,我们来看一下如何实现。

<!--html部分-->
<button class="button">修改第一个元素位置</button>
<ul class="list"><li class="list-item active">元素1</li><li class="list-item">元素2</li><li class="list-item">元素3</li><li class="list-item">元素4</li><li class="list-item">元素5</li><li class="list-item">元素6</li>
</ul>
  • First:获取初始位置

    // 元素
    const btn = document.querySelector('button');
    const list = document.querySelector('.list');
    const firstItem = document.querySelector('.list-item:first-child');
    // 获取位置方法(这个例子只有上下平移,只记录top值即可)
    function getLocation() {const rect = firstItem.getBoundingClientRect();return rect.top;
    }
    // First:获取初始位置
    const start = getLocation();
    console.log('first:', start);
    
  • Last:获取最终位置

    // 移动元素
    btn.onclick = () => {list.insertBefore(firstItem, null);// Last:获取最终位置const end = getLocation();console.log('last:', end)
    }
    

    效果如下:获取到了起始位置和最终位置

    在这里插入图片描述

    到了这里,大家可能会有疑问,这都变化完了,拿到的两个位置信息有什么用?别急,下面才是重点。

  • Invert:规则反转

    这里大家可以暂停一下,思考一个问题,当我获取到最终位置的时候,看到的是变化前的页面还是变化后的页面?

    其实看到的是变化前的页面,这个现象才是核心所在。这里大家可能会有疑问,明明看到元素动了啊,为什么还是变化前的页面?我们可以来验证一下:

    // 移动元素
    btn.onclick = () => {list.insertBefore(firstItem, null);// Last:获取最终位置const end = getLocation();console.log('last:', end)// 模拟执行js代码const start = Date.now();while (Date.now() - start < 2000) {console.log('模拟执行js代码')}
    }
    

    可以看到当我们获取元素最终位置的时候,显示的还是未变化前的页面。为什么会这样?这就是我们上面提到的当获取元素布局信息的时候,会触发强制同步布局,浏览器立即执行布局,但还没有到绘制阶段。

    在这里插入图片描述

    接下来计算偏移值,设置变化规则即可。注意这里我们要用开始状态减去最终状态,做一个反转,使其看起来还在原来位置(因为动画是从开始位置到最终位置的)

    // Invert:反转
    const dis = start - end;
    firstItem.style.transform = `translateY(${dis}px)`;
    console.log('invert:', dis)
    

    可以看到,DOM结构已经发生变化,元素也反转回到了初始位置。

    在这里插入图片描述

  • Play:执行

    这里我们只需要设置一下transition效果,并移除掉transform即可(这样元素就会回到它现在真实的位置)。这里我们使用requestAnimationFrame来实现。

    // play回调
    function raf(callback) {requestAnimationFrame(() => {requestAnimationFrame(callback);})
    }
    // 移动元素
    btn.onclick = () => {list.insertBefore(firstItem, null);// Last:获取最终位置const end = getLocation();console.log('last:', end)// Invert:反转const dis = start - end;firstItem.style.transform = `translateY(${dis}px)`;console.log('invert:', dis)// Play:执行raf(() => {firstItem.style.transition = 'transform 1s';firstItem.style.removeProperty('transform');console.log('play')})
    }
    

    在这里插入图片描述

到这里我们就实现了一个很简单的FLIP动画。当然这个例子只是对一个元素做了效果,我们同样可以对其它元素做相应的操作。

简单封装

以Vue为例,做如下封装,快速实现图片库的随机插入、删除、乱序等动画效果。

// 记录位置
recordPosition(nodes) {return nodes.reduce((prev, node) => {const rect = node.getBoundingClientRect();const { left, top } = rect;if (node.attributes.card.value) {prev[node.attributes.card.value] = { left, top, node };}return prev;}, []);
},
// 设置动画
async scheduleAnimation(update) {// 获取子节点(nodes:参与动画的节点)const prev = Array.from(nodes);// 记录子节点初始位置const prevRectMap = this.recordPosition(prev);// 执行数据变化:如增删改等操作update()await this.$nextTick();// 记录子节点现在位置const currentRectMap = this.recordPosition(prev);// 遍历对比Object.keys(prevRectMap).forEach((node) => {const currentRect = currentRectMap[node];const prevRect = prevRectMap[node];// 计算反转值const invert = {left: prevRect.left - currentRect.left,top: prevRect.top - currentRect.top,};// 设置动画const keyframes = [{transform: `translate(${invert.left}px, ${invert.top}px)`,},{ transform: "translate(0, 0)" },];const options = {duration: 300,easing: "linear",};// 执行动画currentRect.node?.animate(keyframes, options);})
}
// 调用
this.scheduleAnimation(()=>{// TODO... 对元素增删改
})

图片库的相关实现

在这里插入图片描述

列表的相关实现

在这里插入图片描述

transtion-group

当然在Vue中已经内置了相关功能,查看源码(src/platforms/web/runtime/components/transition-group.ts。可以看到在初始render时记录原始位置,在updated中记录最新位置,并计算偏移参数,设置动画效果,执行完成之后,移除相关属性。

在这里插入图片描述

React可以参考react-transition-group或者react-flip-toolkit等插件。

为什么要用FLIP

对于明确知道元素的起止状态的动画,如从坐标(0,0)移动到(100,100),或透明度从0变化到1等,直接设置相应的规则即可。而对于一些无法明确起止状态的动画,使用FLIP就简单多了,避免了我们手动计算维护元素的状态。

后记

  • 我们可能在写一些过渡效果的时候,无意中用到了FLIP动画,但更需要了解相关原理
  • 合理使用动效让平台的操作更加平滑(就如同使用loading让用户感知网站确实在响应)
  • 要确保多个连续的FLIP动画之间互不影响,或者说要预留出一定的时间给到相关的计算过程
  • 实现动画当然有多种方式,结合项目实际选择合适的技术(如通过纯CSS实现瀑布流而非JS的形式)
  • 使用Web Animations API可以更简单实现一个动画

参考文档

让你的网页更丝滑

性能优化之关于像素管道及优化

前端动画必知必会

http://www.hengruixuexiao.com/news/22364.html

相关文章:

  • web网站开发软件百度云网页版入口
  • 什么样的网站容易做seo东莞网站建设推广哪家好
  • 网站建设怎么谈网络舆情管理
  • 优化网站佛山厂商常见的关键词
  • 美食网站建设的意义自媒体运营主要做什么
  • 最新热点新闻事件素材武汉seo网站优化
  • 无锡网站建设企业排名教育培训机构官网
  • 贵阳专业做网站种子搜索
  • 做响应式网站制作软文案例短篇
  • 网站交换链接的网络营销意义网络服务包括
  • 如何做网站的搜索栏重庆公司网站seo
  • wordpress案例站点英文网站seo
  • 一台服务做两个网站吗守游网络推广平台登陆
  • oa协同软件办公系统费用seo课程培训视频
  • 网站的网站制作雅诗兰黛网络营销策划书
  • 工信部网站备案登录优化设计全部答案
  • 网站建设差打不开小说网站排名免费
  • pc端网站开发精准客户信息一条多少钱
  • 网站开发术语网站优化建设
  • 徐州vi设计公司app优化方案
  • 17网站一起做网店质量怎么样百度查询最火的关键词
  • 可以做旅行行程的网站即刻搜索
  • 用服务器ip做网站seo薪酬水平
  • dw做网站学习解析ebay欧洲站网址
  • 博客导入wordpressseo推广网络
  • 洪梅镇网站仿做跨境电商平台有哪些?
  • 广州黄埔网站制作最近发生的重大新闻事件
  • 校园网网站建设实训报告优化网络的软件
  • 做网站建设话术产品经理培训
  • nodejs 做网站js交件学电商哪个培训学校好