整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

25.HTML CSS动画和过渡

25.HTML CSS动画和过渡

现代网页设计中,动画和过渡是提升用户体验的重要手段。通过使用 CSS,我们可以在不影响页面性能的前提下,实现平滑和吸引人的视觉效果。本文将介绍 CSS 动画和过渡的基础知识,并通过几个例子展示如何在你的网站中应用它们。

CSS 过渡(Transitions)

CSS 过渡允许你在 CSS 属性值之间创建平滑的动画效果。当一个元素的属性值改变时,过渡效果会在一定时间内平滑地过渡到新的属性值。

基本语法

transition: property duration timing-function delay;
  • property:指定要添加过渡效果的 CSS 属性。
  • duration:过渡效果的持续时间。
  • timing-function:定义速度曲线的函数。
  • delay:过渡效果的延迟时间。

例子 1:鼠标悬停放大图片

img:hover {
  transform: scale(1.2);
  transition: transform 0.3s ease-in-out;
}

这个例子中,当鼠标悬停在图片上时,图片会在0.3秒内放大到原来的1.2倍大小,过渡效果为ease-in-out。

CSS 动画(Animations)

CSS 动画提供了更强大的控制,允许你创建复杂的动画序列,通过定义关键帧(keyframes)来控制动画的中间状态。

基本语法

@keyframes animation-name {
  from {
    /* 初始状态 */
  }
  to {
    /* 结束状态 */
  }
}

或者使用百分比来定义多个关键帧:

@keyframes animation-name {
  0% { /* 初始状态 */ }
  50% { /* 中间状态 */ }
  100% { /* 结束状态 */ }
}

例子 2:无限旋转图标

@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

.icon-spin {
  animation: spin 2s linear infinite;
}

这个例子创建了一个名为spin的动画,使得图标无限期地旋转。

实战例子

接下来,我们将通过几个实战例子来展示 CSS 动画和过渡的具体应用。

例子 3:按钮点击波纹效果

.button {
  position: relative;
  overflow: hidden;
  transition: background-color 0.3s;
}

.button:after {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: 5px;
  height: 5px;
  background: rgba(255, 255, 255, 0.7);
  opacity: 0;
  border-radius: 100%;
  transform: scale(1, 1) translate(-50%);
  transform-origin: 50% 50%;
}

.button:active:after {
  width: 300px;
  height: 300px;
  opacity: 1;
  transition: width 0.5s, height 0.5s, opacity 0s 0.5s;
}

在这个例子中,当按钮被点击时,会产生一个波纹效果,模拟水波纹扩散。

例子 4:淡入淡出切换效果

.fade-in {
  animation: fadeIn 1s ease-in-out;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

.fade-out {
  animation: fadeOut 1s ease-in-out;
}

@keyframes fadeOut {
  from { opacity: 1; }
  to { opacity: 0; }
}

这个例子中定义了两个动画,一个用于元素的淡入,另一个用于元素的淡出。

示例

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS Animation and Transition Example</title>
<style>
  body {
    font-family: 'Arial', sans-serif;
    margin: 0;
    padding: 0;
    background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
    background-size: 400% 400%;
    animation: gradientBG 15s ease infinite;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
    min-height: 100vh;
  }

  @keyframes gradientBG {
    0% { background-position: 0% 50%; }
    50% { background-position: 100% 50%; }
    100% { background-position: 0% 50%; }
  }

  .logo {
    font-size: 2em;
    color: #007bff;
    margin-bottom: 20px;
    animation: spin 3s linear infinite;
  }

  .scrolling-text {
    margin: 20px 0;
    background-color: #333;
    color: #fff;
    padding: 10px;
    white-space: nowrap;
    overflow: hidden;
    position: relative;
  }

  .scrolling-text p {
    position: absolute;
    width: 100%;
    height: 100%;
    margin: 0;
    line-height: 50px;
    text-align: center;
    /* Starting position */
    transform: translateX(100%);
    /* Apply animation to this element */
    animation: scroll-text 10s linear infinite;
  }

  @keyframes scroll-text {
    0% { transform: translateX(100%); }
    100% { transform: translateX(-100%); }
  }

  .interactive-card {
    background-color: #fff;
    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
    padding: 20px;
    margin: 20px;
    border-radius: 10px;
    transition: transform 0.3s ease, box-shadow 0.3s ease;
  }

  .interactive-card:hover {
    transform: translateY(-10px);
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.3);
  }

  .color-block {
    width: 100px;
    height: 100px;
    background-color: #17a2b8;
    margin: 20px;
    border-radius: 50%;
    transition: background-color 0.5s ease, transform 0.5s ease;
  }

  .color-block:hover {
    background-color: #28a745;
    transform: rotate(180deg);
  }
