HTML与CSS大部分人都认为比较简单, 但真正学习透彻的人却很少。 简单的东西我们不能轻视它, 否则就会连简单的东西都学不好。 当然要是把浏览器对于HTML和CSS的渲染也算进去, 又不是那么简单了。
这部分内容尽量挑一些业务中会涉及, 文档中有但没有更直观的例子的内容来讲。 一些文档中有, 但是过于冗长的部分, 也挑一些重点作为笔记和大家快速参考。
HTML标签语义化 & HTML代码规范
文本和段落
<br />是强制换行, 而<p>用来表示自然段。 不能随意换用, 可以用一个例子来表达它们的区别:
<!-- 这是两段文字, 使用两个<p> -->
<p>第一段文本</p>
<p>第二段文本</p>
<!-- 这是一段文字, 因为排版需要, 需要在段落中强制换行, 所以使用<br /> -->
<p>W3C标准中提到:<br />在XHTML标准中自闭合标签必须要加"/", 在最新的HTML5标准中不需要加"/", 但兼容加"/"的写法。<p/>
另外, 我们可能会给段落设置首字缩进、段落之间的外边距等。 而强制换行前后的文本属于同一个段落, 自然也就不会有这些缩进和边距了, 从样式上来说这也是我们不期望看到的。
HTML实体(entity)
字符 | 实体 |
---|---|
& | & |
< | < |
> | > |
" | " |
错误写法:
<h2>HTML & CSS</h2>
正确写法:
<h2>HTML & CSS</h2>
HTML元素的语义化
HTML中有一类标签只表示修饰含义,请不要使用。 语义化包含两方面:
- 根据XHTML标准, 使用原有的一部分元素替代另一部分元素。 如下表
- 使用HTML5语义化元素, 见扩展阅读。
废弃HTML元素替代HTML元素<b>只表示加粗,没有语义<strong>、<em>表示重要内容<font>用来修饰文本<span>使用css选择器来赋予样式
参考
扩展阅读
下面这些内容在开发wap站点, 对于SEO有要求的时候才需要。
HTML代码规范
- 自闭合元素需要增加"/", 这样可读性更高。 例如<link href=""/>。
- 没有属性的自闭合元素需要增加一个额外的空格。 例如<br />, 但是<img src=""/>因为有属性而不需要增加额外的空格。
- 块状元素可以嵌套行内元素和块状元素, 行内元素不能嵌套块状元素。
行内(内联)元素和块状元素 - 行内元素不会自动换行, 会被内容撑开, 指定宽高无效。
- 块状元素会自动换行布局, 可以指定宽高。
- 可以使用display来修改元素的显示类型, 比如常常使用display: block来将
- 渲染为块状元素。
扩展阅读 - 探究行内元素和块级元素
- 深入理解行内元素的布局
相关问题
当图片加载失败的时候, 非常老旧的浏览器(没错, 就是人人喊打的IE)会显示一张裂图。 如果直接使用alt属性,展示兜底问题, 在视觉上也不好看。 所以我们应该采用设置兜底背景图 + alt的方式来处理。对于alt, 没有SEO要求的纯端内h5可以使用空字符串, 有SEO要求的要根据图片含义来赋值。
CSS选择器
关于inline style
除非需要JS动态计算属性值, 否则也尽量不要使用内联样式属性style。 例如下面这种情况, 窗口的高度只有在运行时才能知道, 那么我们只能使用style属性了。(这是react的jsx语法, 没有学习到也可以大概理解这里就是引用了在属性里插入了一个变量/)
export default () => {
return <div style={{backgroundImage:"url(`${src}`)"}}></div>
}
关于important
一般情况下, 不要使用!important。 这容易导致一些意外的情况。
下面只是一个例子, 实际我们不会这样写代码:
div{
background-image: url('xxx') !important;
}
export default () => {
return <div style={{backgroundImage:"url(`${src}`)"}}></div>
}
这种情况, 我们的style里的高度声明优先级低于声明的300px的固定高度, 就不会起作用了。
后代选择器和子代选择器
大部分情况下, 我们可以使用后代选择器来替代子代选择器。 在Sass等CSS预处理器的嵌套规则中, 默认使用的也是子代选择器。 除非在使用子代选择器的时候, 容易出现不符合预期的情况。 例如:
CSS
.tree li{
font-size: 16px;
border-left: 1px solid #000;
}
.tree li ul li{
font-size: 12px;
}
HTML
<ul class="tree">
<li>
<span>蔬菜</span>
<ul>
<li>番茄</li>
<li>土豆</li>
</ul>
</li>
<li>水果</li>
</ul>
结果
这里我们只是期望一级的列表元素左边增加边框。应该修改一下CSS:
.tree > li{
font-size: 16px;
background-color: blue;
}
.tree li ul li{
font-size: 12px;
}
浏览器默认样式
我们可以发现浏览器对于各种元素有一些默认样式:
- <p>元素默认有一定的上下边距
- <a>元素默认是蓝色的, 鼠标悬停时展示下划线,颜色变为红色等等。
- 有的浏览器<body>元素默认有margin
- …
伪类选择器
<a>元素常用伪类
我们这里选取几个常用的伪类选择器来说明。
- :link,选取未访问过的超链接元素。
- :visited,选取访问过的超链接元素。
- :hover,选取鼠标悬停的元素。端内h5无需考虑。
- :active,选取点中的元素。
a{
text-decoration: none;
}
a:link, a:visited, a:hover, a:active{
color: #000;
}
其他常用伪元素
- :first-children: 表示一组兄弟元素的第一个。
- :last-children: 表示一组兄弟元素的最后一个。
.content-box{
width: 200px;
height: 200px;
border: 10px solid red;
margin: 10px auto;
}
.content-box:first-children{
margin-top: 0;
}
.content-box:last-children{
margin-bottom: 0;
}
<div style="width:220px; padding: 0 5px; background-color: #6cf;">
<div class="content-box"></div>
<div class="content-box"></div>
<div class="content-box"></div>
</div>
伪元素选择器
伪元素选择器实际上创建了一个子元素。 我们常见的用法是利用它来增加一些背景图、 多层的边框等。 目前最常用的主要是这两个:
- ::before
- ::after
可以当做是普通文档流的一个行内子元素。
对于伪元素要注意几个点: - 一般content不能少。 如果是使用伪元素来创建背景图片之类的节点, 一般content是""。
- 伪元素默认是行内元素。
扩展阅读
参考
CSS布局
CSS定位主要有几下几种:
- static: 默认的定位方式, 根据行内元素和块状元素定位方式不同。
- relative: 相对于原本的位置进行一些偏移, 但是仍然会占据原来的位置。
- fixed: 相对页面可视区进行定位。 常用与吸顶/吸底元素。
- sticky: 当窗口滚动到一个阈值时, 元素类似于relative和fixed的组合。
绝对定位
绝对定位的元素会根据向上冒泡查找的第一个非static定位的先代元素的左上角作为坐标轴原定进行定位。 如果找不到找个先代元素, 则相对于浏览器窗口进行定位。
参考
扩展阅读
flex布局
flex布局有自动伸缩的能力, 包括flex-basic、 flex-shrink、 flex-grow这三个属性。
flex-shrink
flex布局需要特别注意flex-shirnk的问题, 例如下面这个例子:
.radio-pannel {
width: 300px;
}
.radio-pannel .item {
width: 300px;
height: 40px;
display: flex;
align-items: center;
}
.radio-pannel .radio {
width: 30px;
height: 50%;
margin: 0;
background: url(./radio_normal.svg) no-repeat center center transparent;
background-size: cover;
flex-shrink: 0; // 如果没有这个声明, 当右边的文本溢出的时候就会自动shrink
}
.radio-pannel .text {
font-size: 16px;
}
<div class="radio-pannel">
<div class="item">
<div class="radio"></div>
<div class="text">Category1 Category1 Category1 Category1 Category1 Category1</div>
</div>
<div class="item">
<div class="radio"></div>
<div class="text">Category2</div>
</div>
</div>
没有声明flex-shrink时, 默认值为1, 如果右边的文本溢出, 则左边的按钮会被缩小:
我们给radio增加属性flex-shrink: 0, 则只有右边元素会被shrink, 此时配合文本溢出省略, 显示不至于错乱:
Flex
- flex: 1。 被当做flex-basic的值。
- flex: auto。 相当于flex: 1 1 auto。 分别为flex-grow | flex-shrink | flex-basis,常用于占满父容器的其他空间。
参考 - Flex 布局教程:语法篇 - 阮一峰
- CSS定位详解 - 阮一峰
- flex - MDN
CSS 盒模型
content-box(默认, 标准模式)
- 内容区域 content area ,由内容边界限制,容纳着元素内容。元素内容包括文本、图像、子元素等。 内容区域尺寸由width、 height、 max-width、 max-height来控制。
- 内边距区域 padding area 由内边距边界限制,扩展自内容区域,负责延伸内容区域的背景,填充元素中内容与边框的间距。
- 边框区域 border area 由边框边界限制,扩展自内边距区域,是容纳边框的区域。
- 外边距区域 margin area 由外边距边界限制,用空白区域扩展边框区域,以分开相邻的元素。
border-box(怪异模式)
与标准模式不同的是, 定义width和height时包括元素的内边距padding和边框border。
有些组件库会使用通配符全局reset。
参考
CSS 块格式化上下文(Block Formatting Context,BFC)
BFC有这些要点:
- 一个BFC内的布局与BFC外界无关。
- 理解BFC的其中一个重要的作用是理解浮动元素不能撑开父元素以及解决方法。(现代业务中, 我们使用flex可以完全替代float的功能, 除非要兼容旧的IE浏览器)
- 注意外边界塌陷问题。
- 出现塌陷问题可以使用创建BFC的方法来解决, 例如使用overflow:auto(一般是想要高度自适应, 同时height: auto)来创建BFC。
参考
扩展阅读
CSS规范 & 实践
相关规范约束工具库有stylelint等,vscode可以安装插件vscode-stylelint。sass。
避免命名空间污染(强制)
要避免命名空间污染, 比如上面的flex-shrink的例子中, .text和.item这样的命名是非常容易重复的, 但是我们把它作为.radio-pannel的后代选择器, 只要保证我们的.radio-pannel是唯一的, 那么就是安全的。
好的做法(只需要保证.radio-pannel全局唯一, 则安全):
.radio-pannel {
/* ... */
}
.radio-pannel .item {
/* ... */
}
.radio-pannel .radio {
/* 因为.radio-pannel的结构并不复杂, 没有必要写成.radio-pannel .item .radio */
}
.radio-pannel .text {
/* ... */
}
糟糕的做法:
.radio-pannel {
/* ... */
}
.item {
/* ... */
}
.radio {
/* ... */
}
.text {
/* ... */
}
属性书写顺序(建议)
建议按照布局 -> 盒模型 -> 文本相关属性 -> 其他背景图动画等视觉属性。 eden的CSS规范也有类似内容, 参见CSS规范 - eden。
这样能避免意外的属性覆盖, 例如:
.panel {
margin-bottom: 6px;
width: 100%;
height: auto;
overflow: auto;
display: flex;
flex-direction: column;
box-sizing: border-box;
padding: 16px;
background-color: #fff;
margin: 0
}
当我们声明一个CSS选择器的时候, 如果属性比较多, 我们又写的很散乱, 就容易出现这样的问题。
杂项
- 当属性的值为0(也只有为0时), 属性的单位可以省略。 例如margin: 0px;可以写成margin: 0。
- 慎用简写属性, 例如只是想定义背景颜色, 应该使用background-color: red;而不要使用background: red; 因为简写属性中没有定义的值, 会自动采用默认值, 这样容易导致不符合预期的展现。
扩展内容
记一次自闭合标签是否需要加"/"的battle记录过程
- 按照XHTML标准, 是必须加的。
- 但是最新的HTML5标准去掉了: https://html.spec.whatwg.org/#start-tags
- 根据HTML标准的问答, 兼容加/的写法, 目前公司的代码规范也是需要加的: https://github.com/whatwg/html/blob/master/FAQ.md
极少情况下你可能需要查询W3C标准, 主要是一些特别特别特别细节的地方, 所有的知乎回答、二手资料都无法证明其正确性的时候。
https://www.w3.org/standards/webdesign/