作者归档:songtianlun

对 tail -f 使用管道

来源: 对 tail -f 使用管道

最近发现 tail -f 时管道后面的程序都会被卡住,才发现 grep,sed,awk 不直接输出到 TTY 时都是带缓冲的。平时跟在 cat 后使用没问题是因为输入管道关闭触发了 flush。本文详细解释其中的坑,以及怎么让 sed, awk, grep 立即 flush。

TL;DR:grep 添加 --line-buffered,sed 添加 -u,awk 调 fflush()。

管道和缓冲

管道 是 Linux/Unix 中进程间通信的一种方式,可以在命令间、进程间传递数据。比如下面的命令用来来打印所有文件不存在的异常。

cat log.txt | grep Error | grep ENOENT

由于 cat 命令会在读完文件后立即退出并关闭 STDOUT,grep 的缓冲会立即 flush,我们会在执行完上述命令后立即看到输出。但如果改成实时打印日志的 tail -f 则会看不到任何输出:

tail -f log.txt | grep Error | grep ENOENT

因为当 grep 的输出不是 TTY(终端) 时,会启用缓冲。输入关闭或缓冲区满时才输出。这个例子中第一个 grep 的输入 tail -f 一直没有关闭,因此缓冲一直不会输出,第二个 grep 也永远不会收到输入。 因此控制台不会有任何输出。

但如果反过来,grep 的输出是 TTY 时就不会缓冲。也就是说 tail -f log.txt | grep Error(注意少了一个 grep)会正常地持续地输出。

检查输出文件

那么 grep 会检查它输出到哪里?虽然理论上有悖于管道的设计,也不那么函数式。 难以想象我们有个函数,它的返回值竟然会取决于这个返回值下一步被用于做什么操作。 不仅是 grep,sed 也有类似的行为,这里不去更多地讨论设计,而是给几个有用的场景:

  1. 当输出到 TTY 时输出带颜色的字符,输出到文件时输出纯文本。
  2. 当输出到 TTY 时执行过程可以提示用户输入,输出到文件时则需要使用默认值或者报错。
  3. 以及 grep 的例子:输出到 TTY 时实时打印,输出到文件或其他程序时缓冲起来(因为尤其是写入磁盘文件时,没必要有输出就写)。

那么怎么判断标准输出的文件描述符呢?