</style>
</head>
<body>

<div class="logo">
  <i class="fas fa-sync-alt"></i> Animated Logo
</div>

<div class="scrolling-text">
  <p>This text scrolls infinitely. Pay attention to how it moves smoothly from right to left.</p>
</div>

<div class="interactive-card">
  <h3>Interactive Card</h3>
  <p>Hover over this card to see it move. It's a simple yet effective way to add interactivity to your design.</p>
</div>

<div class="color-block"></div>

</body>
</html>

  • .logo 类定义了一个徽标,它具有字体大小和颜色,并应用了一个名为 spin 的关键帧动画,使徽标无限旋转。
  • .scrolling-text 类定义了一个包含滚动文本的容器,设置了背景颜色、文字颜色和内边距。
  • .scrolling-text p 选择器定义了滚动文本的样式,包括动画 scroll-text,使文本从右向左无限滚动。
  • .interactive-card 类定义了一个交互式卡片,它具有背景颜色、阴影、内边距和圆角。当鼠标悬停时,它会向上移动并增加阴影,这是通过 transition 属性实现的。
  • .color-block 类定义了一个颜色块,设置了宽度、高度、背景颜色和圆角。当鼠标悬停时,它的背景颜色会改变,并且会旋转 180 度。
  • body 的背景被设置为一个线性渐变,包含四种颜色。通过 background-size 属性,我们扩大了背景尺寸,这样动画在运行时会有更多的空间进行颜色的过渡。
  • @keyframes gradientBG 关键帧动画被创建来改变背景的位置,从而在不同的颜色之间产生平滑过渡的效果。
  • 该动画被设置为无限循环,并且每次循环持续 15 秒,通过 ease 时间函数来平滑过渡。

结语

CSS 动画和过渡是前端开发者的强大工具,它们可以在不牺牲性能的情况下为用户提供流畅、引人注目的界面交互。通过掌握这些技术,你可以创造出更加动态和生动的网页体验。记住,动画应该用来增强用户体验,而不是分散用户的注意力,适量而恰当地使用动画效果是关键。

多大公司面试喜欢问这样一道面试题,输入URL到看见页面发生了什么? 简单来说,共有以下几个过程:

  1. DNS解析
  2. 发起TCP连接
  3. 发送HTTP请求
  4. 服务器处理请求并返回HTTP报文
  5. 浏览器解析渲染页面
  6. 连接结束。

DNS解析

DNS解析实际上就是寻找你所需要的资源的过程。假设你输入www.baidu.com,而这个网址并不是百度的真实地址,互联网中每一台机器都有唯一标识的IP地址,这个才是关键,但是它不好记,乱七八糟一串数字谁记得住啊,所以就需要一个网址和IP地址的转换,也就是DNS解析。下面看看具体的解析过程

具体解析

DNS解析其实是一个递归的过程

输入www.google.com网址后,首先在本地的域名服务器中查找,没找到去根域名服务器查找,没有再去com顶级域名服务器查找,,如此的类推下去,直到找到IP地址,然后把它记录在本地,供下次使用。大致过程就是.-> .com ->google.com. -> www.google.com。 (你可能觉得我多写 .,并木有,这个.对应的就是根域名服务器,默认情况下所有的网址的最后一位都是.,既然是默认情况下,为了方便用户,通常都会省略,浏览器在请求DNS的时候会自动加上)DNS优化

既然已经懂得了解析的具体过程,我们可以看到上述一共经过了N个过程,每个过程有一定的消耗和时间的等待,因此我们得想办法解决一下这个问题!

DNS缓存

DNS存在着多级缓存,从离浏览器的距离排序的话,有以下几种: 浏览器缓存,系统缓存,路由器缓存,IPS服务器缓存,根域名服务器缓存,顶级域名服务器缓存,主域名服务器缓存

DNS负载均衡

不知道你们有没有注意这样一件事,你访问baidu.com的时候,每次响应的并非是同一个服务器(IP地址不同),一般大公司都有成百上千台服务器来支撑访问,假设只有一个服务器,那它的性能和存储量要多大才能支撑这样大量的访问呢?DNS可以返回一个合适的机器的IP给用户,例如可以根据每台机器的负载量,该机器离用户地理位置的距离等等,这种过程就是DNS负载均衡

发起TCP连接

TCP提供一种可靠的传输,这个过程涉及到三次握手,四次挥手,下面我们详细看看 TCP提供一种面向连接的,可靠的字节流服务。 其首部的数据格式如下

字段分析

  • 源端口:源端口和IP地址的作用是标识报文的返回地址。
  • 目的端口:端口指明接收方计算机上的应用程序接口。

TCP报头中的源端口号和目的端口号同IP数据报中的源IP与目的IP唯一确定一条TCP连接。

  • 序号:是TCP可靠传输的关键部分。序号是该报文段发送的数据组的第一个字节的序号。在TCP传送的流中,每一个字节都有一个序号。比如一个报文段的序号为300,报文段数据部分共有100字节,则下一个报文段的序号为400。所以序号确保了TCP传输的有序性。
  • 确认序号:即ACK,指明下一个期待收到的字节序号,表明该序号之前的所有数据已经正确无误的收到。确认号只有当ACK标志为1时才有效。比如建立连接时,SYN报文的ACK标志位为0。
  • 首部长度/数据偏移:占4位,它指出TCP报文的数据距离TCP报文段的起始处有多远。由于首部可能含有可选项内容,因此TCP报头的长度是不确定的,报头不包含任何任选字段则长度为20字节,4位首部长度字段所能表示的最大值为1111,转化为10进制为15,15*32/8=60,故报头最大长度为60字节。首部长度也叫数据偏移,是因为首部长度实际上指示了数据区在报文段中的起始偏移值。
  • 保留:占6位,保留今后使用,但目前应都位0。
  • 控制位:URG ACK PSH RST SYN FIN,共6个,每一个标志位表示一个控制功能。
  • 紧急URG:当URG=1,表明紧急指针字段有效。告诉系统此报文段中有紧急数据
  • 确认ACK:仅当ACK=1时,确认号字段才有效。TCP规定,在连接建立后所有报文的传输都必须把ACK置1。
  • 推送PSH:当两个应用进程进行交互式通信时,有时在一端的应用进程希望在键入一个命令后立即就能收到对方的响应,这时候就将PSH=1。
  • 复位RST:当RST=1,表明TCP连接中出现严重差错,必须释放连接,然后再重新建立连接。
  • 同步SYN:在连接建立时用来同步序号。当SYN=1,ACK=0,表明是连接请求报文,若同意连接,则响应报文中应该使SYN=1,ACK=1。
  • 终止FIN:用来释放连接。当FIN=1,表明此报文的发送方的数据已经发送完毕,并且要求释放。
  • 窗口:滑动窗口大小,用来告知发送端接受端的缓存大小,以此控制发送端发送数据的速率,从而达到流量控制。窗口大小时一个16bit字段,因而窗口大小最大为65535。
  • 校验和:奇偶校验,此校验和是对整个的 TCP 报文段,包括 TCP 头部和 TCP 数据,以 16 位字进行计算所得。由发送端计算和存储,并由接收端进行验证。
  • 紧急指针:只有当 URG 标志置 1 时紧急指针才有效。紧急指针是一个正的偏移量,和顺序号字段中的值相加表示紧急数据最后一个字节的序号。 TCP 的紧急方式是发送端向另一端发送紧急数据的一种方式。
  • 选项和填充:最常见的可选字段是最长报文大小,又称为MSS(Maximum Segment Size),每个连接方通常都在通信的第一个报文段(为建立连接而设置SYN标志为1的那个段)中指明这个选项,它表示本端所能接受的最大报文段的长度。选项长度不一定是32位的整数倍,所以要加填充位,即在这个字段中加入额外的零,以保证TCP头是32的整数倍。
  • 数据部分: TCP 报文段中的数据部分是可选的。在一个连接建立和一个连接终止时,双方交换的报文段仅有 TCP 首部。如果一方没有数据要发送,也使用没有任何数据的首部来确认收到的数据。在处理超时的许多情况中,也会发送不带任何数据的报文段。

