找回密码
 立即注册
首页 业界区 业界 给Markdown渲染网页增加一个目录组件(Vite+Vditor+Handl ...

给Markdown渲染网页增加一个目录组件(Vite+Vditor+Handlebars)(下)

押疙 2025-9-24 16:44:10
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属性,看看每个参数的效果就可以了。如下图所示:
1.png

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:
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.   <meta charset="UTF-8" />
  5.   <link rel="icon" type="image/svg+xml" href="/vite.svg" />
  6.   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7.   <title>Vite App</title>
  8. </head>
  9. <body>
  10.   
  11.    
  12.    
  13.   
  14.   
  15. </body>
  16. </html>
复制代码
对应的样式文件style.css是:
  1. body {
  2.   font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
  3.   margin: 0;
  4.   padding: 0;
  5.   background-color: #f0f0f0;
  6.   display: flex;
  7.   flex-direction: column;
  8.   justify-content: center;
  9.   align-items: center;
  10. }
  11. #app {
  12.   /* 将容器设置为弹性容器。 */
  13.   display: flex;
  14.   flex-direction: row;
  15.   justify-content: center;
  16.   align-items: start;
  17.   gap: 1rem;
  18.   margin-top: 1rem;
  19.   width: 100%;
  20. }
  21. #post-article-placeholder {
  22.   min-width: 600px;
  23.   max-width: 800px;
  24.   flex: 1 1 auto; /* 允许伸缩 */
  25. }
  26. #article-toc-placeholder {
  27.   width: 260px;
  28.   position: sticky;
  29.   top: 0;
  30.   flex: 0 0 auto; /* 固定宽度不伸缩 */
  31. }
复制代码
在这里,我们想让app元素(包含博文内容控件和博文目录控件)居中显示,就设置根元素body为Flexbox布局:
  1. body {
  2.   display: flex;
  3.   flex-direction: column;
  4.   justify-content: center;
  5.   align-items: center;
  6. }
复制代码
这里的样式设置的意思是:

  • flex-direction定义主轴方向,设置成column表示body中的元素像列一样布局,也就是垂直布局。
  • justify-content定义项目在主轴上的对齐方式,设置成center表示垂直方向上居中对齐。
  • align-items定义项目在交叉轴上的对齐方式,设置成center表示在水平方向上居中显示。
app元素设置成居中之后,解下来我们想让app元素的子元素博文内容控件和博文目录控件左右布局,并且顶端对齐。要实现这个功能:当然还是要设置成Flexbox布局:
  1. #app {
  2.   display: flex;
  3.   flex-direction: row;
  4.   justify-content: center;
  5.   align-items: flex-start;
  6. }
复制代码
而这里的样式设置的意思是:

  • 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文档流中。换句话说,一个前端程序员的基本素质就是将原型转换成多层级的包含垂直/水平布局的盒子。比如说稀土掘金网站的首页,根据其布局我们可以进行如下拆分:
2.png

3.2 响应式布局

使用Flexbox布局还有一个好处,那就是可以实现响应式布局。所谓响应式布局,指的是使网页能够在不同的分辨率下都有比较好的浏览体验。结合本文的例子来说:
  1. #app {
  2.   display: flex;
  3. }
  4. #post-article-placeholder {
  5.   flex: 1 1 auto; /* 允许伸缩 */
  6.   min-width: 600px;
  7.   max-width: 800px;
  8. }
  9. #article-toc-placeholder {
  10.   width: 260px;
  11.   flex: 0 0 auto; /* 固定宽度不伸缩 */
  12. }
复制代码
这里的flex 包含了三个子属性:
  1. 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)(上)》中的问题:博文目录是如何始终保证粘在页面的右上角的?因为使用了粘性定位:
  1. #article-toc-placeholder {
  2.   position: sticky;
  3.   top: 0;
  4. }
复制代码
这里的意思就是当博文目录控件离开视图页面的时候,就将博文目录控件的位置粘在页面的顶部(top属性值为0的位置)。看起来这个实现非常简单,但是如果在一些复杂的情况下使用会有一些问题,因为粘性定位本质上是脱离了HTML文档流的。比如说,将博文目录粘在右侧控件的顶部还好,如果是粘在其他特定的位置,就需要精确地控制位置属性,否则就很容易与其他页面元素冲突。
不止粘性定位,浮动(float)、绝对定位(position: absolute)、固定定位(position: fixed)都会脱离HTML文档流,不推荐用来作为主要的布局方式,这里就不细说了。
4 结语

最终的博文目录粘在页面右上角的效果如下所示:
3.png


来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

昨天 00:38

举报

热心回复!
您需要登录后才可以回帖 登录 | 立即注册