注意 [ 是一个命令,-t 是它的参数,可以 man [ 查看详情。

缓冲区满

既然 tail -f 日志看不到输出是因为缓冲区没有 flush,那么缓冲区什么时候会被 flush 呢?有两种情况:

  1. 写入已经结束(类似 JavaScript 中的 Stream.prototype.end() 调用)。但是 tail -f 的输出流永远不会结束,因为 -f 会永远 follow 文件 append。作为对比,cat 命令的输出流会在读到文件尾时结束。比如执行 cat log.txt | grep Error 会立即 flush 并退出。
  2. 缓冲区满。既然叫做 Buffer 一定是有大小的,tail 写入足够多的内容后,grep 的缓冲区就会满,这时也会发生 flush。

那么 grep 的缓冲区是多大呢?既然 tail 的输出不足以填满缓冲区,我们用输出足够多的 yes 命令:

yes Error ENOENT | grep Error | grep ENOENT

yes 命令用来不断地循环(死循环,直到被 Ctrl-C)输出它的参数,因此缓冲很快会满。果然上面的命令我们可以看到大量的输出。

避免缓冲

grep 提供了 --line-buffered 来按照行缓冲,也就是每写满一行 flush 一次:

--line-buffered
     Force output to be line buffered.  By default, output is line buffered when standard output is
     a terminal and block buffered otherwise.

sed 可以用 --unbuffered 来禁用缓冲:

-u, --unbuffered
     load minimal amounts of data from the input files and flush the output buffers more often

awk 作为一门完整的编程语言,需要调用 fflush() 方法来清空缓冲:

The built-in function fflush(expr) flushes any buffered output for the file or pipe expr.

因此前面的例子中给 grep 添加 --line-buffered 即可让它持续地输出:

tail -f log.txt | grep --line-buffered Error | grep ENOENT

注意第二个 grep 不需要添加 --line-buffered,因为它的标准输出是 TTY,默认不会启用缓冲区。 下面是一个更完整的例子,从 log.txt 文件实时读日志,过滤包含 Error 的行,把 harttle 标记去掉,打印出第一列,再过滤得到 ENOENT 的行:

tail -f log.txt | grep --line-buffered Error | sed -u 's/harttle//' | awk '${print $1; fflush()}' | grep ENOENT

References

Vim 使用系统剪切板

来源:Vim 使用系统剪切板

Vim 是运行在 Terminal 里的 Shell 程序,所以要把内容拷贝出来可以通过 Terminal,也可以通过 Vim 自己。不配置 Vim 剪切板时只能通过 Shell 来拷贝粘贴:

  • 通过 Shell 拷贝(比如在 iTerm 里按住 Alt 选取内容)会有问题:比如会包含 Vim 左侧行号、折行变成了换行。
  • 通过 Shell 粘贴有类似的问题:相比于 p 命令,在插入模式下 Ctrl+V 时 Vim 会把内容当作字符键入,触发 Vim 的所有处理键入的插件,比如自动补全、语法检查等。不仅会很慢,而且可能会破坏你的内容(比如粘贴一对括号,可能 Vim 会再帮你自动补全一个多余的右括号)。

所以完美的拷贝粘贴一定要通过 Vim 本身。Vim 中 p(paste)、d(delete)、y(yank)等拷贝粘贴操作使用的是 匿名寄存器 ""(unnamed register),本文就来解释怎么在 Mac/Windows/Linux 上把 Vim 的 匿名寄存器 映射到操作系统的剪切板。

TL; DR

  1. 确保你的 vim 支持剪切板,通过 vim --version | grep clipboard 检查。
  2. 确定你的剪切板寄存器是 "+(XA_SECONDARY)还是 "*(XA_PRIMARY)。
  3. 同步剪切板和匿名寄存器,在 ~/.vimrc 添加配置比如 set clipboard=unnamed。

确保你的 Vim 支持剪切板

你的 Vim Build 没有支持 clipboard,那么无论怎样配置都不会生效。 可以用如下命令检查:

vim --version | grep clipboard

如果输出包含 +clipboard 或 +xterm_clipboard 就支持,如果这两项都是 - 则不支持。例如我的 Vim 输出为(MacOS 上的 macvim):

+clipboard         +keymap            +printer           +vertsplit
+emacs_tags        -mouse_gpm         -sun_workshop      -xterm_clipboard

如果你的 Vim 不支持剪切板,则需要重新安装一个带 clipboard 的 Vim:

重新安装后再执行 vim --version 来查看 clipboard 是否支持。注意:如果安装到了其他路径你需要改 PATH 或重启 Terminal。

确定你的剪切板寄存器

Vim 有 48 个寄存器,y, d, p 等命令一般使用匿名寄存器 "", 支持剪切板的 Vim 会支持额外的选区寄存器 "* 和 "+。 更多 Vim 寄存器的信息,可以参考这篇文章:Vim 寄存器完全手册。

"* 和 "+ 在 Mac 和 Windows 中,都是指系统剪切板(clipboard),例如 "*yy 即可复制当前行到剪切板。 其他程序中复制的内容也会被存储到这两个寄存器中。 在 X11 系统中(绝大多数带有桌面环境的 Linux 发行版),二者是有区别的:

  • "* 指 X11 中的 PRIMARY 选区,即鼠标选中区域。在桌面系统中可按鼠标中键粘贴。
  • "+ 指 X11 中的 CLIPBOARD 选区,即系统剪切板。在桌面系统中可按 Ctrl+V 粘贴。

上述哪个寄存器对应于你的剪切板和 Linux 发行版有关,在配置 Vim 前可以测试一下。 比如用 Vim 打开一个文件,在 normal 模式下(进入 Vim 后默认的模式)键入 gg"*yG, 来把当前文件内容拷贝到 "* 寄存器。键入 gg"+yG 拷贝到 "+ 寄存器。

到目前为止,你已经可以通过命令来拷贝粘贴内容了。接下来我们希望通过 Vim 配置, 让匿名寄存器和系统剪切板同步。

同步剪切板和匿名寄存器

以下配置可以让主选区寄存器 "* 和匿名寄存器 "" 保持同步(即共享剪切板), 一般适用于 Windows 和 MacOS,Linux 下的表现是共享 X11 剪切板、PRIMARY 选区(鼠标中键粘贴)。

set clipboard=unnamed

Vim 7.3.74 及以上支持了 unnamedplus:

set clipboard=unnamedplus

即让剪切板寄存器 "+ 和匿名寄存器 "" 保持同步, Linux 下一般对应于桌面系统的剪切板,比如 GNOME 的系统剪切板、以及 SECONDARY 选区(Ctrl+V 粘贴)。

不支持 clipboard 的情况

如果你的 Vim 不支持 clipboard 且没法升级或其他 clipboard 选项不好使的情况, 可以调用外部命令来实现拷贝粘贴,在 Vim 里直接调用,或设置快捷键调用。 比如 让 Tmux 远程 Vim 使用本地系统的剪切板。

如果在 MacOS 下,可以用 pbcopy/pbpaste 命令来实现。

  • 拷贝一段文本:先按 v 进入 visual 模式选中后执行 :w !pbcopy。拷贝整个文件可以 :%w !pbcopy
  • 粘贴一段文本:把光标移动到要插入的行,执行 :r !pbpaste

如果在 Linux 下,可以借由 xclip 来实现。用 xclip -i -sel c 代替上面的 pbcopy,用 xclip -o -sel -c 代替上面的 pbpaste。

References

Vim 寄存器完全手册

转载自 Vim 寄存器完全手册

常见文本编辑器都会提供剪切板来支持复制粘贴,Vim 也不例外。 不同的是 Vim 提供了 10 类共 48 个寄存器,提供无与伦比的寄存功能。 最常用的 y 操作将会拷贝到默认的匿名寄存器中,我们也可以指定具体拷贝到哪个寄存器中。

一般来讲,可以用 "{register}y 来拷贝到 {register} 中, 用 "{register}p 来粘贴 {register} 中的内容。例如: "ayy 可以拷贝当前行到寄存器 a 中,而 "ap 则可以粘贴寄存器 a 中的内容。

除了 a-z 26 个命名寄存器,Vim 还提供了很多特殊寄存器。合理地使用可以极大地提高效率。例如:

  • "+p 可以粘贴剪切板的内容,
  • ":p 可以粘贴上一个 Vim 命令(比如你刚刚费力拼写的正则表达式),
  • "/p 可以粘贴上一次搜索关键词(你猜的没错,正是 normal 模式下的 /foo 搜索命令)。

在 Vim 中可通过 :reg 来查看每个寄存器当前的值。

寄存器分类

Vim 提供了 10 类寄存器,可在 Vim 中通过 :help registers 查看帮助。

  1. 匿名寄存器 ""
  2. 编号寄存器 "0 到 "9
  3. 小删除寄存器 "-
  4. 26 个命名寄存器 "a 到 "z
  5. 3 个只读寄存器 ":, "., "%
  6. Buffer 交替文件寄存器 "#
  7. 表达式寄存器 "=
  8. 选区和拖放寄存器 "*, "+, "~
  9. 黑洞寄存器 "_
  10. 搜索模式寄存器 "/

1. 匿名寄存器

使用 d, c, s, x 等会删除字符的命令时,被删除字符会进入匿名寄存器 ""。 你可以认为 "" 寄存器是一个指针,指向刚才被存到的寄存器。

在 如何用 Vim 搭建 IDE ? 一文中提到,Mac 下可通过下列设置来让 Vim 共享系统剪切板, 就是这个原理:所有删除和拷贝操作默认都会到匿名寄存器。

set clipboard=unnamed

使用 y 命令未指定寄存器会存到 "0 寄存器中,同时 "" 会与该寄存器保有同样的值。 这意味着你使用 p 和 "p 总会得到同样的结果。

2. 编号寄存器

编号寄存器从 "0 到 "9 共 10 个,其中 "0 保存着拷贝来的字符串,"1 到 "9 保存着删除掉的字符串。 删除操作符包括 s, c, d, x。 删除掉的字符串会被存到 "1 中,上次删除的则会被存到 "2 中。以此类推,Vim 会保存你最近的 9 次删除。

  • 只有整行整行的删除,和通过段落级别的移动指令(包括 %,(,),/,`,?,n,N,{,}) 的删除才会被放到 "1 中。
  • 当用户指定拷贝操作的寄存器时(如 "ap),"0 不会被写入;但删除操作一定会被写入到 "1 中。

"0 寄存器很有用,比如我们 copy 了一段文本然后用它替换另一段文本。 这时默认寄存器 "" 中的值就变成了被替换文本,如果还需要用 copy 的文本继续替换的话就需要 "0p 了。

3. 小删除寄存器

不足一行的小删除则会被放到小删除寄存器中("-),起作用的删除操作符也包括 s, c, d, x。 例如:

dw    # 删除一个词
d9l   # 删除9个字符
cb    # 向前更改一个词

与 "0 寄存器类似,当用户指定寄存器并进行删除时,"- 不会被写入。

4. 命名寄存器

命名寄存器有 "a 到 "z 共 26 个,这些寄存器只有当我们指定时才会被使用。 其实我们在录制宏时,所有键盘操作会以字符串的形式存到寄存器中。 例如录制一个宏存到 "a 寄存器中,内容为更改当前行 cc,改为 foo 字符串:

qaccfoo

然后执行 :reg 来查看寄存器,可以发现 a 寄存器的值是 ccfoo。

小技巧:当使用小写字母进行操作时会覆盖当前寄存器内容,当使用大写字母进行操作时,会追加当前寄存器内容。

5. 只读寄存器

只读寄存器共 3 个,它们的值是由 Vim 提供的,不允许改变:

  • ".:上次 insert 模式中插入的字符串。还记得吗? . 命令可以重复上次操作,而 ". 存储了上次插入。
  • "%:当前文件名,不是全路径,也不是纯文件名,而是从当前 Vim 的工作目录到该文件的路径。例如此时 Harttle 的 Vim 中,"%p 的结果为 _drafts/vim-registers.md。
  • "::上次命令模式下键入的命令。正如 @a 可以执行 "a 寄存器中的宏一样,@: 可以执行上次命令。

6. 交替文件寄存器

交替文件寄存器 "# 存储着当前 Vim 窗口(Window)的交替文件。交替文件(alternate file)是指 Buffer 中的上一个文件,可通过 Ctrl+^ 来切换交替文件与当前文件。

Window 和 Buffer 有什么区别?参见 Vim 多文件编辑:窗口 一文。

7. 表达式寄存器

表达式寄存器 "= 主要用于计算 Vim 脚本的返回值,并插入到文本中。 当我们键入 "= 后光标会移动到命令行,此时我们可以输入任何 Vim 脚本的表达式。 例如 3+2,按下回车并且 p 则会得到 5。

这在我们调试 Vim 脚本时非常有用,比如调用一个函数看它是否有正确的返回值。

8. 选择和拖放寄存器

选择和拖放寄存器包括 "*, "+, 和 "~,这三个寄存器的行为是和 GUI 相关的。

"* 和 "+ 在 Mac 和 Windows 中,都是指系统剪切板(clipboard),例如 "*yy 即可复制当前行到系统剪切板。 其他程序中复制的内容也会被存储到这两个寄存器中。 在 X11 系统中(绝大多数带有桌面环境的 Linux 发行版),二者是有区别的:

  • "* 指 X11 中的 PRIMARY 选区,即鼠标选中区域。在桌面系统中可按鼠标中键粘贴。
  • "+ 指 X11 中的 CLIPBOARD 选区,即系统剪切板。在桌面系统中可按 Ctrl+V 粘贴。

上文所述的 Mac 下 set clipboard=unnamed 会使得系统剪切板寄存器 "* 和 Vim 默认的匿名寄存器 "" 始终保有同样的值,即 Vim 和系统共用剪切板。

有文本拖拽到 Vim 时,被拖拽的文本被存储在 "~ 中。Vim 默认的行为是将 "~ 中内容插入到光标所在位置。 当然你可以给 `

` 做键盘映射。 ## 9. 黑洞寄存器 黑洞寄存器 `”_`,所有删除或拷贝到黑洞寄存器的文本将会消失。 这是为了在删除文本的同时不影响任何寄存器的值,`”_` 通常用于 Vim 脚本中。 ## 10. 搜索寄存器 搜索寄存器 `”/` 用于存储上一次搜索的关键词。Vim 中如何进行搜索呢? 在 normal 模式下按下 `/` 即进入 search 模式,输入关键字并按下回车即可。 该寄存器是可写的,例如 `:let @/ = “harttle”` 将会把 `”harttle”` 写入该寄存器。 下次搜索时不输入搜索词直接回车便会搜索 `”harttle”`。 ## 命令行模式拷贝 值得一提的时,任何寄存器中的值都是可以拷贝到命令模式下的。 比如对于寄存器 `”a` 中的值,在 normal 模式下可以通过 `”ap` 来粘贴;在 command-line 模式下通过 `a` 来粘贴。这一操作存在风险,因为寄存器中的值可能是从网页中拷贝来的。 如果寄存器中的字符串存在 ` ` 字符或 “ 字符,则会时 Vim 回到 normal 模式, 并继续执行寄存器中的命令。为了防范 _剪切板劫持_,可以添加下列的 Vim 配置: “` inoremap + u”+gP “` > 该命令的解释请移步:[http://vim.wikia.com/wiki/Pasting_registers](http://vim.wikia.com/wiki/Pasting_registers) ## 扩展阅读 – 剪切板与 X11 选区:[http://stackoverflow.com/questions/11489428/how-to-make-vim-paste-from-and-copy-to-systems-clipboard](http://stackoverflow.com/questions/11489428/how-to-make-vim-paste-from-and-copy-to-systems-clipboard) – Vikia-Pasting Registers: [http://vim.wikia.com/wiki/Pasting_registers](http://vim.wikia.com/wiki/Pasting_registers) – Vim Help: `:help registers`, `:help quotestar`, `:help quoteplus` # References – [Vim 寄存器完全手册](https://harttle.land/2016/07/25/vim-registers.html)

Vim 宏录制和重放

TL;DR

  1. qa: 录制到寄存器 a 中,可使用 a-z 26 个命名寄存器
  2. 开始操作,做的所有操作都会录制下来,重放时自动操作;
  3. q: 结束录制
  4. @a 重放一次;
  5. 100@a 重放100次;

例子

在编辑某个文件的时候,可能会出现需要对某种特定的操作进行许多次的情况,以编辑下面的文件为例:

;=====================================================================================;This is a sample configuration file when upgrading XXX using InstallShield.;Author:        ini_always;Date:          8/24/2011;Last modified: 9/20/2011;Note: Install script does NOT verify whether the configuration file is in a "WELL";format, a WRONG format may lead to installation failure.;If more information is needed, please check the document for details.;=====================================================================================

这是一个 ini 类型的配置文件,可以看到每一行的最前面有一个逗号,现在如果需要将每行前面的逗号去掉,怎么办?在第一行行首按x,然后按j,然后按x…这样重复下去?确实,我最开始也是这样的,但如果这个文件有100行要这样修改呢?或者1000行?

好吧,少废话,进入正题。所谓宏,在vim里面是指某种特定顺序的一系列操作,我们可以录制自己的操作序列,然后重复这个序列多次,以简化某种重复的操作。vim宏有录制和播放的过程,录制就是你教给vim该怎么操作,播放就是vim照着你教的进行自动操作。因此,对于上面的文件处理,首先要进行宏录制:

1.把光标定位在第一行;

2.在normal模式下输入qa(当然也可以输入qb, qc, etc,这里的a, b, c是指寄存器名称,vim会把录制好的宏放在这个寄存器中)(PS:如果不知道什么是vim的寄存器,请自行放狗搜之);

3.正常情况下,vim的命令行会显示“开始录制”的字样,这时候,把光标定位到第一个字符(按或者|),再按x删除,按j跳到下一行;

4.normal模式下输入q,结束宏录制。

好了,经过以上步骤,我们定义了一个存储在寄存器a中的宏,它的操作序列是:0->x->j,也就是跳到行首,删除,跳到下一行。

现在,第一行已经删除了行首的逗号,而且光标也已经在第二行,现在,在normal模式下输入@a,以播放我们刚录制好的存在寄存器a中的宏。于是,第二行行首的逗号也被删除,光标停在了第三行。

这也不简单啊?你肯定会这样想,要删除100行,我还得输入100个@a,我还不如手动删除呢。呵呵,vim早就想到了,输入7@a,好了,剩下的7行全部搞定了。(PS:在命令前面加数字,就是代表要执行这个命令多少次)

当然,这个例子很简单,但也很典型。利用好vim的宏,可以使一些原本很无聊的工作要简单很多。

References

ArchLinux 快速本地部署 DeepSeek

在 ArchLinux 下借助 Ollama 可以快速运行一个小参数体量的 DeepSeek 本地模型,在我的环境上 纯 CPU 推理也可以获得很快的体验。

安装环境

一行命令即可装好 ollama

$ sudo pacman -S ollama

模型

从 ollama 的 DeepSeek-R1模型页面 可以看到可拉取的模型,包括全量的 671b 模型,以及精炼的小模型表现同样出色。:

  • DeepSeek-R1
  • DeepSeek-R1-Distill-Qwen-1.5B
  • DeepSeek-R1-Distill-Qwen-7B
  • DeepSeek-R1-Distill-Llama-8B
  • DeepSeek-R1-Distill-Qwen-14B
  • DeepSeek-R1-Distill-Qwen-32B
  • DeepSeek-R1-Distill-Llama-70B

模型能力统计

运行

首先打开一个 终端,运行 ollama 服务端

$ ollama serve  
2025/02/18 14:57:36 routes.go:1187: INFO server config env="map[CUDA_VISIBLE_DEVICES: GPU_DEVICE_ORDINAL: HIP_VISIBLE_DEVICES: HSA_OVERRIDE_GFX_VERSION: HTTPS_PROXY: HTTP_PROXY: NO_PROXY: OLLAMA_DEBUG:false OLLAMA_FLASH_ATTENTION:false OLLAMA_GPU_OVERHEAD:0  
OLLAMA_HOST:http://127.0.0.1:11434 OLLAMA_INTEL_GPU:false OLLAMA_KEEP_ALIVE:5m0s OLLAMA_KV_CACHE_TYPE: OLLAMA_LLM_LIBRARY: OLLAMA_LOAD_TIMEOUT:5m0s OLLAMA_MAX_LOADED_MODELS:0 OLLAMA_MAX_QUEUE:512 OLLAMA_MODELS:/home/songtianlun/.ollama/models OLLAMA_MULTIU  
SER_CACHE:false OLLAMA_NOHISTORY:false OLLAMA_NOPRUNE:false OLLAMA_NUM_PARALLEL:0 OLLAMA_ORIGINS:[http://localhost https://localhost http://localhost:* https://localhost:* http://127.0.0.1 https://127.0.0.1 http://127.0.0.1:* https://127.0.0.1:* http://0.0.  
0.0 https://0.0.0.0 http://0.0.0.0:* https://0.0.0.0:* app://* file://* tauri://* vscode-webview://*] OLLAMA_SCHED_SPREAD:false ROCR_VISIBLE_DEVICES: http_proxy: https_proxy: no_proxy:]"  
time=2025-02-18T14:57:36.900+08:00 level=INFO source=images.go:432 msg="total blobs: 11"  
time=2025-02-18T14:57:36.900+08:00 level=INFO source=images.go:439 msg="total unused blobs removed: 0"  
time=2025-02-18T14:57:36.900+08:00 level=INFO source=routes.go:1238 msg="Listening on 127.0.0.1:11434 (version 0.5.7)"  
time=2025-02-18T14:57:36.901+08:00 level=INFO source=routes.go:1267 msg="Dynamic LLM libraries" runners="[cpu cpu_avx cpu_avx2]"  
time=2025-02-18T14:57:36.901+08:00 level=INFO source=gpu.go:226 msg="looking for compatible GPUs"  
time=2025-02-18T14:57:36.944+08:00 level=INFO source=gpu.go:392 msg="no compatible GPUs were discovered"  
time=2025-02-18T14:57:36.944+08:00 level=INFO source=types.go:131 msg="inference compute" id=0 library=cpu variant=avx2 compute="" driver=0.0 name="" total="30.7 GiB" available="7.2 GiB"

不要关闭窗口,在另外一个 shell 窗口运行以下命令启动并使用 deepseek-r1:1.5b 模型:

$ ➜  ~ ollama run deepseek-r1:1.5b  
>>>    
Use Ctrl + d or /bye to exit.  
>>>    
Use Ctrl + d or /bye to exit.  
>>> hello  

<think>  

</think>  

Hello! How can I assist you today? 😊e  

>>>

也可以用 cherry-studio 之类的工具对接使用:

CherryStudio 配置截图

CherryStudio 运行截图

实测 1.5B 模型运行非常流畅,可根据实际情况同样的方法尝试其他更多模型。

其他操作

ollama 其他常用操作如下:

# 在命令行中运行模型
ollama run <模型名称>

# 列出可用模型
ollama list

# 查看模型状态
ollama ps

# 删除模型
ollama rm <模型名称>

# 启动 API 服务
ollama serve

更多详情参见各官网。

References

全球艺术天气网站

介绍一个 每日 AI 艺术天气 网站,能够通过人工智能生成的艺术作品,以独特的视角展现日常气象现象。

入口

TodayAiWeather

TodayAiWeather​

部分城市入口:

收录情况

目前收录了 78 个城市,未来还会根据需要添加更多,有需要可以在本文留言。

​部分统计截图​

功能简介

每日 AI 天气艺术是一个独特的平台,通过人工智能生成的艺术将天气情况可视化。它提供了一种全新的方式,将气象数据转化为艺术表现。主要特点包括:

  • AI 生成的天气艺术: 每日为全球各城市更新天气艺术可视化。
  • 城市特定天气艺术: 探索不同城市的天气艺术,每幅作品反映当地天气状况。
  • 详细天气信息: 每幅艺术作品都附带具体的天气细节,如温度和天气状况。
  • 用户友好界面: 轻松浏览城市及其对应的天气艺术。

使用场景包括:

  • 独特的天气可视化: 以视觉吸引力和艺术性的方式体验天气。
  • 艺术探索: 发现 AI 如何解读和呈现天气数据。
  • 日常灵感: 通过艺术获得每日天气的新视角。
  • 教育工具: 通过视觉表现了解不同城市的天气状况。

LOGO 和 banner

​logo​

​banner​

Demo

​United States-new-york-city-20250202-090832
​United States-chicago-20250202-120237
​Armenia-yerevan-20250128-124329
​Guangzhou-chinese-new-year

Docker 官方脚本一键安装

使用官方脚本安装

curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun

curl -fsSL https://res.frytea.com/d/Dev/Docker/get_docker.sh | bash -s docker --mirror Aliyun

curl -fsSL https://res.frytea.com/d/Dev/Docker/get_docker.sh | DOWNLOAD_URL=http://192.168.25.10/docker  bash -s docker

# ustc
curl -fsSL https://get.docker.com -o get-docker.sh
sudo DOWNLOAD_URL=https://mirrors.ustc.edu.cn/docker-ce sh get-docker.sh

# 也可以自己在内网做一个镜像,将脚本和 docker 软件源全部镜像,可以实现全内网高速安装
curl -fsSL http://192.168.25.9/raw/general/docker/install-docker.sh -o get-docker.sh
sudo DOWNLOAD_URL=http://192.168.25.10/docker sh get-docker.sh

curl -fsSL http://192.168.25.9/raw/general/docker/install-docker.sh |  DOWNLOAD_URL=http://192.168.25.10/docker bash -s

安装完成后使能 docker 服务:

systemctl enable docker
syste sart docker
sudo usermod -aG docker $USER

参考文献

#Docker

《奔跑吧,程序员:从零开始打造产品、技术和团队》

阅读感悟

暂略

阅读摘录

《奔跑吧,程序员:从零开始打造产品、技术和团队》

叶夫根尼·布里克曼 194个笔记

1.2 什么是科技创业公司

◆ 创业公司就是在极度不确定的条件下创造新产品或服务的人类组织。——Eric Ries, 《精益创业》

◆ 创业公司的目标在于快速增长。一家公司成立的时间短并不能让其本身成为创业公司,创业公司也未必要从事科技领域的工作,未必要接受风险投资基金或有某种“退出”的机制。创业公司唯一必不可少的东西就是增长,其他和创业相关的所有东西都是伴随着增长而来的。——Paul Graham, Y Combinator联合创始人,硅谷创业教父,《黑客与画家》作者

◆ 成熟企业拥有的产品已经被市场证明是为大家所接受的,所以它们关注的是扩大规模、优化产品和提升执行效率。而创业公司并不知道什么样的产品能在市场中立足,所以公司的主要注意力将放在试验、尝试和纠错上,重点是寻找一种可重复、可扩展的商业模型

◆ 可以这么说,创业公司的最后一个要素就是它们是按探索模式运作的

◆ 科技创业公司”是具有下述特征的组织。·产品:技术。·环境:极度不确定。·目标:大幅增长。·运作模式:探索。

◆ 这本书的内容既可以用在全新的只有3个人的公司上,也可以用在有着3000人规模的成熟公司新成立的创新机构上。只要你进行的是技术研发,环境总处于变化之中,主要目标是为了增长,机构是以探索的模式在运行,那么书中的内容就适合你

1.3 为什么应该在创业公司中工作

◆ 要在科技创业公司中工作,甚至自己创立这样一家公司,我们应该考虑三个主要因素:更多的机会、更多的所有权以及更多的乐趣。

◆ 一直以来,我们的大脑和身体都通过各种人造部件和技术得到增强。这种情况潜移默化地发生,让人无法觉察

◆ 换句话说,就像Marc Andreessen在2011年预测的那样——“软件正在蚕食世界”。因为科技愈加无所不在,软件公司将会占据越来越多的产业

◆ 也可以使用New Relic、KISSMetrics或者MixPanel,而不用去研发自己的监控软件;可以使用Amazon SES、MailChimp或者SendGrid,而不用去搭建自己的email服务;如果需要logo,可以使用DesignCrowd;如果需要法律服务,可以使用RocketLawyer;如果需要接受付款,可以使用Stripe;如果需要管理客户数据,可以使用Salesforce;如果需要提供客户支持,可以使用Zendesk。

◆ 我们的父母或祖父母很可能会在同一家公司工作50年,顺着职业的阶梯不断攀爬,戴着金表退休[插图]。现在,我们再也享受不到这种待遇了,因为那种工作已经消失了。据统计,美国60年代初期出生的大多数人会在18~46岁从事11.3份工作,这个数字可能在不断地上升,20世纪80年代初期出生的大多数人到26岁时已平均从事了6.2份工作。从第一个数字可以算出,平均一份工作的持续时间还不到3年。大公司的工作并不比小公司的工作更稳定。例如,仅仅在2014年,思科就解雇了6000名员工,IBM解雇了13000名员工,微软解雇了18000名员工,HP则解雇了27000名员工。所以,所谓的工作稳定性已经不复存在。

◆ 我在大学毕业正决定去哪儿的时候得到了一条建议:你应该把硅谷当作一家大公司,其中有Facebook部门、Google部门和一大堆小型创业部门

◆ 真正的风险并不是因加入了小型创业公司而失业——毕竟我们在大公司工作也没办法保证不失业——而是失去机会的风险

◆ 可能某一天要编写数据库查询,第二天又要设计用户界面,之后还得回复客户的服务邮件,中间又要腾出时间准备投资者的融资演讲稿,期间培养出的这些技能将对你今后的职业生涯大有裨益。你也会学到如何应对紧张、压力和风险,会被推出自己的舒适区之外,这才是你真正能学到东西的地方。这也就是为什么很多人在创业公司三个月要比在大公司工作三年学到的还多。

◆ 师综上所述,自主权、掌控力和使命感是激励人的三个最强有力的因素

◆ 如果你找到了一份可以同时提供这三者的工作,那么就是找到了一份你会热爱的工作,也是一份你可以为之自豪的工作

1.5 小结

◆ 在你成长的过程中,人们总是会告诉你:这个世界就是……尽量不要撞了墙也不回头,要努力拥有美好的家庭,要学会享乐,要存下一点钱。那是一种非常有限的生活。生活可以变得更加多彩,只要你发现这样一个简单的事实:你周围的一切,即你所谓的生活,都是由不如你聪明的人组成的,你可以去改变它,可以去影响它,也可以做出自己的东西供他人使用。一旦意识到这一点,你将从此不同。——史蒂夫·乔布斯

2.1 点子从何而来

◆ 点子也不会凭空发展进化出来,物理学的能量守恒定律阐述了能量从来不会凭空产生或湮灭,而是以不同的形式被重新利用,点子也同样遵守这样的守恒定律,所有新的想法只不过是现有想法组合而成的结果

◆ 。但真实的情况是“我们都在用相同的材料做东西”(弗格森语),混搭和重新合成是产生新点子的常见方法[插图]。那是因为创造力的产生可以归结为三个阶段,这三个阶段都不过是不同形式的重新合成:(1)模仿;(2)转换;(3)合并。

◆ 如果我们想要找到创业的好点子,就需要一整堆的“原料”,从而可以在此基础上去研究、注明出处、重新合成、聚合和转换,也就是说,我们需要掌握大量的知识

◆ 其目标,正如史蒂夫·乔布斯所说的,就是努力“让自己感受人类最美好的东西”。

◆ 纵观人类历史,出现了不少多重发现(multiple discovery)的例子,即有两个或多个科学家或发明家在差不多相同的时间内提出相同的想法,比如牛顿和莱布尼茨都在17世纪发表了关于微积分最早的论文,达尔文和华莱士都在19世纪提出了进化论,而格雷和贝尔在同一天提交了电话的发明专利申请。这一切都不是偶然,它表明环境对新点子的涌现有巨大影响

◆ 如果你深深沉浸在某一个主题中,日复一日致力于此,你的潜意识除了解决问题就不干别的了。也许在某天清晨或者午后醒来,你就找到了答案。对于那些并没有想方设法、全心投入解决现有问题的人,潜意识就会在其他事情上“游手好闲”,不可能有什么大作为。所以自我管理的方法就是一旦你有什么真正重要的问题,就不要把其他事情置于自己注意力的中心,你要一直把心思放在这个问题上。让你的潜意识保持在“饥饿”状态,不得不解决你的问题。这样你就可以平静地入睡,等待清晨醒来时得到答案,得来全不费工夫。——Richard Hamming, You and Your Research演讲

2.2 验证

◆ 精益和敏捷方法的核心原则就是尽可能快地把可用的产品放在用户面前,即便产品离最终完成还有很远的距离。相反,瀑布方法则是希望先做出完整的解决方案,再呈现给用户

◆ 在《四步创业法》一书中,Steve Blank描述了一种叫客户开发的过程,该过程应该和产品开发过程同时进行

◆ 我们应该在第一天就把客户纳入开发过程当中,而不是等到产品完成了,才考虑它有没有客户

◆ 客户验证是指,承认我们的产品点子只不过是需要测试的、未经证明的假设,这样的测试必须以尽可能快、尽可能低的成本对真实客户实施。越早向同事之外的人验证你的点子,成功的概率就越大

◆ 可以分解为以下三个连续的阶段[插图]。第一步:验证问题确保找出客户实际面临并且痛苦到愿意掏腰包去解决的问题。第二步:验证MVP实现潜在解决方案的最简可行产品(minimum viable product, MVP),让少量客户购买该产品进行验证。第三步:验证产品把MVP完善为完整的产品,让更多客户去购买,对可扩大化的商业模式进行验证。

◆ 医生想要更多的病人,而不是更有效率的诊所

◆ 高效的诊所就会有更多的病人,但是关注错误的问题会导致整个公司误入歧途

◆ 关注了错误的问题就意味着所有的产品、市场营销策略和促销材料全都是错误的

◆ 在思考问题的大小时,有三个方面需要考虑:频率、密度和痛苦程度。

◆ ·频率:你所解决的问题经常发生吗?·密度:有很多人都会面临这个问题吗?·痛苦程度:该问题只是让人讨厌,还是绝对必须解决?

◆ 考虑市场规模有一个好方法,就是考虑建立一家赚得10亿美元收入的公司的几种方法。·以1美元的价格销售10亿件产品:可口可乐(罐装汽水);·以10美元的价格销售1亿件产品:强生(家用产品);·以100美元的价格销售1000万件产品:暴雪(《魔兽争霸》);·以1000美元的价格销售100万件产品:联想(笔记本电脑);·以1万美元的价格销售10万件产品:丰田(汽车);·以10万美元的价格销售1万件产品:Oracle(企业级软件);·以100万美元的价格销售1000件产品:Countrywide(高端金融抵押公司)。——Balaji S. Srinivasan,斯坦福创业项目工程课程

◆ 由丰田的创始人丰田喜一郎所提倡的,就是五个为什么

2.3 小结

◆ 许多数学家更喜欢因为问题固有的美而去研究问题,而非这些问题有什么实际的好处

3.1 设计

◆ 在顾客看来,界面就是产品。——Jeff Raskin, 《人本界面》

◆ Joel Spolsky把这种情况叫作冰山的秘密。我们所看到的冰山在水面上的那部分只占它总体积的10%;同样,我们可以看到和触碰到的产品的那部分——用户界面,只占全部工作的10%。所以,这个秘密就是大多数人并不清楚这一点。

◆ 以用户为中心的设计应该纳入我们的产品开发过程中,下面是它的五个基本原则:·用户故事;·人物角色;·情感设计;·简单;·可用性测试。

◆ 所谓用户故事,就是从用户的角度简短地描述你所做的东西。它应该回答下面三个问题。·用户是谁?·他们要实现什么?·他们为什么需要?

◆ 如果你是一名程序员,想理解你的用户会更加困难。每个人都会对“一种产品如何工作”形成自己的概念模型。但程序员的模型通常是非常细节化的,一般都处于界面、事件、消息、API、网络协议和数据存储这样的层次,而典型的用户模型通常没有那么多的细节,既不精确也不完整(例如,许多用户是不能区分软件与硬件、显示器与电脑有什么差别的)。这种概念模型上的不匹配会导致程序员很难和用户沟通。

◆ 许多程序员并没有意识到,因为对自己的软件非常了解,所以考虑软件的方式和用户是完全不同的,我们全然记不起初学者面对我们的软件是什么感觉。这种情况称为知识之祸,

◆ 作为程序员,当你在设计软件的时候,你的大脑其实一直都在“听着歌曲”。然而,你的用户却什么都没有听到,他们必须通过你所设计的用户界面(user interface, UI)去使用软件

◆ 你不能期待用户知道你所知道的,你也不能指望用户通过文档或教程来填补这一鸿沟

◆ 正如Steve Krug所说的:“关于说明书你必须知道的最主要的一件事就是,没有人想读说明书。”

◆ 想要做出成功产品的唯一选择就是做出出色的设计

◆ 大多数设计给程序员使用的软件也是设计给电脑用的,而电脑可不在乎可用性的问题

◆ 要成为一名成功的程序员,就得对糟糕的设计有很强的容忍力,几乎要到熟视无睹的地步

◆ 但如果要开发普通人可以使用的软件,就必须和他们一样去感同身受,压制自己作为程序员的许多本能感受

◆ 编程的过程和制作易用产品的过程是格格不入的,简单来说就是程序员的目标和用户的目标是有显著差别的。程序员希望构筑产品的过程顺利简单,用户则希望与程序的交互顺利简单。而这两个目标通常都不会共生于相同的程序。——Alan Cooper, The Inmates Are Running The Asylum

◆ 即便你克服了理解用户的障碍,还会面临第二个问题:他们希望实现什么

◆ 最常见的设计错误就是把用户的目标(他们要实现的是什么)和任务(他们可以如何实现)混淆了

◆ 经典的例子来自于冷战时期的太空竞赛,NASA的科学家意识到无法在太空的微重力环境下使用钢笔,所以花了数百万美元研发出一种带有加压墨盒的钢笔,它可以在零重力、上下颠倒、水下以及高温严寒等各种环境下书写。与此同时,苏联人使用的却是铅笔

◆ 这个故事虽然只是个传闻,但它却精彩地说明了当我们无视根本目标,而对做事情的某个特定方法过于关注时,会有什么荒唐的事情发生

◆ 正如亚伯拉罕·马斯洛所说:“如果你唯一的工具是一把锤子,那么你看到的任何东西都像钉子,我想这对人们是很有诱惑力的。

◆ 把任务从目标中分离出来的一种最佳方法就是使用上一章介绍过的“五个为什么”技巧(阅读2.2.3节了解更多信息)。

◆ 要区分任务和目标之间的差异,有一种很简单的方法。任务会随着技术的变化而变化,但目标有一种讨人喜欢的属性——它会非常稳定。例如要从圣路易斯到旧金山旅行,我的目标始终是速度、舒适性和安全。但在1850年去加州金矿的话,我会在全新的高科技科内斯托加马车中度过这段旅程。为了安全,我还会带上温切斯特来复枪。而在1999年从圣路易斯到硅谷,我会乘坐最新的高科技波音777飞机。——Alan Cooper, The Inmates Are Running The Asylum

◆ 第三个问题“为什么人们需要它”实际上就是强迫你证明为什么你要做你所做的东西,这就是上一章介绍的客户开发过程可以发挥作用的地方(阅读2.2.2节了解更多信息)

◆ 如果该产品或功能并不能为真正的用户解决重要的问题,你就不应该浪费时间去实现它。

◆ 无论什么时候,我们都应该花些时间用书面方式回答这三个用户故事问题,把你的产品点子从脑海中短暂、模糊的想法转变成纸面上具体的文字和图示,这样可以暴露出你在问题理解上存在的一些缺陷

◆ 在Readme文件、维基系统或便利贴上记录几行文本、画出几幅草图,就可以促使自己从用户的角度去感受这种端到端的体验,确保自己知道自己在做什么,为谁做,以及为什么值得做

◆ 这里有另一种可以显著提升设计技能的快捷方法:不要再为“平均的人”设计产品。人平均下来就是不洋不土、不男不女,如果你为平均的每个人做设计,那么谁都不会喜欢你设计出的东西

◆ 真正的平均用户被保存在日内瓦国际标准局的密不透气的地下室中。——Steve Krug, 《点石成金》

◆ 你关注的目标越广泛,错失靶心的必然性就越大

◆ 想让大量人口中50%的人满意你的产品,从而实现50%产品满意度的目标,这种做法是行不通的。我们只能挑选出50%的人,想方设法让他们100%满意,才能实现我们的目标。我们甚至可以瞄准市场中10%的人,让他们100%地心醉神迷,从而取得更大的成功。这听起来可能有点违背我们的直观感觉,但为单个用户进行设计是满足广大人群需求最有效的方式。——Alan Cooper, The Inmates Are Running The Asylum

◆ 人物角色之所以是如此强有力的设计手段,是因为它可以促使你去考虑真正的人,估计他们的真实需求、局限性和个性,最为重要的是,考虑他们的情感

◆ 研究表明,人与计算机及软件之间的交互在很大程度上与人类之间的交互类似

◆ 我们大部分的情感反应是自动产生的,控制这些反应的大脑区域尚未进化到能够对人和举止像人的无生命物体进行区分的程度

◆ Mailchimp把它的吉祥物(一只穿着像邮递员的猴子)放在了几乎所有的页面上,Tumblr的停机页面显示的是一只叫Tumblebeast的神奇小野兽在机房里发泄破坏,而Twitter的停机页面则是一只“失败鲸”(见图3-2)。

◆ 设计的情感因素对用户而言就像功能因素一样重要

◆ 你的产品是能说话的——每天24小时都在和你的客户交谈。——Jason Fried、David Heinemeier Hansson、Matthew Linderman, Getting Real

◆ 只要有可能,我们就应该把软件设计得像把你记在心上、考虑周到的人一样。要记住用户的参数设置,记住他们上次使用你的软件做了什么事情,记住他们过去搜索了什么东西,要尝试使用这些信息预测用户在以后会做什么事情

◆ 响应能力也没必要做得太过花哨,经常被忽视的一种最简单的设计元素,就是要提供基本的反馈

◆ 如果UI没有给出反馈,用户就不知道点击操作是否执行了,要么会连按10多次按钮,要么就失去信心完全放弃了

◆ 人都会犯错,而且还会不断犯错。在设计软件时,要假设用户也会输入错误、点击错误的按钮或者忘了一些重要的信息

◆ 这里不谈人为的错误,而是探讨沟通与交互:我们通常把糟糕的沟通或交互称为错误。当一个人与另一个人合作时,永远不要用错误这个词来形容另一个人的表达方式。因为每个人都希望能够理解他人的话语并做出回应,如果出现了无法理解或看似不恰当的地方,可以质疑,可以澄清,可以继续合作下去。那为什么人与机器之间的交互不能看作是合作呢?——Don Norman, 《设计心理学》

◆ 以下是一些经验法则,可以避免这种错误的发生。·提供帮助和指引,而不是错误消息。例如避免使用“错误”“失败”“问题”“无效”和“异常”这样的词,而是向用户解释程序希望获得的输入与用户的输入之间有什么差异。·在用户输入的同时进行检查(而不是在页面提交之后再进行),并分别给出肯定和否定两种反馈,给出的反馈应该在用户视线附近(而不是页面的顶部)。·永远不要把用户做好的东西弄丢。

◆ 除了显示有帮助的信息,我们也应该试着做出能在一开始防止错误发生的设计。在精益制造中,这种方法称为poka-yoke,这是一个日本术语,意思是“防止错误发生”

◆ 除了要对错误的状态进行处理,还要确保设计能够处理空白状态:应用程序就像用户第一次和它交互、什么数据都没有输入的样子

◆ 如果动态消息是完全空白的,新用户一定不觉得是很好的体验,他们可能不会继续使用你的服务

◆ 几乎所有的创新训练都有一个相同的目标:简单

◆ 《代码大全》的作者、程序员Steve McConnell在书中写道:“攻克复杂性是软件开发中最为重要的技术主题。

◆ Apple的首席设计师Jonathan Ive说:“简单之中蕴含着一种深刻而经久不衰的美。”每个人都在为简单而努力,问题是让事情简单并不是一件简单的事

◆ 我本来想把信写得简短一点,但我没有时间。——Blaise Pascal

◆ 正如Antoine de Saint Exupéry所言:“达到完美并不是没有东西可以添加,而是没有东西可以去除。”

◆ [插图]图3-8:简单(图片由Eric Burke提供)

◆ 在设计上做得比较成功的公司,均认识到加入软件中功能的数量并不受“瑞士军刀空间有限”那样的物理限制,而是受使用软件的人的心理限制

◆ 人们认为专注就是要对你关注的东西点头称是,但是事实并非如此。专注其实是要对其他一百个出现的好主意说不——所以你只能小心挑选。实际上,我对我们不做的事与我们做了的事一样感到自豪。创新就是对1000种东西说不。——史蒂夫·乔布斯

◆ 在这份教程中,我将主要关注两个例子:一是解决一份简历存在的设计问题,这是几乎所有人都非常熟悉的设计任务;二是从头开始设计一个网站(具体而言就是本书的配套网站hello-startup.net),其过程有点像典型的创业产品所需要经历的过程

◆ 实际上所有软件设计的真正核心几乎都是文案

◆ 伟大的界面是写出来的。如果你认为每一个像素、每一个图标和每一种字体都很重要,那么你也要相信,每一个字母都很重要。——Jason Fried、David Heinemeier Hansson、Matthew Linderman, Getting Real

◆ 好的艺术家模仿,伟大的艺术家偷窃。——史蒂夫·乔布斯

◆ 如果你不想立马跳到代码中,可以先使用线框图或原型工具,比如Balsamiq、UXPin或者Justinmind。利用这样的工具,可以从UI元素库拖拽出一些元素进行摆放,组合成一份设计

◆ 布局有一个要点就是亲密性,元素之间的亲近程度表明它们在逻辑上是否相关联。逻辑上联系在一起的元素应该更加接近,没有关联的元素则应该远离一些

◆ 作为经验法则,我们要尽量挑选一条明显的线,让所有东西都向它对齐。换句话说,不要把一些内容左对齐,而另一些内容右对齐,有些内容又居中对齐。另外,要谨慎使用居中对齐,因为这种方式在我们的大脑中并没有建立起一条明显的线,会让设计看起来更加业余。这也仅仅是一条经验法则,你当然可以偶尔打破它,但也必须是有意识而为之

◆ 排版就是安排文本的艺术与科学,目的是让文本易读和美观。这一节将关注排版最重要的几个因素:行宽、行距、字体和样式

◆ 行宽是指每一行的长度。如果文本行太短,读者就会太过频繁地被打断而跳到下一行。如果文本行太长,读者就没耐心把它读完

◆ 行距是行与行之间的垂直间距。和行宽一样,如果行距设置得太小或太大,文本的阅读都会比较困难。行距的最佳尺寸一般都是字体尺寸的120%~145%

◆ 总的来看,所有字型都可以分成五类:衬线字型、无衬线字型、装饰性字型、手写型和等宽字型

◆ 。衬线字型作为最古老的字型,不仅可以追溯到使用印刷术的年代,甚至可以一路追溯到古罗马人刻在石头上的字母。所以,如果想要有“传统的”感觉,就可以在标题中使用衬线字型

3.2 MVP

◆ 。执行是昂贵的,所以你需要尽可能低成本、快速地向客户验证你遇到的每一个新问题和想法。最好的方法就是实现所谓的最简可行产品(minimum viable product),或者叫MVP。

◆ [插图]图3-35:如何实现可行的MVP,图片由Henrik Kniberg提供

◆ 我问(我的客户)“如果产品是免费的,有多少人会真的购买或使用”的目的就是把价格因素抛开,看看产品本身是否能够让客户心动。如果做到了,我会接着问几个问题:“好了,这个产品不是免费的。事实上,假设我要收取你们100万美元,你们还会购买吗?”虽然这种对话听起来有点儿像开玩笑,但我一直在用这种方法。为什么呢?因为超过一半的时候,客户会像这样说:“Steve,你怕是疯了吧。这个产品不会值25万美元以上。”其实,我只不过想让客户告诉我,你们愿意支付多少钱而已。——Steve Blank, 《四步创业法》

◆ 在《创新的扩散》一书中,Everett Rogers把客户分成了5种类型。(1)创新者愿意承担新技术的风险,因为技术本身就是他们生活中的主要兴趣,不管功能如何,他们总是留心寻找最新的发明。(2)早期采用者也愿意承担新技术的风险,不仅仅因为他们对技术感兴趣,还因为他们很容易联想到该技术将会给生活带来什么样的好处。(3)早期的大多数客户是迫切需要解决具体问题的。他们能够想象到新技术是怎样成为解决方案的,但又知道许多新的技术革新最终都会失败,所以在自己购买新技术之前,他们更愿意等待,看看该技术是否能解决他人的问题。(4)后期的大多数客户也有需要解决的具体问题,但他们不喜欢使用新技术去解决问题。他们更愿意等到一项技术成熟,自身已经成为标准,并且已经具备了很好的支持体系才会购买。(5)滞后者会尽可能避免使用新技术。他们是最后采纳新发明的人,而且通常都是在别无选择的情况下才会采纳。

◆ Pinterest的创始人会去咖啡店里亲自让陌生人使用他们的产品,也会去Apple的体验商店把所有的浏览器首页都设置为Pinterest

◆ 蒂姆·库克不会在你买了笔记本电脑之后给你寄一张手写的卡片——他做不到,但你可以。这就是小公司的好处:你可以提供大公司实现不了的服务。一旦意识到现有的一些习惯做法并没有超出用户的预期体验,不妨好好想想,我们可以用多少手段去取悦用户,这是很有意思的。——Paul Graham, Y Combinator联合创始人,硅谷创业教父,《黑客与画家》作者

◆ 当你还是一家小型创业公司,仍然还在验证自己的点子时,做一些无法规模化的事情去获得早期的客户是你可以承担的方式。如果点子可行,后续可以通过自动化的方式,让这一过程变得更具扩展性;但如果点子不可行(大多数点子都是这样的结果),那么你也节省了大量的时间,因为你不需要为了错误的事情而做一大堆自动化工作

◆ 另外,这种方式可以让你直接接触业务的烦琐细节,你会成为领域的专家,而这一点在前面已经说过,它对于想出伟大的点子是至关重要的。

3.3 小结

◆ 用户界面就像讲笑话,如果非得解释清楚,就不那么好玩了。——Martin Leblanc, iconfinder创始人

4.1 数据

◆ 产品经理的工作就是要把两件简单的事情说清楚:·我们正在进行什么比赛?·我们怎么得分?把这两件事情做对,就可以不经意间聚集一批在技术、运维、质量、设计和市场推广上具备天赋的杰出人才,在同一个方向上聚力前行。没有这两点,无论做多少优化和执行管理,都拯救不了你。——Adam Nash, Wealthfont主席、CEO

4.2 营销

◆ 以下是创业公司最常见的4种营销渠道:·口口相传;·市场推广;·销售;·品牌化。

◆ 传播产品信息最强大的方法就是不自己去传播,而是让你的客户去传播

◆ 近来许多人都在谈论如何使用“病毒营销策略”,但现实中却没有这样的东西。在所有社交网络上出现的病毒式传播的博客文章或视频并不是一种市场推广策略,而是纯属好运

◆ 病毒式传播不仅仅是另一种形式的口口相传,如果你想突破我们前面讨论的实现途径(做出更好的产品、提供出色的客户服务),更进一步激发人们对你的产品进行口头宣传,需要的不是一种“病毒式的市场推广策略”,而是让产品进入一种病毒式循环。

◆ 同样,Apple最成功的广告之一 ——“不同凡想”(Think Different)并不是在介绍电脑或CPU速度,也不是在介绍Apple为什么比微软更出色,而是在回答“Apple是谁”以及“它代表什么”的问题。

第二部分 技术

◆ 好的技术栈的扩展要快于需要进行的维护。

◆ 谈到技术的作用,WhatsApp团队就是一个很好的例子。该团队基于Erlang搭建了一个技术栈,可以支持每秒7000万条Erlang消息、4500万用户,每天500亿条消息,每年7.2万亿条消息[插图],而完成这一切的团队只有32个工程师

◆ 当然,这里讲WhatsApp的故事并不是说所有人都应该用Erlang。各种成功的创业公司都会基于他们所有可能想得到的技术,去实现他们的产品。这一章会帮助你解决“创业中可以使用什么样的技术栈”这一问题。首先,我会描绘如何选择最初的技术栈,如何随着时间推移使它逐步进化;接着,将把实现内部技术方案、购买商业软件和使用开源软件之间的权衡利弊呈现给大家;最后,我会深入谈谈创业公司最常遇到的3个技术决定的一些细节,即编程语言、服务器端框架和数据库

5.2 技术栈的进化

◆ 当我(离开Google)到了AdMob后,我心中的第一个冲动就是“噢,垃圾垃圾垃圾”。当然我没有说出口,因为作为领导者,学会的更重要的一课就是在开始说之前先闭上嘴巴去听。但是我脑子里想的是:“在Google我们是不会这样做的,在Google我们是不会这样做的,在Google我们是不会这样做的。”这句话在脑海里闪过了好多次之后,我才意识到这并不是在Google,我要解决的是不同的问题,面对的是不同的技术文化——这是很好的事情,真的很好

◆ 我们先从需要在很早就做出的一个决定开始:如何为创业公司选择初始的技术栈?我可以只用一句话来回答:熟悉什么就用什么

◆ 这句话源于我为这本书所做的访谈,我可以告诉你,每一家创业公司选择的只不过是创始团队最精通的技术。LinkedIn是用Java实现的,因为创始团队了解Java; GitHub的创始人全部都是Ruby开发者,所以他们也是用Ruby去实现网站的;Twitter主要用的是Rails,因为他们的早期员工中有许多人熟悉Rails。Foursquare开始时使用PHP,因为这是联合创始人Dennis Growley所了解的;Pinterest使用的是Python,因为创始团队对Python比较熟悉

◆ 学习一门新的技术、享受它承诺的所有理论上的好处可能很好玩,但在创业早期,我们的目标是认识到用户需要什么,其他任何花时间的事情都是浪费。在早期,产品的用户和代码都不多,所以可扩展性并不是太大的挑战,我们要做的就是尽可能快地进行迭代

◆ 如果你的创业公司足以成功地生存到“下一周”,也许你可以让技术栈有所进化,使之满足新的需求。例如,Twitter开始时用的都是Ruby on Rails,但发展起来之后,就不得不迁移到Scala和JVM上;HubSpot从.NET和SQLServer迁移到JVM和MySQL、Hadoop及HBase; Coursera现在从PHP迁移到了Scala; LinkedIn在它的发展历史中已经尝试了十多种技术,包括Java Servlets、Groovy on Rails、JRuby on Sinatra、Java和SpringMVC、JavaScript和Node.js,以及Scala和Play Framework

◆ 最初选择的技术并不是关键,最初的决定在最后看来一定是错的,唯一的问题是它会错多久。关键在于,你要在遇到拐点时有壮士断腕的勇气,而不是为了存活而一层一层地给它贴上创可贴。遵循这样的准则极其重要。从目前来看,这比紧跟潮流、为了做出初始的最佳技术决定而进行无穷无尽的设计分析要更为重要。我们应该做的是,确保把自己和环境锻造成能够适应各种变化,能够知道什么时候是重建的合适时机。——Kevin Scott, LinkedIn高级副总裁、Admob副总裁、Google主管

5.3 内部实现、购买商业产品,还是使用开源产品

◆ 一个残忍的事实是:当你的关键业务过程运行在内部情况不清楚(更别提修改)的不透明代码上时,你就失去了对业务的控制。你对供应商的需要超过了供应商对你的需要——因为这一巨大的不平衡,你只能付钱、付钱、再付钱。——Eric S. Raymond, 《大教堂与集市》

◆ 简而言之,每当使用商业产品时,就是将公司的一部分投注在无法控制的第三方身上

◆ 如果某些技术自己实现起来非常复杂、很容易出错、要花大量时间,但开源和商业领域已经有很好的方案,那么作为创业公司,就永远不要自己去实现这些技术。下面列出了部分这样的技术

◆ ·安全:加密、密码存储、信用卡存储。·Web技术:HTTP服务器、服务器端和客户端框架。·数据系统:数据库、NoSQL存储、缓存、消息队列。·软件分发:版本控制、构建系统、自动化部署。·计算机科学:基本数据结果(映射、列表、集)、排序算法。·处理通用数据格式的库:XML、HTML、CSV、JSON、URLs。·实用库:日期/时间操作、字符串操作、日志记录。·操作系统。·编程语言。

◆ 如果你要从头开始实现上述系统中的任何一个,只能有两个原因:一是以学习为目的的个人项目,二是你的创业公司对其中的某项技术有极其独特的需求

◆ Google就是一个很明显的“非自主发明不可”的栈,它所有的一切都是内部编写出来的。在Google的时候,我想可能除了gcc之外,我没用过任何一种开源工具或库。部分原因是Google领先行业内其他所有公司5年或5年以上。Google所做的东西,就是像MapReduce(使用无数低成本的商业硬件去运行分布式系统)这样的产品,他们基本上都是在发明和普及很多这样的产品。这些产品现在全都成了行业标准,但是大部分在Google之前并不存在。我觉得Goolge就是因为比其他公司超前了许多,所以不得不去实现,这样的境况也许又成为了一种自我增强,因为我们已经形成也适应了非自主发明不可的文化。——Brain Larson, Google和Twitter的软件工程师

◆ [插图]图5-1:内部实现、购买商业产品或使用开源产品

5.4 选择编程语言

◆ 每一种编程语言对于如何解决问题都有不同的哲学。我们可以把编程语言的范式当作是该语言的词汇和语法,决定了你如何说和可以怎么说。目前很少有确切的证据表明某种范式优于其他范式[插图],但某些范式相比其他范式可以更方便地表达一些想法

◆ Ruby支持线程,但它有全局解释器锁(Global Interpreter Lock, GIL),这意味着一次只能执行一个线程。此外,大多数主流的Ruby库执行的是同步I/O,在等待磁盘读取或网络调用返回的时候会阻塞线程。这导致了Ruby并不是处理大量并发的高效语言

◆ 当你选择一门语言时,面对的不仅仅是技术上的权衡取舍,而是一个社区。就像选择一间酒吧一样,没错,你去酒吧是为了品尝美酒,但那还不是最重要的——酒吧更是人们休闲和聊天的地方。这和选择计算机语言的道理是一样的,一门语言随着时间的推移会建立起社区,不仅仅是人,还包括软件方面的产物:工具、库等。这就是为什么有一些语言理论上比其他语言要出色,实际却不如其他语言的原因之一——它们还没有建立起健全的社区。——Joschua Bloch, Sun公司分布式工程师、Google首席Java架构师

◆ 我们可以应用三个过滤条件快速缩短这一列表:适用问题、编程范式和性能需求

◆ 例如,一家做计算机视觉和机器学习系统的创业公司,应该根据适用问题把这份列表限制为三门语言:C++、Java和Python。如果该创业公司更偏爱静态类型,就可以把Python从列表中剔除。最后,如果他们实现的是高性能的实时系统,就不能使用垃圾回收,这样就只剩下了C++

◆ 一家做Web应用程序的创业公司,最有可能觉得Java、JavaScript、PHP、Python、Ruby和Scala最适合解决他们的问题。如果该团队更喜欢动态类型,可能会从清单中去掉Java和Scala。如果他们中有一小部分人已经熟悉Python,并发现几个Django插件可以节省许多时间,Python将成为他们的最佳选择

5.5 选择服务器端框架

◆ 库和框架之间的区别是什么呢?通常的答案就是控制反转:我们把库插入到代码中并调用它们,反之我们把代码插入到框架中并让它们去调用你

◆ 这也称为好莱坞原则:不要给我们打电话,我们会打电话给你

◆ 如果你在开发Web服务,除非你调用socket.accept并编写自己的HTTP解析代码,否则总是应该把代码插入到某种调用你的框架中

◆ 这种框架也许是像Ruby on Rails这样的全栈框架,可以把控制器(controller)插入到处理请求中;或者是更加精简的框架,比如原始的HTTP服务器,可以插入函数去处理HTTP消息。无论哪种情况,你都离不开框架。所以,选择库还是框架通常都不是问题,问题是选择最精简的框架还是选择全栈框架

◆ 全栈框架,比如Ruby on Rails,就是一种为大多数常见任务内置提供了默认解决方案的框架,像路由、数据建模、视图渲染、国际化、配置和测试。最精简的框架,比如Sinatra,只为你提供简单的基本功能——也许只有HTTP路由,再内置一点其他功能,你自己想办法处理各种常见任务

◆ 任何库复杂到一定的程度之后,都会包含一个临时的、不合规范的、充满程序错误的、运行速度很慢的、只有一半功能的全栈Web框架,这是向格林斯潘的编程第十定律致敬。该定律告诉我们,任何C或Fortran程序复杂到一定程度之后,都会包含一个临时开发的、不合规范的、充满程序错误的、运行速度很慢的、只有一半功能的Common Lisp实现

◆ 全栈框架包含所有内置功能只有一个原因:现实中的大部分应用程序都需要它们。即便你现在并不太用得上这些功能,框架中内置这些功能增加的成本也不多,所以因为某种程度上“感觉繁重”就舍弃不用,未免有点目光短浅。当然,并不是每一个内置的解决方案都能满足你的需求,所以要寻找80%~90%的默认方案都能满足要求的框架。一旦它不能满足需要,你可以立马用定制的库去代替

◆ 大多数Web框架都提供了渲染HTML的模板库。当我们评估模板库的时候,主要需考虑内置的视图辅助方法、服务器端与客户端的对比、有逻辑和无逻辑模板的对比。

◆ 许多Web框架,比如Ruby on Rails、Servlets和Django,会为每一个请求分配一个线程(或进程),在等待I/O调用的时候(比如等待数据库或远程Web服务的响应)阻塞该线程。

◆ 如果线程太少,很容易出现所有线程都被占用而处于等待I/O的状态,阻止线程对任何新请求的处理,即便大部分线程仅仅是在空等待;如果线程太多,就会引发额外的内存使用和上下文切换导致的巨大开销。所以,确定合适的线程数量也是很困难的,因为它取决于服务器的负载和下游依赖项的延迟情况,而这一切都是经常处于变化中的

◆ 处理I/O更高效的方式是使用基于非阻塞I/O实现的Web服务端,比如Node.js或者Netty。

◆ 利用这种方式,在等待I/O完成的时候,我们并不是将线程阻塞,而是注册一个回调(或者承诺),该线程就可以继续处理其他请求。当回调被触发时,线程可以将请求唤起,完成对它的处理。因为I/O处理的时间会比其他进程内的处理时间长好几个量级,所以异步处理I/O的方式使我们对服务器资源的利用更加高效。通常来说,非阻塞服务器的每个CPU核心只需要一个线程(或进程),并且对下游的延迟情况也不那么敏感

◆ 和所有性能问题一样,找到答案的唯一方式就是进行性能测试和测量。读者可以查看TechEmpower Web框架基准测试作为入门,或者阅读第7章了解有关性能测量的内容。

◆ 跨站点请求伪造(Cross-Site Request Forgery, CSRF)攻击是指恶意网站让用户在受信任的网站上执行有害的动作。

◆ 例如,假设你访问win-an-ipad.com网站,该网站让你在表单中输入一些数据并提交,这样你就有机会赢得一部iPad。但你不知道的是这个表单实际上被提交到了Amazon,这是一个你信任并且已经登录的网站。如果Amazon没有CSRF保护,攻击者就可以精心制作出符合要求的表单,Amazon会将提交的表单解释为你在购买东西,因为浏览器会将你的Amazon cookies和提交的内容一起发送出去

◆ 为了防范CSRF攻击,Web框架应该具有为每位用户生成短暂的随机令牌的机制,将其存放在cookie中,如果body中的令牌和cookie中的令牌不匹配,则拒绝提交表单。这样在渲染自己网站上的合法表单时,我们就可以轻松地将令牌作为隐藏的表单字段,把它包含在表单中。当攻击者尝试渲染网站上的恶意表单时,他们无法读取你的cookies,也就无法猜测到正确的令牌值

◆ 下面列出了一些截至2015年最流行和成熟的框架,按照编程语言划分并根据首字母进行了排序,内容主要来源于HotFrameworks和我自己的经验。·C#:.NET。·Clojure:Ring、Compojure、Hoplon。·Go:Revel、Gorilla。·Groovy:Grails。·Haskell:Snap、Happstack、Scotty。·Java:Spring、Play Famework、DropWizard、JSF、Struts。·JavaScript:express.js、sails.js、derby.js、geddy.js、koa、kraken.js、meteor。·Perl:Mojolicious、Catalyst、Dancer。·PHP:Laravel、Phalcon、Symfony、CakePHP、Yii、Zend。·Pyhton:Django、Flask。·Ruby:Ruby on Rails、Sinatra。·Scala:Play Framework、Spray。

◆ 应用三个过滤条件,可以快速删减这个列表,即编程语言、适用问题和可扩展性

第6章 整洁的代码

◆ 编程是一种让他人了解你想让电脑做什么的艺术。——Donald Knuth

◆ 作为一名程序员,只有不到50%的工作时间是花在编程任务上的。编程的时间里面,阅读代码和编写代码的时间比大大超过了10∶1,而实际花在编写代码的极少部分的时间中,80%以上的时间又是在维护代码,即修改或修复已有的代码。如果一天工作8小时,能有5分钟花在编写新代码上就已经不错了。结果就是,程序员的工作并不是在编写代码,而是在理解代码。

8.3 构建

◆ 理想状态就是每一次提交都是完全实现了某一个单一目的、大小合理的单元

◆ 开发人员同时完全隔离工作数周或数月,到了最后一分钟又尝试将所有的代码合并到一起。这个过程就是所谓的后期集成,就像我们在本章开头看到的LinkedIn的故事一样,通常都会导致灾难

◆ 更好的方法就是第二种选择所描述的,是持续集成,所有开发人员定期(每天或者每天多次)将代码合并到一起,这一过程可以尽早暴露设计中的问题,避免在错误的方向上走得太远,我们也可以增量式地改进设

9.3 组织设计

◆ [插图]图9-2:不同公司的组织结

9.6 办公室

◆ 分心是专注工作的敌人。对于基本的脑力劳动(比如算法)来说,只要一小点办公室噪声都会产生影响。编程甚至需要更加集中的注意力,你必须把问题加载到大脑中,就像用纸牌搭房子,需要花时间并且耗费大量的脑力,而且一丁点儿干扰都可能把整个屋子弄倒,让你不得不从头开始

◆ [插图]图9-7:这就是不要打断程序员工作的

◆ 研究表明,一名程序员平均要花10~15分钟才能从干扰中恢复过来,重新开始编写代码。一个小时被干扰4次,就足以让你的生产效率下降到零

◆ 这就是为什么搞开发的人为了回答你的问题,眼睛从屏幕离开时会给你一个如此不友善的眼神。因为他们脑子里的纸牌屋已经摇摇欲坠了。仅仅因为存在会被打断的可能性,就会让这些开发人员不敢开始困难的项目。这也是为什么他们喜欢在深夜工作的原因,也是他们几乎不可能在隔间里写出出色软件的原因(除非在深夜)。——Paul Graham, Y Combinator联合创始人,硅谷创业教父,《黑客与画家》作者

◆ 也许你就是这样的人(我知道我曾经就是)。你甚至会对自己长时间的工作感到自豪,认为自己是个英雄。但是更长的时间——每周超过50个小时,并不会提高工作效率。这一切只会增加压力、损害健康、让你犯下粗心的错误,最终情绪沮丧、逃离工作。换句话说,需要英雄事迹就是一种失败的信号,意味着一些事情严重缺乏规划和管理

◆ 不需要英雄的环境好过一个团队都是英雄的环境。——Ernie Miller, Nvisium技术主管

9.8 沟通

◆ 健康的公司文化鼓励员工去分享坏的消息。可以自由、公开讨论其问题的公司也可以快速地解决这些问题,而掩盖问题的公司则会打击员工参与的积极性。所以CEO的做法应当是:营造一种文化,奖励(而非惩罚)人们将问题公开,使得问题得以解决。——Ben Horowitz, 《创业维艰

9.10 小结

◆ 《基业长青》一书对一项6年研究项目的结果进行了概括,该项目致力于研究成功打造一家“有远见的公司”的必要条件——被认为是所在行业中最出色的公司之一。这样的公司历经多年,产品和领导也经受住了考验,对世界产生了持续的影响,比如迪士尼、IBM、波音和通用电气

◆ 《基业长青》中有一个关键发现,就是有远见的公司的领导会关注创立伟大的组织而不是伟大的产品——那样的公司只是“制作钟表的”,而不是“时代的讲述者”。他们最伟大的产物并不是特定的想法或产品,而是公司本身及其代表的东西

10.1 寻找创业公司的工作

◆ 我曾经遇到过一个人,他是一家银行的软件工程师(不是JP摩根或者其他顶级的银行,只是中等的、相对不那么知名的区域银行),在两三年前给我发了电子邮件,说到“我想加入一家创业公司,应该做些什么呢”。我的回答是,出去参加两三次黑客马拉松,花几个星期去做项目。你可以把你的简历水平从B或C变成至少B+或A-,这一点在几个月内就可以做到,然后再去硅谷,申请公司职位就可以了,因为湾区或任何科技中心的机会要比其他城市的机会多得多。他在一年后发邮件给我,告诉我他已经成了Uber早期的工程师,赚到了许多钱,现在的情况好了很多。——Gayle Laakmann McDowell, CareerCup创始人、CEO

◆ 读者不妨访问http://www.hello-startup.net/resources/jobs/网站找找你周边的编码竞赛

◆ 如果想让社区关注你,最好的方法就是为社区做贡献:做演讲、写博客、将代码开源、处理邮件列表、在Stack Overflow上回答问题、在IRC上聊天。只要我参见会议或聚会小组,离开时便可以获得5~10个新的联系人;只要我在会议或聚会小组上做展示,离开时便可以获得几十个新的联系人。读

◆ 如果不能通过人脉找到工作,那么退而求其次,看看能不能让工作找到你。在过去的5年,我已经收到大约1300封电子邮件,这些邮件来自创业公司的创始人、招聘经理和招聘人员。我的收件箱在几乎每个工作日都会收到至少一个工作机会,我不再需要申请工作——而是工作向我申请。

◆ 几乎每一名程序员都可以在恰当的地方创建一个网络身份,从而实现类似的事情。如果想让公司找到你,你的名字应该出现在它们会去的地方

11.2 招聘什么人

◆ 创业的低谷非常之深,几乎没有人可以独自承受这一切。如果有多名创始人,团队精神会使他们以看似违背能量守恒定律的方式凝聚在一起。每个人都认为“我不能让我的朋友失望”,这是人性中最强大的力量之一,在仅有一名创始人的情况下,他将失去这一力量。——Paul Graham, Y Combinator联合创始人,硅谷创业教父,《黑客与画家》作者

◆ 两个创始人通常是通往成功的最好途径。你可以平均分配工作和股权,也没有政治操作的空间。三个创始人也没有问题:只是在职责划分上会更困难一些,但总可以通过投票决定。一旦超过了三人,事情会变得越来越不稳定,做出决定也变得更加困难,职责和股权的分配也更难处理,更有可能出现政治问题和内耗

◆ 开始的时候,我只会聘请全栈的人,因为不想有人说:“这不是我的工作。”在公司最开始的阶段,每个人头上都要顶着好多帽子。只有到了稍后期,我才会去招聘专才。——Julia Grace, Weddinglovely联合创始人、Tindie CTO

◆ 这里有一个重要的提醒:专才的反面并非是通才。不是任何方面的专家并不意味着你就擅长各个方面。真正的通才是那些多面手的人,你把一些新东西放在他们面前,他们就会把它带走并弄清楚它是如何工作的。他们拥有永不满足的好奇心,愿意对所有东西都稍做尝试。但你要是看看他们的简历,就会看到大量行业的经历(例如旅游、医药、社交网络、消费者、部署自动化、编程语言设计)以及职业角色(例如开发人员、技术主管、产品经理、设计师)

◆ 如果你听到一个开发人员说“噢,不,我不是搞前端的”,或者因下一个项目不得不学习新的编程语言时有所畏缩,这样的人可能就不是通才

◆ 真正的通才喜欢学习新东西,不管问题的领域是什么,也不管他们是否已有相关经验

◆ 当你需要调优数据库查询、建立复制或共享表格,也许就是时候去招聘一个专职DBA了;当你需要管理数以千计的服务器、把代码部署到多个数据中心、建立24×7的网站监控,也许就是时候去招募一个专职发布工程师了;当你的网站规模大到经常遭受黑客和垃圾邮件的攻击,也许就是时候招募一支专职安全团队了。但要提防招聘那些只擅长一种技能而别无他长的人。相反,我们需要T型的人,这一点已经在2.1.1节讨论过

◆ 我们并不是要编写更多的代码,而是要编写正确的代码。10倍能力的程序员实际上是10倍能力的决策制定者

◆ 你是想要10个平均水平的科学家还是1个牛顿呢?10个普通的科学家想不出运动定律、引力理论或者微积分原理,但1个牛顿却可以做到。你是想让埃隆·马斯克去运营公司,还是想把钥匙交给10个普通的执行官?10个普通的执行官想不出Paypal、电动汽车、可回收火箭和超级高铁,但1个埃隆·马斯克却可以做到

◆ 超级明星程序员,就像超级明星运动员,是格外稀少的。如果你尝试根据只招聘“摇滚明星”的原则去制订自己的招聘策略,或者更糟的情况是,如果你的公司招摇过市,好像已经是一群“摇滚明星”,你就永远无法发展你的团队

◆ 开发人员在能力上也许会有巨大的差异,但是这一点不能掩盖下面这三个关键的事实:(1)开发人员的表现会根据不同的任务而有所不同;(2)开发人员可以逐步变得更好;(3)大多数软件都是由团队而不是由个人开发的。

◆ 第一个事实意味一个公司中10倍能力的开发人员在另一家公司中可能只是1倍能力甚至0.1倍能力的开发人员。文化、激情和使命才是至关重要的(阅读第9章了解更多信息)。

◆ 只有聪明才智是不够的,也许你和这样的聪明程序员共事过,他可以滔滔不绝地说上几个小时,介绍一种技术与另一种技术相比,在理论上有什么好处,他会花许多时间去撰写设计文档、架构图和UML图,但是从来没有实际给出过任何代码。我们有时候称他们为设计师,有时候又称他们为教授。不管怎么样,创业公司需要的不仅仅是聪明的人,还需要能够把事情做好的人。我们需要的是可以权衡取舍、可以利用不完美的信息做决定、能够理解完成比完美更好的人

◆ 注意,我们要寻找的这种“聪明”和IQ或者漂亮的学历并没有多大关系,更多的是要有清晰的思维和解决问题的能力

◆ 你还要花大量时间和你所招聘的人在一起,在小型创业公司中更是如此。设想你要每天都和这个人一起吃午饭,要他们去评审你的代码,要花时间去了解他们或者从他们身上学习东西,当网站出了问题他们会在凌晨3点打电话给你。虽然你没必要希望招聘到能够变成朋友的人,但你肯定要避免招聘到你无法相处的人

◆ 在许多公司中,这种品格有一个好听的名字:无混蛋规则。这是一条很好的规则,但不是“混蛋”还不够,你真正需要的是找到很好地与你的公司文化相契合的人(阅读第9章,了解有关创业文化的深入讨论)

11.3 寻找出色的人选

◆ 假设你是一个有两名合伙人的团队,想要招聘12名技术人员。你认为完成这一任务要花多少时间?答案是:大约990小时,或者在一整年里每周花大概20小时去招聘。

12.2 学习的技巧

◆ 我已经发现了三种让我的研究时间变得更有效率的方法。第一,设立具体的、可测量的目标。例如,我为2015年设定的目标是阅读30本书(我用Goodreads来记录我的进度)。

◆ 我还有一个目标,就是每年至少学一种主要的新技术,比如一种新的编程语言或数据库,我发现“七周七种”系列图书,比如《七周七语言》[插图]《七周七数据库》[插图]和《七周七并发模型》[插图],都是实现这一目标很好的方法,因为这些书会向你介绍各种各样的技术,还会重点强调不同的编程范式,

— 来自微信读书

s3cmd 常见用法

常见用法

  • 列举所有 Buckets
    $ s3cmd ls
  • 创建 bucket,且 bucket 名称是唯一的,不能重复。
    s3cmd mb s3://my-bucket-name
  • 删除空 bucket
    s3cmd rb s3://my-bucket-name
  • 列举 Bucket 中的内容
    s3cmd ls s3://my-bucket-name
  • 上传 file.txt 到某个 bucket,
    s3cmd put file.txt s3://my-bucket-name/file.txt
  • 上传并将权限设置为所有人可读
    s3cmd put --acl-public file.txt s3://my-bucket-name/file.txt
  • 批量上传文件
    s3cmd put ./* s3://my-bucket-name/
  • 下载文件
    s3cmd get s3://my-bucket-name/file.txt file.txt
  • 批量下载
    s3cmd get s3://my-bucket-name/* ./
  • 删除文件
    s3cmd del s3://my-bucket-name/file.txt
  • 来获得对应的bucket所占用的空间大小
    s3cmd du -H s3://my-bucket-name
  • 设置S3 bucket的Public权限
    s3cmd setacl s3://myexamplebucket.calvium.com/ --acl-public --recursive

临时链接

s3cmd signurl s3://example-bucket/image.jpg 1657457538
  • example-bucket — the name of the bucket that hosts the file,
  • image.jpg — the file you want to share,
  • 1657457538 — link expiry time in the Timestamp format, use the converter to convert time formats.

References

跟着 《Hell Yes! CSS!》和 AI 学 CSS

最近发现 ★ wizard zines 中的这本 《Hell Yes! CSS!》 对于理解 CSS 的核心概念特别有用。结合 DeepSeek 的解释,对于理解 CSS 似乎非常有帮助,因此结合原文核心内容和 DeepSeek 的解释汇集为本文。

《Hell Yes! CSS!》是一本杂志,短短几十页将 CSS 的核心概念用n漫画的形式讲述清楚,是我在看 《Modern CSS with Tailwind Flexible Styling Without the Fuss – Second Edition (beta B3.0) (Noel Rappin)》这本书时推荐的。本文不会带有全部的原文内容,而只会有一些关键的页面,如需查看原文请自行寻找或购买。

Hell Yes! CSS!

Hell Yes CSS (Julia Evans) (Z-Library)-01

P3-TOC

Hell Yes CSS (Julia Evans) (Z-Library)-03

这是《Hell Yes CSS》小册子的目录部分,列出了书中涵盖的主要主题和章节。以下是对每个主题的简要解释:

ATTITUDE(态度)

  1. CSS isn’t easy: CSS 并不容易掌握,尤其是对于初学者来说,理解和应用 CSS 可能需要时间和实践。
  2. CSS isn’t design: CSS 是一种实现设计的工具,但它本身并不等同于设计。设计是关于视觉和用户体验的决策,而 CSS 是实现这些决策的技术手段。
  3. CSS specifications: CSS 规范是由 W3C(万维网联盟)制定的标准文档,定义了 CSS 的各种特性和行为。
  4. backwards compatibility: 向后兼容性指的是新版本的 CSS 特性在旧浏览器中仍然能够正常工作或优雅降级。

BASICS(基础)

  1. selectors: 选择器用于选择 HTML 元素并应用样式。常见的选择器包括元素选择器、类选择器、ID 选择器等。
  2. specificity: 特异性是决定哪个 CSS 规则将应用于元素的规则。特异性较高的规则会覆盖特异性较低的规则。
  3. default stylesheets: 默认样式表是浏览器为 HTML 元素提供的默认样式。不同的浏览器可能有不同的默认样式。
  4. units: CSS 单位用于定义长度、宽度、间距等。常见的单位包括像素(px)、百分比(%)、em、rem 等。

LAYOUT(布局)

  1. inline vs block: 行内元素(inline)和块级元素(block)是 HTML 元素的两种基本显示方式。行内元素不会独占一行,而块级元素会。
  2. the box model: 盒模型是 CSS 布局的基础,每个元素都被视为一个矩形盒子,包括内容、内边距(padding)、边框(border)和外边距(margin)。
  3. padding & margin: 内边距(padding)是内容与边框之间的空间,外边距(margin)是元素与其他元素之间的空间。
  4. borders: 边框是围绕元素内容和内边距的线条,可以设置宽度、样式和颜色。
  5. flexbox basics: Flexbox 是一种用于创建灵活布局的 CSS 模块,特别适合一维布局(行或列)。
  6. CSS grid: areas: CSS 网格布局(Grid)是一种用于创建复杂二维布局的 CSS 模块,网格区域(areas)是网格布局中的一个概念。
  7. centering: 居中是 CSS 布局中的常见需求,可以通过多种方式实现,如使用 Flexbox 或 Grid。
  8. position: absolute: 绝对定位(absolute positioning)允许元素相对于其最近的定位祖先元素进行定位。

GETTING FANCY(高级技巧)

  1. hiding elements: 隐藏元素可以通过多种方式实现,如设置 display: none 或 visibility: hidden。
  2. stacking contexts: 堆叠上下文(stacking context)是 CSS 中用于管理元素层叠顺序的概念。
  3. CSS variables: CSS 变量允许你在样式表中定义可重用的值,并在整个文档中使用。
  4. transitions: 过渡(transitions)允许你在 CSS 属性值变化时创建平滑的动画效果。

MAKING IT WORK(实际应用)

  1. media queries: 媒体查询(media queries)用于根据设备的特性(如屏幕宽度)应用不同的样式,常用于响应式设计。
  2. the CSS inspector: CSS 检查器是浏览器开发者工具的一部分,用于检查和调试网页的 CSS。
  3. testing checklist: 测试清单是一系列步骤或检查点,用于确保 CSS 在不同浏览器和设备上正常工作。

这个目录涵盖了从基础到高级的 CSS 主题,适合不同水平的读者学习和参考。如果你对某个具体主题有疑问或需要更详细的解释,请告诉我!

P6-CSS specifications

Hell Yes CSS (Julia Evans) (Z-Library)-06

这段内容介绍了 CSS 规范(CSS specifications)的基本概念和相关信息。以下是对内容的详细解释:

CSS 规范(CSS Specifications)

  1. CSS 规范的定义:

    • CSS 规范是由 W3C(万维网联盟)制定的标准文档,详细描述了 CSS 的各种特性和行为。
    • 每个 CSS 特性(如 max-width、flexbox、transforms 等)都有其独立的规范文档。
  2. CSS 2:

    • CSS 2 是早期的 CSS 规范版本,发布于 1998 年。它包含了 CSS 的基础特性,如盒模型、选择器、文本样式等。
    • 尽管现在有很多新的 CSS 特性,CSS 2 仍然是学习 CSS 基础的重要参考。
  3. 现代 CSS 规范:

    • 如今,每个 CSS 特性都有独立的规范文档。例如,flexbox、grid、transforms 等都有各自的规范。
    • 你可以在 W3C 的 CSS 规范页面 找到所有这些规范。
  4. 浏览器对规范的实现:

    • 主流浏览器(如 Chrome、Firefox、Safari、Edge)通常会遵循 CSS 规范来实现 CSS 特性。
    • 但有时浏览器可能存在 bug 或未完全实现某些特性,导致行为与规范不一致。
  5. CSS 版本(Levels):

    • CSS 的版本被称为“级别”(Levels),例如 CSS Level 1、CSS Level 2、CSS Level 3 等。
    • 新的 CSS 级别只会添加新特性,而不会改变现有 CSS 代码的行为。这意味着旧代码在新版本中仍然有效。
  6. 新特性的实现:

    • 新的 CSS 特性需要时间才能被浏览器广泛支持。你可以使用 Can I use 网站来查看某个 CSS 特性在不同浏览器版本中的支持情况。

关键术语解释

  1. max-width: 一个 CSS 属性,用于设置元素的最大宽度。如果内容超过这个宽度,元素会自动调整大小以适应。
  2. flexbox: 一种 CSS 布局模块,用于创建灵活的、响应式的布局。
  3. transforms: 一种 CSS 特性,允许你对元素进行旋转、缩放、倾斜等变换。
  4. Can I use: 一个网站,用于检查不同浏览器对 CSS、HTML5 和 JavaScript 特性的支持情况。

这段内容强调了 CSS 规范的重要性,并解释了如何通过规范文档和工具(如 Can I use)来学习和使用 CSS。

P7-backwards compatibility

Hell Yes CSS (Julia Evans) (Z-Library)-07

这段内容讨论了 CSS 的向后兼容性(backwards compatibility),并解释了它对开发者的影响。以下是对内容的详细解释:

向后兼容性(Backwards Compatibility)

  1. 定义:

    • 向后兼容性指的是浏览器能够支持旧的 HTML 和 CSS 代码,即使这些代码是多年前编写的。
    • 例如,1988 年编写的 CSS 代码在现代浏览器中仍然可以正常运行。
  2. 优点:

    • 长期稳定性: 由于浏览器支持旧的代码,开发者可以放心地编写 CSS,而不必担心未来的浏览器更新会破坏现有的样式。
    • 投资价值: 花费时间调试和编写的 CSS 代码在未来仍然有效,这使得学习和使用 CSS 成为一项值得的投资。
  3. 挑战:

    • 奇怪的 CSS 单位: 由于 CSS 需要支持旧的行为,一些 CSS 单位(如 px、em、rem 等)可能看起来很奇怪或难以理解。这些单位的设计考虑了历史兼容性。
    • 复杂性: 为了确保兼容性,CSS 的某些部分可能变得复杂,开发者需要花费更多时间调试和适配。
  4. 标准和实验性特性:

    • 如果开发者使用了非标准的或实验性的 CSS 特性,可能会失去向后兼容性。例如,某些浏览器可能会停止支持实验性特性,导致网站样式失效。
    • 示例:如果 Firefox 停止支持某个实验性特性,依赖该特性的网站可能会“崩溃”。

现代 CSS 开发建议

  1. 不需要支持所有旧浏览器:

    • 开发者不需要确保 CSS 在 1988 年的浏览器中正常工作,只需关注用户实际使用的浏览器即可。
    • 使用工具(如 Can I use)检查目标浏览器的支持情况。
  2. 新特性的优势:

    • 新的 CSS 特性通常更易于使用,并且能够更好地满足现代网页设计的需求。
    • 例如,现代 CSS 特性(如 flexbox、grid、media queries)使得响应式设计(responsive design)变得更加简单。
  3. 用户期望的变化:

    • 自 1988 年以来,用户对网站的期望发生了巨大变化。现代网站需要适应多种设备和屏幕尺寸,而新的 CSS 特性正是为此设计的。

关键术语解释

  1. CSS 单位:

    • CSS 单位用于定义长度、宽度、间距等。常见的单位包括:
      • px(像素):绝对单位。
      • em:相对于父元素的字体大小。
      • rem:相对于根元素(`

        `)的字体大小。

      • %:百分比单位,相对于父元素的尺寸。
  2. 响应式设计(Responsive Design):

    • 一种网页设计方法,使网站能够根据设备的屏幕尺寸自动调整布局和样式。
  3. 实验性特性:

    • 浏览器引入的新特性,可能尚未成为标准。这些特性通常带有浏览器前缀(如 -webkit-、-moz-),并且可能在未来被修改或移除。

这段内容强调了 CSS 向后兼容性的重要性,同时也提醒开发者不必过度关注旧浏览器的支持。现代 CSS 特性更易于使用,并且能够更好地满足现代网页设计的需求。

P8-a few CSS selectors

Hell Yes CSS (Julia Evans) (Z-Library)-08

这段内容介绍了一些常见的 CSS 选择器(CSS Selectors),这些选择器用于选择 HTML 元素并应用样式。以下是对每个选择器的详细解释:


1. .button

  • 作用: 选择所有具有 class="button" 的元素。
  • 示例:
    <a class="button">Click me</a>
    .button { color: red; }

2. div > .button

  • 作用: 选择所有作为 div 元素直接子元素的 .button 元素。
  • 示例:
 ```

3. :checked

  • 作用: 选择所有被选中的复选框(<input type="checkbox">)或单选按钮(<input type="radio">)。
  • 示例:
    <input type="checkbox" id="agree">
    <label for="agree">I agree</label>
    :checked { background-color: yellow; }

4. div

  • 作用: 选择所有 `
    ` 元素。
  • 示例:
This is a div
 ```
 ```css
 div { border: 1px solid black; }
 ```

5. div .button

  • 作用: 选择所有作为 div 元素后代的 .button 元素(不一定是直接子元素)。
  • 示例:
 ```

6. .button, #welcome

  • 作用: 选择所有 .button 元素和 id="welcome" 的元素(逗号表示“或”)。
  • 示例:
    <a class="button">Click me</a>
    <div id="welcome">Welcome!</div>
    .button, #welcome { color: blue; }

7. a:hover

  • 作用: 选择所有鼠标悬停在其上的 <a> 元素。
  • 示例:
    <a href="#">Hover over me</a>
    a:hover { color: green; }

8. #welcome

  • 作用: 选择具有 id="welcome" 的元素。
  • 示例:
    <div id="welcome">Welcome!</div>
    #welcome { font-size: 20px; }

9. div.button

  • 作用: 选择所有具有 class="button" 的 `
    ` 元素。
  • 示例:
    <div class="button">Click me</div>
    div.button { background-color: yellow; }

10. [href^="http"]

  • 作用: 选择所有 href 属性值以 http 开头的 <a> 元素。
  • 示例:
    <a href="http://example.com">External link</a>
    <a href="/about">Internal link</a> <!-- 不匹配 -->
    [href^="http"] { color: purple; }

11. tr:nth-child(odd)

  • 作用: 选择表格中所有奇数行(` ` 元素)。
  • 示例:
Row 1
Row 2
Row 3
 ```
 ```css
 tr:nth-child(odd) { background-color: lightgray; }
 ```

这些选择器是 CSS 中非常常用的工具,能够帮助你精确地选择并样式化 HTML 元素。

P9-specificity

Hell Yes CSS (Julia Evans) (Z-Library)-09

这段内容详细解释了 CSS 特异性(Specificity) 的概念,即当多个 CSS 规则应用于同一个元素时,浏览器如何决定使用哪个规则。以下是对内容的详细解释:


1. 什么是特异性(Specificity)?

  • 当多个 CSS 规则为同一个元素的同一个属性设置不同的值时,浏览器需要决定使用哪个规则。
  • 特异性 是浏览器用来确定哪个规则优先级更高的机制。特异性越高的规则,优先级越高。

2. 特异性的计算规则

  • 特异性是基于选择器的类型和组合来计算的。以下是选择器的优先级(从高到低):
    1. !important: 最高优先级,但应谨慎使用,因为它难以覆盖。
    2. 内联样式(Inline Styles): 直接在 HTML 元素中使用的 style 属性。
    3. ID 选择器(#id): 如 #start-link。
    4. 类选择器(.class)、伪类选择器(:pseudo-class): 如 .button 或 :hover。
    5. 元素选择器(element): 如 div 或 a。

3. 示例解析

  • 示例 1:

    a:visited {
        color: purple;
        font-size: 1.2em;
    }
    #start-link {
        color: orange;
    }
    • 对于 <a id="start-link" href="#"> 元素:
      • color: orange 会被应用,因为 #start-link(ID 选择器)比 a:visited(伪类选择器)具有更高的特异性。
      • font-size: 1.2em 仍然会从 a:visited 规则中应用,因为没有其他规则覆盖它。
  • 示例 2:

    .sidebar .link {
        color: orange;
    }
    #header a {
        color: purple;
    }
    • 对于 <div id="header"><a class="link"> 元素:
      • color: purple 会被应用,因为 #header a(ID + 元素选择器)比 .sidebar .link(类 + 类选择器)具有更高的特异性。

4. !important 的作用

  • !important 是 CSS 中的一种强制优先级机制,它会覆盖其他所有规则。
  • 示例:
    a {
        color: blue !important;
    }
    #start-link {
        color: orange;
    }
    • 即使 #start-link 具有更高的特异性,color: blue 仍然会被应用,因为它使用了 !important。
  • 注意: 过度使用 !important 会导致代码难以维护,应尽量避免。

5. 内联样式的优先级

  • 内联样式(直接在 HTML 元素中使用 style 属性)的优先级高于外部或内部样式表中的规则。
  • 示例:
    <a id="start-link" href="#" style="color: green;">Link</a>
    • 即使有 #start-link { color: orange; },color: green 仍然会被应用,因为内联样式的优先级更高。

6. 总结

  • 特异性 是 CSS 中非常重要的概念,它决定了当多个规则冲突时,哪个规则会被应用。
  • 优先级顺序:!important > 内联样式 > ID 选择器 > 类/伪类选择器 > 元素选择器。
  • 尽量避免使用 !important,以保持代码的可维护性。

P10-default stylesheets

Hell Yes CSS (Julia Evans) (Z-Library)-10

这段内容介绍了 默认样式表(Default Stylesheets) 和 CSS 属性的优先级。以下是对内容的详细解释:


1. 默认样式表(Default Stylesheet)

  • 定义: 每个浏览器都有一个默认样式表(也称为“用户代理样式表”),用于为 HTML 元素提供基本的样式。
  • 作用: 默认样式表确保即使没有自定义 CSS,HTML 元素也能以合理的方式显示。
  • 示例:
    h1 {
        font-size: 2em;
        font-weight: bold;
    }
    • 这是 Firefox 默认样式表中对 `

      ` 元素的定义。


2. 不同浏览器的默认样式

  • 不同浏览器(如 Chrome、Firefox、Safari、Edge)的默认样式表可能有所不同。
  • 常见差异: 按钮(<button>)和表单元素(如 <input>、<select>)的默认样式差异较大。

3. 查看默认样式表

  • 你可以查看浏览器的默认样式表。例如,Firefox 的默认样式表位于:
    resource://gre-resources/
  • 这些文件定义了浏览器如何在没有自定义 CSS 的情况下渲染 HTML 元素。

4. 初始值(Initial Value)

  • 每个 CSS 属性都有一个默认的 初始值,这是在 CSS 规范中定义的。
  • 如果没有样式表(包括默认样式表和自定义样式表)为某个属性设置值,浏览器会使用该属性的初始值。
  • 示例:
    • background-color 的初始值是 transparent(透明)。
    • font-size 的初始值通常是 medium。

5. CSS 属性的优先级

CSS 属性可以通过以下 5 种方式设置,优先级从低到高依次为:

  1. 初始值(Initial Value):

    • 如果没有任何样式表设置属性值,浏览器会使用初始值。
  2. 浏览器的默认样式表(User Agent Stylesheet):

    • 浏览器为 HTML 元素提供的默认样式。
  3. 网站的样式表(Author Stylesheet):

    • 开发者编写的 CSS 文件或 ` ` 标签中的样式。
  4. 用户样式表(User Stylesheet):

    • 用户自定义的样式表(较少见)。
  5. 内联样式(Inline Styles):

    • 直接在 HTML 元素中使用 style 属性设置的样式,优先级最高。

6. 示例

  • HTML:
    <h1 style="color: red;">Hello World</h1>
  • CSS:
    h1 {
        color: blue;
    }
  • 结果: `

    ` 的文字颜色为红色,因为内联样式的优先级高于网站的样式表。


7. 总结

  • 默认样式表确保 HTML 元素在没有自定义 CSS 时也能正常显示。
  • 不同浏览器的默认样式可能有所不同,尤其是按钮和表单元素。
  • CSS 属性的优先级从低到高依次为:初始值 < 默认样式表 < 网站样式表 < 用户样式表 < 内联样式。
  • 了解这些优先级有助于更好地控制网页的样式。

P11-units

Hell Yes CSS (Julia Evans) (Z-Library)-11

这段内容介绍了 CSS 单位(Units),包括绝对单位和相对单位,并解释了它们的用途和区别。以下是对内容的详细解释:


1. CSS 单位的分类

CSS 单位分为两类:

  • 绝对单位(Absolute Units): 固定大小的单位,不随其他因素变化。
  • 相对单位(Relative Units): 相对于其他值(如字体大小或视口大小)的单位,具有灵活性。

2. 绝对单位

  • 常见绝对单位:
    • px(像素)
    • pt(点,1pt = 1/72 英寸)
    • pc(派卡,1pc = 12pt)
    • in(英寸)
    • cm(厘米)
    • mm(毫米)
  • 特点:
    • 绝对单位的大小是固定的,不会随页面缩放或用户设置变化。
    • 示例:font-size: 16px; 表示字体大小为 16 像素。

3. 相对单位

  • 常见相对单位:
    • em: 相对于父元素的字体大小。
    • rem: 相对于根元素(`

      `)的字体大小。

    • vw: 相对于视口宽度的 1%。
    • vh: 相对于视口高度的 1%。
    • %: 相对于父元素的尺寸。
  • 特点:
    • 相对单位具有灵活性,能够根据上下文动态调整大小。

4. rem 单位

  • 定义: rem 是相对于根元素(`

    `)的字体大小的单位。

  • 特点:
    • 1rem 等于根元素的字体大小(通常为 16px,除非显式修改)。
    • rem 是设置字体大小的好单位,因为它在整个文档中保持一致。
  • 示例:
    html {
        font-size: 16px;
    }
    .model {
        width: 20rem; /* 20 * 16px = 320px */
    }

5. em 单位

  • 定义: em 是相对于父元素的字体大小的单位。
  • 特点:
    • 如果父元素的字体大小为 16px,1.5em 就是 24px。
    • em 的值会随着父元素的字体大小变化。
  • 示例:
    .parent {
        font-size: 16px;
    }
    .child {
        font-size: 1.5em; /* 1.5 * 16px = 24px */
    }

6. 的特殊性

  • 在所有单位中相同:
    • 无论使用 px、em、rem 还是其他单位, 的值都是相同的。
    • 示例:margin: 0; 表示外边距为 0。
  • 与 none 的区别:
    • border: 0; 设置边框宽度为 0。
    • border: none; 设置边框样式为无。

7. 绝对单位的实际大小

  • 1 inch = 96px:
    • 在屏幕上,CSS 中的 1 inch 并不等于实际的 1 英寸,1px 也不一定等于屏幕的物理像素。
    • 这与 设备像素比(Device Pixel Ratio) 有关,高分辨率屏幕可能会将 1 个 CSS 像素映射为多个物理像素。

8. rem 和 em 的辅助功能

  • 优势:
    • 使用 rem 和 em 可以使页面更好地适应不同的用户设置。
    • 如果用户增加了浏览器的默认字体大小,使用 rem 和 em 的元素会自动缩放,提升可访问性。
  • 示例:
    .model {
        width: 20rem; /* 根据根元素字体大小动态调整 */
    }

9. 总结

  • 绝对单位(如 px、in)适合需要固定大小的场景。
  • 相对单位(如 rem、em、%)适合需要灵活性和响应式设计的场景。
  • rem 和 em 有助于提升页面的可访问性,特别是在用户调整字体大小时。

P12-inline vs block

Hell Yes CSS (Julia Evans) (Z-Library)-12

这段内容详细解释了 内联元素(Inline Elements) 和 块级元素(Block Elements) 的区别,以及如何使用 display 属性来控制元素的布局行为。以下是对内容的详细解释:


1. 内联元素(Inline Elements)

  • 特点:
    • 默认情况下,内联元素在页面上水平排列。
    • 它们不会独占一行,而是与其他内联元素共享同一行。
    • 内联元素忽略 width 和 height 属性(除非使用 line-height 调整高度)。
  • 常见内联元素:
    • <a>、<span>、<strong>、<i>、<small>、<abbr>、<img>、<q>、<code> 等。
  • 示例:
    <a href="#">Link</a>
    <span>Text</span>
    <img src="image.jpg" alt="Image">

2. 块级元素(Block Elements)

  • 特点:
    • 默认情况下,块级元素在页面上垂直排列,每个元素独占一行。
    • 块级元素可以设置 width 和 height 属性。
  • 常见块级元素:
    • `

      `、`

  • 示例:
Block 1

Block 2

 ```

3. display 属性

  • 作用: display 属性用于控制元素的布局行为,包括:
    1. 元素本身是内联、块级还是其他类型。
    2. 子元素的布局方式(如 flex、grid 等)。
  • 常见值:
    • inline: 元素表现为内联元素。
    • block: 元素表现为块级元素。
    • inline-block: 元素表现为内联元素,但可以设置 width 和 height。
    • flex: 元素表现为弹性盒子容器。
    • grid: 元素表现为网格容器。

4. inline-block 的特殊性

  • 特点:
    • inline-block 使块级元素像内联元素一样水平排列,同时保留块级元素的特性(如可以设置 width 和 height)。
  • 示例:
    .box {
        display: inline-block;
        width: 100px;
        height: 100px;
        background-color: lightblue;
    }
    <div class="box">Box 1</div>
    <div class="box">Box 2</div>

5. 内联元素的例外情况

  • <img> 元素:
    • <img> 是内联元素,但它是一个 替换元素(Replaced Element),可以设置 width 和 height。
  • line-height:
    • 对于其他内联元素,可以通过 line-height 调整高度。

6. 布局的灵活性

  • 如果需要更复杂的布局,可以使用 display: flex 或 display: grid。
  • 示例:
    .container {
        display: flex;
        justify-content: space-between;
    }
    
    <div class="container">
Item 1
Item 2
 </div>
 ```

7. 总结

  • 内联元素 水平排列,适合用于文本或小部件。
  • 块级元素 垂直排列,适合用于布局容器。
  • 使用 display 属性可以灵活控制元素的布局行为,如 inline-block、flex 或 grid。

P13-the box model

Hell Yes CSS (Julia Evans) (Z-Library)-13

这段内容详细解释了 CSS 盒模型(Box Model),包括盒模型的组成部分及其行为。以下是对内容的详细解释:


1. 盒模型的基本概念

  • 定义: 每个 HTML 元素都被视为一个矩形盒子,这个盒子由以下部分组成:
    1. 内容(Content): 元素的实际内容(如文本、图片等)。
    2. 内边距(Padding): 内容与边框之间的空间。
    3. 边框(Border): 围绕内容和内边距的线条。
    4. 外边距(Margin): 盒子与其他元素之间的空间。

2. 盒模型的组成部分

  • 内容(Content):
    • 由 width 和 height 属性定义。
  • 内边距(Padding):
    • 使用 padding 属性设置。
    • 示例:padding: 10px;。
  • 边框(Border):
    • 使用 border 属性设置。
    • 示例:border: 1px solid black;。
  • 外边距(Margin):
    • 使用 margin 属性设置。
    • 示例:margin: 20px;。

3. width 和 height 的行为

  • 默认情况下,width 和 height 只定义内容区域的大小,不包括内边距、边框和外边距。
  • 示例:
    .box {
        width: 100px;
        height: 100px;
        padding: 10px;
        border: 5px solid black;
        margin: 20px;
    }
    • 实际占用的总宽度 = width + padding + border + margin = 100px + 20px + 10px + 40px = 170px。

4. box-sizing: border-box

  • 作用: 将 width 和 height 定义为包括内容、内边距和边框的总大小。
  • 示例:
    .box {
        box-sizing: border-box;
        width: 100px;
        height: 100px;
        padding: 10px;
        border: 5px solid black;
    }
    • 实际内容区域的宽度 = width – padding – border = 100px - 20px - 10px = 70px。
  • 优点: 使用 border-box 可以更直观地控制元素的总大小。

5. 外边距合并(Margin Collapse)

  • 定义: 当两个垂直相邻的元素都有外边距时,它们的外边距会合并为一个外边距(取较大的值)。
  • 示例:
    .box1 {
        margin-bottom: 20px;
    }
    .box2 {
        margin-top: 30px;
    }
    • box1 和 box2 之间的实际外边距为 30px(而不是 50px)。
  • 注意: 外边距合并只发生在垂直方向上,水平方向不会合并。

6. 事件触发的范围

  • 内边距和边框: 点击内边距或边框会触发元素的 onclick 事件。
  • 外边距: 点击外边距不会触发元素的 onclick 事件。

7. 总结

  • 盒模型 是 CSS 布局的基础,理解其组成部分(内容、内边距、边框、外边距)非常重要。
  • 使用 box-sizing: border-box 可以更直观地控制元素的总大小。
  • 外边距合并 是 CSS 中的一个常见现象,特别是在垂直布局中。

P14-padding + margin syntax

Hell Yes CSS (Julia Evans) (Z-Library)-14 这段内容详细介绍了 内边距(Padding) 和 外边距(Margin) 的语法及其区别。以下是对内容的详细解释:


1. 内边距(Padding)的语法

  • 定义: 内边距是内容与边框之间的空间,可以使用 padding 属性设置。

  • 四种设置方式:

    1. 所有边相同:
      padding: 1em;
      • 上下左右的内边距均为 1em。
    2. 垂直和水平:
      padding: 1em 2em;
      • 上下内边距为 1em,左右内边距为 2em。
    3. 上、水平、下:
      padding: 1em 2em 3em;
      • 上内边距为 1em,左右内边距为 2em,下内边距为 3em。
    4. 上、右、下、左:
      padding: 1em 2em 3em 4em;
      • 上内边距为 1em,右内边距为 2em,下内边距为 3em,左内边距为 4em。
  • 记忆技巧:

    • TRBL: 顺序为 Top(上)、Right(右)、Bottom(下)、Left(左)。
    • 顺时针方向: 从顶部开始,顺时针依次设置。

2. 单独设置某一边的内边距

  • 可以使用以下属性单独设置某一边的内边距:
    padding-top: 1em;
    padding-right: 10px;
    padding-bottom: 3em;
    padding-left: 4em;

3. 外边距(Margin)的语法

  • 定义: 外边距是元素与其他元素之间的空间,可以使用 margin 属性设置。
  • 语法与 padding 相同:
    margin: 1em; /* 所有边相同 */
    margin: 1em 2em; /* 垂直和水平 */
    margin: 1em 2em 3em; /* 上、水平、下 */
    margin: 1em 2em 3em 4em; /* 上、右、下、左 */
  • 单独设置某一边的外边距:
    margin-top: 1em;
    margin-right: 10px;
    margin-bottom: 3em;
    margin-left: 4em;

4. 内边距与外边距的区别

  1. 位置:
    • 内边距 在元素内部,背景颜色会覆盖内边距。
    • 外边距 在元素外部,背景颜色不会覆盖外边距。
  2. 点击事件:
    • 点击内边距会触发元素的点击事件,点击外边距不会。
  3. 居中:
    • 可以使用 margin: auto; 实现水平居中,但 padding 不能用于居中。
  4. 负值:
    • 外边距可以为负值(如 margin: -10px;),但内边距不能为负值。

5. 边框宽度(Border Width)的语法

  • 边框宽度的设置顺序与 padding 和 margin 相同:
    border-width: 1em 2em 3em 4em; /* 上、右、下、左 */

6. 总结

  • 内边距 和 外边距 的语法非常相似,都可以通过简写形式或单独属性设置。
  • 内边距在元素内部,外边距在元素外部。
  • 外边距可以用于居中,且支持负值;内边距不支持负值。

P15-borders

Hell Yes CSS (Julia Evans) (Z-Library)-15

这段内容详细介绍了 边框(Border) 及其相关属性,包括边框样式、圆角、阴影和轮廓。以下是对内容的详细解释:


1. 边框的组成部分

  • 定义: 边框由三个部分组成:
    1. 边框宽度(Border Width): 如 2px。
    2. 边框样式(Border Style): 如 solid(实线)。
    3. 边框颜色(Border Color): 如 black(黑色)。
  • 简写语法:
    border: 2px solid black;

    等同于:

    border-width: 2px;
    border-style: solid;
    border-color: black;

2. 边框样式(Border Style)

  • 常见样式:
    • solid: 实线。
    • dotted: 点线。
    • dashed: 虚线。
    • double: 双线。
    • 其他样式:inset(内嵌)、groove(凹槽)等。
  • 示例:
    border-style: dotted;

3. 单独设置某一边的边框

  • 可以使用以下属性单独设置某一边的边框:
    border-bottom: 2px solid black;

    其他属性:

    • border-top
    • border-right
    • border-left

4. 圆角(Border Radius)

  • 定义: border-radius 用于设置元素的圆角。
  • 示例:
    border-radius: 10px; /* 圆角半径为 10px */
    border-radius: 50%; /* 将正方形变为圆形 */
  • 特点:
    • 可以使用百分比或固定值(如 px、em)。
    • 设置为 50% 时,正方形元素会变为圆形。

5. 阴影(Box Shadow)

  • 定义: box-shadow 用于为元素添加阴影。
  • 语法:
    box-shadow: 5px 5px 8px black;
    • 5px: 水平偏移(x 轴)。
    • 5px: 垂直偏移(y 轴)。
    • 8px: 模糊半径(blur radius)。
    • black: 阴影颜色。
  • 示例:
    box-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); /* 带透明度的阴影 */

6. 轮廓(Outline)

  • 定义: outline 类似于边框,但它不会影响元素的尺寸。
  • 特点:
    • 轮廓不占用空间,不会改变布局。
    • 常用于 :hover 或 :focus 状态,提升可访问性。
  • 示例:
    outline: 2px solid blue;
  • 可访问性:
    • 在键盘导航时,轮廓可以帮助用户识别当前聚焦的元素。

7. 总结

  • 边框 由宽度、样式和颜色组成,可以使用简写语法或单独属性设置。
  • 圆角 通过 border-radius 实现,支持百分比和固定值。
  • 阴影 通过 box-shadow 添加,可以设置偏移、模糊半径和颜色。
  • 轮廓 类似于边框,但不影响布局,常用于提升可访问性。

P16-flexbox basics

Hell Yes CSS (Julia Evans) (Z-Library)-16

这段内容介绍了 Flexbox 的基础知识,包括如何使用 display: flex 创建弹性布局,以及常见的 Flexbox 属性。以下是对内容的详细解释:


1. Flexbox 的基本概念

  • 定义: Flexbox 是一种用于创建灵活布局的 CSS 模块,特别适合一维布局(行或列)。
  • 使用方法: 在父元素上设置 display: flex;,其子元素会自动成为弹性项目(flex items)。

2. flex-direction 属性

  • 作用: 定义子元素的排列方向。
  • 默认值: flex-direction: row;(子元素水平排列)。
  • 其他选项:
    • row: 子元素从左到右排列。
    • row-reverse: 子元素从右到左排列。
    • column: 子元素从上到下排列。
    • column-reverse: 子元素从下到上排列。
  • 示例:
    .container {
        display: flex;
        flex-direction: row;
    }

3. flex-wrap 属性

  • 作用: 控制子元素是否换行。
  • 默认值: flex-wrap: nowrap;(子元素不换行,可能会溢出容器)。
  • 其他选项:
    • wrap: 子元素在容器宽度不足时换行。
    • wrap-reverse: 子元素换行,但顺序相反。
  • 示例:
    .container {
        display: flex;
        flex-wrap: wrap;
    }

4. justify-content 属性

  • 作用: 控制子元素在主轴(水平方向)上的对齐方式。
  • 常见值:
    • center: 子元素居中对齐。
    • flex-start: 子元素向主轴起点对齐(默认值)。
    • flex-end: 子元素向主轴终点对齐。
    • space-between: 子元素均匀分布,首尾元素贴边。
    • space-around: 子元素均匀分布,周围留有相等空间。
  • 示例:
    .container {
        display: flex;
        justify-content: center;
    }

5. align-items 属性

  • 作用: 控制子元素在交叉轴(垂直方向)上的对齐方式。
  • 常见值:
    • center: 子元素居中对齐。
    • flex-start: 子元素向交叉轴起点对齐。
    • flex-end: 子元素向交叉轴终点对齐。
    • stretch: 子元素拉伸以填满容器高度(默认值)。
  • 示例:
    .container {
        display: flex;
        align-items: center;
    }

6. 嵌套 Flexbox

  • 特点: 可以在一个 Flexbox 容器中嵌套另一个 Flexbox 容器,以实现更复杂的布局。
  • 示例:
    <div class="container">
        <div class="item">Item 1</div>
        <div class="item">Item 2</div>
        <div class="nested-container">
            <div class="nested-item">Nested Item 1</div>
            <div class="nested-item">Nested Item 2</div>
        </div>
    </div>
    .container {
        display: flex;
    }
    .nested-container {
        display: flex;
    }

7. 总结

  • Flexbox 是一种强大的布局工具,适合创建灵活的、响应式的一维布局。
  • 常用属性包括 flex-direction、flex-wrap、justify-content 和 align-items。
  • 可以通过嵌套 Flexbox 容器实现更复杂的布局。

P17-CSS grid! areas!

Hell Yes CSS (Julia Evans) (Z-Library)-17

这段内容介绍了 CSS Grid 中的一个强大功能:网格区域(Grid Areas)。通过网格区域,你可以以直观的方式定义复杂的布局。以下是对内容的详细解释:


1. CSS Grid 的基本概念

  • 定义: CSS Grid 是一种用于创建二维布局的 CSS 模块,适合复杂的网页布局。
  • 网格区域(Grid Areas): 网格区域允许你为布局中的每个部分命名,并通过名称来放置元素。

2. 使用网格区域的步骤

  • 步骤 1: 编写 HTML 结构

    <div class="grid">
        <div class="top">Header</div>
        <div class="side">Sidebar</div>
        <div class="main">Content</div>
    </div>
  • 步骤 2: 定义网格区域

    .grid {
        display: grid;
        grid-template-columns: 200px 800px; /* 定义两列,宽度分别为 200px 和 800px */
        grid-template-areas:
            "header header"  /* 第一行:header 占据两列 */
            "sidebar content"; /* 第二行:sidebar 和 content 各占一列 */
    }
    • grid-template-areas 通过直观的方式定义布局,类似于绘制布局图。
  • 步骤 3: 为每个元素分配网格区域

    .top {
        grid-area: header; /* 将 .top 元素放置在 header 区域 */
    }
    .side {
        grid-area: sidebar; /* 将 .side 元素放置在 sidebar 区域 */
    }
    .main {
        grid-area: content; /* 将 .main 元素放置在 content 区域 */
    }

3. 布局效果

  • 最终布局:
    ---------------------
    |       Header       |
    ---------------------
    | Sidebar | Content  |
    ---------------------
  • 解释:
    • header 区域占据整个第一行。
    • sidebar 和 content 区域分别占据第二行的两列。

4. 网格区域的优势

  • 直观性: 通过 grid-template-areas,你可以以近乎视觉化的方式定义布局,便于理解和维护。
  • 灵活性: 网格区域可以轻松调整布局结构,只需修改 grid-template-areas 的值即可。

5. 总结

  • CSS Grid 的网格区域功能非常适合创建复杂的二维布局。
  • 通过 grid-template-areas 和 grid-area,你可以直观地定义和分配布局区域。
  • 这种方法使布局代码更易读、更易维护。

P18-centering

Hell Yes CSS (Julia Evans) (Z-Library)-18

这段内容介绍了如何在 CSS 中实现 文本居中 和 块级元素居中,并提供了多种方法。以下是对内容的详细解释:


1. 文本居中

  • 方法: 使用 text-align 属性。
  • 示例:
    h2 {
        text-align: center;
    }
  • 效果: 文本在容器中水平居中。

2. 块级元素水平居中

  • 方法: 使用 margin: auto;。
  • 示例:
    <div class="parent">
        <div class="child"></div>
    </div>
    .child {
        width: 400px;
        margin: auto; /* 水平居中 */
    }
  • 注意: margin: auto; 只能实现水平居中,不能实现垂直居中。

3. 块级元素垂直居中

  • 方法 1: 使用 Grid 布局

    .parent {
        display: grid;
        place-items: center; /* 水平和垂直居中 */
    }
    • 解释: place-items: center; 是 justify-items 和 align-items 的简写,用于在 Grid 容器中居中子元素。
  • 方法 2: 使用 Flexbox 布局

    .parent {
        display: flex;
        justify-content: center; /* 水平居中 */
        align-items: center; /* 垂直居中 */
    }
    • 解释: justify-content 控制主轴(水平方向)的对齐,align-items 控制交叉轴(垂直方向)的对齐。

4. 使用 Flexbox 或 Grid 仅居中一个元素

  • 示例:
    <div class="parent">
        <div class="child">Centered!</div>
    </div>
    .parent {
        display: flex; /* 或 display: grid; */
        justify-content: center;
        align-items: center;
    }
  • 效果: 即使只有一个子元素,也可以使用 Flexbox 或 Grid 轻松实现居中。

5. 总结

  • 文本居中: 使用 text-align: center;。
  • 块级元素水平居中: 使用 margin: auto;。
  • 块级元素垂直居中: 使用 Grid 的 place-items: center; 或 Flexbox 的 justify-content: center; align-items: center;。
  • Flexbox 和 Grid 不仅适用于复杂布局,也适合简单的居中需求。

P19-position:absolute

Hell Yes CSS (Julia Evans) (Z-Library)-19

这段内容详细介绍了 position: absolute 的使用方法及其行为。以下是对内容的详细解释:


1. position: absolute 的基本概念

  • 定义: position: absolute; 用于将元素从文档流中移除,并相对于其 包含块(containing block) 进行定位。
  • 包含块: 包含块是距离该元素最近的、position 不为 static 的祖先元素。如果没有这样的祖先元素,则包含块为 &lt;body&gt;。

2. position: absolute 的使用

  • 示例:
    <div id="parent">
        <div id="square"></div>
    </div>
    #parent {
        position: relative; /* 设置包含块 */
    }
    #square {
        position: absolute;
        top: 1em;
        left: 1em;
    }
  • 解释:
    • #parent 设置了 position: relative;,因此 #square 会相对于 #parent 进行定位。
    • #square 的左上角距离 #parent 的左上角分别为 1em。

3. top、bottom、left、right 属性

  • 作用: 这些属性用于设置绝对定位元素相对于包含块的位置。
  • 示例:
    #square {
        position: absolute;
        top: 50%; /* 距离包含块顶部 50% */
        bottom: 2em; /* 距离包含块底部 2em */
        right: 30px; /* 距离包含块右侧 30px */
        left: -3em; /* 距离包含块左侧 -3em */
    }
  • 注意:
    • 可以使用负值(如 left: -3em;)。
    • 如果同时设置 left 和 right,元素的宽度会根据包含块的宽度自动调整。

4. 绝对定位元素的行为

  • 脱离文档流: 绝对定位元素会从文档流中移除,不会影响其他元素的布局。
  • 父元素是否扩展: 父元素不会扩展以适应绝对定位的子元素。绝对定位元素的位置和大小不会影响父元素的尺寸。

5. 常见问题

  • 宽度计算:
    • 默认情况下,width 不包括边框和内边距。如果设置了 width: 100%;,元素可能会超出包含块的范围。
    • 可以使用 box-sizing: border-box; 来使 width 包括边框和内边距。
  • 包含块的设置:
    • 如果未设置包含块(即所有祖先元素的 position 均为 static),绝对定位元素会相对于 &lt;body&gt; 进行定位。

6. 总结

  • position: absolute 用于将元素从文档流中移除,并相对于包含块进行定位。
  • 包含块是距离该元素最近的、position 不为 static 的祖先元素。
  • 使用 top、bottom、left、right 可以精确控制绝对定位元素的位置。
  • 绝对定位元素不会影响父元素的尺寸。

P20-hiding elememts

Hell Yes CSS (Julia Evans) (Z-Library)-20

这段内容介绍了在 CSS 中隐藏元素的几种方法,并解释了它们的区别。以下是对内容的详细解释:


1. display: none;

  • 作用: 完全隐藏元素,元素不会占据任何空间。
  • 特点:
    • 元素从文档流中移除,其他元素会重新排列以填补空白。
    • 元素不可见,也无法通过点击或屏幕阅读器访问。
  • 示例:
    .hidden {
        display: none;
    }

2. visibility: hidden;

  • 作用: 隐藏元素,但元素仍占据空间。
  • 特点:
    • 元素不可见,但仍会占据布局空间。
    • 元素无法通过点击访问,但对屏幕阅读器可见。
  • 示例:
    .hidden {
        visibility: hidden;
    }

3. opacity: 0;

  • 作用: 使元素完全透明,但仍占据空间。
  • 特点:
    • 元素不可见,但仍会占据布局空间。
    • 元素可以通过点击访问,对屏幕阅读器也可见。
    • 可以与 transition 结合使用,实现淡出效果。
  • 示例:
    .fade-out {
        opacity: 0;
        transition: opacity 1s ease;
    }
    .fade-out:hover {
        opacity: 1;
    }

4. z-index

  • 作用: 控制重叠元素的堆叠顺序。
  • 特点:
    • 仅对定位元素(position 不为 static)有效。
    • 可以与其他隐藏方法结合使用,控制元素的可见性和堆叠顺序。
  • 示例:
    .overlay {
        position: absolute;
        z-index: -1; /* 将元素置于其他元素下方 */
    }

5. 如何选择隐藏方法

  • display: none;:
    • 适用于完全移除元素,且不需要保留空间的情况。
  • visibility: hidden;:
    • 适用于需要保留元素空间的情况。
  • opacity: 0;:
    • 适用于需要实现淡出效果或保留交互性的情况。

6. 总结

  • display: none;: 完全隐藏元素,不占据空间。
  • visibility: hidden;: 隐藏元素,但保留空间。
  • opacity: 0;: 使元素透明,保留空间和交互性。
  • z-index: 控制重叠元素的堆叠顺序。

P21-stacking contexts

Hell Yes CSS (Julia Evans) (Z-Library)-21

这段内容详细介绍了 堆叠上下文(Stacking Contexts) 的概念及其对 z-index 的影响。以下是对内容的详细解释:


1. 堆叠上下文的基本概念

  • 定义: 堆叠上下文是 CSS 中用于管理元素层叠顺序的一种机制。每个堆叠上下文都是一个独立的层叠环境,元素在同一个堆叠上下文中的层叠顺序由 z-index 决定。
  • 类比: 堆叠上下文类似于 Photoshop 中的图层,每个图层(堆叠上下文)内部有自己的层叠顺序。