需要注意的是: (A)不要将确认序号Ack与标志位中的ACK搞混了。 (B)确认方Ack=发起方Req+1,两端配对。

三次握手

第一次握手:

客户端发送syn包(Seq=x)到服务器,并进入SYN_SEND状态,等待服务器确认;

第二次握手:

服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(Seq=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;

第三次握手:

客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

握手过程中传送的包里不包含数据,三次握手完毕后,客户端与服务器才正式开始传送数据。理想状态下,TCP连接一旦建立,在通信双方中的任何一方主动关闭连接之前,TCP 连接都将被一直保持下去。

为什么会采用三次握手,若采用二次握手可以吗? 四次呢?

建立连接的过程是利用客户服务器模式,假设主机A为客户端,主机B为服务器端。

采用三次握手是为了防止失效的连接请求报文段突然又传送到主机B,因而产生错误。失效的连接请求报文段是指:主机A发出的连接请求没有收到主机B的确认,于是经过一段时间后,主机A又重新向主机B发送连接请求,且建立成功,顺序完成数据传输。考虑这样一种特殊情况,主机A第一次发送的连接请求并没有丢失,而是因为网络节点导致延迟达到主机B,主机B以为是主机A又发起的新连接,于是主机B同意连接,并向主机A发回确认,但是此时主机A根本不会理会,主机B就一直在等待主机A发送数据,导致主机B的资源浪费。

采用两次握手不行,原因就是上面说的失效的连接请求的特殊情况。而在三次握手中, client和server都有一个发syn和收ack的过程, 双方都是发后能收, 表明通信则准备工作OK.

为什么不是四次握手呢? 大家应该知道通信中著名的蓝军红军约定, 这个例子说明, 通信不可能100%可靠, 而上面的三次握手已经做好了通信的准备工作, 再增加握手, 并不能显著提高可靠性, 而且也没有必要。

四次挥手

数据传输完毕后,双方都可释放连接。最开始的时候,客户端和服务器都是处于ESTABLISHED状态,假设客户端主动关闭,服务器被动关闭。

第一次挥手:

客户端发送一个FIN,用来关闭客户端到服务器的数据传送,也就是客户端告诉服务器:我已经不会再给你发数据了(当然,在fin包之前发送出去的数据,如果没有收到对应的ack确认报文,客户端依然会重发这些数据),但是,此时客户端还可以接受数据。 FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。

第二次挥手:

服务器收到FIN包后,发送一个ACK给对方并且带上自己的序列号seq,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号)。此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。

此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。

第三次挥手:

服务器发送一个FIN,用来关闭服务器到客户端的数据传送,也就是告诉客户端,我的数据也发送完了,不会再给你发数据了。由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。

第四次挥手:

主动关闭方收到FIN后,发送一个ACK给被动关闭方,确认序号为收到序号+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2?MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。

服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些

至此,完成四次挥手。

为什么客户端最后还要等待2MSL?

MSL(Maximum Segment Lifetime),TCP允许不同的实现可以设置不同的MSL值。

第一,保证客户端发送的最后一个ACK报文能够到达服务器,因为这个ACK报文可能丢失,站在服务器的角度看来,我已经发送了FIN+ACK报文请求断开了,客户端还没有给我回应,应该是我发送的请求断开报文它没有收到,于是服务器又会重新发送一次,而客户端就能在这个2MSL时间段内收到这个重传的报文,接着给出回应报文,并且会重启2MSL计时器。

