先看看最终的效果图
以前和同事闲话吹牛说还能背诵元素周期表前20个元素,后来默想了一下已经背不起来了,又一次日常打脸
。后来偶尔想起来这个事儿,总想翻翻元素周期表(主要还是元素周期表太“漂亮”了,非常好的体现了元素的性质规律)。
这两天又想起这个事儿,就想这个东西用 HTML5 表现的话是不是很容易?看结构似乎用 CSS 的 Grid 布局方式比较好做,刚好也熟悉下 Grid 布局特性。
在网上搜了下元素周期表,总整体布局来看分为两大块,第一部分就是上面凹字形的元素表了。第二部分就是镧系元素和锕系元素的扩展展示部分。
那么 HTML 的部分就先放两个 Div 充当这两个部分的容器。
上面代码中的两个 div 就是容器了。他们的 id 分别设置为 periodicTable 和 series(变量名字不要太在意,我词汇匮乏每次起名都很费劲
),都有一个 container 类名。
下面再看每个化学元素的展示,如下图所示:
每个元素包含三个部分,左上角的原子量,右上角的元素符号,下面的元素中文名称。很容易写出氢元素的 HTML 结构如下:
- [/code]外层用一个 div 包裹,里面元素的具体内容用三个 span 表示。按代码所示分别给各个 HTML 元素添加一个类名。将上面这段代码放在 id 为 periodicTable 的 div 内部。
- HTML代码如下所示:
- [list][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][*][/list][code]
复制代码 页面效果如下:
元素的原子数,元素符号,中文名称都在一行,怎么把它们按照元素周期表上的那种方式排列呢?方法有很多,这里我们采用 CSS 的 flex 布局实现。在 HTML 代码中的 Style 标签内添加如下 CSS 样式代码:
- * grid-template-columns 属性指定 Grid 中的 列 (主要是列宽)如何设置。
复制代码- * repeat 函数表明重复 18 次,设置 列宽 为 1fr,
复制代码- * fr 表示按比例设置列宽 18 个 1fr 就表示设置为 18 列,每列宽度是 1/(18*1)
复制代码- grid-template-columns: repeat(18, 1fr);
复制代码- flex-wrap: wrap; /* 设置为需要换行 */
复制代码- border: 0.5px solid #666; /* 给元素添加一个灰色的边框 */
复制代码 将 atom 和 symbol 的 宽度设置为 50%,并且设置他们的父元素(element 类)的 flex-wrap (换行模式)为 wrap(换行),这样 元素的原子量和元素符号就会占一行,元素名称就会落到第二行,这样就达到了我们想要的效果。
效果图:
我们再添加第二个元素--氦元素,看看效果。
可以看到氦元素和氢元素紧紧的挨在一起了,氦应该是在第一行最右边也就是第 18 列的位置。我们给氦元素的 div 添加一个 Grid 布局相关的属性来实现这个目的。
- [/code]代码
- [list][*][/list][code]style="grid-column-start: 18;"
复制代码 表示添加内联样式,设置 grid-column-start: 18; 表示这个本元素在 Grid 中的列位置从第18列开始(位置编号从 1 开始)。
现在 HTML 页面看起来是这样的:
可以看到氦元素已经到最右边去了。
如果这样一个个添加的话,也太麻烦了。每个元素的样式布局和 HTML 代码一样,对于这样重复的工作当然是使用代码实现最简单咯。
我们先用一个数组来表示所有元素。
- { symbol: "H", name: "氢" },
复制代码- { symbol: "He", name: "氦" },
复制代码- { symbol: "Li", name: "锂" },
复制代码 通过遍历数组 elements 来生成所有表示元素的 HTML 代码。然后将容器 HTML 元素的 innerHTML 设置为生成的代码。
具体 js 代码如下:
- elements.forEach((item, i) => {
复制代码- document.getElementById('periodicTable').innerHTML = html;
复制代码 页面效果如下:
还有几个地方需要调整。
- 部分元素的位置需要调整,例如氦元素需要偏移到 18 列,硼元素需要偏移到 13 列。
- 注意到元素表中有两个位置比较特殊,57号元素镧元素的位置实际上是多个元素,镧下面的锕元素的位置也是。现在的表中57号以后的元素原子数显示已经不对了,需要处理一下
- 一般元素表会区分金属元素与非金属元素。
还需要提一下的是,在使用数组 elements 表示化学元素的时候,元素对象中并没有元素的原子数信息,在数组索引隐含了这个信息,这个做法不是太好,在每个对象中包含化学元素的原子信息是一个更好的做法(这里因为我是从网上查的元素信息,使用正则替换的方法生成的这个数组代码,缺失了原子数信息,这里偷懒就没补了)。
下面逐个解决上面的问题。首先是元素位置的调整,可以在遍历 elements 数组是根据化学元素的原子数进行判断,增加偏移信息设置。只有氦、硼、铝三个元素是需要偏移的,所以直接判断还可以接受。
数组遍历部分代码修改如下:
- elements.forEach((item, i) => {
复制代码- style = 'style="grid-column-start:18;"'
复制代码- if (atom === 5 || atom === 13) {
复制代码- style = 'style="grid-column-start:13;"'
复制代码 接下来是第二个问题,对镧系元素及其后面元素的原子数的处理。由于 57 和 89 号元素的位置原子数是一个范围,元素名称也比较普通的长,所以两个位置的字体要缩小一下,以方便展示。
对于第三个问题,通过给金属元素及非金属元素设置不同的背景色来区分。
在样式部分增加如下样式代码:
- background-color: #acc0f0;
复制代码- background-color: #c89f4d;
复制代码- .element.series .symbol {
复制代码 在数组遍历函数中修改代码,根据化学元素的原子数进行判断。
- const isNonmetal = (atom) => {
复制代码- return nonmetal.some(range => {
复制代码- elements.forEach((item, i) => {
复制代码- } else if (atom > 57 && atom < 75) {
复制代码- } else if (atom === 75) {
复制代码- if (typeof atom === 'number') {
复制代码- className = isNonmetal(atom) ? 'nonmetal' : 'metal';
复制代码- style = 'style="grid-column-start:18;"'
复制代码- if (atom === 5 || atom === 13) {
复制代码- style = 'style="grid-column-start:13;"'
复制代码- document.getElementById('periodicTable').innerHTML = html;
复制代码 现在页面看起来是这个样子的:
已经像模像样了,还差最后一点,对镧系元素和锕系元素的详细展示。有了上面的基础,这个就简单了。
样式部分添加代码如下:
- background-color: #f4c2a7;
复制代码- background-color: #e78b5b;
复制代码 js代码部分添加如下代码:
- { symbol: "La", name: "镧" },
复制代码- { symbol: "Ce", name: "铈" },
复制代码- { symbol: "Pr", name: "镨" },
复制代码- { symbol: "Nd", name: "钕" },
复制代码- { symbol: "Pm", name: "钷" },
复制代码- { symbol: "Sm", name: "钐" },
复制代码- { symbol: "Eu", name: "铕" },
复制代码- { symbol: "Gd", name: "钆" },
复制代码- { symbol: "Tb", name: "铽" },
复制代码- { symbol: "Dy", name: "镝" },
复制代码- { symbol: "Ho", name: "钬" },
复制代码- { symbol: "Er", name: "铒" },
复制代码- { symbol: "Tm", name: "铥" },
复制代码- { symbol: "Yb", name: "镱" },
复制代码- { symbol: "Lu", name: "镥" }
复制代码- { symbol: "Ac", name: "锕" },
复制代码- { symbol: "Th", name: "钍" },
复制代码- { symbol: "Pa", name: "镤" },
复制代码- { symbol: "U", name: "铀" },
复制代码- { symbol: "Np", name: "镎" },
复制代码- { symbol: "Pu", name: "钚" },
复制代码- { symbol: "Am", name: "镅" },
复制代码- { symbol: "Cm", name: "锔" },
复制代码- { symbol: "Bk", name: "锫" },
复制代码- { symbol: "Cf", name: "锎" },
复制代码- { symbol: "Es", name: "锿" },
复制代码- { symbol: "Fm", name: "镄" },
复制代码- { symbol: "Md", name: "钔" },
复制代码- { symbol: "No", name: "锘" },
复制代码- { symbol: "Lr", name: "铹" }
复制代码- let series = document.getElementById('series');
复制代码- LaLu.forEach((item, i) => {
复制代码- style = 'style="grid-column-start:4;"'
复制代码- AcLr.forEach((item, i) => {
复制代码- style = 'style="grid-column-start:4;"'
复制代码- series.innerHTML = seriesHTML;
复制代码 现在元素周期表就完整了(最后两个元素的中文名称输入法还打不出来,意会一下)。
最后还有个地方需要调整一下。
当页面宽度不足时,元素的显示空间会被压缩,变得很难看。所以我们在 container 的样式中设置一个合适的宽度,这样当页面宽度不足时会产生滚动条,不会导致显示变形。
- grid-template-columns: repeat(18, 1fr);
复制代码 将 container 的 width 设置为 1206px 是个不错的值,1206 是 18 的整数倍(每行有 18 个元素),这样会避免一些细微的像素级偏差问题。
到此元素周期表的 HTML5 展示就完成了,点击下方阅读原文可以查看最终效果及代码。
Grid 布局功能是一个非常强大的功能,这篇文章不是 Grid 布局功能的详细介绍,只是稍稍展示了下 Grid 布局的威力,要想学习更多 Grid 布局的内容可以查看相关的 MDN 文章。
btw:现在公众号的插入代码功能比原来好多了啊,一般情况下也够用了,不用在别处编辑再粘贴过来了
,好久没写了之前搞代码排版的那个网页都找不到了
Grid MDN 参考链接:
https://developer.mozilla.org/zh-CN/docs/Glossary/Grid
|
|