2. z-index 的作用

  • 作用: z-index 用于控制元素在堆叠上下文中的层叠顺序。
  • 示例:
    .first {
        z-index: 3;
    }
    .second {
        z-index: 0;
    }
    • .first 元素会显示在 .second 元素的上方,因为它的 z-index 值更大。

3. z-index 的限制

  • 问题: 有时即使一个元素的 z-index 值更大,它也可能不会显示在另一个元素的上方。
  • 原因: 元素可能位于不同的堆叠上下文中。z-index 只在同一个堆叠上下文中有效。
  • 示例:
    .parent1 {
        z-index: 0;
    }
    .parent2 {
        z-index: 10;
    }
    .child {
        z-index: 2;
    }
    • 如果 .child 位于 parent1 的堆叠上下文中,而 parent2 位于另一个堆叠上下文中,parent2 的 z-index: 10 会使整个堆叠上下文位于 parent1 的上方,即使 .child 的 z-index 更大。

4. 创建堆叠上下文

  • 方法: 以下属性会创建新的堆叠上下文:
    • position 为 absolute、relative、fixed 或 sticky,并且 z-index 不为 auto。
    • opacity 小于 1。
    • transform、filter、will-change 等属性。
  • 示例:
    #modal {
        z-index: 5;
        position: absolute; /* 创建新的堆叠上下文 */
    }

