像骑自行车一样自然地设计网页。

——Sion

✍文章痕迹

写作时间线

2025-01-?

某日打开github星标榜,发现storybook项目。

2025-03-30

阅读《版式设计原理》

2025-03-31

再次产生创建STUDIO网站的念头,初步想法是使用React进行构建

2025-04-01~4-02

阅读《大前端三剑客——Vue+React+Flutter》,旋即弃置

2025-06-09

  • 受两年前喜欢的hexo主题《Paper》作者影响,尝试学习Sigma
  • 观看视频教程《零基础学Figma》[^2]

2025-06-10

2025-06-14

意识到Figam的局限性——只是一个原型设计软件,开始接触react。

2025-06-15

理性看待Figma。Figma可以作为指导性文件来勾勒整体的轮廓而后以此为基础进行开发,同时可以进行简单的封面制作。

2025-07-25

因为MES系统维护需要,借阅《JavaScript 技术手册》,开始系统学习js。


平日走路、工作、骑车,脑海里或多或少会浮现出一些念头,可能是一个照片的绝妙机位,一个有趣的游戏原型,一段悦耳的节奏,可能是一幅以天空为背景的插画,也可能是对网站主页的一个构建。有人说这叫灵感,我却以为这是虚感,不过是一阵风吹来,恰到好处地拂动了脑海里几个不同的念头而已,在这感觉没有落地之前,是毫无意义的。那如何让这些念头变得有意义呢?我觉得要去培养,去一点一滴地呵护它,如同养一盆花一般,让慢慢地成长,才会赋予其意义。

本文动笔的契机就是许多个念头的累积让这颗种子发了芽,至于到底能不能长大开花,甚至结果,我也不管,当下哩,我就静静地看着它,想起来了就浇点水~

写在开始的预期

本次试验要做出来几个原型,大概有这些:

  • 星际牛仔片头设计

  • 国画风格:留白——文本让位图像

  • 45°布局:

  • 90°布局:即直排版

  • 社会主义革命和建设时期宣传海报风格的当代演绎

  • 细朱文为主的拟物线条风格

  • 图表,数据可视化相关。

  • 个人主页、工作室主页、专题展示页(摄影、篆刻、绘画)

设计工具

figma

figma给我的初步观感:像做PPT一样设计网页。

本文定位只是一个辅助学习用的很随便的草稿,非教程,非笔记

  • 我们可以通过多种方式去补足这些知识,​“三大构成”就是开始系统认知设计或者UI设计的第一步。​“三大构成”包含《平面构成》(The Plane Constitution)、​《色彩构成》(The ColorConstitution)和《立体构成》(Three-Dimensional Constitutes),通过这三本书,我们可以在更高的理论层面来对设计有个系统的认知。
  • 如果还有时间,伊顿的《设计与形态》​《康定斯基论点线面》​,福兰可·惠特福特的《包豪斯》也是非常适合设计师夯实基础的著作。

与时下流行的Material Design不同(尽管我也觉得这种设计很美观),笔者本次实践主要目标是向前求索:追寻、挖掘、表现古文古画古书上图像与符号的关联关系。具体到就是(竖排版,模仿自然)。

  • 图形绘制能力是几乎所有设计师都必须具备的一项能力,如果说版式设计能力决定了UI设计师60%的能力要素,那么图形绘制能力则让你的技能分从60分精进到80分甚至更高。

  • UI设计师学习的工具有以下几类,首先是

    • 图形绘制工具,如Sketch(Windows下有Adobe XD)​、Figma、Photoshop,这也是当今设计师用得比较多的主流工具,从难易程度上来说,Sketch(XD)和Figma上手难度最低,操作最简单。
    • 交互工具,在UI设计稿完成前,这类工具可以帮我们绘制低保真的线框图;而设计稿完成后,我们需要用这类工具将其处理成高保真演示原型。最常见的交互工具,可以统称为“连连看工具”​,只需按照页面的顺序,将点击区域及目标区域进行连接即可。目前大部分的设计工具都提供了此类连线功能,如Sketch、XD、Figma等。当然,也有更复杂的工具,如Flinto、Principle及一些在线设计工具(如墨刀)​,都可以完成从设计稿导入到连线导出,最终形成可以在手机上真实点击的效果,这类工具的特色是做出更接近手机真实动作效果的演示,比如论坛图、下拉刷新、页面滚动等。
    • 进阶类的图形绘制工具,以Photoshop或者Adobe illustrator为代表。用以完成界面中的一些图形化设计工作,如插画、字体、Logo设计。
    • 动效(微交互)效果的设计、3D视觉工具等。这类工具有Adobe的After Effect和Cinema 4D,通常学习成本较高,需要花费更多精力才能有所收获。
      作者推荐的软件

linux设计老师傅(穷人版)的工具箱

目前掌握程度简单自评:

Adobeillustrator(3年+)

Adobephotoshop(2年)

清华大学出版社提供了第二章的样章,微信阅读排版不好,还是读这个舒服。

Figam中的Frame(画框)与html中的<iframe>内嵌框架元素标签有类似的含义.

  • Figma的交互设计比较有趣的一点就是,特定的工具只有在激活的时候才会出现,非激活状态或者不可用状态下是完全隐藏的。
figma可以创建文本样式与组件以便复用 文本转化为矢量(Flatten Selection)进行编辑
  • 导出内容:“①使用切片工具划定需要导出的内容;②选中某个图层,在右侧的属性检查器中,找到“Export”选项,并单击加号,设定导出倍数、后缀和图片格式。”

  • 快捷键说明(基本与PPT一致)

    • Ctrl + D :副本
    • Ctrl + G :编组
    • Ctrl + +Shift+G :取消编组
    • 拖拽调整数值:与Blender类似
    • 选择矢量图形,然后直接粘贴可以将图形贴到矢量图形中。
  • 创建蒙版步骤

    1. 新建一个矢量图层,右键新建蒙版(mask)
    2. 此时左侧会生成一个蒙版组(Mask Group)
    3. 把图片放进蒙版组里面
    4. (调整图片或者矢量图形可以得到不同的画面)

问题

  • Figma对竖排没有支持,插件vertja的实现方式是文本框溢出,不能简单转换成css。

🕳前端框架

Npm

package.json的版本号写法:
1. ^(插入符号,Caret)

  • 含义:允许更新到当前主版本号下的最新版本(不破坏向后兼容性)。
  • 规则^x.y.z 允许更新 y 和 z,但保持 x 不变。
  • 示例
    • ^1.2.3 → 允许 1.x.x(如 1.2.41.3.0),但禁止 2.0.0
    • ^0.y.z:因为主版本是 0(初始开发阶段),仅允许更新 z(如 ^0.1.2 → 0.1.x)。
      2. ~(波浪符号,Tilde)
  • 含义:允许更新到当前次版本号下的最新补丁版本(更保守)。
  • 规则~x.y.z 仅允许更新 z,保持 x 和 y 不变。
  • 示例
    • ~1.2.3 → 允许 1.2.x(如 1.2.4),但禁止 1.3.0 或 2.0.0
    • ~1.0.0 → 仅允许 1.0.x

3. 无符号(精确版本)

  • 直接写 x.y.z 表示严格锁定该版本,不自动更新。

4. 其他符号

  • ><>=<=:指定版本范围。
  • * 或 x:匹配任意版本(不推荐)。
  1. 选取建议
  • ^:默认行为(npm install --save 使用),平衡新功能和稳定性。
  • ~:更严格,适合需要最小化更新的场景。
  • 锁定文件:实际安装版本由 package-lock.json 或 yarn.lock 精确控制,确保团队一致性。

NG-ZORRO

NG-ZORRO(Angular 组件库)

Ionic

Ionic 移动端框架

JavaScript

