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

Making An Indicator With Pure CSS

简单的说明一下,使用这个标题并不就是说要使用全英文来写这篇文章,主要是实在想不到更好的叫法了,也不知道怎么样能够更好的翻译成中文。

可以简单地理解为:使用 CSS 来实现一个阅读文章时的简单的进度条效果。

本文所需要用到的背景知识点包括:background-size, linear-gradient, calc() 函数, vh 单位

Indicator 是什么?可以把它看作是一个指标,这种指标其实很常见,在我们阅读文章的时候,我们会将文章向上滚动,一些网站的做法就是给用户一个指标,标示用户已经读了多少内容了,这个指标就类似于一个进度条的样子,鼠标每向上或者向下滚动一点,这“进度条”会增加或者减少一点。用户阅读完毕的时候,它的长度也会达到整个网页的宽度。

一般情况下,如果要实现一个这样的效果,我们首先想到的肯定是使用 JavaScript。通过使用 JavaScript 来根据用户滚动的距离,然后,将这个距离和 Indicator 的总长度以及剩余内容的高度综合进行比较,进行一些换算,然后改变 Indicator 的长度,这样,就实现了一个 Indicator 了。

本文不会讲解如何使用 JavaScript 来实现此效果,如果有需要的,可以参考 Bloomberg Article Scroll Indicator。

那么,本文主要讲解的就是如何使用 CSS 来实现此效果。

首先,我们将 HTML 都写好了(由于涉及到滚动,所以,可以随意的多加点内容,此处只是示范性地写了一点内容,具体的读者可以自行添加更多内容):

<header>
    <h1>Scroll Indicator</h1>
</header>
<main>
    <h2>I was interested to see if I could make a scroll indicator like this with just CSS.</h2>
    <p>You can! But maybe you shouldn't. This is an interesting consequence of a bunch of hacks held together with duct tape. It uses z-index hacks, gradient hacks and tricks with calc and viewport units.</p>
    <p>Having said that, hacks are not always bad. I love hacks and many of us have made quite a good living selling floats and clearfixes.</p>
    <p>The techniques used here are well supported, if not conventional. If you can read the CSS, understand how it works, and how to change it, and you think this works better for you than JavaScript, feel free to implement it. Just be aware of the z-index behaviour and possible conflict with other CSS using negative z-index.</p>
    <hr>
    <p>Cras mattis consectetur purus sit amet fermentum. Donec id elit non mi porta gravida at eget metus. Donec id elit non mi porta gravida at eget metus. Aenean lacinia bibendum nulla sed consectetur.</p>
    <h3>Tristique Aenean Etiam Cras</h3>
    <p>Donec id elit non mi porta gravida at eget metus. Donec ullamcorper nulla non metus auctor fringilla. Nulla vitae elit libero, a pharetra augue. Donec sed odio dui. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.</p>
    <p>Cras mattis consectetur purus sit amet fermentum. Donec id elit non mi porta gravida at eget metus. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Etiam porta sem malesuada magna mollis euismod. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec ullamcorper nulla non metus auctor fringilla.</p>
    <p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Donec ullamcorper nulla non metus auctor fringilla. Sed posuere consectetur est at lobortis. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Aenean lacinia bibendum nulla sed consectetur. Nulla vitae elit libero, a pharetra augue.</p>
    <p>Donec sed odio dui. Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor. Cras mattis consectetur purus sit amet fermentum. Maecenas sed diam eget risus varius blandit sit amet non magna.</p>
</main>

然后,我们简单的调整一下样式:

html,
body {
    margin: 0;
    padding: 0;
}

body {
    font-family: "Times New Roman", Courier, monospace;
    font-size: 1.25rem;
}

由于我们滚动的时候,需要让 header 保持不动,所以,需要给它设置 position: fixed;

header {
    position: fixed;
    top: 0;
    width: 100%;
    height: 125px;
    padding: 0 10%;
    background: #ffffff;
}

然后,为了避免 main 元素包含的内容被 header 覆盖,我们需要让 main 往下挪一些,同时给它设置一个 padding

main {
    margin-top: 125px;
    padding: 10px 10%;
}

OK,大概的调整就这些,我们现在来构思如何实现这个 Amazing 的效果。

按照使用 JavaScript 来实现这个效果的思想,那么,我们就需要先去计算一个百分比——也就是滚动的文章长度与总的剩余文章长度的比。

如下图所示:

图片描述

