网页开发入门|10 综合练习二:导航栏
又到了综合练习时间!这次我们将一起做一个导航栏。

又到了综合练习时间!
现在的我们不但了解了很多常见的HTML
的标签,也了解很多常用的CSS
样式属性。
接下来,让我们启动一个新的实战项目,一方面综合练习一下已经掌握的知识,另一方面也为未来要学习到的内容埋下线索。
需求分析
这次我们将一起做一个导航栏Navigator。
导航栏通常位于网页的顶部,方便用户快速的找到需要前往的板块。



可以看到,根据不同网站的特性,有些导航栏设计的比较简约,还有一些比较复杂。
这次综合练习,让我们挑战一个相对复杂的任务,来复刻一下B站的二级导航栏:

与上次综合练习的图文展示页面不同,这次的页面主要呈现出左右排列的样子,而不是上下排列。
主要分为左、中、右三个部分:

图标区域TabZone

左边的内容尺寸较大,配有icon
,且颜色也比较突出,另外根据人们从左到右的阅读习惯,左边的内容通常也更容易被优先关注到,看来这一部分是网页设计者比较希望用户更关注的内容。
菜单区域MenuZone

中间部分,略列了一些主要的频道,并且在频道的一旁列出了近期的更新数量。其实对一个比较成熟的平台来说,列出这个数字的意义并不是很大,很多是用于营造一种火热的气氛。
推广链接区域LinkZone

最右侧,列出一些近期在推广的功能的入口,同样为了吸引点击,使用了icon
并且颜色较为突出。
接下来,让我们先在workspace
中创建一个新文件navigator.html
,然后逐一实现本页面。
图标区域的实现

图标区域的样式,可以有两种理解方式:
一种是看做两排,一排是icon
,另一排是文字;
还有一种,可以看做共有4组图标,每一组图标由上方的icon
和下方文字组成,然后整体成横向排列。
相对来说,后一种理解更加符合本页面的设计逻辑,因为icon
和文字是一定是成对出现的。
我们也采用后面这种理解方式,尝试写出第一组图标。
图片和文字都是行内元素,默认是水平排列的,为了让他们可以垂直排列,我们分别使用一个div
标签将其包围起来。
<div class="tab-icon"><img src="assets/bili-shouye.png"></div>
<div class="tab-text">首页</div>

通过CSS
调整一下图片的尺寸和文字的样式,还有文字与图片的间距。
.tab-icon img{
width: 36px;
}
.tab-text {
color: #212121;
font-size: 14px;
margin: 4px 0;
}

经过调整后,我们发现整体上和谐了很多,但是文字却是歪的。这是因为文字默认是居左对齐,我们可以通过设定文字的对齐方向text-align: center
来将文字居中。
.tab-text {
color: #212121;
font-size: 14px;
margin: 4px 0;
text-align: center;
}

效果并不尽如人意,文字直接基于整个浏览器窗口居中了,而不是与上方图片的中间对齐。
这是因为div
是块元素,块元素会独占一行,所以对块元素内的内容居中,将会成为整行的中心。
我们可以通过明确的设定div
的宽度,让它与图片的宽度一致,以实现与图片中心的对齐。
.tab-text {
color: #212121;
font-size: 14px;
margin: 4px 0;
text-align: center;
width: 36px;
}

实现了一组图标,我们就可以很容易的实现另外的三组。
在CSS
的类选择器的帮助下,我们只需要添加HTML
代码即可,不再需要重复写样式了。
<div class="tab-icon"><img src="assets/bili-shouye.png" /></div>
<div class="tab-text">首页</div>
<div class="tab-icon"><img src="assets/bili-dongtai.png" /></div>
<div class="tab-text">动态</div>
<div class="tab-icon"><img src="assets/bili-remen.png" /></div>
<div class="tab-text">热门</div>
<div class="tab-icon"><img src="assets/bili-pindao.png" /></div>
<div class="tab-text">频道</div>
但这时我们遇到了一个新的问题,因为块级元素的独占一行的特性,这四组内容形成了纵向排列,而不是水平排列。

当我们既想用与块级元素可以设定宽度的能力(没有宽度就没办法居中对齐了),又想向行内元素一样可以不用自动换行,我们需要使用一种新的元素类型:行内块级元素inline-block。
实际上img
就是一种典型的行内块级元素,只不过我们之前没有特别强调它的这个特点。
不幸运的是并没有一个行内块级元素,是类似div
一样的容器型元素,允许我们放入任何子元素。
不过,可以通过修改某个元素的样式display: inline-block
,强行将一个元素的类型转换为行内块级元素。
让我们把每一组图标都使用一个新的div
包围起来,并设定其class
方便进行样式设定。
<div class="tab-group">
<div class="tab-icon"><img src="assets/bili-shouye.png" /></div>
<div class="tab-text">首页</div>
</div>
<!-- 以下省略类似代码 -->
设定样式,并顺便调整一下水平方向的间距:
.tab-group {
display: inline-block;
margin: 8px;
}

菜单区域的实现

这个区域整体是由多个类似的部分组合而成,每个部分由一些文字和后面的数字组成。
但为什么出现了两排,也有两种理解方式:一种我们可以理解为原本就是设计了两排;还有一种是因为这个区域的宽度不足,导致的换行,当高度也容纳不下了,更多的内容被折叠进了「更多」里面。
后一种理解方式相对更灵活一些,当以后增加或删除菜单项时基本不会影响页面的布局。我们也采用这种理解方式,但暂时先不考虑如何将多的内容折叠进「更多」里。
首先,我们来实现其中一组菜单项的效果。
<div class="menu-item">
<span class="menu-text">动画</span>
<span class="menu-number">999+</span>
</div>
span
是与div
类似的行内容器型元素,可以包围任何其他元素。
对应的样式代码:
.menu-item {
display: inline-block;
}
.menu-text {
color: #212121;
font-size: 14px;
}
.menu-number {
display: inline-block;
font-size: 12px;
background: #73c9e5;
border-radius: 2px;
color: #fff;
margin-left: 1px;
}

接下来把其余的组也加上,同样只需要添加HTML
代码。
<div class="menu-item">
<span class="menu-text">动画</span>
<span class="menu-number">999+</span>
</div>
<div class="menu-item">
<span class="menu-text">音乐</span>
<span class="menu-number">999+</span>
</div>
<div class="menu-item">
<span class="menu-text">舞蹈</span>
<span class="menu-number">999+</span>
</div>
<!-- 以下省略类似代码 -->

所有内容都列进了一行,但我们希望内容在「放映厅」后面自动换行,所以还需把这些内容装进一个宽度合适的父元素里:
<div class="menu-zone">
<div class="menu-item">
<span class="menu-text">动画</span>
<span class="menu-number">999+</span>
</div>
<div class="menu-item">
<span class="menu-text">音乐</span>
<span class="menu-number">999+</span>
</div>
<div class="menu-item">
<span class="menu-text">舞蹈</span>
<span class="menu-number">999+</span>
</div>
<!-- 以下省略类似代码 -->
</div>
.menu-zone {
display: inline-block;
width: 600px;
}

设定了公共父元素之后,换行没问题了,但是又出现对齐的问题,这主要是由于每个数字的宽度不一样而导致的。
数字的宽度也会不一样吗?是的!影响字符宽度的除了字号以外还有字体。在不同的字体下每个字符的宽度会有些许的区别,但有一类字体里所有字符的宽度是一样的,这类字体称作「等宽字体monospaced」。等宽字体常用于代码编辑器等,对「对齐」要求比较高的场景下。
我们需要将数字部分的宽度设为固定值,所以行内块级元素又要出场了。这次我们需要将原本是行内元素的span
设定为行内块级元素,使它拥有被设定宽度的能力。
同时,还需要将数字部分设为居中,以避免内容偏到一边去。
.menu-number {
display: inline-block;
font-size: 12px;
background: #73c9e5;
border-radius: 2px;
color: #fff;
margin-left: 1px;
width: 32px;
text-align: center;
}