JavaScript 常见的功能包括:

  • 以指定尺寸、位置和样式(比如是否有边框、菜单、工具栏等)打开新窗口;
  • 提供用户友好的导航帮助,比如下拉菜单
  • 检验 Web 表单输入的数据,在向 Web 服务器提交表单之前确保数据格式正确;
  • 在特定事件(比如鼠标光标经过页面元素之上)发生时,改变页面元素的外观与行为;(每次浏览器要加载和显示页面时,都需要解释(更专业的术语是“解析”)构成页面的 HTML 源代码。在解析过程中,浏览器建立一个内部模型来表示文档里的内容,这个模型就 是 DOM(Document Object Model)。在浏览器渲染页面的可见内容时,就会引用这个模型。可以使用 JavaScript 来访问 和编辑这个 DOM 的各个部分,从而改变页面的显示内容和用户交互的方式。)
  • 检测和发现特定浏览器支持的高级功能,比如第三方插件,或是对新技术的原生支持。

“JavaScript 是一种解释型语言,不是 C++或 Java 那样的编译语言。JavaScript 指令以纯文本形式传递给浏览器,然后依次解释执行。它们不必先“编译”成只有计算机处理器能够理解的机器码,这让JavaScript 程序很便于阅读,能够迅速 地进行编辑,然后在浏览器里重新加载页面就可以进行测试。”

html使用<script>...</script>标签,可以在html代码中直接包含JavaScript语句,也可以在标签里定义一些特有的熟悉。对于 HTML4里,需要使用type属性:<script type="text/javascript">,在本栈的主题配置文件里,就存在这样的写法,

1
2
3
4
5
6
- <script src="https://npm.elemecdn.com/echarts@4.9.0/dist/echarts.min.js"></script>
- <script type="text/javascript" src="https://fastly.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
- <script charset="UTF-8" id="LA_COLLECT" src="//sdk.51.la/js-sdk-pro.min.js"></scri
- <script> new LingQue.Monitor().init({id:"3FTSzvJ4NLnOUYqy",sendSuspicious:true});</script>
- <script src='/js/mastodon-timeline.js'></script>
- <script src='/js/embed.js'></script>

DOM

“浏览器每次加载和显示页面时,都在内存里创建页面及其全部元素的一个内部表示体系, 也就是 DOM。在 DOM 里,页面的元素具有一个逻辑化、层级化的结构,就像相互关联的父对象和子对象组成了一个树形的结构。这些对象及其相互关系构成了 Web 页面及显示页面的 浏览器的抽象模型。每个对象都有“属性”列表来描述它,而利用 JavaScript 可以使用一些 方法来操作这些属性。”

DOM全称:Document Object Model,即文档对象模型,如上所述,它是浏览器解析渲染HTML源码过程中所用到的一个模型规则。DOM可以类比成康德哲学里的图式——连接感性直观与理性的中介。(W3C的目的是让DOM不仅应用于Web页面与Js,也能用于任何编程语言和XML。)

在浏览器的疆域里,DOM模型的框架是由许多对象进行表示的,最顶级的DOM对象是window,他是一切对象的父对象,示例如下:

以hexo官网为例,在控制台输入window.location后会显示如下信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1. Location {ancestorOrigins: DOMStringList, href: 'https://hexo.io/zh-cn/', origin: 'https://hexo.io', protocol: 'https:', host: 'hexo.io'}
2. ancestorOrigins: DOMStringList {length: 0}
3. assign: ƒ assign()
4. hash: ""
5. host: "hexo.io"
6. hostname: "hexo.io"
7. href: "https://hexo.io/zh-cn/"
8. origin: "https://hexo.io"
9. pathname: "/zh-cn/"
10. port: ""
11. protocol: "https:"
12. reload: ƒ reload()
13. replace: ƒ replace()
14. search: ""
15. toString: ƒ toString()
16. valueOf: ƒ valueOf()
17. Symbol(Symbol.toPrimitive): undefined
18. [[Prototype]]: Location

有了树形结构,就可以通过线性的方式找到节点下任何一个对象,

  1. window.document.body:HTML页面的<body>部分在DOM里就是document对象的一个子对象。类似的:
    1. window.document.domain:HTML页面的domin
    2. window.document.title:HTML页面的<title>...</title>
  2. window.object.method:不仅仅是对象甚至是属性或方法也可以通过这种方式进行表示。

window 对象永远包含当前浏览器窗口,所以使用 window.document 就可以访问当前文档。作为一种简化表示,使用 document 也能访问当前文档。
如果是打开了多个窗口,或是使用框架集,那么每个窗口或框架都有单独的 window 和 document 对象,为了访问其中的某一个文档,需要使用相应的窗口名称和文档名称

交互的方法

  • object.method
  1. 命令window.alert(),浏览器弹出一个包含“确定”按钮的窗口:
1
2
<script>window.alert("问世界好在");</script>
//alert(document.title),浏览器将显示当前页面的标题,对象可以作为变量来进行操作。

这是句点表示法的案例,调用了windows对象的alert()方法。在实际编写过程中,window作为DOM的最顶层,因而上述语句中的window.可以忽略掉。
2. window.document.write("主页body啦啦啦"),浏览器将页面全部内容覆写成<body>主页body啦啦啦</body>
3. confirm(),弹出一个模态对话框,向用户弹出一个选择的对话框,选择不同值,会返回不同值,也可以直接

1
var answer = confirm("你吃饭没有啊?");
  1. prompt(),弹出一个对话框,用户可以输入信息(第二个参数可以输入默认信息)。
1
2
whatmeal = prompt("吃啥饭?","面条儿")
'煎饼'
  1. getElementById():通过id调用DOM。如果想从 HTML 页面里选择具有某个特定 ID 的元素,我们只需要把相应元素的 ID 作为 参数来调用 document 对象的 getElementById()方法,它就会返回特定 ID 的页面元素所对应的 DOM 对象。比如调用hexo官网里id为intro-feature-list的部分
1
document.getElementById("intro-feature-list")

脚本示例

在Web页面里嵌入JavaScript有两种方法,第一种方法是直接包含在HTML文件里:

1
2
3
<script>
... Javascript 语句 ...
</script>

第二种方法是将js代码保存到单独的文件里,然后使用<script>元素的src(源)属性来指定文件名,从而把这个文件包含到页面里:

如果不在同一文件夹内,要使用相对路径,或者用网络存到一个链接上。
1
<script src='code.js'> </script>

值得注意的是:不能使用同一个<script>元素来包含外部 JavaScript 文件,同时包含 JavaScript 语句,因为如果利用<script>元素的 src 属性包含了外部 JavaScript 文件,就不能在<script></script>之间包含 JavaScript 语句了,而是这个区域必须为空。

按照惯例,JavaScript 代码文件的名称扩展名是.js。但从实际情况来看,代码文 件的名称可以使用任何扩展名,浏览器都会把其中的内容当作 JavaScript 来解释。

JavaScript 语句必须包含在定义这些元素的 HTML 的后面。在代码读取和执行完毕之后,页 面呈现才会继续,直到页面完成。对于一些包含函数的js文件,最好是放在<head>...</head>区域里,这样它会被首先加载,以后就可以在任何位置调用它了

鼠标事件

为了增加交互功能,我们需要知道用户在页面唯一的肢体延申——鼠标,在什么时间,存在于何处、在做什么等。这些基本因素我们称之为event(事件)。

  1. onClick:在点击之后执行此事件
  2. onMouseOver:当鼠标进入页面的某个元素所占据的区域时,会触发此事件
  3. onMouseOut:当鼠标离开页面的某个元素所占据的区域时,会触发此事件

利用 onMouseOveronMouseOut 事件处理器可以在鼠标位于图像上方时改变图像的显 示方式。为此,当鼠标进入图像区域时,可以利用onMouseOver 改变元素的 src 属性; 而当鼠标离开时,利用 onMouseOut 再把这个属性修改回来。