假设我们文章的总长度为 a,以红色的线为界限,超出红线上的部分即为滚动的距离。那么,我们此刻滚动的距离为 xz 代表的是滚动的进度百分比,红线的总长度 y 即为我们的 Indicator 的总长度,也就是所谓的 100%。那么,我们需要的肯定是以下的关系:

x / a === z / y;

那么,计算出来的滚动的进度百分比 z 应该就是:

z = (x * y) / a;

好了,这是 JavaScript 的大概思路,我们已经了解了,我们先把这个结果放这儿,来看看如何使用 CSS 来实现。

在这里,我们需要用到两个 CSS 属性和一个 CSS 方法和一个 CSS 单位——linear-gradient, background-position 和 calc() 和 vh

简单的介绍一下这两个属性:

1.background-position 接受 1 到 4 个参数,默认值为 0% 0%。可以设置的值有 top right bottom left center,前四个值后面还可以跟具体的数值或者百分比。如果不加方向说明,直接设置数值或者百分比,位置则会以 left top 进行定位。注意:此处的 top right bottom left 定位是以 padding-box(即 padding 的外沿框) 进行定位的。
(若要了解详细内容,可查看 background-position | MDN。)

2.关于 linear-gradient,即用来创建线性渐变。这个函数可接受多个参数值,其中,第一个表示渐变的方向,如果不写的话,默认为 to bottom,其余分别是 to top | left | right,后面的参数表示渐变的颜色,可以有多个颜色,每一个颜色后面还可以指定颜色的渐变位置。
(若要了解详细内容,可查看 linear-gradient | MDN。)

注意:由于 linear-gradient 生成的是一个 CSS image 对象,所以,这个函数只能应用在需要的数据类型是 image 的属性(如 background-image, background)上。也就是说,如果在 color 或者 background-color 属性上应用这个函数的话,将会不起作用。

3.关于 calc() 函数,可以用来动态计算 CSS 的属性值。比如 calc(100px - 10px) 最终结果就为 90px;
若要了解详细内容,可查看 calc | MDN。

注意:为了让这个函数向上兼容,以后可能会在 calc 的内部允许使用关键字(或者说变量),而这些关键字(或者变量)就包含连字符(即减号),所以,为了避免解析冲突,要在运算符的前后加上空格。其中,+ 和 - 前后必须加上空格,* 和 / 前后不要求,但为了一致性,最好也都加上空格。

4.关于 vh 单位,这个单位代表的意思即 ViewHeight,即浏览器可视区域的高度。与百分比类似,100vh = height: 100%
(若要了解详细内容,可查看 length | MDN。)

那么,我们使用 CSS 实现的话,思路和 JavaScript 稍微有一点区别。但原理是一样的,我们仍然需要计算一个比例。

还是来看一张图:

图片描述

我们将我们的我们让 Indicator 的宽度和 body 等宽(好吧,其实就是 100%,此处这样话会好理解一点),然后,注意到黄色的三角形了吗,当我们向上滚动的时候,黄色的三角形也会跟着向上滚动,同时,它会和长度为 y 的 Indicator 发生交叉,Indicator 会从三角形截出一段距离 z。这时候,黄色三角形向上移动的距离是 x。那么,要达到 Indicator 的效果,我么肯定要满足下面的条件:

x / a === z / y;

所以,这样计算出来,我们的 z 就是:

z = (x * y) / a;

注意到没,其实和我们上面的使用 JavaScript 时的计算结果是一样的。所以,原理相同,我们只需要变通一下就好了。

那么,怎么用 CSS 写出来呢?

注意到黄色三角形了吗,它上面还有一个白色三角形,它们两个是对称的,由两种不同的颜色组成,正好可以将其作为我们的 Indicator 的高亮色和默认色。

我们把这两种颜色作为 body 的背景颜色,文章就在这个背景的上面,那么,我们滚动文章的时候,背景也会跟着动,就会有以上图中的效果了。