第二,防止类似与“三次握手”中提到了的“已经失效的连接请求报文段”出现在本连接中。客户端发送完最后一个确认报文后,在这个2MSL时间中,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样新的连接中不会出现旧连接的请求报文。

为什么建立连接是三次握手,关闭连接确是四次挥手呢?

建立连接的时候, 服务器在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。 而关闭连接时,服务器收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,而自己也未必全部数据都发送给对方了,所以己方可以立即关闭,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送,从而导致多了一次。

发送HTTP请求

首先科补一个小知识,HTTP的端口为80/8080,而HTTPS的端口为443

发送HTTP请求的过程就是构建HTTP请求报文并通过TCP协议中发送到服务器指定端口 请求报文由请求行请求报头请求正文组成。

请求行

请求行的格式为Method Request-URL HTTP-Version CRLF eg: GET index.html HTTP/1.1 常用的方法有: GET,POST, PUT, DELETE, OPTIONS, HEAD。

常见的请求方法区别

这里主要展示POST和GET的区别

常见的区别

  • GET在浏览器回退时是无害的,而POST会再次提交请求。
  • GET产生的URL地址可以被Bookmark,而POST不可以。
  • GET请求会被浏览器主动cache,而POST不会,除非手动设置。
  • GET请求只能进行url编码,而POST支持多种编码方式。
  • GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
  • GET请求在URL中传送的参数是有长度限制的,而POST么有。
  • 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
  • GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
  • GET参数通过URL传递,POST放在Request body中。

注意一点你也可以在GET里面藏body,POST里面带参数

重点区别

GET会产生一个TCP数据包,而POST会产生两个TCP数据包。

详细的说就是:

  • 对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);
  • 而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

注意一点,并不是所有的浏览器都会发送两次数据包,Firefox就发送一次

请求报头

请求报头允许客户端向服务器传递请求的附加信息和客户端自身的信息。

从图中可以看出,请求报头中使用了Accept, Accept-Encoding, Accept-Language, Cache-Control, Connection, Cookie等字段。Accept用于指定客户端用于接受哪些类型的信息,Accept-Encoding与Accept类似,它用于指定接受的编码方式。Connection设置为Keep-alive用于告诉客户端本次HTTP请求结束之后并不需要关闭TCP连接,这样可以使下次HTTP请求使用相同的TCP通道,节省TCP连接建立的时间。

请求正文

当使用POST, PUT等方法时,通常需要客户端向服务器传递数据。这些数据就储存在请求正文中。在请求包头中有一些与请求正文相关的信息,例如: 现在的Web应用通常采用Rest架构,请求的数据格式一般为json。这时就需要设置Content-Type: application/json。

更重要的事情-HTTP缓存

HTTP属于客户端缓存,我们常认为浏览器有一个缓存数据库,用来保存一些静态文件,下面我们分为以下几个方面来简单介绍HTTP缓存

  • 缓存的规则
  • 缓存的方案
  • 缓存的优点
  • 不同刷新的请求执行过程

缓存的规则

缓存规则分为强制缓存协商缓存

强制缓存

当缓存数据库中有客户端需要的数据,客户端直接将数据从其中拿出来使用(如果数据未失效),当缓存服务器没有需要的数据时,客户端才会向服务端请求。

协商缓存

又称对比缓存。客户端会先从缓存数据库拿到一个缓存的标识,然后向服务端验证标识是否失效,如果没有失效服务端会返回304,这样客户端可以直接去缓存数据库拿出数据,如果失效,服务端会返回新的数据

强制缓存的优先级高于协商缓存,若两种缓存皆存在,且强制缓存命中目标,则协商缓存不再验证标识。

缓存的方案