5. 堆叠上下文的嵌套

  • 默认行为: 元素的子元素会共享其堆叠上下文。
  • 示例:
    <div class="parent">
        <div class="child"></div>
    </div>
    .parent {
        z-index: 1;
        position: relative; /* 创建堆叠上下文 */
    }
    .child {
        z-index: 10;
    }
    • .child 的 z-index 只在 .parent 的堆叠上下文中有效。

6. 总结

  • 堆叠上下文 是 CSS 中管理元素层叠顺序的重要机制。
  • z-index 只在同一个堆叠上下文中有效。
  • 通过 position、opacity、transform 等属性可以创建新的堆叠上下文。
  • 如果 z-index 没有按预期工作,可能是因为元素位于不同的堆叠上下文中。

P22-CSS cariables

Hell Yes CSS (Julia Evans) (Z-Library)-22

这段内容介绍了 CSS 变量(CSS Variables) 的基本用法,包括如何定义、使用和动态修改变量。以下是对内容的详细解释:


1. CSS 变量的定义

  • 语法: 使用 -- 前缀定义变量。
  • 作用域: 变量可以在任何选择器中定义,其作用域为定义它的选择器及其子元素。
  • 示例:
    body {
        --text-color: #f79; /* 定义变量 --text-color */
    }
    #header {
        --text-color: #c50; /* 在 #header 及其子元素中覆盖 --text-color */
    }

