页布局对改善网站的外观非常重要。
请慎重设计您的网页布局。
实例
使用 <div> 元素的网页布局
[demo]
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style type="text/css">
div#container{width:500px}
div#header {background-color:#99bbbb;}
div#menu {background-color:#ffff99;height:200px;width:150px;float:left;}
div#content {background-color:#EEEEEE;height:200px;width:350px;float:left;}
div#footer {background-color:#99bbbb;clear:both;text-align:center;}
h1 {margin-bottom:0;}
h2 {margin-bottom:0;font-size:18px;}
ul {margin:0;}
li {list-style:none;}
</style>
</head>
<body>
<div id="container">
<div id="header">
<h1>Main Title of Web Page</h1>
</div>
<div id="menu">
<h2>Menu</h2>
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
</div>
<div id="content">Content goes here</div>
<div id="footer">Copyright W3School.com.cn</div>
</div>
</body>
</html>
[/demo]
如何使用 <div> 元素添加布局。
使用 <table> 元素的网页布局
[demo]
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<table width="500" border="0">
<tr>
<td colspan="2" style="background-color:#99bbbb;">
<h1>Main Title of Web Page</h1>
</td>
</tr>
<tr valign="top">
<td style="background-color:#ffff99;width:100px;text-align:top;">
<b>Menu</b><br />
HTML<br />
CSS<br />
JavaScript
</td>
<td style="background-color:#EEEEEE;height:200px;width:400px;text-align:top;">
Content goes here</td>
</tr>
<tr>
<td colspan="2" style="background-color:#99bbbb;text-align:center;">
Copyright W3School.com.cn</td>
</tr>
</table>
</body>
</html>
[/demo]
如何使用 <table> 元素添加布局。
网站布局
大多数网站会把内容安排到多个列中(就像杂志或报纸那样)。
可以使用 <div> 或者 <table> 元素来创建多列。CSS 用于对元素进行定位,或者为页面创建背景以及色彩丰富的外观。
提示:即使可以使用 HTML 表格来创建漂亮的布局,但设计表格的目的是呈现表格化数据 - 表格不是布局工具!
HTML 布局 - 使用 <div> 元素
div 元素是用于分组 HTML 元素的块级元素。
下面的例子使用五个 div 元素来创建多列布局:
实例
[demo]
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style type="text/css">
div#container{width:500px}
div#header {background-color:#99bbbb;}
div#menu {background-color:#ffff99; height:200px; width:100px; float:left;}
div#content {background-color:#EEEEEE; height:200px; width:400px; float:left;}
div#footer {background-color:#99bbbb; clear:both; text-align:center;}
h1 {margin-bottom:0;}
h2 {margin-bottom:0; font-size:14px;}
ul {margin:0;}
li {list-style:none;}
</style>
</head>
<body>
<div id="container">
<div id="header">
<h1>Main Title of Web Page</h1>
</div>
<div id="menu">
<h2>Menu</h2>
<ul>
<li>HTML</li>
<li>CSS</li>
<li>JavaScript</li>
</ul>
</div>
<div id="content">Content goes here</div>
<div id="footer">Copyright W3School.com.cn</div>
</div>
</body>
</html>
[/demo]
上面的 HTML 代码会产生如下结果:
使用 div 和 CSS 进行布局
HTML 布局 - 使用表格
使用 HTML <table> 标签是创建布局的一种简单的方式。
可以使用 <div> 或者 <table> 元素来创建多列。CSS 用于对元素进行定位,或者为页面创建背景以及色彩丰富的外观。
提示:即使可以使用 HTML 表格来创建漂亮的布局,但设计表格的目的是呈现表格化数据 - 表格不是布局工具!
下面的例子使用三行两列的表格 - 第一和最后一行使用 colspan 属性来横跨两列:
实例
[demo]
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<table width="500" border="0">
<tr>
<td colspan="2" style="background-color:#99bbbb;">
<h1>Main Title of Web Page</h1>
</td>
</tr>
<tr valign="top">
<td style="background-color:#ffff99;width:100px;text-align:top;">
<b>Menu</b><br />
HTML<br />
CSS<br />
JavaScript
</td>
<td style="background-color:#EEEEEE;height:200px;width:400px;text-align:top;">
Content goes here</td>
</tr>
<tr>
<td colspan="2" style="background-color:#99bbbb;text-align:center;">
Copyright W3School.com.cn</td>
</tr>
</table>
</body>
</html>
[/demo]
上面的 HTML 代码会产生以下结果:
使用表格进行布局
HTML 布局 - 有用的提示
提示:使用 CSS 最大的好处是,如果把 CSS 代码存放到外部样式表中,那么站点会更易于维护。通过编辑单一的文件,就可以改变所有页面的布局。如需学习更多有关 CSS 的知识,请访问我们的 CSS 教程。
提示:由于创建高级的布局非常耗时,使用模板是一个快速的选项。通过搜索引擎可以找到很多免费的网站模板(您可以使用这些预先构建好的网站布局,并优化它们)。
HTML 布局标签
标签 描述
<div> 定义文档中的分区或节(division/section)。
<span> 定义 span,用来组合文档中的行内元素。
通过使用框架,你可以在同一个浏览器窗口中显示不止一个页面。
实例
垂直框架
[demo]
<html>
<frameset cols="25%,50%,25%">
<frame src="/example/html/frame_a.html">
<frame src="/example/html/frame_b.html">
<frame src="/example/html/frame_c.html">
</frameset>
</html>
[/demo]
本例演示:如何使用三份不同的文档制作一个垂直框架。
水平框架
[demo]
<html>
<frameset rows="25%,50%,25%">
<frame src="/example/html/frame_a.html">
<frame src="/example/html/frame_b.html">
<frame src="/example/html/frame_c.html">
</frameset>
</html>
[/demo]
本例演示:如何使用三份不同的文档制作一个水平框架。
框架
通过使用框架,你可以在同一个浏览器窗口中显示不止一个页面。每份HTML文档称为一个框架,并且每个框架都独立于其他的框架。
使用框架的坏处:
开发人员必须同时跟踪更多的HTML文档
很难打印整张页面
框架结构标签(<frameset>)
框架结构标签(<frameset>)定义如何将窗口分割为框架
每个 frameset 定义了一系列行或列
rows/columns 的值规定了每行或每列占据屏幕的面积
编者注:frameset 标签也被某些文章和书籍译为框架集。
框架标签(Frame)
Frame 标签定义了放置在每个框架中的 HTML 文档。
在下面的这个例子中,我们设置了一个两列的框架集。第一列被设置为占据浏览器窗口的 25%。第二列被设置为占据浏览器窗口的 75%。HTML 文档 "frame_a.htm" 被置于第一个列中,而 HTML 文档 "frame_b.htm" 被置于第二个列中:
<frameset cols="25%,75%">
<frame src="frame_a.htm">
<frame src="frame_b.htm">
</frameset>
基本的注意事项 - 有用的提示:
假如一个框架有可见边框,用户可以拖动边框来改变它的大小。为了避免这种情况发生,可以在 <frame> 标签中加入:noresize="noresize"。
为不支持框架的浏览器添加 <noframes> 标签。
重要提示:不能将 <body></body> 标签与 <frameset></frameset> 标签同时使用!不过,假如你添加包含一段文本的 <noframes> 标签,就必须将这段文字嵌套于 <body></body> 标签内。(在下面的第一个实例中,可以查看它是如何实现的。)
更多实例
如何使用 <noframes> 标签
[demo]
<html>
<frameset cols="25%,50%,25%">
<frame src="/example/html/frame_a.html">
<frame src="/example/html/frame_b.html">
<frame src="/example/html/frame_c.html">
<noframes>
<body>您的浏览器无法处理框架!</body>
</noframes>
</frameset>
</html>
[/demo]
本例演示:如何使用 <noframes> 标签。
混合框架结构
[demo]
<html>
<frameset rows="50%,50%">
<frame src="/example/html/frame_a.html">
<frameset cols="25%,75%">
<frame src="/example/html/frame_b.html">
<frame src="/example/html/frame_c.html">
</frameset>
</frameset>
</html>
[/demo]
本例演示如何制作含有三份文档的框架结构,同时将他们混合置于行和列之中。
含有 noresize="noresize" 属性的框架结构
[demo]
<html>
<frameset cols="50%,*,25%">
<frame src="/example/html/frame_a.html" noresize="noresize" />
<frame src="/example/html/frame_b.html" />
<frame src="/example/html/frame_c.html" />
</frameset>
</html>
[/demo]
本例演示 noresize 属性。在本例中,框架是不可调整尺寸的。在框架间的边框上拖动鼠标,你会发现边框是无法移动的。
导航框架
[demo]
<html>
<frameset cols="120,*">
<frame src="/example/html/html_contents.html">
<frame src="/example/html/frame_a.html" name="showframe">
</frameset>
</html>
[/demo]
本例演示如何制作导航框架。导航框架包含一个将第二个框架作为目标的链接列表。名为 "contents.htm" 的文件包含三个链接。
内联框架
[demo]
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<iframe src="./imagecopy1234567890/test.jpg"></iframe>
<p>一些老的浏览器不支持 iframe。</p>
<p>如果得不到支持,iframe 是不可见的。</p>
</body>
</html>
[/demo]
本例演示如何创建内联框架(HTML 页中的框架)。
跳转至框架内的一个指定的节
[demo]
<html>
<frameset cols="20%,80%">
<frame src="/example/html/frame_a.html">
<frame src="/example/html/link.html#C10">
</frameset>
</html>
[/demo]
本例演示两个框架。其中的一个框架设置了指向另一个文件内指定的节的链接。这个"link.htm"文件内指定的节使用 <a name="C10"> 进行标识。
使用框架导航跳转至指定的节
[demo]
<html>
<frameset cols="180,*">
<frame src="/example/html/content.html">
<frame src="/example/html/link.html" name="showframe">
</frameset>
</html>
[/demo]
本例演示两个框架。左侧的导航框架包含了一个链接列表,这些链接将第二个框架作为目标。第二个框架显示被链接的文档。导航框架其中的链接指向目标文件中指定的节。
lt;marquee>...</marquee>普通卷动
<marquee behavior=slide>...</marquee>滑动
<marquee behavior=scroll>...</marquee>预设卷动
<marquee behavior=alternate>...</marquee>来回卷动
<marquee direction=down>...</marquee>向下卷动
<marquee direction=up>...</marquee>向上卷动
<marquee direction=right></marquee>向右卷动
<marquee direction=left></marquee>向左卷动
<marquee loop=2>...</marquee>卷动次数
<marquee width=180>...</marquee>设定宽度
<marquee height=30>...</marquee>设定高度
<marquee bgcolor=FF0000>...</marquee>设定背景颜色
<marquee scrollamount=30>...</marquee>设定卷动距离
<marquee scrolldelay=300>...</marquee>设定卷动时间
<!>字体效果
<h1>...</h1>标题字(最大)
<h6>...</h6>标题字(最小)
<b>...</b>粗体字
<strong>...</strong>粗体字(强调)
<i>...</i>斜体字
<em>...</em>斜体字(强调)
<dfn>...</dfn>斜体字(表示定义)
<u>...</u>底线
<ins>...</ins>底线(表示插入文字)
<strike>...</strike>横线
<s>...</s>删除线
<del>...</del>删除线(表示删除)
<kbd>...</kbd>键盘文字
<tt>...</tt> 打字体
<xmp>...</xmp>固定宽度字体(在文件中空白、换行、定位功能有效)
<plaintext>...</plaintext>固定宽度字体(不执行标记符号)
<listing>...</listing> 固定宽度小字体
<font color=00ff00>...</font>字体颜色
<font size=1>...</font>最小字体
<font style =font-size:100 px>...</font>无限增大
<!>区断标记
<hr>水平线
<hr size=9>水平线(设定大小)
<hr width=80%>水平线(设定宽度)
<hr color=ff0000>水平线(设定颜色)
<br>(换行)
<nobr>...</nobr>水域(不换行)
<p>...</p>水域(段落)
<center>...</center>置中
<!>连结格式
<base href=位址>(预设好连结路径)
<a href=位址></a>外部连结
<a href=位址 target=_blank></a>外部连结(另开新视窗)
<a href=位址 target=_top></a>外部连结(全视窗连结)
<a href=位址 target=页框名></a>外部连结(在指定页框连结)
<!>贴图/音乐
<img src=图片位址>贴图
<img src=图片位址 width=180>设定图片宽度
<img src=图片位址 height=30>设定图片高度
<img src=图片位址 alt=提示文字>设定图片提示文字
<img src=图片位址 border=1>设定图片边框
<bgsound src=MID音乐档位址>背景音乐设定
<!>表格语法
<table aling=left>...</table>表格位置,置左
<table aling=center>...</table>表格位置,置中
<table background=图片路径>...</table>背景图片的URL=就是路径网址
<table border=边框大小>...</table>设定表格边框大小(使用数字)
<table bgcolor=颜色码>...</table>设定表格的背景颜色
<table borderclor=颜色码>...</table>设定表格边框的颜色
<table borderclor=颜色码>...</table>设定表格边框的颜色
<table borderclordark=颜色码>...</table>设定表格暗边框的颜色
<table borderclorlight=颜色码>...</table>设定表格亮边框的颜色
<table cellpadding=参数>...</table>指定内容与格线之间的间距(使用数字)
<table cellspacing=参数>...</table>指定格线与格线之间的距离(使用数字)
<table cols=参数>...</table>指定表格的栏数
<table frame=参数>...</table>设定表格外框线的显示方式
<table width=宽度>...</table>指定表格的宽度大小(使用数字)
<table height=高度>...</table>指定表格的高度大小(使用数字)
<td colspan=参数>...</td>指定储存格合并栏的栏数(使用数字)
<td rowspan=参数>...</td>指定储存格合并列的列数(使用数字)
<!>分割视窗
<frameset cols="20%,*">左右分割,将左边框架分割大小为20%右边框架的大小浏览器会自动调整
<frameset rows="20%,*">上下分割,将上面框架分割大小为20%下面框架的大小浏览器会自动调整
<frameset cols="20%,*">分割左右两个框架
<frameset cols="20%,*,20%">分割左中右三个框架
<分割上下两个框架
<frameset rows="20%,*,20%">分割上中下三个框架
<! - - ... - -> 注解
<a href target> 指定超连结的分割视窗
<a href=#锚的名称> 指定锚名称的超连结
<a href> 指定超连结
<a name=锚的名称> 被连结点的名称
<address>....</address> 用来显示电子邮箱地址
<b> 粗体字
<base target> 指定超连结的分割视窗
<basefont size> 更改预设字形大小
<bgsound src> 加入背景音乐
<big> 显示大字体
<blink> 闪烁的文字
<body text link vlink> 设定文字颜色
<body> 显示本文
<br> 换行
<caption align> 设定表格标题位置
<caption>...</caption> 为表格加上标题
<center> 向中对齐
<cite>...<cite> 用於引经据典的文字
<code>...</code> 用於列出一段程式码
<comment>...</comment> 加上注解
<dd> 设定定义列表的项目解说
<dfn>...</dfn> 显示"定义"文字
<dir>...</dir> 列表文字标签
<dl>...</dl> 设定定义列表的标签
<dt> 设定定义列表的项目
<em> 强调之用
<font face> 任意指定所用的字形
<font face> 任意指定所用的字形
<font size> 设定字体大小
<form action> 设定户动式表单的处理方式
<form method> 设定户动式表单之资料传送方式
<frame marginheight> 设定视窗的上下边界
<frame marginwidth> 设定视窗的左右边界
<frame name> 为分割视窗命名
<frame noresize> 锁住分割视窗的大小
<frame scrolling> 设定分割视窗的卷轴
<frame src> 将html档加入视窗
<frameset cols> 将视窗分割成左右的子视窗
<frameset rows> 将视窗分割成上下的子视窗
<frameset>...</frameset> 划分分割视窗
<h1>~<h6> 设定文字大小
<head> 标示文件资讯
<hr> 加上分格线
<html> 文件的开始与结束
<i> 斜体字
<img align> 调整图形影像的位置
<img alt> 为你的图形影像加注
<img dynsrc loop> 加入影片
<img height width> 插入图片并预设图形大小
<img hspace> 插入图片并预设图形的左右边界
<img lowsrc> 预载图片功能
<img src border> 设定图片边界
<img src> 插入图片
<img vspace> 插入图片并预设图形的上下边界
<input type name value> 在表单中加入输入栏位
<isindex> 定义查询用表单
<kbd>...</kbd> 表示使用者输入文字
<li type>...</li> 列表的项目 ( 可指定符号 )
<marquee> 跑马灯效果
<menu>...</menu> 条列文字标签
<meta name="refresh" content url> 自动更新文件内容
<multiple> 可同时选择多项的列表栏
<noframe> 定义不出现分割视窗的文字
<ol>...</ol> 有序号的列表
<option> 定义表单中列表栏的项目
<p align> 设定对齐方向
<p> 分段
<person>...</person> 显示人名
<pre> 使用原有排列
<samp>...</samp> 用於引用字
<select>...</select> 在表单中定义列表栏
<small> 显示小字体
<strike> 文字加横线
<strong> 用於加强语气
<sub> 下标字
<sup> 上标字
<table border=n> 调整表格的宽线高度
<table cellpadding> 调整资料栏位之边界
<table cellspacing> 调整表格线的宽度
<table height> 调整表格的高度
<table width> 调整表格的宽度
<table>...</table> 产生表格的标签
<td align> 调整表格栏位之左右对齐
<td bgcolor> 设定表格栏位之背景颜色
<td colspan rowspan> 表格栏位的合并
<td nowrap> 设定表格栏位不换行
<td valign> 调整表格栏位之上下对齐
<td width> 调整表格栏位宽度
<td>...</td> 定义表格的资料栏位
<textarea name rows cols> 表单中加入多少列的文字输入栏
<textarea wrap> 决定文字输入栏是自动否换行
<th>...</th> 定义表格的标头栏位
<title> 文件标题
<tr>...</tr> 定义表格美一行
<tt> 打字机字体
<u> 文字加底线
<ul type>...</ul> 无序号的列表 ( 可指定符号 )
<var>...</var> 用於显示变数
家好,我是皮汤。最近业务调整,组内开启了前端工程化方面的基建,我主要负责 CSS 技术选型这一块,针对目前业界主流的几套方案进行了比较完善的调研与比较,分享给大家。
目前整个 CSS 工具链、工程化领域的主要方案如下:
而我们技术选型的标准如下:
- 开发速度快
- 开发体验友好
- 调试体验友好
- 可维护性友好
- 扩展性友好
- 可协作性友好
- 体积小
- 有最佳实践指导
目前主要需要对比的三套方案:
- Less/Sass + PostCSS 的纯 CSS c侧方案
- styled-components / emotion 的纯 CSS-in-JS 侧方案
- TailwindCSS 的以写辅助类为主的 HTML 侧方案
## 纯 CSS 侧方案
### 介绍与优点
> 维护状态:一般
> Star 数:16.7K
> 支持框架:无框架限制
> 项目地址:https://github.com/less/less.js
Less/Sass + PostCSS 这种方案在目前主流的组件库和企业级项目中使用很广,如 ant-design 等
它们的主要作用如下:
- 为 CSS 添加了类似 JS 的特性,你也可以使用变量、mixin,写判断等
- 引入了模块化的概念,可以在一个 less 文件中导入另外一个 less 文件进行使用
- 兼容标准,可以快速使用 CSS 新特性,兼容浏览器 CSS 差异等
这类工具能够与主流的工程化工具一起使用,如 Webpack,提供对应的 loader 如 sass-loader,然后就可以在 React/Vue 项目中建 `.scss` 文件,写 sass 语法,并导入到 React 组件中生效。
比如我写一个组件在响应式各个断点下的展示情况的 sass 代码:
```
.component {
width: 300px;
@media (min-width: 768px) {
width: 600px;
@media (min-resolution: 192dpi) {
background-image: url(/img/retina2x.png);
}
}
@media (min-width: 1280px) {
width: 800px;
}
}
```
或导入一些用于标准化浏览器差异的代码:
```
@import "normalize.css";
// component 相关的其他代码
```
### 不足
这类方案的一个主要问题就是,只是对 CSS 本身进行了增强,但是在帮助开发者如何写更好的 CSS、更高效、可维护的 CSS 方面并没有提供任何建议。
- 你依然需要自己定义 CSS 类、id,并且思考如何去用这些类、id 进行组合去描述 HTML 的样式
- 你依然可能会写很多冗余的 Less/Sass 代码,然后造成项目的负担,在可维护性方面也有巨大问题
### 优化
- 可以引入 CSS 设计规范:BEM 规范,来辅助用户在整个网页的 HTML 骨架以及对应的类上进行设计
- 可以引入 CSS Modules,将 CSS 文件进行 “作用域” 限制,确保在之后维护时,修改一个内容不会引起全局中其他样式的效果
#### BEM 规范
B (Block)、E(Element)、M(Modifier),具体就是通过块、元素、行为来定义所有的可视化功能。
拿设计一个 Button 为例:
```
/* Block */
.btn {}
/* 依赖于 Block 的 Element */
.btn__price {}
/* 修改 Block 风格的 Modifier */
.btn--orange {}
.btn--big {}
```
遵循上述规范的一个真实的 Button:
```
<a class="btn btn--big btn--orange" href="#">
<span class="btn__price"></span>
<span class="btn__text">BIG BUTTON</span>
</a>
```
可以获得如下的效果:
#### CSS Modules
CSS Modules 主要为 CSS 添加局部作用域和模块依赖,使得 CSS 也能具有组件化。
一个例子如下:
```
import React from 'react';
import style from './App.css';
export default () => {
return (
<h1 className={style.title}>
Hello World
</h1>
);
};
```
```
.title {
composes: className;
color: red;
}
```
上述经过编译会变成如下 hash 字符串:
```
<h1 class="_3zyde4l1yATCOkgn-DBWEL">
Hello World
</h1>
```
```
._3zyde4l1yATCOkgn-DBWEL {
color: red;
}
```
CSS Modules 可以与普通 CSS、Less、Sass 等结合使用。
## 纯 JS 侧方案
### 介绍与优点
> 维护状态:一般
> Star 数:35.2K
> 支持框架:React ,通过社区支持 Vue 等框架
> 项目地址:https://github.com/styled-components/styled-components
使用 JS 的模板字符串函数,在 JS 里面写 CSS 代码,这带来了两个认知的改变:
- 不是在根据 HTML,然后去写 CSS,而是站在组件设计的角度,为组件写 CSS,然后应用组件的组合思想搭建大应用
- 自动提供类似 CSS Modules 的体验,不用担心样式的全局污染问题
同时带来了很多 JS 侧才有的各种功能特性,可以让开发者用开发 JS 的方式开发 CSS,如编辑器自动补全、Lint、编译压缩等。
比如我写一个按钮:
```
const Button = styled.button`
/* Adapt the colors based on primary prop */
background: ${props => props.primary ? "palevioletred" : "white"};
color: ${props => props.primary ? "white" : "palevioletred"};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
render(
<div>
<Button>Normal</Button>
<Button primary>Primary</Button>
</div>
);
```
可以获得如下效果:
还可以扩展样式:
```
// The Button from the last section without the interpolations
const Button = styled.button`
color: palevioletred;
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
// A new component based on Button, but with some override styles
const TomatoButton = styled(Button)`
color: tomato;
border-color: tomato;
`;
render(
<div>
<Button>Normal Button</Button>
<TomatoButton>Tomato Button</TomatoButton>
</div>
);
```
可以获得如下效果:
### 不足
虽然这类方案提供了在 JS 中写 CSS,充分利用 JS 的插值、组合等特性,然后应用 React 组件等组合思想,将组件与 CSS 进行细粒度绑定,让 CSS 跟随着组件一同进行组件化开发,同时提供和组件类似的模块化特性,相比 Less/Sass 这一套,可以复用 JS 社区的最佳实践等。
但是它仍然有一些不足:
- 仍然是是对 CSS 增强,提供非常大的灵活性,开发者仍然需要考虑如何去组织自己的 CSS
- 没有给出一套 “有观点” 的最佳实践做法
- 在上层也缺乏基于 styled-components 进行复用的物料库可进行参考设计和使用,导致在初始化使用时开发速度较低
- 在 JS 中写 CSS,势必带来一些本属于 JS 的限制,如 TS 下,需要对 Styled 的组件进行类型注释
- 官方维护的内容只兼容 React 框架,Vue 和其他框架都由社区提供支持
整体来说不太符合团队协作使用,需要人为总结最佳实践和规范等。
### 优化
- 寻求一套写 CSS 的最佳实践和团队协作规范
- 能够拥有大量的物料库或辅助类等,提高开发效率,快速完成应用开发
## 偏向 HTML 侧方案
### 介绍与优点
> 维护状态:积极
> Star 数:48.9K
> 支持框架:React、Vue、Svelte 等主流框架
> 项目地址:https://github.com/tailwindlabs/tailwindcss
典型的是 TailwindCSS,一个辅助类优先的 CSS 框架,提供如 `flex` 、`pt-4` 、`text-center` 、`rotate-90` 这样实用的类名,然后基于这些底层的辅助类向上组合构建任何网站,而且只需要专注于为 HTML 设置类名即可。
一个比较形象的例子可以参考如下代码:
```
<button class="btn btn--secondary">Decline</button>
<button class="btn btn--primary">Accept</button>
```
上述代码应用 BEM 风格的类名设计,然后设计两个按钮,而这两个类名类似主流组件库里面的 Button 的不同状态的设计,而这两个类又是由更加基础的 TailwindCSS 辅助类组成:
```
.btn {
@apply text-base font-medium rounded-lg p-3;
}
.btn--primary {
@apply bg-rose-500 text-white;
}
.btn--secondary {
@apply bg-gray-100 text-black;
}
```
上面的辅助类包含以下几类:
- 设置文本相关: `text-base` 、`font-medium` 、`text-white` 、`text-black`
- 设置背景相关的:`bg-rose-500` 、`bg-gray-100`
- 设置间距相关的:`p-3`
- 设置边角相关的:`rounded-lg`
通过 Tailwind 提供的 `@apply` 方法来对这些辅助类进行组合构建更上层的样式类。
上述的最终效果展示如下:
可以看到 TailwindCSS 将我们开发网站的过程抽象成为使用 Figma 等设计软件设计界面的过程,同时提供了一套用于设计的规范,相当于内置最佳实践,如颜色、阴影、字体相关的内容,一个很形象的图片可以说明这一点:
TailwindCSS 为我们规划了一个元素可以设置的属性,并且为每个属性给定了一组可以设置的值,这些属性+属性值组合成一个有机的设计系统,非常便于团队协作与共识,让我们开发网站就像做设计一样简单、快速,但是整体风格又能保持一致。
TailwindCSS 同时也能与主流组件库如 React、Vue、Svelte 结合,融入基于组件的 CSS 设计思想,但又只需要修改 HTML 上的类名,如我们设计一个食谱组件:
```
// Recipes.js
import Nav from './Nav.js'
import NavItem from './NavItem.js'
import List from './List.js'
import ListItem from './ListItem.js'
export default function Recipes({ recipes }) {
return (
<div className="divide-y divide-gray-100">
<Nav>
<NavItem href="/featured" isActive>Featured</NavItem>
<NavItem href="/popular">Popular</NavItem>
<NavItem href="/recent">Recent</NavItem>
</Nav>
<List>
{recipes.map((recipe) => (
<ListItem key={recipe.id} recipe={recipe} />
))}
</List>
</div>
)
}
// Nav.js
export default function Nav({ children }) {
return (
<nav className="p-4">
<ul className="flex space-x-2">
{children}
</ul>
</nav>
)
}
// NavItem.js
export default function NavItem({ href, isActive, children }) {
return (
<li>
<a
href={href}
className={`block px-4 py-2 rounded-md ${isActive ? 'bg-amber-100 text-amber-700' : ''}`}
>
{children}
</a>
</li>
)
}
// List.js
export default function List({ children }) {
return (
<ul className="divide-y divide-gray-100">
{children}
</ul>
)
}
//ListItem.js
export default function ListItem({ recipe }) {
return (
<article className="p-4 flex space-x-4">
<img src={recipe.image} alt="" className="flex-none w-18 h-18 rounded-lg object-cover bg-gray-100" width="144" height="144" />
<div className="min-w-0 relative flex-auto sm:pr-20 lg:pr-0 xl:pr-20">
<h2 className="text-lg font-semibold text-black mb-0.5">
{recipe.title}
</h2>
<dl className="flex flex-wrap text-sm font-medium whitespace-pre">
<div>
<dt className="sr-only">Time</dt>
<dd>
<abbr title={`${recipe.time} minutes`}>{recipe.time}m</abbr>
</dd>
</div>
<div>
<dt className="sr-only">Difficulty</dt>
<dd> · {recipe.difficulty}</dd>
</div>
<div>
<dt className="sr-only">Servings</dt>
<dd> · {recipe.servings} servings</dd>
</div>
<div className="flex-none w-full mt-0.5 font-normal">
<dt className="inline">By</dt>{' '}
<dd className="inline text-black">{recipe.author}</dd>
</div>
<div class="absolute top-0 right-0 rounded-full bg-amber-50 text-amber-900 px-2 py-0.5 hidden sm:flex lg:hidden xl:flex items-center space-x-1">
<dt className="text-amber-500">
<span className="sr-only">Rating</span>
<svg width="16" height="20" fill="currentColor">
<path d="M7.05 3.691c.3-.921 1.603-.921 1.902 0l1.07 3.292a1 1 0 00.95.69h3.462c.969 0 1.372 1.24.588 1.81l-2.8 2.034a1 1 0 00-.364 1.118l1.07 3.292c.3.921-.755 1.688-1.539 1.118l-2.8-2.034a1 1 0 00-1.176 0l-2.8 2.034c-.783.57-1.838-.197-1.539-1.118l1.07-3.292a1 1 0 00-.363-1.118L.98 9.483c-.784-.57-.381-1.81.587-1.81H5.03a1 1 0 00.95-.69L7.05 3.69z" />
</svg>
</dt>
<dd>{recipe.rating}</dd>
</div>
</dl>
</div>
</article>
)
}
```
上述食谱的效果如下:
可以看到我们无需写一行 CSS,而是在 HTML 里面应用各种辅助类,结合 React 的组件化设计,既可以轻松完成一个非常现代化且好看的食谱组件。
除了上面的特性,TailwindCSS 在响应式、新特性支持、Dark Mode、自定义配置、自定义新的辅助类、IDE 方面也提供非常优秀的支持,除此之外还有基于 TailwindCSS 构建的物料库 Tailwind UI ,提供各种各样成熟、好看、可用于生产的物料库:

因为需要自定的 CSS 不多,而需要自定义的 CSS 可以定义为可复用的辅助类,所以在可维护性方面也是极好的。
### 不足
- 因为要引入一个额外的运行时,TailwindCSS 辅助类到 CSS 的编译过程,而随着组件越来越多,需要编译的工作量也会变大,所以速度会有影响
- 过于底层,相当于给了用于设计的最基础的指标,但是如果我们想要快速设计网站,那么可能还需要一致的、更加上层的组件库
- 相当于引入了一套框架,具有一定的学习成本和使用成本
### 优化
- Tailwind 2.0 支持 [JIT](https://blog.tailwindcss.com/tailwindcss-2-1 "JIT"),可以大大提升编译速度,可以考虑引入
- 基于 TailwindCSS,设计一套符合自身风格的上层组件库、物料库,便于更加快速开发
- 提前探索、学习和总结一套教程与开发最佳实践
- 探索 styled-components 等结合 TailwindCSS 的开发方式
## 参考链接
- [CSS 工程化发展历程](https://bytedance.feishu.cn/docs/doccnTRF0OZtJMgKuo3y0hIDMbc# "CSS 工程化发展历程")
以上便是本次分享的全部内容,希望对你有所帮助^_^
喜欢的话别忘了 分享、点赞、收藏 三连哦~
欢迎关注公众号 程序员巴士,来自字节、虾皮、招银的三端兄弟,分享编程经验、技术干货与职业规划,助你少走弯路进大厂。
*请认真填写需求信息,我们会在24小时内与您取得联系。