1 引言
在上一篇文章《给Markdown渲染网页增加一个目录组件(Vite+Vditor+Handlebars)(上)》中笔者介绍了如何实现在Markdown渲染网页中加一个目录组件。不过,上一篇文章中只是介绍了一下功能也就是JavaScript部分的具体实现。其实要实现这个功能,另外一个关键就是样式也就是CSS部分的设计。
阅读本文可能需要的前置文章:
- 《通过JS模板引擎实现动态模块组件(Vite+JS+Handlebars)》
- 《使用Vditor将Markdown文档渲染成网页(Vite+JS+Vditor)》
- 《给Markdown渲染网页增加一个目录组件(Vite+Vditor+Handlebars)(上)》
2 基础
在前端三剑客(HTML+CSS+JavaScript)中笔者认为CSS是最麻烦的,具体就麻烦在CSS并不是一个遵循程序员思维的语言,反而它遵循的是设计师的思维:要求对排版规则的掌控,要求能熟能生巧的积累,最好还要有一点美术审美。大部分的计算机语言都相通,但是CSS却特立独行。
另外,笔者觉得市面上关于CSS的中文教程也大多不太行,很多都是CSS属性的堆砌。笔者记得学习过一本CSS教程,光是开头介绍字体的设置就讲了一个很大的章节,这真的很难让初学者入门。有的人说CSS的属性要靠记忆,这是文科的思维,有一点道理在里面;但是笔者认为CSS作为一门计算机语言,还是有一些理性思维在里面的。其中,最理性最程序员思维的部分就是网页布局:设计出来的页面中的元素,至少要听你指挥,出现在你想要放置的位置。
2.1 盒子模型
盒子模型是网页布局中最基础的概念,定义了如何处理单个HTML元素。具体来说,就是每一个HTML元素都被看作是一个矩形的盒子,这个盒子由内容(content)、内边距(padding)、边框(border)和外边距(margin)组成。这个概念应该来说属于老生常谈了,基本上每个介绍CSS的教程都会首先介绍它。其实要掌握这个概念不用费那么多精力,对着浏览器后台开发工具调试一下padding、border和margin属性,看看每个参数的效果就可以了。如下图所示:
2.2 HTML文档流
HTML文档流(Document Flow)也是网页布局最基础概念之一,指的是HTML页面中的元素,默认按照从上到下、从左到右的顺序对页面元素进行排列和渲染的方式。这个理论听起来非常自然,甚至有点像废话文学;但确实就是网页布局的关键所在:
- HTML页面中的元素如果没有进行特定的排版设置,那么从上到下、从左到右的顺序就是HTML元素的默认位置,这让我们确定了通过CSS调整样式的起始值。
- HTML页面中元素大部分处于文档流中,即使通过CSS调整了位置,也只是改变了局部的布局方式,大体上仍然遵循这个规则。
- 大多数情况下HTML页面中的元素最好不要脱离文档流,因为脱离文档流往往需要比较精细的控制,除非少部分需求真的需要这么做。
在文档流中,HTML元素可以分为三种类型:
类型特点示例标签块级元素独占一行,自动换行,可设置宽高div, p, h1 到 h6行内元素不独占一行,宽度由内容决定,不能设置宽高span, a, strong行内块元素行内显示,但可以设置宽高display: inline-block2.3 现代布局方式
与网页布局最直接相关的属性就是display,最基础的几种属性值如下:
- display: none; 元素不会被显示,也不占据任何空间,常用于隐藏元素。
- display: block; 元素作为块级元素显示(独占一行),可以设置宽度、高度、内外边距。前面介绍的块级元素display的默认属性值就是block。
- display: inline;元素作为内联元素显示(和其他内联元素在同一行),不能设置宽度和高度。前面介绍的行内元素display的默认属性值就是inline。
- display: inline-block;结合了inline和block的特性,可以在同一行显示,并且可以设置宽度、高度、内外边距。常用于横向排列的导航栏或按钮组。
对于现代网页设计来说,更为重要的是display: flex;和display: grid;这两种属性值。其中display: flex;更为重要一点,也就是所谓的弹性盒子布局(Flexbox)。
3 实现
3.1 弹性盒子布局
那么接下来就结合本文的具体实例来讲解Flexbox布局。回到本例的index.html:- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8" />
- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>Vite App</title>
- </head>
- <body>
-
-
-
-
-
- </body>
- </html>
复制代码 对应的样式文件style.css是:- body {
- font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
- margin: 0;
- padding: 0;
- background-color: #f0f0f0;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- }
- #app {
- /* 将容器设置为弹性容器。 */
- display: flex;
- flex-direction: row;
- justify-content: center;
- align-items: start;
- gap: 1rem;
- margin-top: 1rem;
- width: 100%;
- }
- #post-article-placeholder {
- min-width: 600px;
- max-width: 800px;
- flex: 1 1 auto; /* 允许伸缩 */
- }
- #article-toc-placeholder {
- width: 260px;
- position: sticky;
- top: 0;
- flex: 0 0 auto; /* 固定宽度不伸缩 */
- }
复制代码 在这里,我们想让app元素(包含博文内容控件和博文目录控件)居中显示,就设置根元素body为Flexbox布局:- body {
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- }
复制代码 这里的样式设置的意思是:
- flex-direction定义主轴方向,设置成column表示body中的元素像列一样布局,也就是垂直布局。
- justify-content定义项目在主轴上的对齐方式,设置成center表示垂直方向上居中对齐。
- align-items定义项目在交叉轴上的对齐方式,设置成center表示在水平方向上居中显示。
app元素设置成居中之后,解下来我们想让app元素的子元素博文内容控件和博文目录控件左右布局,并且顶端对齐。要实现这个功能:当然还是要设置成Flexbox布局:- #app {
- display: flex;
- flex-direction: row;
- justify-content: center;
- align-items: flex-start;
- }
复制代码 而这里的样式设置的意思是:
- flex-direction: row;表示app中的元素像行一样布局,也就是左右水平布局。
- justify-content: center;表示app中的元素在水平方向上向中心靠齐。
- align-items: flex-start表示app中的元素在垂直方向上,沿着起始位置靠齐,也就是顶端对齐。
可以调整一下这些属性的值来加深对布局的理解。比如align-items的值设置成center,那么博文目录控件就会与博文内容控件在垂直居中对齐;设置成flex-end博文目录控件则会与博文内容控件底部对齐。justify-content的设置在某些情况下非常有用:比如需要在水平方向上(这里的主轴方向)靠左对齐,就设置成flex-start;需要靠右对齐,就设置成flex-end;需要两端对齐,就设置成space-between。
Flexbox布局的好处就在这里,它可以通过设置垂直布局和水平布局,形成了一种对网页布局的通解:只要你拆分的盒子数量和层级够多,那么网页元素可以始终控制在HTML文档流中。换句话说,一个前端程序员的基本素质就是将原型转换成多层级的包含垂直/水平布局的盒子。比如说稀土掘金网站的首页,根据其布局我们可以进行如下拆分:
3.2 响应式布局
使用Flexbox布局还有一个好处,那就是可以实现响应式布局。所谓响应式布局,指的是使网页能够在不同的分辨率下都有比较好的浏览体验。结合本文的例子来说:- #app {
- display: flex;
- }
- #post-article-placeholder {
- flex: 1 1 auto; /* 允许伸缩 */
- min-width: 600px;
- max-width: 800px;
- }
- #article-toc-placeholder {
- width: 260px;
- flex: 0 0 auto; /* 固定宽度不伸缩 */
- }
复制代码 这里的flex 包含了三个子属性:- flex: <flex-grow> <flex-shrink> <flex-basis>;
复制代码 具体的含义是:
子属性描述flex-grow定义项目的放大比例,默认为 0(不放大)flex-shrink定义项目的缩小比例,默认为 1(可缩小)flex-basis定义项目在分配多余空间之前的初始大小,可以是长度值(如 200px)、百分比(如 auto)等对于博文内容控件,flex: 1 1 auto;的意思是:
- flex-grow: 1:该元素会尽可能地占据剩余空间。
- flex-shrink: 1:该元素在空间不足时可以被压缩。
- flex-basis: auto:该元素的初始宽度由其内容或显式设置的 width 决定。
对于博文目录控件,flex: 0 0 auto;的意思是:
- flex-grow: 0:该元素不会扩展。
- flex-shrink: 0:该元素不会压缩。
- flex-basis: auto:项目的初始大小由其内容或显式设置的 width 决定。
也就是说,博文目录的宽度保持原有大小不参与伸缩;而博文内容控件则会根据容器空间进行伸缩。这也是这种布局方式被称为弹性盒子布局的原因,在这种布局方式下,页面中的元素可以灵活响应页面分辨率宽高的变化。不过,在现代网页中文档内容区域的宽度范围通常在600px到800px之间,这里就设置博文内容控件的最小宽度为600px,最大宽度为800px。
当然响应式布局的内涵不止这一点,响应式布局最终希望在不同设备(如桌面电脑、平板电脑和手机)上都有最佳的浏览体验,这需要自动根据屏幕尺寸和方向自动调整布局结构、元素大小及位置;要实现这一点还是离不开Flexbox布局。
3.3 粘性定位
在这里,笔者就回答一下上一篇文章《给Markdown渲染网页增加一个目录组件(Vite+Vditor+Handlebars)(上)》中的问题:博文目录是如何始终保证粘在页面的右上角的?因为使用了粘性定位:- #article-toc-placeholder {
- position: sticky;
- top: 0;
- }
复制代码 这里的意思就是当博文目录控件离开视图页面的时候,就将博文目录控件的位置粘在页面的顶部(top属性值为0的位置)。看起来这个实现非常简单,但是如果在一些复杂的情况下使用会有一些问题,因为粘性定位本质上是脱离了HTML文档流的。比如说,将博文目录粘在右侧控件的顶部还好,如果是粘在其他特定的位置,就需要精确地控制位置属性,否则就很容易与其他页面元素冲突。
不止粘性定位,浮动(float)、绝对定位(position: absolute)、固定定位(position: fixed)都会脱离HTML文档流,不推荐用来作为主要的布局方式,这里就不细说了。
4 结语
最终的博文目录粘在页面右上角的效果如下所示:
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |