从零开始的前端学习手记 构建篇

从零开始的前端学习手记 构建篇
LuooU整个学习路线构建在:HTML 简介 - 学习网络开发 | MDN Web 中文网之上。
构建,顾名思义,就是很浅地过一遍。
HTML
我开始写前端的时候已经比较晚了,因为学校有相关的作业要求,故HTML这个板块用成果为楔,慢慢道来。
1 |
|
这是一段html代码,用浏览器打开它,我们可以得到一个网页。
网页的效果是这样的:
HTML是什么?
HTML(超文本标记语言)会告诉浏览器如何构建你访问的网页,它由一系列元素(elements)组成。
1 | <a> </a> |
元素
元素就是这种由标签(tags,<>)包裹的东西,你可以使用它们来包围、封装、标记内容的不同部分,使它们以某种方式显示或运行。
现在把视角看向网页最上方的文字,
我们希望文本独立存在,就可以通过<p></p>(paragraph)元素指定。
比如第一句,这是我的html网页,将由
1 | <p> |
来实现。
中间就是元素的内容。
但是,这个代码只能达到这样的效果:
我想要他居中,就需要用到元素的属性(attributes)。
属性
1 | <p style="text-align:center;"> |
属性包含元素的额外信息。
比如<img>元素(image)可以拥有众多属性,
src:指定图片位置(url地址/图片路径)alt:指定图片文本描述(图片刷不出来的替代文本)width/height:分别制定图片宽度和高度

属性有这些(从HTML 属性 | 菜鸟教程转):
初步了解,按需使用,要用再学。
看代码:
html一般分为head和body,head代表创建一个包含html内容的容器,页面不会显示head其中的内容。
关于声明:
前两行, 第一行声明必须加,声明此文件是html文件。
第二行规定页面语言,这将影响浏览器跳不跳翻译功能。
>>> 中文用zh-Hans/zh-CN,英文用en.
关于头(head):
头元素包含的这些也很重要。
<meta charset="UTF-8">:表示元数据。 其中的charset属性指定字符编码为UTF-8,通常是要加上的。<meta name=" " content=" ">:指定这个页面将随设备宽度变化而变化,初始不缩放。<title>代表该网站的标题,比如我们在浏览器里看到的这些。
关于体(body):
现在再回头看代码的主体:
1 | <body style="text-align: center;"> |
-
第一行:
bodybody是和head相对应的元素。
我在这里直接
style="text-align: center;",给了他一个居中的属性,意味着在这个body之中的所有元素全部默认居中。 -
header(页眉)header元素相当于这个网站内容的一个标题(其实就是字体变大)。当然现在的header更加自由,已经变成了<h1>至<h6>,拥有更加多的字体大小。其中
<h1>元素的属性title,是将鼠标悬停时将看到的文字。 -
main:像main主函数一样,这里就是我们网页内容的主体。
-
<a></a>超链接:拥有一个
href属性,该属性表示前往的链接。 -
<p></p>段落:正常文本。
-
<hr>:水平分割线(horizontal rule),类似于:
-
<table></table>:表格,其中的属性有通用的
id,class,style等,表格的样式一般都已经靠class+CSS的组合来控制了。
但是单html,我们使用border作为边框宽度、cellpadding作为单元格内边距、cellspacing作为单元格之间的间距、width/height作为表格宽高、align作为表格对齐方式、bgcolor作为背景色,还有不太常用的frame(控制表格外边框哪几边显示)、rules控制内部线条显示方式。依然是按需取用。
-
style中的参数都是什么?margin:外边距,写两个值时分别是上下外边距和左右外边距。 这里就是让表格上下空出20px的距离。
border-collapse:是表格的特有属性,用来控制单元格边框的合并方式。 默认是
separate->每个单元格有自己的边框。 而
collapse->把相邻单元格的边框合并成一条线。text-align:控制文字的对齐方式,将被子元素(<td>/<th>)继承。 有
left/right/center. -
<thead></thead>:表头(table head),就是第一行的内容。
-
<tr></tr>:表格的一行(table row)。
-
<th></th>:表头单元格(table header cell)。
-
-
<tbody></tbody>:表格主体(table body)。
-
<td></td>:普通单元格
然后其中有一行嵌套了一个超链接,所以嵌套元素也就这样,依然可以被
style等修改样式,这个是改的字体颜色。
-
总结一下:
-
<thead>:表头 -
<tbody>:表格内容<thead>/<tbody>需要搭配<tr>(表格的一行)使用,内部需要<th>(表头单元格)/<td>普通单元格来填充。
-
-
-
footer(页脚):页脚就是页面最下面的内容。
<div>:定义一个块级容器,没有什么含义,但是方便CSS控制样式。
在这里我规定超链的宽度为父容器宽度的25%,那么在我超链内的图片,就也默认继承超链区域的宽度。我们介绍一下
display:inline-block;display:规定元素怎么在页面里排队占位,其中三种常见的参数,可以看一看:block(块级元素)独占一整行(前后自动换行) 可以设置宽高、调整内外边距 <div> <p> <h1>默认就是 blockinline(行内元素)不会换行,元素会像文字排在一整行里 不能设置宽高(宽高由内容决定) <a>, <span>, <em>默认是 inlineinline-block(行内块元素)可以一行放多个、不一定换行 可以设置宽高、调整内外边距 适合按钮、卡片、图标一行排多个的布局 在这里我将超链设置为行内块元素,意味着我可以调整这个“超链盒子”的宽高了。
而超链盒子,又意味着这一整块区域都将是超链区域,点击跳转。它的子容器
img,我调整宽度100%,意味着图片将铺满这个25%宽度的盒子。 这样,就避免了超链可点区域远大于图片显示区域的问题。
最后超链返回顶部,
#top锁定页眉的top.(这个
id就是CSS给的钩子)
然后我们就可以过渡到CSS阶段了🤓,虽然说用style很方便很高级,但是既然要学css,就少用这种内联样式,单独开css文件写样式才是正解。
CSS
在这里,我们目标是修饰html阶段的结业文件,让他更有网页味。
我们以html为锚点向外推进。
了解CSS
-
什么是CSS?
CSS(Cascading Style Sheets,层叠样式表)可以给HTML文档和XML应用添加样式,扩展名是.css.听过html的很难没听过css,后者功能的强大有目共睹。
-
如何引入CSS?
只需要在html文件的
<head>里添加一行:1
<link href="style.css" rel="stylesheet" />
注意
href要指向css文件。 -
怎么使用CSS?
需要了解基本选择器(元素选择器
例:h1、类选择器例:.card、ID选择器例:#top)、声明块。CSS规则由两个主要的部分构成:选择器、一条或多条声明。
- 选择器通常是需要改变样式的HTML元素,声明由一个属性和一个值组成。
声明以分号结束,由大括号括起。
例如,我想给我的
top一个红色字体,我就可以在css中写:1
2
3#top{
color:red;
}然后在head里用link指向该css文件就可以了。
- 选择器通常是需要改变样式的HTML元素,声明由一个属性和一个值组成。
盒子模型(Box Model):
任何HTML元素都可以看成矩形的盒子。
在这里我们弄懂margin(外边距)/padding(内边距)/border(边框).
margin是边框外的透明区域,
border是内边距和内容外的边框,你可以把他变粗变细,甚至是删除他。
padding是内容周围的透明区域,
content就是盒子的内容,比如文本、图像。
当然盒子还有宽高width/height。
Flexbox布局:
flexbox(弹性盒子)是一种响应式布局方式,这种布局方式在显示设备不同(屏幕大小、设备类型)的情况下,可以依然确保元素拥有恰当的行为。
可以尽量规避CSS中元素溢出和奇怪缩放的问题。
当我们写display: flex,我们就开启了一个flexbox。(只要html元素可以容纳文本等内容,就可以成为flexbox)
让我们用Flexbox Froggy - A game for learning CSS flexbox打开flexbox的新篇章。
一个池塘,代表一个容器。既然已经是flexbox,那他就会有flexbox拥有的所有属性。我们慢慢讲:
横着的叫主轴(初始方向从左到右),竖着的叫交叉轴(初始方向从上到下)。
正常情况下,我们的元素将从两个轴的起点开始堆叠–>青蛙的位置,如果存在两个元素,那将先按主轴的方向堆叠,比如第二关的青蛙:
关于justify-content属性(主轴对齐):
我们需要知道justify-content属性,控制对齐位置的属性。其中三个值:
| flex-start(默认) | flex-end | center |
|---|---|---|
| 把flex项目对齐到主轴的起点 | 把flex项目对齐到主轴的终点 | 把flex项目对齐到主轴的中央 |
| 左对齐 | 居中对齐 | 右对齐 |
那很明显,这一关我们要把青蛙放到右边,只需要写一行:
1 | justify-content: flex-end; |
第二关写:
1 | justify-content: center; |
还有三个值:
| space-between | space-around | space-evenly |
|---|---|---|
| 两侧紧贴边缘,间隙平均 | 两侧不贴边缘,但是由于中间容器将共用间隙,因此中央间隙是两侧间隙的两倍大小 | 中央两侧间隙等大 |
![]() |
![]() |
![]() |
关于align-items/align-self属性(交叉轴对齐):
如果要在交叉轴上对齐这几个青蛙,就要用到align-items属性,其中几个值:flex-start/flex-end/center都和上面主轴的justify-content类似。
我们同时写:
1 | align-items: center; |
就可以让元素在屏幕上居中。
此外,使用align-self将定义单个元素的交叉轴对齐逻辑,这将覆盖父容器align-items属性的继承。
关于flex-direction属性(主轴方向):
还有一个属性:flex-direction,默认值为row,表示主轴水平从左到右;row-reverse表示主轴水平从右到左;column表示主轴竖直从上到下;column-reverse表示主轴竖直从下到上。
这些将影响justify-content和align-items的逻辑。
关于order属性:
你可以使用order属性指定单个项目,更改它的显示位置。
order值范围是:-2~2.
关于flex-wrap属性(换行):
flex-wrap属性接受以下取值:
| nowrap | wrap | wrap-reverse |
|---|---|---|
| 元素将固定在一行里,收缩页面对应元素也会收缩。 | 元素在空间不够时会绕到第二行。 | 元素将反向绕行,从下到上排列。 |
![]() |
![]() |
![]() |
收缩是因为每一个元素都有一个属性:flex-shrink:1,这将给予他们收缩的能力。如果改成0,元素将在保持原来大小的情况下溢出容器。
还有一个类似的属性:flex-grow:1,这将让元素尝试填满父容器的可用空间,如果容器有额外空间,元素就会变宽。
其他的数字仅在相互比较时有意义,如果某一个元素的
flex-grow值为5,其他元素为1,意味着这个元素的增长速度是其他元素的五倍。给元素设置
max-width/min-width将设置他们增长或收缩的尺寸的最值。
和flex-direction:column共用,可以达到竖着绕行的效果。
但是这个绕行一点都不均匀,你可以理解成每一行有一个独立的主轴和交叉轴。在这种情况下,align-items只会控制各自交叉轴的对齐情况,这时候我们就需要其他的属性控制他们整体的对齐,
它就是:align-content。
关于align-content属性(交叉轴全局对齐):
他的值和justify-content差不多,拥有flex-start/flex-end/center,它还有space-between/space-evenly/space-around,
还有比较特殊的stretch(默认),它将把每一行拉伸得足够长,尽量填满交叉轴上的可用空间,所以绕行不均匀。
比如这是align-content: flex-start;的效果。
在尝试上面这些值时,推荐加一个属性:gap: 20px;,以此代替margin。
关于flex-flow属性(主轴方向、换行):
flex-wrap和flex-direction的结合体,在这个属性里,你将可以融合二者,直接写出:
1 | flex-flow: row wrap; |
这表示横向正排列,换行。
因此这个布局,我们也可以使用flex-flow:column wrap;实现。
Level 23:
是的,已经Level 23了。
用如下css布局即可让青蛙回家:
Level 24:
是的,最终章!
用如下css布局就可以让青蛙回家:
结业项目:
这个项目也是博采众长了,去各种网站里找了css代码,一点一点扒过来学,还有就是自己的一些奇思妙想,前端真好玩。
Flexbox属性的继承关系:
在此之前,我们得讲讲Flexbox的家规:只管亲儿子,不管孙子。
比如在这里:
我给menu设置了display:flex,但是当我在给buttons设置gap时,却发现无效。
这是因为父容器menu只负责分开这里的icon1和buttons,不会把属性继续继承到button上,所以我们需要给buttons再写一个display:flex;。
粘性定位:
1 | <div class="menu"> |
我想让menu一直悬浮在页面最上方,就可以使用position: sticky;粘性定位,但是需要注意的是,需要设置top/left/bottom/right中的任意一个属性、以确定元素何时固定。
例如:
1 | .menu{ |
top: 0;代表当菜单元素紧贴网页顶端时开始固定。
阴影:
CSS中可以给元素设置阴影,用box-shadow属性即可。
可以指定五个值,X轴偏移量、Y轴偏移量、模糊半径、扩散半径、颜色。
比如我写:
1 | box-shadow: 5px 5px 5px rgba(0,0,0,0.5); |
就可以得到左上角光源的阴影效果。
自定义滚动条:
我们可以针对 WebKit 内核(Chrome, Edge, Safari)使用伪元素,设置其scrollbar属性,具体实现方法如下:
1 | ::-webkit-scrollbar:{ |
流光按钮:
我们得先认识一下::before/::after伪元素:
::before/::after
我们完全可以把伪元素当做一个正常的html元素,但是伪元素是添加在css中的,因此我们可以用伪元素在不污染html结构的情况下添加一些特殊样式。
伪元素绝对需要加的属性是content,不想拥有任何内容就写content: "";,没有这个就不会显示。
before和after的区别是一个在父元素的前面,一个在父元素的后面。但是真的有区别吗?
他的位置会被我们用position: absolute;定义(别忘了给父元素写上position: relative;),再使用top/left/bottom/right去精确控制位置,所以前后在这里就没有意义了。
因为伪元素默认是行内元素,所以有时候还需要单独设置display: block;.
1 | <div class="menu"> |
1 | .btn-item{ |
这是一个流光按钮的css代码,实现逻辑很简单:
- 第一层是一个
class: btn-item的容器,他规定了按钮的边界; - 第二层是一个带渐变光效动画的伪元素;
- 第三层是一个
<span>遮罩,深灰色的板子盖住大部分动画,只留下一个边框,就实现了彩色光带按钮。
这个overflow,可以删掉看看。
功能是隐藏溢出的部分,这句话就是核心。
为什么这里要写四倍宽?这里先要讲一下动画的逻辑,就是直接让这个元素平移,如果我们能每次平移一个按钮的宽度,就可以无缝衔接(因为我们的渐变色是首尾相接的)。四倍宽和我们接下来动画里的-25%刚好联动,
简单计算:400% * 25% = 100%.
linear-gradient
linear-gradient:linear–>线性的,gradient–>渐变,这个函数就是css用来创建线性渐变图像的,这个图像是由浏览器实时绘制的(通常用在background-image(简写为background)中)。
有两个参数,第一个是方向(决定渐变线的走向),两种写法:
-
关键词:
to right/bottom/...:从左往右、从上到下(默认),还可以写
to bottom right:从左上到右下。 -
角度deg:
0deg:从下往上 (12点方向) ⬆️90deg:从左往右 (3点方向) ➡️180deg: 从上往下 (6点方向) ⬇️270deg: 从右往左 (9点方向) ⬅️
第二个参数就是颜色:
既可以写成red, blue这种均匀分布,也可以写成 red, orange, yellow, green, blue这样的均匀分布,想写多少颜色就多少颜色。
当然还可以控制位置,在颜色后面加百分比,告诉浏览器这个颜色最纯的位置在哪。
比如:
1 | background: linear-gradient(to right, red 50%, blue 50%); |
前50%都是红色的,然后马上变成蓝色。其实我们上面的只是省略了%,我们写成red, blue的时候已经默认red 0%, blue 100%了。
这是Gemini给的形象解释:
书接上文,那为啥不直接写100% * 100%呢?
原因在width不大,动画就不能小,这样太慢不丝滑。所以background-size我们也对应弄小,因为有四倍的图片所以不怕穿帮了。
z-index是层级,设成负数就可以把图层往下移,成为背景。
animation是在调用动画,第一个值代表动画名字,第二个值代表动画周期,第三个值代表匀速,第四个值代表无限循环。默认设置暂停,因为下面我们要设置:hover,鼠标移上去再动。
1 | .btn-item:hover::before { |
顶层遮罩,我们要遮住中间的部分。内部圆角通常要比外层圆角小一点点,视觉才协调。
动画帧@keyframes radium,定义radium这个动画的逻辑。
0%理解成开始,100%理解成结束,从起始位置0%到终止位置,向左移动25%,就这么简单。
背景渐变动画:
类似地,我们看看这个:
1 | body { |
font-family:字体栈,逻辑是规定浏览器使用字体的优先级。既有兼容性,又美观。
-
"Helvetica Neue", Helvetica, Arial:这是mac和windows的经典字体,英文字体,所以放在最开头。当浏览器遇到汉字,英文字体就显示不出来了,这时候就会向后找中文字体。 -
"PingFang SC", "Heiti SC", "Microsoft YaHei", "WenQuanYi Micro Hei":mac、windows、linux自带的中文字体,中文字体里的英文一般没有英文字体的英文好看。 -
sans-serif:保底的无衬线字体。(这段代码感觉有点啰嗦)
字体:
1 | .text1 h1 { |
-
rem:相对单位,r代表root根目录,指向浏览器的根字体设置,3rem就是三倍默认字体大小。所以字体大小就用rem解决。
-
视觉层级:越重要的内容用对比度越高的颜色。
滚动吸附 scroll-snap:
1 | html { |
从html开始,因为这个滚动吸附我也研究了一会。
滚动吸附需要在html全局生效,否则可能出现双层容器,配上我们设置的::webkit滚动条,场面一度无法控制。
其中的两个属性:scroll-behavior让滚动更丝滑(点击#top锚点链接时竟然是慢慢滑过去的),scroll-snap-type设置了滚动吸附的方向为垂直方向,然后用mandatory将页面强制拉到最近的一个指定位置去。
这是滚动的一些基础设置,然后就是吸附点:
我们给子元素main-page和page带上了一些样式,scroll-snap-align决定对齐方式。
start:表示当吸附发生时,板块的顶部要和容器的顶部对齐。
vh=Viewport Height.设成100代表这个板块和屏幕一样高,保证了每一页都能占满整个屏幕。main-page设成90是因为第一页用90看起来舒服点。
点击下载结业文件
JavaScript
学习JS,我们的路线依然是以实用主义为纲领,但这次我们尝试继续美化结业文件。
JavaScript是什么?它是Web的编程语言,可以控制网页的行为,功能同样十分强大。
和css一样,我们用外联脚本,在html里写一个src指向js脚本。
1 | <script src="a.js"></script> |
到js文件内部,就得用理解编程语言的思维去理解了。
实现打字机动效
我想实现如下效果,要怎么做?
可以尝试循环迭代的思路,变量i一次次指向不同的字符,是不是就行了。
1 | const text = "一个热爱 Web 的人"; |
使用const定义一个text常量(注意是常量),让它作为待打印的字符库。
1 | let i = 0; |
使用let定义一个i变量,作为迭代变量。
1 | if (i < text.length) { |
就这样实现迭代,但是我们还需要一个循环,循环无非就是让这个i++重复执行,可以用while和for,但是我们这里有更简单的方法:
1 | function typewriter(){ |
使用function定义一个typewriter函数,函数内部是一个if迭代,通过setTimeout()来实现循环。
setTimeout()是延迟执行函数的方法,参数有三个,第一个是要延迟执行的函数,第二个是延迟时间(单位毫秒),第三个是传参。
举两个例子应该差不多了:
1 | setTimeout(function(){ |
console.log()算是入门级的js代码了,类似python里的print,c里的printf,只不过这个是以一个浏览器弹窗的形式打印出来的。
或者这样写:
1 | setTimeout(()=>{ |
第二个例子(传参):
1 | function a(title,content){ |
不要写成a(),不然会立即执行。
取消延迟执行用clearTimeout(),将常量指向setTimeout()的定时器ID(const a = setTimeout()),后续写clearTimeout(a);就好了。
所以在typewriter内部延迟执行typewriter,实现了间隔输出和循环(递归)的效果。
那怎么实现一个个输出呢,这点我们还是没有弄好。
理解一下逻辑,我们如果把原来的p段落清空,
就可以通过一次递归,向其中加一个字符的方法实现“打字”效果。具体操作是先选择typer,再+=。
选择typer的脚本:
1 | const element = document.getElementByID("typer"); |
document指向全局文档,使用get Element By ID()的方法,选择其中ID为typer的元素,并赋值到element常量上。
+=的脚本:
1 | element.textContent += text.charAt(i); |
这和英文有什么区别。。。
合起来:
1 | const text = "一个热爱 Web 的人"; |
最后一行,执行函数。


比如我们在浏览器里看到的这些。








.gif)