推广链接区的实现

这部分的整体结构与上个部分几乎完全一样,一共有6组内容成两排排列。每组内容都有一个icon
和对应的文字成左右排列。
直接上代码。
<div class="link-zone">
<div class="link-item">
<span class="link-icon"><img src="assets/bili-read.svg"></span>
<span class="link-text">专栏</span>
</div>
<div class="link-item">
<span class="link-icon"><img src="assets/bili-activity.svg"></span>
<span class="link-text">活动</span>
</div>
<!-- 以下省略类似代码 -->
</div>
.link-zone {
display: inline-block;
width: 260px;
}
.link-item {
display: inline-block;
height: 32px;
}
.link-icon img {
width: 1.8em;
height: 1.8em;
}
.link-text {
display: inline-block;
color: #212121;
font-size: 14px;
}

我们发现这里出现了icon
和文字没有对齐的问题,也就是垂直方向的居中问题。
造成这个问题的原因有两个,其一是因为icon
资源本身就有白边,其二是因为在垂直方向上默认的对齐位置是所在行的基线Baseline。
在英文字母中,基线的定义比较明确,即小写的x
下边沿两点之间的连线就是基线。
汉字与英文字母不同,没有基线的概念,我们简单理解为距离田字格的下边沿约1/4的位置,如下图所示。

而img
元素的基线就是图片的下底,所以它默认会与同行小写字母x
的下边沿对齐。

如果同一排是汉字的话,会是这样的效果:

可想而知,三种行内元素有三种不同的基线,默认对齐的效果一定不会尽如人意。
通过样式属性vertical-align
,可以修改元素在垂直方向上的对齐线。但它与text-align
不同,vertical-align
是用于子元素的,而不是父元素,也就是说允许在行里的每个元素都有自己的对齐方法。
在代码里,将图片和文字都与本行的中线对齐:
.link-icon img {
width: 1.8em;
height: 1.8em;
vertical-align: middle;
}
.link-text {
display: inline-block;
color: #212121;
font-size: 14px;
vertical-align: middle;
}

分割线的实现
在三个主要部分之间,还有垂直分割线。

我们在上一次综合练习时,了解到hr
元素可以创造出一个水平分割线。但不幸的是HTML
的标签中,没有定义垂直分割线。
我们可以使用盒模型来模拟一根分割线,此处依然需要的是一个行内块级元素:
<div class="vertical-separator"></div>
以及CSS
样式:
.vertical-separator {
display: inline-block;
width: 1px;
height: 46px;
background-color: #e7e7e7;
margin: 8px;
}

小结
对比成稿和原稿,相似度已经非常高了,但是仍在很多细节处出现了问题。


首先,依然是对齐和间距问题,尽管可以通过盒模型,以及相应对齐的样式属性进行调整,但如果亲自试一试会发现实现难度还是很大的。
对齐和间距等问题,都是布局Layout的问题,即如何在页面上更好更舒服的排列各个元素的位置。
然后,还有一处细节问题,动态的右上角有时会有一个小红点,用来提醒用户这里有一些新内容可以看。但我们还不知道如何将两个元素重叠在一起。

最后,还有一些需要通过动图才能看出来的效果。

网页相比别的媒介来说,最大的优点就是可以对用户的操作进行响应,这也是我们目前所有页面所欠缺的能力。
让我们带上这些问题,迈向下一阶段的旅途。
我将本课程所有的代码托管在gitee
上了,你可以点击这个链接,或到gitee.com
上搜索弦五 网页开发入门,查看和获取本课程的全部代码。