整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

2021 年你需要知道的 CSS 工程化技术

家好,我是皮汤。最近业务调整,组内开启了前端工程化方面的基建,我主要负责 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 ,提供各种各样成熟、好看、可用于生产的物料库:

![](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1cb983da6f71470b91ac764d14907998~tplv-k3u1fbpfcp-zoom-1.image)

因为需要自定的 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 工程化发展历程")


/ 感谢支持/

以上便是本次分享的全部内容,希望对你有所帮助^_^

喜欢的话别忘了 分享、点赞、收藏 三连哦~

欢迎关注公众号 程序员巴士,来自字节、虾皮、招银的三端兄弟,分享编程经验、技术干货与职业规划,助你少走弯路进大厂。

5自适应是现在主流的技术,导航栏菜单是最常见的一种,今天我们一起来学习一下它是如何使用HTML,CSS和JavaScript来构建响应式导航栏和汉堡菜单的。

这就是它的样子,是不是很熟悉呢?

H5导航菜单

好的,那就先从HTML开始:

<header class=”header”>
<nav class=”navbar”>
<a href=”#” class=”nav-logo”>WebDev.</a>
<ul class=”nav-menu”>
<li class=”nav-item”>
<a href=”#” class=”nav-link”>Services</a>
</li>
<li class=”nav-item”>
<a href=”#” class=”nav-link”>Blog</a>
</li>
<li class=”nav-item”>
<a href=”#” class=”nav-link”>About</a>
</li>
<li class=”nav-item”>
<a href=”#” class=”nav-link”>Contact</a>
</li>
</ul>
<div class=”hamburger”>
<span class=”bar”></span>
<span class=”bar”></span>
<span class=”bar”></span>
</div>
</nav>
</header>

通过这些代码,我们实现了:

  • 给header标签指定名为header的CSS类的,可以作为导航菜单的容器。
  • 给nav标签指定名为navbar的CSS类。
  • 具有nav-logo类的链接
  • 具有nav-menu类的ul
  • 在ul内部,我们有4个具有nav-item类的li
  • 在每个nav-item中,都有一个包含nav-link类的链接
  • 至于汉堡菜单,我已在代码中添加了一个具有hamburger类的div,且此div中有3个带bar类的span

以上就是我们需要的HTML代码。

现在让我们添加CSS样式重置代码

(此外,我们将导入所需的字体,并添加一些基本的CSS来重置所有的默认样式。)

@import url(‘https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,500;1,400&display=swap’);

* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

html {
font-size: 62.5%;
font-family: ‘Roboto’, sans-serif;
}

li {
list-style: none;
}

a {
text-decoration: none;
}

现在让我们给每个元素逐个添加样式:

header和navbar:

.header{
border-bottom: 1px solid #E2E8F0;
}

.navbar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 1.5rem;
}


hamburger样式:

.hamburger {
display: none;
}

.bar {
display: block;
width: 25px;
height: 3px;
margin: 5px auto;
-webkit-transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out;
background-color: #101010;
}


其他元素的基本样式:

.nav-menu {
display: flex;
justify-content: space-between;
align-items: center;
}

.nav-item {
margin-left: 5rem;
}

.nav-link{
font-size: 1.6rem;
font-weight: 400;
color: #475569;
}

.nav-link:hover{
color: #482ff7;
}

.nav-logo {
font-size: 2.1rem;
font-weight: 500;
color: #482ff7;
}

完成这些之后,看起来应该是这样的:

但是它不是响应式的,所以我们还需要添加媒体查询css代码。

@media only screen and (max-width: 768px) {
.nav-menu {
position: fixed;
left: -100%;
top: 5rem;
flex-direction: column;
background-color: #fff;
width: 100%;
border-radius: 10px;
text-align: center;
transition: 0.3s;
box-shadow:
0 10px 27px rgba(0, 0, 0, 0.05);
}

.nav-menu.active {
left: 0;
}

.nav-item {
margin: 2.5rem 0;
}

.hamburger {
display: block;
cursor: pointer;
}

}


这里媒体查询就是通过设置position: fixed; left: -100%;来隐藏nav-menu。

此外,我们将hamburger设置为display: block;,所以现在可见。