2. CSS 变量的使用

  • 语法: 使用 var() 函数引用变量。
  • 示例:
    body {
        color: var(--text-color); /* 使用变量 --text-color */
    }
  • 注意: 变量名必须以 -- 开头。

3. 在 CSS 中进行数学运算

  • 方法: 使用 calc() 函数对变量进行数学运算。
  • 示例:
    #sidebar {
        width: calc(var(--my-var) + 1em); /* 计算宽度 */
    }

4. 通过 JavaScript 动态修改变量

  • 方法: 使用 JavaScript 动态修改 CSS 变量的值。
  • 示例:
    let root = document.documentElement;
    root.style.setProperty('--text-color', 'black'); /* 将 --text-color 修改为黑色 */
  • 效果: 修改后的变量值会立即应用到所有使用该变量的元素。

5. CSS 变量的优势

  • 复用性: 可以在多个地方使用同一个变量,便于统一管理和修改。
  • 动态性: 通过 JavaScript 可以动态修改变量的值,实现实时样式更新。
  • 作用域: 变量的作用域可以限制在特定的选择器及其子元素中,避免全局污染。

6. 总结

  • CSS 变量 通过 -- 前缀定义,使用 var() 函数引用。
  • 可以在 CSS 中使用 calc() 对变量进行数学运算。
  • 通过 JavaScript 可以动态修改变量的值,实现实时样式更新。
  • CSS 变量提高了样式的复用性和灵活性。

P23-transitions

Hell Yes CSS (Julia Evans) (Z-Library)-23

这段内容详细介绍了 CSS 过渡(Transitions) 的基本概念和使用方法。以下是对内容的详细解释:


1. CSS 过渡的基本概念

  • 定义: CSS 过渡用于在元素的样式发生变化时,创建平滑的动画效果。
  • 触发条件: 样式变化可以通过伪类(如 :hover)或 JavaScript 代码触发。

2. 过渡的使用

  • 语法: 使用 transition 属性定义过渡效果。
  • 示例:
    a {
        color: blue;
        transition: all 2s; /* 所有属性变化在 2 秒内完成 */
    }
    a:hover {
        color: red; /* 鼠标悬停时颜色变为红色 */
    }
  • 效果: 当鼠标悬停在链接上时,颜色从蓝色平滑过渡到红色,持续 2 秒。

3. 过渡的三个部分

  • transition 属性 包含三个部分:
    1. 属性: 指定要过渡的 CSS 属性(如 color、width 等)。
    2. 持续时间: 指定过渡的持续时间(如 1s)。
    3. 时间函数: 指定过渡的速度曲线(如 ease)。
  • 示例:
    a {
        transition: color 1s ease; /* 颜色变化在 1 秒内以 ease 速度曲线完成 */
    }

4. 可过渡的属性

  • 可过渡的属性: 大多数数值和颜色属性都可以过渡,例如:
    • font-size
    • rotate
    • width
  • 不可过渡的属性: 一些属性(如 list-style-type)无法过渡。
  • 示例:
    .box {
        width: 100px;
        transition: width 1s ease;
    }
    .box:hover {
        width: 200px; /* 宽度从 100px 过渡到 200px */
    }

5. 过渡的优势

  • 平滑动画: 过渡可以使样式变化更加平滑和自然。
  • 提升用户体验: 通过过渡效果,可以增强用户交互的视觉反馈。

6. 总结

  • CSS 过渡 通过 transition 属性实现,用于在样式变化时创建平滑的动画效果。
  • 过渡包含三个部分:属性、持续时间和时间函数。
  • 大多数数值和颜色属性都可以过渡,但某些属性(如 list-style-type)无法过渡。

P24-media queries

Hell Yes CSS (Julia Evans) (Z-Library)-24

这段内容详细介绍了 媒体查询(Media Queries) 的基本概念和使用方法,以及如何通过媒体查询实现响应式设计。以下是对内容的详细解释:


1. 媒体查询的基本概念

  • 定义: 媒体查询允许你根据设备的特性(如屏幕宽度、设备类型等)应用不同的 CSS 样式。
  • 语法: 使用 @media 规则定义媒体查询。
  • 示例:
    @media print {
        #footer {
            display: none; /* 打印时隐藏页脚 */
        }
    }

2. 基于屏幕宽度的媒体查询

  • max-width: 应用于屏幕宽度小于或等于指定值的情况。
    @media (max-width: 500px) {
        /* 小屏幕样式 */
    }
  • min-width: 应用于屏幕宽度大于或等于指定值的情况。
    @media (min-width: 950px) {
        /* 大屏幕样式 */
    }

3. 设备类型

  • screen: 用于计算机和移动设备的屏幕。
  • print: 用于打印网页时的样式。
  • 其他类型: 还包括 tv、tty、speech、braille 等。

4. 可访问性相关的媒体查询

  • prefers-reduced-motion: 检测用户是否偏好减少动画。
    @media (prefers-reduced-motion: reduce) {
        /* 减少动画的样式 */
    }
  • prefers-color-scheme: 检测用户是否偏好深色模式。
    @media (prefers-color-scheme: dark) {
        /* 深色模式样式 */
    }

5. 组合媒体查询

  • 语法: 可以使用 and 组合多个条件。
  • 示例:
    @media screen and (max-width: 1024px) {
        /* 屏幕宽度小于等于 1024px 时的样式 */
    }

6. Viewport Meta 标签

  • 作用: 确保网页在移动设备上正确显示。
  • 示例:
    <meta name="viewport" content="width=device-width, initial-scale=1">
  • 解释:
    • width=device-width: 使页面的宽度与设备的屏幕宽度一致。
    • initial-scale=1: 设置页面的初始缩放比例为 1。

7. 总结

  • 媒体查询 允许你根据设备的特性应用不同的 CSS 样式,是实现响应式设计的关键工具。
  • 常见的媒体查询包括基于屏幕宽度、设备类型和用户偏好的查询。
  • 使用 viewport meta 标签可以确保网页在移动设备上正确显示。

P25-the CSS inspector

Hell Yes CSS (Julia Evans) (Z-Library)-25

这段内容介绍了 CSS 检查器(CSS Inspector) 的功能及其在调试和开发中的重要性。以下是对内容的详细解释:


1. CSS 检查器的基本概念

  • 定义: CSS 检查器是浏览器开发者工具的一部分,用于检查和调试网页的 CSS。
  • 主要功能:
    • 查看和编辑元素的 CSS 属性。
    • 查看被覆盖的 CSS 属性。
    • 查看计算样式(Computed Styles)。
    • 调试布局(如盒模型、Flexbox、Grid 等)。

2. 如何使用 CSS 检查器

  • 打开方式:
    • 通常可以通过右键点击页面元素并选择“检查”(Inspect)来打开。
    • 不同浏览器可能有不同的快捷键或菜单选项。
  • 示例:
    <button>Click me</button>
    • 右键点击按钮并选择“检查”,可以查看和编辑按钮的 CSS 属性。

3. 查看和编辑 CSS 属性

  • 功能: 在 CSS 检查器中,可以直接编辑元素的 CSS 属性,并实时查看效果。
  • 示例:
    button {
        display: inline-block;
        color: var(--orange);
        border: 1px solid black;
    }
    • 在检查器中,可以修改 color 或 border 属性,并立即看到按钮样式的变化。

4. 查看被覆盖的 CSS 属性

  • 功能: CSS 检查器会显示哪些样式被覆盖,并解释原因(如更高的特异性或 !important)。
  • 示例:
    button {
        color: red; /* 被覆盖 */
    }
    button.special {
        color: blue; /* 实际应用的样式 */
    }
    • 检查器会显示 color: red; 被 color: blue; 覆盖。

5. 查看计算样式(Computed Styles)

  • 功能: 计算样式显示了元素最终应用的所有 CSS 属性值。
  • 示例:
    • 如果某个链接的 font-size 最终计算为 12px,检查器会显示这一结果。

6. 调试布局

  • 盒模型(Box Model):
    • 检查器可以显示元素的内边距(padding)、边框(border)和外边距(margin)。
  • Flexbox 和 Grid:
    • 一些浏览器(如 Firefox)提供了专门的工具来调试 Flexbox 和 Grid 布局。

7. 不同浏览器的工具

  • 浏览器差异: 不同浏览器的 CSS 检查器可能有不同的功能和界面。
    • Firefox: 提供强大的 Flexbox 和 Grid 调试工具。
    • Chrome: 提供详细的盒模型和计算样式查看功能。

8. 总结

  • CSS 检查器 是开发和调试网页样式的强大工具。
  • 主要功能包括查看和编辑 CSS 属性、查看被覆盖的样式、查看计算样式以及调试布局。
  • 不同浏览器的检查器可能有不同的功能和工具。

P27-thanks for reading

Hell Yes CSS (Julia Evans) (Z-Library)-27

这段内容总结了 CSS 学习资源,并感谢了参与制作这本小册子的人员。以下是对内容的详细解释:


1. CSS 学习资源推荐

  • CSS Tricks:
    • 网站: css-tricks.com
    • 特点: 提供数百篇有用的博客文章和指南,例如关于居中和 Flexbox 的指南。
  • Can I use…:
    • 网站: caniuse.com
    • 特点: 提供浏览器对 CSS 特性的支持情况,帮助你了解哪些浏览器版本支持特定的 CSS 功能。
  • Mozilla Developer Network (MDN):
    • 网站: developer.mozilla.org
    • 特点: 提供关于 CSS、JavaScript、HTML 和 HTTP 的详细参考文档。
  • W3C CSS 规范:
    • 网站: w3.org/TR/css
    • 特点: 提供 CSS 规范的官方文档,适合作为参考工具。

2. 感谢参与人员

  • 封面设计: Vladimir Kasikovic
  • 编辑: Dolly Lanuza, Kamal Marhubi
  • 技术审阅: Melody Starling
  • 感谢所有测试读者: 感谢他们的反馈和支持。

3. 总结

  • CSS 是一个庞大的主题,这本小册子只是冰山一角。
  • 推荐了一些高质量的学习资源,帮助你进一步深入学习 CSS。
  • 感谢所有为这本小册子做出贡献的人员。

总结

这本书内容涵盖了 CSS 基础知识、布局技巧、调试工具 和 学习资源,对于了解 CSS 核心知识很有用,部分内容不易理解的,结合 DeepSeek 的解释能够帮助快速理解。

References