数据类型与运算

  • 数字:0xA十六进制;0b1010001二进制;0o4545八进制;8.848e38848000e-3科学计数法(代表8848000×103\color{blue}8848000\times 10^{-3} )。js中可以表示的数字的最小值 Number.MIN_VALUE253-2^{53},最大值 Number.MAX_VALUE2532^{53}

Number()可以把数字的字符串转化成数字(在给 Number()传递某个值作为一个参数时,该函数将尽全力返回一个对等的数值。如果 它不能返回数值,将返回 NaN。),而toString()则可以将数字转化成字符串。

node 环境
1
2
3
4
> A='0xB'
'0xB'
> Number(A)
11

js用 Number 对象来表示各种数值类型,包括整数和浮点数。通常,我们不需要 操心自己创建 Number 对象,因为 JavaScript 会将数值转换为 Number 类的一个实例。一些用法如下:

  1. number.isNaN():检测是否非数值
  2. number.isInteger():检测是否是整数
  3. Number.isFinite():检测是否是无穷大。
  4. Number.parseFloat()和 Number.parseInt():将字符串解析成浮点数或者整数。
  • 字符串,转义相关(超过\uhhh\u{},ES6新增特性)
  • 布尔,boolean
  • 复合类型,{},中间以逗号隔开,可以同时放置各种字段。使用点运算符来随时操作对象的特性(js的重要特点,这个写法太优雅了。)
复合类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> let dog001 = {name:'小黑', color: 'black'}
undefined
> dog001.name
'小黑'
> dog001.color
'black'
> dog001.color = ‘white’
'white'

> delete dog001.name
true
> dog001.name
undefined
> dog001
{ color: 'black' }
  1. 数组[111,222,333,444]
  2. 变量声明(js变量对大小写敏感,因而可以用“骆驼大小写”的方式来编写一个更具可读性的变量,如GodIsDead💀)
    • let:变量。在区块{}作用域内有效,处于暂时性死区区块外无定义则会报错。
    • const:常量,一次声明而后不能重新初始化、 重新声明或重新赋值。
    • var:声明变量,在创建时便被初始化,被赋值为undefined,有提升行为(全局变量):在未指定值之前,会被定义为undefined

undefined代表“值没有定义”的值,其在JavaScript中不是保留字,在函数中可以被拿来作为变量名称,但尽量不要用它。通过void可以在任何值或表达式前产生undefined。类似的还有null表示没有对象,令对象为null相当于给它置空。NaN:当结果无法运算时,便会产生此值。

  1. 加减乘除运算:js中的数字是IEEE 754标准64位浮点数,使用分数以及指数来表示小数,然而有些小数无法用分数表示,这就导致比如0.3之类的数字会有浮点数误差。如果要避免需要用第三方库bignumber.js来解决
    1. *:乘法
    2. **:指数
    3. %:取模
    4. /:除法
    5. ++:自加操作
    6. --:自减操作
    7. -= AnNobodyCareLittleNumber:自减去一个数值

严格模式,ES5后新增,若误用了不好或早期规则含混不清的特性,就会报错。使用use strict来进入严格模式。
8. 比较运算:使用 \===、!== 来进行比较
9. 逻辑运算:&&||!这个返回值要研究研究。
1. A && B:A为真,则不论B真假都返回B;A为假,则直接返回A
2. A || B:A为真,则不论B真假都返回A;A为假,则直接返回B。(可以看作默认返回值,输入A假,返回B作为默认值)
3. !A:A为真,返回false,A为假(0),返回true

返回值为TRUE
1
0 || `` && NaN || !undefined || null
  1. 条件运算:表达式 ? 成立返回值 : 失败返回值。可用于局部的判断语句,减少程序体量。

流程语法