我们还添加了一个额外的类.nav-menu.active,它在nav-menu上设置left: 0;。现在,到了添加javascript的时候了,以便在我们单击汉堡菜单时,会在nav-menu上添加此active类。

添加JavaScript

const hamburger = document.querySelector(“.hamburger”);
const navMenu = document.querySelector(“.nav-menu”);

hamburger.addEventListener(“click”, mobileMenu);

function mobileMenu() {
hamburger.classList.toggle(“active”);
navMenu.classList.toggle(“active”);
}


此处的函数mobileMenu()在hamburger和nav-menu上也添加了一个active类,从而打开mobile menu。单击hamburger时,我们可以使用hamburger上的active类来创建X动画。现在就开始做吧。

// Inside the Media Query.

.hamburger.active .bar:nth-child(2) {
opacity: 0;
}

.hamburger.active .bar:nth-child(1) {
transform: translateY(8px) rotate(45deg);
}

.hamburger.active .bar:nth-child(3) {
transform: translateY(-8px) rotate(-45deg);
}

现在看起来应该是这样的:

但是有一个问题,当我们单击链接时,汉堡菜单不会关闭。现在让我们解决一下这个问题。

const navLink = document.querySelectorAll(“.nav-link”);

navLink.forEach(n => n.addEventListener(“click”, closeMenu));

function closeMenu() {
hamburger.classList.remove(“active”);
navMenu.classList.remove(“active”);
}

closeMenu()函数从nav-menu和hamburger中删除active类,从而关闭mobile menu。

H5导航菜单就是这样,实现了用HTML,CSS和javascript构建一个响应式的导航栏菜单。希望你喜欢并分享这篇文章。感谢大家的阅读。

更多干货等着你~ 点赞、分享,关注哦

到前端技术,不少朋友一定会感到有些陌生。但其实,前端,你每天都在接触。

你正在使用的APP,你正在浏览的网页,这些你能看到的界面,都属于前端。

而前端最重要的三大技术,HTML,CSS,JavaScript,则是每一个前端开发者必须具备的技能。

掌握这些技能,你可以快速地做出一个酷炫的APP界面或者一个简单大方的网站页面。因此,就让我们一起来快速学习一下这三门技术吧。



以下内容节选自实验楼训练营课程《Vue.js 和 Node.js 构建内容发布系统》。

实验介绍

本实验主要介绍一下前端的基础知识,对比认识一下各个框架的代码编写方式,并介绍我们本次技术选型的主要思路。对于前端三大技术 HTML、CSS、JavaScript,简单的介绍了基本情况和常用语法。中间介绍了现代框架的一些情况,并通过实际的案例,用代码直观的认识一下各种框架的实现方式。最后分析一下项目的技术选型。

知识点

  • HTML、CSS、JavaScript 快速概览
  • 前端框架概览和选型
  • 后端选型
  • 数据库选型
  • Web 服务器选型

前端技术简介

本节我们简单介绍一下前端最基础 HTML, CSS, JavaScript 三驾马车。虽然本课程预设的读者为零基础开发者,但是前端开发一定会这三种技术的运用有要求。建议抽空学习 《 Web 前端工程师路径》 中的阶段 1 甚至阶段 2。这里仅做语法介绍和基本使用的概览。

在此之前先认识一下实验环境。实验环境和 VS Code 使用体验基本一致。你可以启动一个终端,并在其中输入 Linux 命令。

后面的命令无特殊说明的都是在此终端命令行中输入。大多数命令可以多开终端窗口分别执行。

那么下面我们就快速的了解一下。

HTML

HTML 全称超文本标记语言,几乎是从万维网和浏览器产生伊始就存在的。主要用于结构化信息来方便浏览器展示。

以标签对作为主要特征,如<p>这是一个段落</p>。这些标签会被浏览器解析成不同的模块,比如 p 标签就是一个段落,img 标签就是一个图片,a 标签就是一个超链接,标签名不区分大小写。

立刻就来尝试一下吧。首先通过命令行新建一个 demo 目录:

mkdir demo

然后命令行进入 demo 目录:

cd ./demo

新建一个 hello.html 文件,可以在实验环境左边的浏览框内在 demo 上右键选择 New File 然后命名为 hello.html;或者也可在命令行终端输入 touch hello.html,同样是新建文件。

在其中输入以下内容:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>标题</title>
  </head>
  <body>
    正文
  </body>
