HTML 与 CSS
总结回顾面试中常见的 HTML 与 CSS 考点;
HTML
1. 如何理解 HTML 语义化
根据内容结构选择合适的标签,写出便于阅读与理解,同时利于搜索引擎优化的代码;
2. 为什么要语义化
- 在没有 CSS 的情况下也能呈现良好的网页内容结构与代码结构;
- 提高用户体验,如 title、alt 等解释属性的使用;
- 利于 SEO,因为爬虫依赖标签来确定上下文和各个关键字的权重;
- 方便其他设备解析,如盲人阅读器、屏幕阅读器等;
- 便于团队开发与维护,代码的可读性高,而且遵循标准对未来的兼容性也更好;
3. 如何做才能遵循语义化
- 减少使用无语义的标签,如 div、span、i、b 等;
- 不使用纯样式标签,改用 CSS,如 b、font、u 等;
- 需要强调的文本使用对应的标签,如加粗可以使用 strong 而不是 b,斜体使用 em 而不是 i;
- 为每个 input 标签添加对应的说明 label 标签,为 input 设置 id 属性,同时在 label 标签上使用 for=id 属性关联对应的 input;
4. HTML5 新增的语义化标签
- header 表示网页或 section 的页眉;
- footer 表示网页或 section 的页脚;
- nav 表示网页导航;
- section 表示网页中的一段或一节;
- article 表示表示网页中自成一体的内容;
- aside 表示侧边栏,通常放置与 article 相关的辅助信息;
新增的太多了,还有多媒体标签 audio、video,画图 canvas,日期 time,高亮显示 mark 等;
CSS
1. 块级元素与内联元素
块级元素
块级元素为display: [block | table];
的元素;
常见的块级元素有 div、h1 ~ h6、ul、ol、li、table、p 等;
块级元素的特点
- 元素独占一行;
- 元素的宽高、内边距、边框、外边距都可以通过 CSS 控制;
- 元素默认的宽度为 auto,也就是父级元素的宽度;
- 元素内部可以放置其他块级元素或内联元素;
- p 是一个特殊的块级文本元素,内部只能放置文本或内联元素;
内联元素
内联元素为display: [inline | inline-block];
的元素;
内联元素又分为行内元素和行内块元素;
行内元素
行内元素为display: inline;
的元素,常见的行内元素有 span、a、strong、em、button 等;
行内元素的特点
- 相邻元素在同一行排列,直到触碰容器的边缘才会换行;
- 直接设置宽高无效;
- 只能设置水平方向的外边距;
- 默认宽度就是自身内容的宽度;
- 元素内部只能放置文本或其他行内元素;
行内块元素
行内块元素为display: inline-block;
的元素,常见的行内块元素有 img、input 等;
行内块元素的特点
- 相邻元素在同一行排列,但之间有空白间隙;
- 宽高、内边距、边框、外边距也可以通过 CSS 控制;
- 默认宽度就是自身内容的宽度;
2. 盒模型
- 盒模型由 content、padding、border、margin 四部分组成;
- 盒模型分为标准盒模型与 IE 盒模型;
- 标准盒模型的宽高属性仅包含 content;
- IE 盒模型的宽高则包含 content、padding 和 border;
- 可以使用 CSS 的 box-sizing 属性切换盒模型,属性值 border-box 表示 IE 盒模型,content-box 表示标准盒模型;
盒模型的宽度计算
问题来了:
首先,offsetWidth 是啥?
offsetWidth = content + padding + border 的宽度;
引申扩展一下:
clientWidth = content + padding 的宽度;
scrollWidth = content + padding 的宽度;
咦,clientWidth 和 scrollWidth 的宽度一样哎,是的,在内容没有溢出的情况下,它俩的计算方式是一样的;
但是,当内容溢出时(啥叫内容溢出,就是内容太多出现滚动条的时候),scrollWidth > clientWidth,scrollWidth 表示的是内容的实际宽度,而 clientWidth 则表示当前内容可视区域的宽度,二者的宽度都不包含滚动条的宽度;
举个例子 🌰:当前窗口可以显示 800px 宽度的内容,当内容宽度为 1000px 时,scrollWidth 获取的就是 1000px,而 clientWidth 为 800px,它不随内容宽度的变化而变化,只跟窗口的可视宽度有关;
现在来回答上面的问题:
再扩展一下,如果要让 box 的 offsetWidth 为 100,如何修改?
offsetWidth 的定义是不是和 IE 盒模型很像(当然了,这个标准就是微软提交的),既然要让盒模型的宽高包含 padding 和 border,只需要修改盒模型就可以了;
上图 👆box-sizing: content-box;
,默认属性;
下图 👇box-sizing: border-box;
;
差距很直观吧;
3. margin
margin 纵向重叠
如上图,请问内容为AAA
的 p 标签与内容为BBB
的 p 标签之间的 margin 值是多少?
答案是 15px,原因有三:
- 相邻元素的 margin-top 和 margin-bottom 会发生重叠;
- margin 纵向重叠会取重叠区域的最大值;
- 空白内容也会发生重叠;
margin 负值
对 margin 的 top、left、right、bottom 设置负值,有何效果?
- top:元素自身向上移动,影响相邻元素向上移动;
- left:元素自身向左移动,影响相邻元素向左移动;
- right:元素自身不会移动,但 CSS 可读宽度减小,影响相邻元素向左移动;
- bottom:元素自身不会移动,但 CSS 可读高度减小,影响相邻元素向上移动;
4. BFC
Block Format Context,块级格式化上下文,一块独立渲染的区域,内部元素的渲染不会影响边界以外的其他元素;
触发 BFC 的条件
- 浮动元素,元素的 float 属性不为 none;
- 绝对定位元素,元素的 position 属性为 absolute 或 fixed;
- display 不为 visible 的元素;
- 行内块元素,元素的 display 为 inline-block;
- 弹性元素,display 为 flex 或 inline-flex 的元素的直接子元素;
- 网格元素,display 为 grid 或 inline-grid 的元素的直接子元素;
- display 为 flow-root 的元素;
- 表格,display 为 table、inline-table、table-cell 等的元素;
BFC 的应用场景
- 清除浮动;
- 父子元素 margin 重叠;
5. float 布局
圣杯布局和双飞翼布局一般用于 PC 端两侧内容固定,中间内容随着视口宽度自适应的三栏布局需求,且中间栏的主体优先加载和渲染,内容最重要嘛;
圣杯布局
圣杯布局出自Matthew Levine
的文章In Search of the Holy Grail;
首先是 dom 结构:
1 | <div class="container"> |
可以看到内容主体center
位于最前面,这样主体内容就到了文档流的最前面,实现了优先加载和渲染;
接着是 css 内容,首先是基础布局:
1 | .container { |
这样就实现了如下图的布局,这里为了方便描述,给它们添加了固定高度和背景色;
可以看到,由于 center 占据了父级元素 100% 的宽度,所以 left 和 right 只能被挤到下一行排列,同时这也是布局的精髓,正因为是被挤到下一行的,所以只使用 margin-left 负值就能让它们到达指定位置,妙啊;
然后就是将 left 和 right 分别移动到左边和右边,由于父元素有 padding,所以 left 和 right 会覆盖 center 对应宽度的内容:
1 | .container { |
这里为了查看效果,给父元素添加背景色,同时触发 BFC,使父元素高度不再塌陷;
效果如下 👇:
最后,使用相对定位将 left 和 right 定位到指定位置:
1 | .left { |
可以看到,center 被遮挡的内容也显示了,圣杯布局就完成了;
抱歉,还没有完,由于圣杯布局使用了定位,所以当视窗尺寸小于 left * 2 + right 的尺寸时,页面布局就会完全乱掉:
这里为什么是 left * 2 呢,由于 left 使用了position: relative
,所以就意味着在 center 区域中,还存在着一个 left 的宽度,所以页面的最小宽度应该是 left * 2 + right,也就是 200 * 2 + 100 = 550px;
去除无用设置,最终的 CSS 如下:
1 | .container { |
圣杯布局完成;
双飞翼布局
双飞翼布局始于淘宝 UED,据说出自玉伯之手,链接无;
首先是 dom 结构:
1 | <div class="container"> |
不同于圣杯布局,双飞翼布局多了一层 dom 结构;
然后是基础布局:
1 | .container { |
同样,为了方便查看效果,添加诸多啰嗦的设置,如背景色,固定高度等;
双飞翼布局不再由父元素控制 center 的显示区域,而是添加一层 dom 结构,通过 margin 去预留 left 和 right 的空间,同时免除了使用 position 的隐患,效果如下 👇:
最后使用 margin-left 负值,将 left 和 right 放置到预留位置:
1 | .left { |
布局完成:
总结与思考
圣杯布局与双飞翼布局各有优缺点,不过个人感觉双飞翼无论从布局的理解和布局的通用性,似乎更胜一筹,仁者见仁,智者见智。
不过这不是重点,重点是考点是什么?
首先,当然是 float 布局,还有清除浮动,BFC 以及 margin 负值等内容,这些都是基本功,一道题包含了这么多内容,是不是很有意思;
clearfix
清除浮动的方案有很多,不过随着自适应布局走向台前,用的不是很多了,这里就提两个常见的方案(要手写哦 😯);
伪元素:
1
2
3
4
5
6
7
8
9
10.clearfix::after {
content: "";
display: table;
clear: both;
}
/* IE 兼容性 */
.clearfix {
*zoom: 1;
}建议跟着规范走,伪元素使用双冒号,伪类使用单冒号;
触发 BFC,太常用,例子就不写了;
6. flex 布局
flex 布局已经很常见的,不会的童鞋赶紧去学习MDN;
flex 布局中需要掌握的内容:
- flex-direction:主轴方向,默认 row;
- justify-content:主轴对齐方式;
- align-items:交叉轴对齐方式;
- align-self:元素自身在交叉轴的对齐方式,会覆盖 align-items 的设置;
- flex-wrap:是否换行;
以上属性是必须掌握的,下面的属性需要知道:
flex-grow:元素放大,分配主轴剩余空间;
flex-shrink:元素缩小;
flex-basis:元素初始尺寸;
flex 简写表示 flex-grow, flex-shrink, flex-basis;
flex 简写值 flex-grow flex-shrink flex-basis initial 0 1 auto auto 1 1 auto none 0 0 auto 1 1 1 0
用 flex 实现三点骰(tou)子
1 | <div class="box"><span></span><span></span><span></span></div> |
1 | .box { |
效果如下:
很简单吧,只要了解 flex 的各个属性很容易写出来;
扩展 - 用 flex 实现三栏布局
浮动布局的缺点不言而喻,现在自适应布局使用的更多,动手尝试一下;
首先是 dom 结构,以圣杯布局的 dom 结构为例:
1 | <div class="container"> |
然后是 CSS 设置:
1 | .container { |
使用 flex-basis 指定 left 和 right 的初始尺寸,然后用 order 将 left 放置在左侧;
7. 定位
- absolute 和 relative 分别依据什么定位?
- 居中对齐的实现方式
这里就不重复说明了,居中对齐请参考我的另一篇博客用 CSS 实现元素水平垂直居中;
8. line-height 的继承
line-height 的继承分为三种情况:
具体的数值,子元素直接继承该数值;
比例,子元素直接继承该比例;
百分比(坑在这里),先根据父元素的 font-size 和百分比计算出具体的数值,然后被子元素继承;
考点就在百分比这里,是先计算后继承,而不是直接继承;
9. 响应式
rem 是一个相对长度单位,相对于根元素 html,任何使用长度的地方都可以使用;
em 是一个相对长度单位,相对于父元素;
px 是一个绝对长度单位;
响应式布局的方案
- 媒体查询(media-query),根据不同的屏幕宽度区间设置根元素的 font-size,然后使用 rem,缺点是粒度较大,呈阶梯状;
- vw / wh / vmax / vmin,根据浏览器视口的宽度或高度(包含滚动条)更细粒度的适配,更丝滑,不兼容低版本浏览器;