break可以离开switch、for、while、do…while的区块,break与continue可以搭配标签使用,离开整个区块。

  1. if分支判断:条件默认
单层判断
1
2
3
4
5
6
if(条件){
语句A;
}
else{
语句B;
}
多层判断
1
2
3
4
5
6
if(条件){
语句A;
}
else if(条件2){
语句C;
}
  1. Switch 复合分支,使用break进行结束跳转
switch
1
2
3
4
5
6
7
8
9
10
11
switch(number){
case 10:
score= 'S';
break;
case 9:
score= 'A';
break;
case 8:
score= 'B';
break;
}
  1. for 循环,先判断后执行循环语句
for
1
2
3
for(let number=1; number<10; number++){
console.log(number);
}
1. `for of`,循环访问数组中(of)的值`for(let nuumber of [10,20,30])`
2. `for in`,列举对象的特性名称,搭配`[]`运算符使用
3. `for`循环分三部分,变量声明+循环退出条件+表达式,变量声明

js中{}表示对象,[]/·访问对象的属性。

  1. While循环,先循环语句后执行判断
while
1
2
3
4
do{
语句;
}
while(条件表达式);

函数

函数
1
2
3
function hello() {
alert("问世界好在")
}

在页面加载时,包含在函数定义区域内的代码不会执行,而是静静地等待,直到“调用” 的时候才会执行。

  1. 声明函数function。如果没有return值,则返回undefined。函数名称必须以字母或下画线开头,可以包含字母、数字和下画线,不能包含空格、标 点符号和其他特殊字符。
1
2
3
4
5
6
7
let n1 = 100
let n2 = 200
console.log(max(n1,n2));

function max(n1,n2){
return n1 > n2 ? n1:n2;
}

语句中如果不写分号结束,则js会以分行判断结束。

辗转相除法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function gcd(m,n){
if(n ===0){
return m;
}
return gcd(n,m%n);
}

let m = 999;
let n = 666;
let r = gcd(n,m);
if(r === 1){
console.log('互质');
}
else {
console.log('最大公因子', r);
}

如果函数只是在重复操作,那么其应用范围将大大受限,可以通过参数传递的方式来拓展其功能。用latex中的函数能更直观地理解,下面的2就是入参的个数,#1#2为参数在函数内的值。

1
2
3
4
5
\newcommand{\hello}[2]{
hello,\textbf{#1},\textit{#2}
}

\hello{世界}{你好}

在javascript中,需要定义每一个函数的具体名称,并确保包含了与函数定义相匹配的参数数量,比如下面的求和函数,需要四个入参:

1
2
3
4
function plus(a,b,c,d) {
alert(a+b+c);
}
plus(1,1,2,3)

对于简单的函数,可以采用匿名函数的写法:

1
var sayHello = function() { alert("Hello"); };

更简洁直观的写法是利用所谓的箭头函数=>下面以上述加法函数为例:

➕➕
1
2
3
4
5
6
7
8
9
//写在一行
plus = (a,b,c,d) => alert(a+b+c+d);

//写在多行
plus = (a,b,c,d) => {
let dongdong = a+b;
let qiang = c+d;
alert(dongdong+qiang);
}

浏览器相关

js可以通过window.history来访问浏览器历史记录,history对象只有一个长度的属性,表示用户访问过的页面的数量,history对象有许多种方法:

  1. forward():相当于前进
  2. backward():相当于后退
  3. go(number):跳转到历史记录列表里相应匹配的URL里(或许可以实现无法后退的效果)

通过location则可以“帮助”用户导航至新页面,location.href = 'www.newpage.com'

css

按钮背景动画:

1
2
3
4
5
6
7
8
9
10
.glowing-button::before, .glowing-button::after, .glowing-button-alt::before, .glowing-button-alt::after {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 200%;
height: 100%;
background: radial-gradient(circle, rgba(255, 255, 255, 0.3), rgba(0, 0, 0, 0));
transform: rotate(45deg);
animation: glow 4s linear infinite;