上面的内容让我们大概了解了缓存机制是怎样运行的,但是,服务器是如何判断缓存是否失效呢?我们知道浏览器和服务器进行交互的时候会发送一些请求数据和响应数据,我们称之为HTTP报文。报文中包含首部header和主体部分body。与缓存相关的规则信息就包含在header中。boby中的内容是HTTP请求真正要传输的部分。举个HTTP报文header部分的例子如下:

我们依旧分为强制缓存和协商缓存来分析。

强制缓存

对于强制缓存,服务器响应的header中会用两个字段来表明——Expires和Cache-Control。

Expires

Exprires的值为服务端返回的数据到期时间。当再次请求时的请求时间小于返回的此时间,则直接使用缓存数据。但由于服务端时间和客户端时间可能有误差,这也将导致缓存命中的误差,另一方面,Expires是HTTP1.0的产物,故现在大多数使用Cache-Control替代。

Cache-Control

Cache-Control有很多属性,不同的属性代表的意义也不同。

  • private:客户端可以缓存
  • public:客户端和代理服务器都可以缓存
  • max-age=t:缓存内容将在t秒后失效
  • no-cache:需要使用协商缓存来验证缓存数据
  • no-store:所有内容都不会缓存。

协商缓存

协商缓存需要进行对比判断是否可以使用缓存。浏览器第一次请求数据时,服务器会将缓存标识与数据一起响应给客户端,客户端将它们备份至缓存中。再次请求时,客户端会将缓存中的标识发送给服务器,服务器根据此标识判断。若未失效,返回304状态码,浏览器拿到此状态码就可以直接使用缓存数据了。

对于协商缓存来说,缓存标识我们需要着重理解一下,下面我们将着重介绍它的两种缓存方案。

Last-Modified