</html>

然后右击文件选择 Open With → Preview。

看到了吗?其实我们就是新建了一个 .html 后缀的文本文件,然后浏览器就可以将其中的内容展示出来。你也可以在自己的桌面上新建一个,然后使用浏览器打开看看效果。

这里嵌套代码的缩进格式是为了美观和可读性,并无严格要求。

head 标签中是一些暂时无需用到的头部信息,渲染的主体是 body 标签。下面我们修改 body 标签里面的内容,填入一些常用标签来直观感受一下。

<body>
  <h1>页面标题</h1>
  <div>一个块容器</div>
  <div>又一个块容器</div>
  <p>这里是段落了,间距变大</p>
  <div>一个块容器</div>
  <div>
    <div>
      多层嵌套:
      <div>内部第一个</div>
      <div>内部第二个</div>
    </div>
  </div>
</body>

保存之后切换到浏览标签看一看,有没有感觉被忽悠了?嵌套没嵌套根本没体现出来,就像 Word 里排了一下版,按了几个回车。

因为我们没有对显示样式进行修改,那是 CSS 的事。HTML 主要管内容的组织结构。

这里有一点针对学习的小建议,本课程中给到的全部代码请手动输入,忘记复制和粘贴快捷键。

而且最好不要机械的一个字符一个字符照着抄,尽量看过一行或一小段代码之后,靠短暂的印象去输出,别怕出错,只有过脑子并输出实践,才是最快掌握一项技能的捷径。

以上两句话是本课程中最有价值内容之一。

下面我们接着修改刚才的代码,再给 body 中添加几个常用标签。每次修改和保存之后记得到预览页看看样式的变化。

<h4>4 级标题</h4>
<ul>
  <li>
    HTML
  </li>
  <li>
    CSS
  </li>
  <li>
    JavaScript
  </li>
</ul>
<div>
  <a href="https://www.shiyanlou.com" target="_blank"
    >点击超链接跳转至实验楼首页</a
  >
</div>
<div>
  <img
    src="https://static.shiyanlou.com/frontend/dist/img/9f43b00.svg"
    alt=""
    width="200"
  />
</div>

最后的链接标签 a 和图片标签 img 出现了标签属性,属性为 attr="value" 格式,可以给标签增加更丰富的信息。

同时 img 标签还是一个单标签,不需要在后面添加 </img> 配合使用。

至此对 HTML 的简要介绍告一段落。

互联网上看到的各种五彩缤纷网页都是由这些 HTML 组成的,但是为什么我们写的这么难看?下一节我们就要学习一下如何用 CSS 美化页面。

CSS

CSS 全称层叠样式表,是专门用来修饰 HTML 样式的一种语言。我们修改一下上节的 hello.html 文件来直观感受一下。


内部代码块引入

在 head 标签内部增加以下 style 代码块:

<head>
  <meta charset="UTF-8" />
  <title>标题</title>
  <style type="text/css">
    div {
      border: 1px solid blue;
      padding: 2px;
      margin: 10px;
    }
  </style>
</head>

这是再切换到预览页,发现没那么平铺直叙了。

这就是 CSS 的第一种引入方式,HTML 内置代码块。

大括号外面的 div 是标签选择器,这里选中了本页面中的所有 div 元素。大括号里面是属性名与赋值,属性名都是固定的关键字,并已规定好了值的类型和可选范围。

读代码也就大概知道了,我们将 div 的边框设置为 1 像素宽、固体(单线型)、蓝色,填充(内边距)2 像素,边缘空白(外边距)10 像素。现在可以练习调整一下各个数字,预览看看发生了什么?

再说点题外话,懂一些英文对程序员来说非常必要,除了可以凭感觉就读懂没学过的代码,还可以在面向 Google 编程、面向 Stack Overflow 编程、面向 Github Issues 编程时游刃有余。


外部文件引入

然后我们再试一下外部文件引入,在 hello.html 的同级目录新建 hello.css,输入以下内容保存:

div {
  color: green;
  border: 2px dotted red;
}

然后修改 hello.html,在 style 标签后面增加一行 link 标签,添加引入类型和地址:

<style type="text/css">
  div {
    border: 1px solid blue;
    padding: 2px;
    margin: 10px;
  }