body {
    background: linear-gradient(to right top, #0089f2 50%, #DDD 50%);
    background-position: 0 125px;
    background-size: 100% calc(100% - 100vh + 5px);
    background-repeat: no-repeat;
}

注意到第一个属性的设置了吗,我们将两个颜色的位置都设置成了 50%,那么,这就相当于简便的过渡区域趋于无限小,看上去就相当于两种颜色累积在一起。

第二个属性,我们将背景的位置进行了更改,将其往下移动了 125px,这个距离正好是我们的 header 的高度。这样,在我们没有滚动的时候,Indicator 的进度将会是 0;。

第三个属性,看着这么长一个计算的等式,其实计算的是我们的剩余文章的长度。100% 即文章的总长度,100vh 即我们所看到的文章的长度,至于那个 5px 是什么,那是我们预留出来显示 Indicator 的高度。

OK,我们现在来看效果将会是下面这张图片显示的样子。

图片描述

我们看到,当我们向上滚动的时候,headermain 的交界处的蓝色区域在变化,对,这就是我们将要实现的 Indicator 的原型。

那么,既然是一个 Indicator,那他就应该有一个 Indicator 的样子。我们需要把下面的那些全部遮住,只留出 Indicator 的那一条 progress bar。

所以,我们继续完善代码:

body:before {
    content:'';
    position: fixed;
    top: 127px;
    bottom: 0;
    width: 100%;
    z-index: -1;
    background: white;
}

我们通过使用一个伪元素来把 body 中多余的背景给隐藏掉。

设置 top: 127px; 目的即让 Indicator 的高度为 2px,即到顶部的距离减去 header 的距离。

至此,我们使用 CSS 制作的 Indicator 就上大功告成了。

下面是我们实现的所有代码和效果:

CSS only scroll indicator

本文参考自 https://codepen.io/MadeByMike...,我在此基础上对其进行了一些优化。如果有问题,欢迎在评论区留言,Feel Free To Ask。

相关文章:

  • python编程中的if __name__ == 'main': 的作用和原理
  • [raspberry pi3] zram设置
  • MyEclipse Site
  • 金蝶出现问题该怎么解决
  • Access 中数据库操作时提示from子句语法错误
  • rsync服务之配置文件rsyncd.conf详细说明
  • 【223】◀▶ IDL HDF 文件操作说明
  • 角色和权限Hibernate实体映射配置
  • C言语指向数组元素的指针
  • 常见问题解决
  • T-SQL 之 自定义函数
  • Comparable和Comparator排序接口
  • 驰骋工作流引擎表单设计控件-关系类控件-明细表(3)
  • 第一篇、C_高精度加法
  • 【域控管理】父域的搭建
  • CODING 缺陷管理功能正式开始公测
  • golang中接口赋值与方法集
  • leetcode98. Validate Binary Search Tree
  • Magento 1.x 中文订单打印乱码
  • maven工程打包jar以及java jar命令的classpath使用
  • 基于遗传算法的优化问题求解
  • 阿里云ACE认证学习知识点梳理
  • 湖北分布式智能数据采集方法有哪些?
  • ​用户画像从0到100的构建思路
  • #define
  • #stm32整理(一)flash读写
  • #我与Java虚拟机的故事#连载02:“小蓝”陪伴的日日夜夜
  • (1) caustics\
  • (10)STL算法之搜索(二) 二分查找
  • (3)选择元素——(17)练习(Exercises)
  • (5)STL算法之复制
  • (pt可视化)利用torch的make_grid进行张量可视化
  • (十)【Jmeter】线程(Threads(Users))之jp@gc - Stepping Thread Group (deprecated)
  • (转载)PyTorch代码规范最佳实践和样式指南
  • .NET6 命令行启动及发布单个Exe文件
  • .NET国产化改造探索(一)、VMware安装银河麒麟
  • .Net接口调试与案例
  • .NET中两种OCR方式对比
  • .pyc文件是什么?
  • // an array of int
  • @ModelAttribute 注解
  • [ Linux 长征路第五篇 ] make/Makefile Linux项目自动化创建工具
  • [ vulhub漏洞复现篇 ] Celery <4.0 Redis未授权访问+Pickle反序列化利用
  • [.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序...
  • [AIGC 大数据基础]hive浅谈
  • [ASP.NET MVC]如何定制Numeric属性/字段验证消息
  • [Avalon] Avalon中的Conditional Formatting.
  • [BSGS算法]纯水斐波那契数列
  • [BZOJ 3531][Sdoi2014]旅行(树链剖分+线段树)
  • [Bzoj4722]由乃(线段树好题)(倍增处理模数小快速幂)
  • [dfs] 图案计数
  • [HITCON 2017]SSRFme perl语言的 GET open file 造成rce
  • [lesson17]对象的构造(上)
  • [Linux]于Mac在配置Linuxserver安装Nginx+PHP
  • [ORM]register db Ping `default`, Error 1130: Host '' is not allow connect to this MySQL server