Last-Modified:服务器在响应请求时,会告诉浏览器资源的最后修改时间。

  • if-Modified-Since:浏览器再次请求服务器的时候,请求头会包含此字段,后面跟着在缓存中获得的最后修改时间。服务端收到此请求头发现有if-Modified-Since,则与被请求资源的最后修改时间进行对比,如果一致则返回304和响应报文头,浏览器只需要从缓存中获取信息即可。 从字面上看,就是说:从某个时间节点算起,是否文件被修改了
  • 如果真的被修改:那么开始传输响应一个整体,服务器返回:200 OK
  • 如果没有被修改:那么只需传输响应header,服务器返回:304 Not Modified
  • if-Unmodified-Since:从字面上看, 就是说: 从某个时间点算起, 是否文件没有被修改
  • 如果没有被修改:则开始`继续'传送文件: 服务器返回: 200 OK
  • 如果文件被修改:则不传输,服务器返回: 412 Precondition failed (预处理错误)

这两个的区别是一个是修改了才下载一个是没修改才下载。

Last-Modified 说好却也不是特别好,因为如果在服务器上,一个资源被修改了,但其实际内容根本没发生改变,会因为Last-Modified时间匹配不上而返回了整个实体给客户端(即使客户端缓存里有个一模一样的资源)。为了解决这个问题,HTTP1.1推出了Etag。

Etag

Etag:服务器响应请求时,通过此字段告诉浏览器当前资源在服务器生成的唯一标识(生成规则由服务器决定)

  • If-None-Match:再次请求服务器时,浏览器的请求报文头部会包含此字段,后面的值为在缓存中获取的标识。服务器接收到次报文后发现If-None-Match则与被请求资源的唯一标识进行对比。
  • 不同,说明资源被改动过,则响应整个资源内容,返回状态码200。
  • 相同,说明资源无心修改,则响应header,浏览器直接从缓存中获取数据信息。返回状态码304.

但是实际应用中由于Etag的计算是使用算法来得出的,而算法会占用服务端计算的资源,所有服务端的资源都是宝贵的,所以就很少使用Etag了。

缓存的优点

  • 减少了冗余的数据传递,节省宽带流量
  • 减少了服务器的负担,大大提高了网站性能
  • 加快了客户端加载网页的速度 这也正是HTTP缓存属于客户端缓存的原因。

不同刷新的请求执行过程

浏览器地址栏中写入URL,回车

  • 浏览器发现缓存中有这个文件了,不用继续请求了,直接去缓存拿。(最快)

F5

  • F5就是告诉浏览器,别偷懒,好歹去服务器看看这个文件是否有过期了。于是浏览器就战战兢兢的发送一个请求带上If-Modify-since。

Ctrl+F5

  • 告诉浏览器,你先把你缓存中的这个文件给我删了,然后再去服务器请求个完整的资源文件下来。于是客户端就完成了强行更新的操作.

服务器处理请求并返回HTTP报文

它会对TCP连接进行处理,对HTTP协议进行解析,并按照报文格式进一步封装成HTTP Request对象,供上层使用。这一部分工作一般是由Web服务器去进行,我使用过的Web服务器有Tomcat, Nginx和Apache等等 HTTP报文也分成三份,状态码响应报头响应报文

状态码

状态码是由3位数组成,第一个数字定义了响应的类别,且有五种可能取值:

  • 1xx:指示信息–表示请求已接收,继续处理。
  • 2xx:成功–表示请求已被成功接收、理解、接受。
  • 3xx:重定向–要完成请求必须进行更进一步的操作。
  • 4xx:客户端错误–请求有语法错误或请求无法实现。
  • 5xx:服务器端错误–服务器未能实现合法的请求。 平时遇到比较常见的状态码有:200, 204, 301, 302, 304, 400, 401, 403, 404, 422, 500

常见状态码区别

200 成功

请求成功,通常服务器提供了需要的资源。

204 无内容

服务器成功处理了请求,但没有返回任何内容。

301 永久移动

请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。

302 临时移动

服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。

304 未修改

自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。

400 错误请求

服务器不理解请求的语法。

401 未授权

请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。

403 禁止

服务器拒绝请求。

404 未找到

服务器找不到请求的网页。

422 无法处理

请求格式正确,但是由于含有语义错误,无法响应

500 服务器内部错误

服务器遇到错误,无法完成请求。

响应报头

常见的响应报头字段有: Server, Connection...。

响应报文

你从服务器请求的HTML,CSS,JS文件就放在这里面

浏览器解析渲染页面

  • 这个图就是Webkit解析渲染页面的过程。解析HTML形成DOM树
  • 解析CSS形成CSSOM 树
  • 合并DOM树和CSSOM树形成渲染树
  • 浏览器开始渲染并绘制页面 这个过程涉及两个比较重要的概念回流重绘,DOM结点都是以盒模型形式存在,需要浏览器去计算位置和宽度等,这个过程就是回流。等到页面的宽高,大小,颜色等属性确定下来后,浏览器开始绘制内容,这个过程叫做重绘。浏览器刚打开页面一定要经过这两个过程的,但是这个过程非常非常非常消耗性能,所以我们应该尽量减少页面的回流和重绘

性能优化之回流重绘

回流

当Render Tree中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。

会导致回流的操作:

  • 页面首次渲染
  • 浏览器窗口大小发生改变
  • 元素尺寸或位置发生改变
  • 元素内容变化(文字数量或图片大小等等)
  • 元素字体大小变化
  • 添加或者删除可见的DOM元素
  • 激活CSS伪类(例如::hover)
  • 查询某些属性或调用某些方法

一些常用且会导致回流的属性和方法:

  • clientWidth、clientHeight、clientTop、clientLeft
  • offsetWidth、offsetHeight、offsetTop、offsetLeft
  • scrollWidth、scrollHeight、scrollTop、scrollLeft
  • scrollIntoView()、scrollIntoViewIfNeeded()
  • getComputedStyle()
  • getBoundingClientRect()
  • scrollTo()

重绘

当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。

优化

CSS

  • 避免使用table布局。
  • 尽可能在DOM树的最末端改变class。
  • 避免设置多层内联样式。
  • 将动画效果应用到position属性为absolute或fixed的元素上。
  • 避免使用CSS表达式(例如:calc())。

JavaScript

  • 避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。
  • 避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。
  • 也可以先为元素设置display: none,操作结束后再把它显示出来。因为在display属性为none的元素上进行的DOM操作不会引发回流和重绘。
  • 避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
  • 对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。

动高亮效果

  • 源码

<style>
  a {
    text-decoration: none;
    color: #8c7ae6;
    font-size: 24px;
    box-shadow: inset 0 0 0 #8c7ae6;

    transition: all 300ms ease-in-out;
  }

  a:hover {
    box-shadow: inset 180px 0 0 0 #8c7ae6;
    color: white;
  }

</style>
<a href="#">Hover this link</a>

文本交换效果

  • 源码
<style>
  a {
    overflow: hidden;
    position: relative;
    display: inline-block;
  }

  a::before,
  a::after {
    content: "";
    position: absolute;
    width: 100%;
    left: 0;
  }
  a::before {
    background-color: #54b3d6;
    height: 2px;
    bottom: 0;
    transform-origin: 100% 50%;
    transform: scaleX(0);
    transition: transform 0.3s ease-in-out;
  }
  a::after {
    content: attr(data-replace);
    height: 100%;
    top: 0;
    transform-origin: 100% 50%;
    transform: translate3d(200%, 0, 0);
    transition: transform 0.3s ease-in-out;
    color: #54b3d6;
  }

  a:hover::before {
    transform-origin: 0% 50%;
    transform: scaleX(1);
  }
  a:hover::after {
    transform: translate3d(0, 0, 0);
  }

  a span {
    display: inline-block;
    transition: transform 0.3s ease-in-out;
  }

  a:hover span {
    transform: translate3d(-200%, 0, 0);
  }

  body {
    display: grid;
    font-size: 27px;
    height: 100vh;
    place-items: center;
  }

  a {
    text-decoration: none;
    color: #18272f;
    font-weight: 700;
    vertical-align: top;
  }
</style>

<p>Hover <a href="#" id="style-2" data-replace="this link">
  <span>this link</span>
</a></p>

背景拉伸效果

  • 源码
<style>
  a {
    text-decoration: none;
    color: #18272f;
    font-weight: 700;
    position: relative;
  }

  a::before {
    content: "";
    background-color: #00a8ff;
    position: absolute;
    left: 0;
    bottom: 3px;
    width: 100%;
    height: 8px;
    z-index: -1;
    transition: all 300ms ease-in-out;
  }

  a:hover::before {
    bottom: 0;
    height: 100%;
  }

  body {
    display: grid;
    font-size: 27px;
    line-height: 1.5;
    height: 100vh;
    place-items: center;
  }
</style>

<p>Hover this <a href="#">cool</a> link.</p>

从右到左颜色交换效果

  • 源码
<style>
  a {
    background-image: linear-gradient(to right, #54b3d6, #54b3d6 50%, #000 50%);
    background-size: 200% 100%;
    background-position: -100%;
    display: inline-block;
    padding: 5px 0;
    position: relative;

    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    transition: all 300ms ease-in-out;
  }

  a:before {
    content: "";
    background: #54b3d6;
    display: block;
    position: absolute;
    bottom: -3px;
    left: 0;
    width: 0;
    height: 3px;
    transition: all 300ms ease-in-out;
  }

  a:hover {
    background-position: 0;
  }

  a:hover::before {
    width: 100%;
  }

  body {
    display: grid;
    font-size: 27px;
    height: 100vh;
    place-items: center;
  }
</style>

<a href="">Hover This Link</a>

彩虹下划线效果

  • 源码
<style>
  a {
    color: black;
    text-decoration: none;
    background: linear-gradient(to right, #64c8c8, #64c8c8),
      linear-gradient(to right, #ff0000, #ff00b4, #0064c8);
    background-size: 100% 3px, 0 3px;
    background-position: 100% 100%, 0 100%;
    background-repeat: no-repeat;
    transition: background-size 400ms;
  }

  a:hover {
    background-size: 0 3px, 100% 3px;
  }

  body {
    display: grid;
    font-size: 27px;
    font-weight: 700;
    height: 100vh;
    place-items: center;
  }
</style>

<a href="">Hover This Link</a>

原文地址:https://css-tricks.com/css-link-hover-effects/