</style>
<link rel="stylesheet" href="hello.css" />

预览看看,文字颜色变为绿色,边框的样式也被更新为 2 像素宽、点线型红色。

同样是 div 选择器,为什么边框的样式被覆盖了呢?注意 CSS 在同样条件下会后面代码覆盖前面,可以尝试交换 link 标签和 style 标签块的顺序看看。


行间样式

最后一种叫行间样式,这个结构更简单。修改 hello.html 中的 <div>内部第一个</div> 为

<div style="margin: 60px 0 10px 30px ;color:purple;">内部第一个</div>

样式覆盖前两种方式了,因为行间样式的优先级较高。这里涉及到选择器权重,先给一个简单公式了解一下。

!important > 行间样式 > ID > class | 伪类 | 属性选择 > 标签 > 继承 | 通配符。

多个选择器作用时权重相加。这里算 CSS 里有点复杂的部分,暂时不展开。

这里还有个小知识点是内外边距 margin 和 padding 接受的完整的值是四个,顺序固定为“上 右 下 左”。如果省略参数则从末尾计算对向合并。比如:

  • margin:40px 20px 50px; 三个参数时,左右同为 20px。
  • margin:40px 20px; 两个参数时 上下同为 40px, 左右同为 20px。
  • margin:40px; 一个参数时呢?请自行尝试理解。

CSS 先讲这么多,虽然没有把我们的页面变多好看,但最起码知道努力的方向了。

JavaScript

制作 JavaScript 的快速入门简直非常伤脑筋。比起前两种技术 HTML 和 CSS,这是货真价实的编程语言了。

也是我们后面要用到的 Vue.js 和 Node.js 中的根基,一下子又很难讲很多,所以还是希望同学们能重视起来系统学习一下,最起码读到后面的代码时不至于陷入“这是啥这又是啥”的窘境。

来段代码直观认知一下,还是先内部代码块引入。

在 hello.html 的 head 标签内增加一个代码块:

    <link rel="stylesheet" href="./hello.css">
    <script>
      let message = "字符串提示";
      function showMSG(msg) {
        alert(msg);
      }
    </script>

修改 hello.html 的 h1 标签为:

<h1 onclick="showMSG(message)">页面标题</h1>

保存预览,点击“页面标题”,会弹出提示框。

JavaScript 代码加载之后就会执行,不存在编译阶段。行末的分号绝大多数时候可以省略。

我们先定义了一个变量 message,并赋值为“字符串提示”。定义变量关键字原是 var,ES6 新增关键字 let 有更清晰的作用域,可替代使用。

学习 JavaScript 经常会碰到 ES6、ES7 之类的名词,实际上是 ECMAScript 标准的版本号的意思。可以简单理解为新版标准为 JavaScript 添加特定新特性。

然后我们定义了一个函数 showMSG,并添加一个形参 msg。在函数体内部调用浏览器弹框方法,显示 msg 的值。function 是定义函数的关键字,暂时先把它当做一个功能封闭的盒子,当函数调用时,执行函数体内的代码。

调用部分是先给 h1 标签添加了 onclick 点击事件,被点击时触发 showMSG(message),也就是把 message 传给了 msg。

之后再试一下调用外部 js 文件,新建 demo.js 文件,写入下面内容并保存。

message = "修改一下字符串";

然后修改 hello.html 文件,在 script 代码块后面增加一行:

<script src="./demo.js"></script>

这次保存预览,点击“页面标题”,可以看到弹窗的文字变了。这个演示了 script 代码块在页面可以同时存在多个,也是顺序调用,而且互相之间可以直接访问。文件命名也没有要求,希望不会逼死强迫症。

JavaScript 就是为什么网页可以做那么多交互的源头了。掌握起来任重道远。

以上内容节选自实验楼训练营课程《Vue.js 和 Node.js 构建内容发布系统》。


这三门前端技术先了解到这里,想要更深入学习如何使用前端技术构建内容发布系统,比如做个高逼格的博客,搭建一个交流社区,或者为企业制作官网等,可以访问实验楼官网搜索《Vue.js 和 Node.js 构建内容发布系统》这门课。

课程会提供完整的虚拟机环境,手把手教大家如何从头构建实现一个前后端分离的内容发布系统,包括了前端页面、后端服务、数据库等。