作者归档:songtianlun

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: nonevisibility: 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-widthflexboxtransforms 等)都有其独立的规范文档。
  2. CSS 2:

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

    • 如今,每个 CSS 特性都有独立的规范文档。例如,flexboxgridtransforms 等都有各自的规范。
    • 你可以在 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 单位(如 pxemrem 等)可能看起来很奇怪或难以理解。这些单位的设计考虑了历史兼容性。
    • 复杂性: 为了确保兼容性,CSS 的某些部分可能变得复杂,开发者需要花费更多时间调试和适配。
  4. 标准和实验性特性:

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

现代 CSS 开发建议

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

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

    • 新的 CSS 特性通常更易于使用,并且能够更好地满足现代网页设计的需求。
    • 例如,现代 CSS 特性(如 flexboxgridmedia 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): 如 diva

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

6. 的特殊性

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

7. 绝对单位的实际大小

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

8. remem 的辅助功能

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

9. 总结

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

P12-inline vs block

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

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


1. 内联元素(Inline Elements)

  • 特点:
    • 默认情况下,内联元素在页面上水平排列。
    • 它们不会独占一行,而是与其他内联元素共享同一行。
    • 内联元素忽略 widthheight 属性(除非使用 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)

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

      `、`

  • 示例:
Block 1

Block 2

 ```

3. display 属性

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

4. inline-block 的特殊性

  • 特点:
    • inline-block 使块级元素像内联元素一样水平排列,同时保留块级元素的特性(如可以设置 widthheight)。
  • 示例:
    .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),可以设置 widthheight
  • line-height:
    • 对于其他内联元素,可以通过 line-height 调整高度。

6. 布局的灵活性

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

7. 总结

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

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):
    • widthheight 属性定义。
  • 内边距(Padding):
    • 使用 padding 属性设置。
    • 示例:padding: 10px;
  • 边框(Border):
    • 使用 border 属性设置。
    • 示例:border: 1px solid black;
  • 外边距(Margin):
    • 使用 margin 属性设置。
    • 示例:margin: 20px;

3. widthheight 的行为

  • 默认情况下,widthheight 只定义内容区域的大小,不包括内边距、边框和外边距。
  • 示例:
    .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

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

5. 外边距合并(Margin Collapse)

  • 定义: 当两个垂直相邻的元素都有外边距时,它们的外边距会合并为一个外边距(取较大的值)。
  • 示例:
    .box1 {
        margin-bottom: 20px;
    }
    .box2 {
        margin-top: 30px;
    }
    • box1box2 之间的实际外边距为 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)的语法

  • 边框宽度的设置顺序与 paddingmargin 相同:
    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%; /* 将正方形变为圆形 */
  • 特点:
    • 可以使用百分比或固定值(如 pxem)。
    • 设置为 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-directionflex-wrapjustify-contentalign-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 区域占据整个第一行。
    • sidebarcontent 区域分别占据第二行的两列。

4. 网格区域的优势

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

5. 总结

  • CSS Grid 的网格区域功能非常适合创建复杂的二维布局。
  • 通过 grid-template-areasgrid-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-itemsalign-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. topbottomleftright 属性

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

4. 绝对定位元素的行为

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

5. 常见问题

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

6. 总结

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

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 位于另一个堆叠上下文中,parent2z-index: 10 会使整个堆叠上下文位于 parent1 的上方,即使 .childz-index 更大。

4. 创建堆叠上下文

  • 方法: 以下属性会创建新的堆叠上下文:
    • positionabsoluterelativefixedsticky,并且 z-index 不为 auto
    • opacity 小于 1。
    • transformfilterwill-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;
    }
    • .childz-index 只在 .parent 的堆叠上下文中有效。

6. 总结

  • 堆叠上下文 是 CSS 中管理元素层叠顺序的重要机制。
  • z-index 只在同一个堆叠上下文中有效。
  • 通过 positionopacitytransform 等属性可以创建新的堆叠上下文。
  • 如果 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 属性(如 colorwidth 等)。
    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: 用于打印网页时的样式。
  • 其他类型: 还包括 tvttyspeechbraille 等。

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;
    }
    • 在检查器中,可以修改 colorborder 属性,并立即看到按钮样式的变化。

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

《赵玉平说职场智慧》

阅读感悟

职场道路必经之路,通透一些人间的事情。

阅读摘录

《赵玉平说职场智慧》

赵玉平 137个笔记

第一章 好领导要送公明——宋江的团队领导策略

◆ 宋江这个没形象、没背景、没水平的人,凭什么领导了英雄团队?宋江的团队领导策略其实就在他的名字中,宋公明——送、公、明。

送——及时雨不是白叫的

◆ 宋江,绝对是一个会送的领导。你要钱我给你钱,你要机会我给你机会,你要感情我给你感情……而且送得很贴心,比如对李逵,李逵有母亲没父亲,是个缺少父爱的人。所以,宋江对李逵张嘴就骂,举手就打,转过身掏出钱来,你要多少钱我都给你。再如对武松,武松不光没有父爱,也缺少母爱。宋江对武松的管理,就要柔和得多,融合了很多母爱的因素

◆ 送得多、送得贴心,就稳定了团队,凝聚了人心,所以领导会送是很重要的。而且,给钱给物不能瞎给、乱给,升米恩,斗米仇,你必须要给得有策略、有道理

◆ 宋江有儒家思想。你看《水浒》里边有儒、道、佛各家的代表人物,像鲁智深是佛家,公孙胜是道家,宋江则是儒家

◆ 儒家有一个说法:要是遇到可怜人,能帮人家就帮人家;要帮不了人家,就快步从人家眼前通过,不要在人家面前嘚瑟、招摇

◆ 武松的性格就是心高气傲,瞧不起别人,平时闹别扭,喝点酒就和别人起冲突。武松眼前的处境和他自己的行为有着直接关系

◆ 在现代团队管理中,我们认为,一个团队成员应该有两种行为:第一种,关系行为,就是处理人和人之间的关系,搭建人脉平台,构造满意度和和谐氛围;第二种,任务行为,就是完成工作指标。很多没经验的人可能就把精力都用到关系行为上面,或者都用到任务行为上面。精力用到一个方面是不对的,必须两条腿走路,平衡前进

◆ 武松就是片面的人,他觉得,只要我有本事,只要我把工作完成了,只要我能力上去了,我怕什么?我才不理你们呢。所以武松跟其他人的关系处得非常不好。再加上武松脾气大,比较骄傲,喝点酒,张嘴就骂,抡拳就打。整个公司除了董事长柴大官人之外,剩下的副总以下他都打过,报销个差旅费也能把财务科打一遍。所以说,武松就属于能力很强、人际关系特差的人

◆ 人际关系差,就产生了巨大问题,下面的人总到柴大官人那儿汇报说,武松这个人有问题。有本事还得有名声,名声没了,本事就被埋没了

◆ 在团队当中,特别是有本事的人,要很融洽地处理好与周围人的关系。企业的“企”字怎么写?上面一个“人”,下面一个“止”,这叫无人则止。把人脉关系搞垮了,事业就要停顿了。

◆ 武松就是这样有本事但是不会处理关系的人,结果呢?汇报的人多了,柴大官人就对武松有意见了。这一下,职位不给了,工资不发了,奖金扣除了,连医药费都不报了,所以武松发烧只能烤火,饿着肚子。这一方面体现了,武松这个人,没处理好关系行为;另一方面,也体现了柴大官人这个领导,对下面有本事的人关心不够啊。

◆ 宋江的做法值得称道,这叫“把名给在明处,把利给在暗处,当众给面子,背后给红包”。为什么给好处、给实惠的时候要悄悄地?因为宋江很深刻地理解一个道理:看重名的人想要过好日子,他的排场、他的花费,要比一般人大。但是和这些人能直接谈钱吗?不能,一提钱,脸面就没了。所以这些人的苦恼在于既离不开钱,又不能谈钱。宋江高明啊,把形象和面子给在明处,把实惠和利益给在暗处。当众发一张大奖状,给朵大红花,大家热烈鼓掌,宣扬他的事迹,给一个好待遇,安排一个好职务;散了会之后,私下里没人的地方,悄悄给一个大口袋,口袋里装的全是金子。给完之后,转身就走了。这是宋江的贴心之处。很多领导舍得给,但是不会贴着心给。而宋江的做法让武松心里特感动

◆ 在心理学层面有一句话叫,日常交往拉近距离,关键事件深化感情

◆ 现代心理学有个分支,叫人际关系心理学,其中有一个特别棒的理论:要跟一个人拉拢感情,拉近心理距离,最有效、最简单的方法是什么呢?就是请对方吃饭。吃饭能交流感情,吃饭能造就亲密的氛围。我们一般都跟家里人吃饭,所以一起吃饭,能造就认同感,形成家里人的感觉

◆ 什么叫感情?所谓有感情,就是有回忆呀。感情可以消失,只要你忍住不去回忆,感情就会消失;感情可以创造,只要你跟一个人一起,做很多值得回忆的事情,终究有一天,他会对你产生感情。所以你要对一个人积累感情,就一定得跟他做很多值得回忆的美好的事情。你要激发一个人的感情,怎么办呢?就跟他一起回忆美好的过去,回忆得越多,这人对你的感情就越深

◆ 在这个高明的策略中,有四点可以借鉴:第一,根据对方的需求,打造差异化的激励方案;第二,日常工作拉近距离,关键事件升华感情;第三,先制造回忆,后产生感情,有了感情以后再做大事;第四,精神的内容要有物质的载体

公——大公无私才能成就大公司

◆ 什么叫公?公的第一层含义就是在做公事的时候,能够把情绪放在一边,不管有多么不良的情绪,一旦面对工作,都能把情绪调整过来,能用工作态度、工作眼光对待人和事

◆ 人至少要有三个频道:有一个工作频道,正襟危坐、慷慨激昂;有一个娱乐频道,开开心心、又蹦又跳、活力四射;还有一个体育频道,认真锻炼、生龙活虎。不同的频道得用不同的情绪,人家宋江就是有不同频道的人。

◆ 很多团队领导没这个频道,家里的烦恼带到公司去,公司的烦恼带到家里来。公司里有事朝家里发火,家里有事朝公司发火。一天到晚,主要的工作状态就俩字——“串台”。这是不对的。领导的工作千头万绪,接触那么多的人,得学会转频道。一个人有若干个格子,这件事装在这个格子里,那件事装在那个格子里,绝不干扰别的格子

◆ 在宋江的团队当中,基本上都是黑社会分子,很多人都像张横一样,曾经威胁过他的性命,而且差一点就要了他的命。比如“矮脚虎”王英,那王英当初在清风山上,就差一点要了宋江的命,宋江却积极给他找媳妇。这些事情宋江居然都可以放下,把私人恩怨搁在一边

◆ 刘邦平定天下以后,下属都急着要待遇,不给就要谋反。但刘邦又没时间各个都给。事实上,很多领导面临这一情况,金山银山在这儿搁着,时间紧、任务重,大家都闹着要,你又不可能都给。当领导不能“天女散花”,得作考核算指标,这需要时间啊。但员工急,等不起。如何让又哭又闹的孩子等着排队,不抢眼前的饭,这是团队领导的高明之处

◆ 这个策略叫给待遇由远及近。你还就得先给那些跟你有过节的、闹过对立的、跟你拍过桌子瞪过眼睛的、平时不服气的人。你给这样的人一个公公正正的待遇,可以让整个团队稳定,这叫稳定的力量、凝聚的力量。刘邦跟张良的交往当中,张良有定汉四策。这四策当中,封雍齿排在第一位。古书上讲这叫“封一人而安天下”。

◆ 所以,“公”的含义也就是:给感情立个频道,学会用公心对待私人恩怨。给待遇设个顺序,能够由远及近,先给不顺眼的人公正待遇。你能做到这些,那就是“公”了。

明——看到大节,也看到小处

◆ “大树将军”因此成为典故,形容有才华、有水平、有贡献,但是不爱过度炫耀的人

◆ “老黄牛”要是挨饿了,就没人愿意再当“老黄牛”了;英雄要是死了,就没人愿意再当英雄了。所以,要让“老黄牛”披红戴花、有草有料,要让英雄不死,只有这样,才能有更多的人去做基础工作。

◆ 这就是为什么伯乐不常有:当伯乐不快乐,当伯乐没待遇。当完伯乐之后,千里马闪光了,我自己连饭都没得吃了,那我当伯乐干什么?

◆ 这叫不要让发现和培养人才的人被冷落。于是,齐国人就发现了,虽然我们自己没本事,但没关系,我们发现培养一个人才照样可以过好日子。于是,齐国伯乐辈出;于是,千里马辈出。

◆ 在团队管理中,建议大家:第一,别让默默无闻在一线的人受冷落;第二,别让发现和培养人才的人受冷落。做到这两点了,你的团队才能够有足够的后劲。

◆ 我们说,没有人干不成事,但人一扎堆,没干事,先出事,所以不能让人闲下来

◆ 人没事做,感觉被冷落,就要闹事;感觉有闲心,就要捣乱

◆ 老员工没事做,身体会垮掉;年轻人没事做,不长本事

◆ 人就像一辆自行车,天天骑没事,要是扔在楼下两个月,准垮

◆ 现代团队管理管这叫“人人有事做,处处忙起来”。没什么事做怎么办?先找点正事,学习培训、技能提升都行

◆ 企业可以有闲事,但不能有闲人,你得让大家都忙起来

◆ 这个策略叫“不断搅动锅里的水,让所有员工总在运动当中”。中国古人讲“流水不腐,户枢不蠹”。运动是进步的基础,停顿了就麻烦了

◆ 生命在于运动,管理在于折腾

第二章 给你一个干的理由——宋江的精神激励策略

◆ 干工作,没有物质是不行的,只有物质是不够的

◆ 带领团队谨记“要做一个会树大旗的领导”。

◆ 人为什么会工作?工作的驱动力在哪儿?结论很简单,人做工作、干事业,驱动力有两个:利益驱动和价值承诺。

屁股决定脑袋的理论根源

◆ 《聊斋志异》里的书生代表中国男人,特别是知识分子,在恋爱过程中的六大劣根——分别是“胆小、怕事、吃软饭、花心、好色、不负责”。

◆ 问:为什么狐狸精那么喜欢书生?答:因为写书的人是个书生

◆ 要是杀猪的写《聊斋志异》,狐狸精一定喜欢杀猪的;打铁的写《聊斋志异》,狐狸精一定喜欢打铁的;你要写《聊斋志异》,那狐狸精肯定喜欢你这个类型的;我要写《聊斋志异》,狐狸精肯定喜欢上了《百家讲坛》、身高1.8米以上,尤其是正在研究《水浒》的博士。这叫利益点决定观点,通俗化地讲,就是屁股决定脑袋。这人哪,屁股坐在哪个利益点上,脑袋中就会自然有哪种想法。这是不受主观意志控制的。

◆ 所以看人先看利益点,看完利益点,他即使不说话,也能知道他是怎么想的

◆ 要改变一个人,先改变他的利益点,只要利益点变了,观点自然就会变

◆ 要了解人,先要了解他的利益点,观点是会撒谎的,但利益点不会,一看就准

◆ 利益是一个人在团队中,做工作、表达观点主张时最主要的驱动力

◆ 我们带小团队要看个人利益,带大团队要看分利集团

◆ 《水浒》的基本团队模式就是共享财富,即“大秤分金,小秤分银;大碗喝酒,小碗吃肉”

◆ 所以一个公司在制定战略的过程中,一定要加上这一条:“关注一线。”假如不包含这一条,你的战略就是一纸空文

◆ 为什么有本事、够忠诚、有能力的人不出业绩?我认为主要原因是他对公司没有认同感

◆ 人的积极性从哪儿来?第一,在工作中有个人利益、有实惠;第二,让他觉得有价值、能认同

愿景规划——另类的激励

◆ 当团队领导的,得让他们看到砖和烂泥背后壮丽的大厦。

◆ 你有资源。还要拿到开采证或者正好有一个团队,他们要开采。这就是资源加机遇,保证你赚第一桶金。从第二桶金到第五桶金靠坚固的社会平台、稳定的人脉关系。从第五桶金到第十桶金靠有效的内部管理

◆ 题。第十桶金以后靠文化建设

◆ 普通员工有实惠了,那么他就因自己已经拿得很多了,出于良心、出于回报、出于情感,会帮忙盯着。高层的人因为有理想了,他会出于责任、价值观、个人主动性而帮你盯着

◆ 管理中有一句话,“一个人的问题是个人问题,几个人的问题是领导问题,一群人的问题是制度问题”。

◆ 实在的领导做小事,高明的领导做大事

◆ 光实在不行,把实在的问题展示了,把眼前实惠讲完了,只能调动低层次的人,不是思想水平低,而是生活层次低的人

◆ 高明的领导,在实在的基础上,还得设计一个远大的理想

◆ 工作如同建设一栋大厦,一到十楼叫实惠,十楼以上那叫境界。如果没有实惠,上来就讲境界,讲理想,那是空中楼阁。但是一直在讲一到十楼的事,没有更高的境界,只能是低矮的楼房

第三章 找对人才能做对事——领导必备的小班底

◆ 和,即条件相容,和平共处。同,即结论一致,观点一致

◆ 高水平的人,追求条件相容,和平共处,不强求观点一致,结论一致;低水平的人不考虑条件、对象和场景,非得强求结论一致,观点一致,结果会引发更多的矛盾冲突

◆ 宋江在给英雄排位的时候,实际上搭了两个班子:一个小班子,一个大班子

做不好人事就做不了大事

◆ 一个领导在带队伍、做工作、做事业的时候,一定既要有大班子,又要有小班子。大班子管工作,小班子管生活;大班子管战略,小班子管事务

◆ 所以,不谋心、不利私、不越权,这样的人去给我们当替身是最合适的

◆ 领导用贴身助手,就得用背景简单、资历比较浅的年轻人

◆ 所以领导用助手,要用资历浅、背景简单的年轻人,又安全又好用,过两年就提拔他,提拔起来之后再用一个,这是正确的方法

◆ 二把手给一把手管事务,一把手安排自己的人给二把手管事务,再找个年轻、没背景的人给自己管事务,这就是梁山在班子搭建上的智慧,这智慧很值得玩味呀。

◆ 宋江在选择替心、替口、替身、替手、替脸这五种角色上,颇费心思,但收获颇丰。其中,替心、替口这两种人最重要,也最难找。

摇扇子的做领导不会做的事

◆ 聪明的人只是聪明,高明的人会使用自己的聪明

◆ 聪明人会做傻事,这叫智慧。努力的人会慢半拍,这叫高明。聪明容易,高明难

◆ 在现代团队管理中,做事业就像开车,你会踩油门,那是力量,你会踩刹车,那叫智慧

◆ 孔子的学生里,道德风范最高的是颜回,最有勇气的是子路,最聪明的要属子贡。

◆ 垂头丧气的人和得意扬扬的人,都有问题。中医讲,草木得天地之偏气而茂盛,人得天地之和气而茂盛。得正气人才能不卑不亢,喜气洋洋,一团和气,而且,才能守得住富贵

◆ 主张一种东西,但是,完全不按这种主张去做,这种人就不是什么好人,而且早晚得给自己惹祸

◆ 在团队管理中,有些事情我们做不到,可以不主张,但主张了就一定得做到,怕就怕自己主张自己做不到,还让别人去做,这种人在领导岗位上早晚得出问题。

◆ 这就叫“主张一套,自己做的是另一套”,这样的领导都会出事

◆ 一般来说,聪明人最大的优点是聪明,最大的缺点是太聪明

◆ 聪明人有三道难关:第一道叫认同关;第二道叫感情关;第三道叫安全关。这三道关都过了,你才能活下来。笨人只需要过感情关,跟人家成为好朋友就可以了,聪明人却要过三关。所以看看我们周围,笨人活下来的可能性大,聪明人活下来的可能性小

◆ 真正聪明的人,真正有水平的人,面临一个共同问题就是,做事情在哪个节骨眼上入手,最能得到认可

◆ 我们生活在一个认可的年代,不让员工认可你得“死”,不让领导认可你得“死”,不让客户认可你得“死”。所以获得认可非常重要

◆ 从古到今的所有厉害的人,都要过认可关,再有本事,没人认可也是白搭,会委屈死的。

◆ 。《论语》中也说过:“不愤不启,不悱不发。”即你不着急我不给你提意见,我提了意见,你不认可,你的评价就比较低。我非得等你着急了,才给你提意见,而且我的意见特别到位,一句话就把你的火给扑灭了,那你就认可我了。

◆ 这叫你不疼,我不给你下药;你不苦,我不给你下糖;你不发烧,我不给你退烧,你没烧,我给你吃两片退烧药,你还说我害你呢。所以,吴用就等着关键时刻

◆ 关于掌握工作节奏,给大家引述另外一个反面例子,他俩一对照,你就知道工作节奏的重要性。这个反面例子也是四大名著里的名人,就是《西游记》里的孙悟空

◆ 关于工作节奏,总结两句话:第一句,积极但不能着急。

◆ 第二句,被动而不主动。

◆ 你再有本事,你也是个下属,中国古人有一句话叫“干活不由东,累死也无功”。

◆ 聪明人的第二道难关是感情关

◆ 举个例子,我们雇了一个财务经理,如果是自己人,水平越高,我们越放心;如果是个外人,水平越高,我们越不放心。这叫感情引路,聪明跟进

◆ 聪明人的第三道难关是安全关。

◆ 聪明的人不跟公司的上级领导们谈领导艺术,你谈完了,他们就该担心你的谋略那么多,万一跟他们玩心眼,怎么办?

◆ 其实吴用是在偷偷地帮宋江,但是吴用不把这事说明了,他从来没有让宋江感觉过他知道宋江愿意当一把手,这就叫装傻

◆ 聪明人能做傻事,聪明人能躲在暗处,聪明人做事能慢半拍,这叫智慧。

抡板斧的做领导不能做的事

◆ 一个领导,身边最好有两个人,一个是出主意的,我们叫摇扇子的人;另一个是帮你出头,拍桌子,瞪眼睛的,叫抡板斧的人

◆ 作为一把手争得太急、说得太绝,又会伤害自己的面子和尊严。这时你身边就得准备一个李逵这样的人,让他站出来替你说,帮你争

◆ 这种人应该有三个特点:第一,是鲁,敢发脾气,拍桌子,能使用差异化的手段震慑对手。第二,是忠,一心干事业,一心对领导,怎么骂,怎么打,都不留阴影,他能理解领导。第三,是直,竹筒倒豆子,装什么子弹开什么枪,让怎么说就怎么说。

◆ 吴用好找,李逵不好找,管理学就是这样,团队当中每个岗位都有合适的人,每个岗位都有合适的事。你看这人鲁莽,用好了就是优点。没有不合适的人,只有不匹配的工作,人在匹配的岗位上工作就会很合适。

晁盖的第一桶“人”

◆ 所以建团队,第一条,也是最根本的一条,叫作彼此的信任

◆ 信任成本是团队的最大成本,很多事情本来可以低成本、高效率地完成。为什么完不成?没有信任

◆ 我们现在往往用契约和法律手段来建立信任,但是契约和法律有漏洞,必须还有更深入的东西来弥补信任

◆ 古人有一句话叫“树怕扒皮,人怕见面”。见重要的人谈大事,怎么能发条微信,聊个QQ呢?那叫儿戏。你得亲自去,在正式场合寒暄几句,然后整整衣服,坐下再说

◆ 当天想到的事情得当天去做。在现代管理学中,这叫日落法则,即今天想到的事情,在太阳落山之前得开始行动

◆ 这叫认同公司、认同事业、认同领导、认同任务,只有这四个认同都做到了,此人才能参与我们的工作。

◆ 所以,要上梁山:第一,你喜欢梁山这个公司吗?第二,你喜欢落草当黑社会这份事业吗?第三,你喜欢梁山首领宋江吗?第四,宋头领让你下山抢劫,你去吗?只有这四条都点头了,你才算是我们的人。

◆ 吴用就要考核三阮这四个问题,但是,谈的是风险任务,又不能直接考核,所以,吴用使用了旁敲侧击法。这种方法,我们在选重大人事岗位时可以用,在非正式场合使用闲聊的手段旁敲侧击,问问他这四条行不行

宋江的用人“妙招”

◆ 在重大的商务谈判之前,千万不要接受人家的礼物、吃人家的饭,否则你心里就解除武装了,就已经投降了。等你再说话的时候,你的谈判能力、你的原则立场,都会不自觉地发生变化

◆ 对有才华、有水平的年轻人才,可以给权力,给重担,但是级别一定要逐级提升。

亲贤治小,胜过“高人”的管理之道

◆ 多样化团队中,既要有君子,也要有小人;既要有神,也要有鬼。你看庙里,菩萨、佛祖慈悲为怀,普度众生,慈眉善目。但是庙门口的护法面目非常凶。

◆ 第三步,换副笑脸劝住他。最后还得用温暖的手段解决,不能激化矛盾,不能真动手打,但你要不镇他、不吓他,他不服气。你要是上来就赔个笑脸,他觉得你软弱可欺,就可能抡圆了给你一嘴巴。不能做软弱可欺的人,实力还是很重要的

◆ 这叫君子做不了小人的事,高人做不了低事。管得住一个国、一个省,不见得能管得住一个村。小人的事由谁来做?由车老板来做,正合适

◆ 当领导的得记住,你虽有很多文明手段,但不能没有野蛮手段。当你遇到野蛮人,用文明手段解决不了,得靠别的手段。你碰见狗,狗冲你叫,你不能冲狗叫。你的员工抬手给你一个嘴巴,你还不能还手,挨打不还手,丢人,还手更丢人。这时候怎么办?很简单,我们身边养条藏獒,就能管住天下的狗。怕挨打,我们身边带一个大汉,谁打你他挡着。宋江为什么走到哪儿,都带着李逵?在黑社会下基层,身边要带一更黑的,这叫震慑力。

◆ 所以,小人不好管,你得管着;小人不顺眼,你得忍住;小人不爱干,你得把他激励起来

◆ 做大事,能用君子叫人品,会用小人叫水平。我们要做既有人品,又有水平的领导,才能把天下大事摆平

◆ 小人虽然有他的用处,但对小人必须小心。让小人办事,小人就可能会提许多无理的要求。你若是满足,他会贪得无厌;你若是不满足,就会招小人忌恨。怎么办?该满足的就满足,不该满足的就委婉拒绝。拒绝的技巧是特别重要的

◆ 在团队冲突当中,大量的冲突原因都是人家向你提要求,你拒绝,而且拒绝得太直接、太生硬。

◆ 其一,龙颜无恩。真正做大事的领导只记你的坏处,不记你的好处,不管有多大的贡献,只要你敢违反纪律,都会动狠手杀你。不要以为人家会念旧情,要看眼前,看表现。其二,小人可怕。宁得罪君子,不得罪小人。君子相斗狠在当前,小人相斗狠在背后。小人要是恨上你,他眼前笑呵呵的,但是,过二三十年,再给你下狠招儿,这叫不怕贼偷,就怕贼惦记。其三,领导身边的人不能得罪。一个看大门的,你把他得罪了,说不定啥时候,他告你一状,你的人生和事业就崩溃了。所以,领导身边的人要敬而远之。不能给他好处,也别跟他有冲突,离远点比较好

◆ 夷射,不是死在龙颜无恩上,不是死在小人可怕上,也不是死在领导身边的人不好应付上,而是死在他自己没有拒绝的技巧上

◆ 他只会用简单粗暴的方法拒绝别人,那一定会出事的。人家跟你要酒,你不愿意给,有很多方法拒绝

◆ 第一,可以无限期拖延。“这个酒现在不能给你,人多眼杂,等将来有机会我一定给你”,什么时候有机会,不知道。第二,找个东西替代。“这个酒不能给你,没关系,赵老师那儿有酒,他又不喝酒,你去朝他要。”第三,设个条件来转移。“我现在不能给你,明天早上你过来,我再给你。”第二天早上跟秘书说:“那人来朝我要酒,就说我不在啊。

◆ 现在的人际沟通理论,给了我们拒绝的六个字口诀,适用于各种人际冲突。这六个字是:承认,苦衷,出路

◆ 承认,就是我不能给你东西,但我要承认你的要求是正当的,承认咱俩的关系是亲密的,承认你是有贡献、需要关照的。承认之后讲苦衷,说我愿意给你,但是,我不能给你,原因是……最重要的是出路,拒绝别人,不给别人指明出路,你的拒绝只能打一半分,必须指明出路

◆ 现代行为学给了我们一个基本框架,当我们跟一个人发生冲突的时候,应当使用以下几个手段:竞争,又叫直接拒绝,毫不犹豫,斩钉截铁,只关注自己,不关注他人。妥协,又叫答应,没有任何条件,无条件答应,只关注对方,不关注自己。回避,“这事现在说不清,咱别说了,过些日子再说”

取长补短,善待有缺点的人

◆ 一个团队要解散时,男人眼泪汪汪,女生稀里哗啦,都掉眼泪。但是原因不一样,这叫动情机制。女孩子动感情掉眼泪,一定是舍不得一个氛围、一个团队。所以团队解散时,女孩子掉眼泪,我们人人都感动,她的眼泪中有我们的一份。男人稀里哗啦掉眼泪,绝对是因为舍不得一个人,你甭感动,那人不是你。

◆ 我们常说,似水柔情。让一个男人脑子进水的感情,就叫似水柔情;而让一个男人脑子进开水的感情,就叫火热的似水柔情

◆ 真实的世界是有很多缺点、毛病和遗憾的。但因为真实,才稳定,要不真实,就反常

◆ 现代管理学有个基本结论:稳定的人际关系,是基于缺点展示和缺点认同的

◆ 不能光看优点,缺点是稳定的基础,优点是发展的基础。先有稳定才能发展,没地基哪行?

越是亲信越不能亲近

◆ 我们一定得记住,在团队管理中,就算有过命的交情,就算是掏心窝子的兄弟,你在他面前该讲理想就讲理想,该正襟危坐就正襟危坐,该谈人生就谈人生

◆ 管好自己身边亲信的人,有一个管理原则,叫近严远宽,先严后宽

错位的王伦:庸人能否当领导

◆ 领导就要像宋江那样,像刘邦那样,通过良好的待遇政策和激励政策,通过给理想、给实惠,调动比你强的专家、人才给你干工作。

◆ 从王伦这个小聪明,我们看到了狭隘领导的第二个错误——人为制造内耗,刻意增加自己的权力

◆ 现代团队管理认为权力有两类:一类叫职位权力,是上级给你的奖罚资源;另一类叫个人权力

◆ 个人权力,第一,看本事;第二,看人品、看风格。

◆ 关于获得人心,《孙子兵法》上有一种说法,当领导要做到四个字,“上下同欲”。什么叫上下同欲?上是上级,下是下属,同是相同,欲是个人的动机

不到位的晁盖:鸠占鹊巢的悲哀

◆ 晁盖犯了三大基本错误:第一,让二把手管重大人事安排;第二,让二把手主外,一把手主内;第三,在做事情上,跟二把手争一时之短长。

梁山公司的人与事

◆ 有本事的人发脾气,那叫个性;没本事敢发脾气,那叫找死。

— 来自微信读书

Rails 7 已有项目引入 Bootstrap 3

若是新项目,在 Rails 7 之后直接使用 rails new test -j esbuild --css bootstrap 即可,若是已有项目,使用下面步骤引入:

主要步骤

安装 cssbundling-rails 管理 CSS

bundle add cssbundling-rails
./bin/rails css:install:bootstrap

做了以下几件事情:

  • 它会创建 builds 文件夹,并在清单文件中链接它
  • 它会删除 application.css 文件,因为它会生成自己的文件。
  • 它添加了一个 package.json 文件来存储 Javascript 依赖项。
  • 它会安装 foreman gem,并为其生成一个配置文件。
  • 它添加了一个 bin/dev 脚本来启动 rails 服务器,并监视 CSS 文件的任何更改。
  • 它会创建特定于 Bootstrap 的 scss 文件,该文件将被捆绑到一个 application.css 文件中。
  • 它将安装 package.json 文件中列出的所有 Javascript 依赖项。
  • 它将 Bootstrap 字体路径附加到 assets 路径。
  • 它将 Bootstrap Javascript 导入添加到 application.js 文件中。
  • 最后,它配置 build:css 命令并运行它来构建 application.css 文件。

安装 jsbundling-rails 处理 JS 绑定

bundle add jsbundling-rails
./bin/rails javascript:install:esbuild

上述脚本做了这些事情:

  • 它会检查 builds 文件夹,但因为我们已经有了它,所以它不会做任何事情。
  • 它将 javascript_include_tag 添加到应用程序布局文件中。
  • 它在 foreman 配置文件中添加一个任务,以监视任何 Javascript 更改。
  • 它安装 esbuild 打包器,并尝试构建 Javascript 代码。

疑难问题

$ esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=assets
✘ [ERROR] Could not resolve "controllers"

    app/javascript/application.js:3:7:
      3 │ import "controllers"
        │        ~~~~~~~~~~~~~
        ╵        "./controllers"

  Use the relative path "./controllers" to reference the file "app/javascript/controllers/index.js".
  Without the leading "./", the path "controllers" is being interpreted as a package path instead.

1 error
node:child_process:866
    throw err;
    ^

Error: Command failed: /Users/cezar/Work/ror/bootstrap/node_modules/esbuild-darwin-arm64/bin/esbuild app/javascript/application.js --bundle --sourcemap --outdir=app/assets/builds --public-path=assets
    at checkExecSyncError (node:child_process:828:11)
    at Object.execFileSync (node:child_process:863:15)
    at Object.
<anonymous> (/Users/cezar/Work/ror/bootstrap/node_modules/esbuild/bin/esbuild:209:28)
    at Module._compile (node:internal/modules/cjs/loader:1099:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
    at node:internal/main/run_main_module:17:47 {
  status: 1,
  signal: null,
  output: [ null, null, null ],
  pid: 94418,
  stdout: null,
  stderr: null
}

Node.js v17.8.0
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

因为我们有一些 import maps 留下的代码,这与 jsbundling-rails gem 的工作方式相冲突。

因此,让我们解决这些问题。

修复安装

首先要做的是安装 turbo-railsstimulus 包。

yarn add @hotwired/turbo-rails
yarn add @hotwired/stimulus

然后,我将调整 application.js 文件中的导入路径,并删除旧的刺激导入。

--- a/app/javascript/application.js
+++ b/app/javascript/application.js
-import "controllers"
+import "./controllers";

--- a/app/javascript/controllers/index.js
+++ b/app/javascript/controllers/index.js
-import { application } from "controllers/application"
-
-// Eager load all controllers defined in the import map under controllers/**/*_controller
-import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
-eagerLoadControllersFrom("controllers", application)
-
-// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
-// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
-// lazyLoadControllersFrom("controllers", application)
+import { application } from "./application";

在应用程序布局文件中,我将删除 javascript_importmap_tags 帮助程序,因为它不再需要。

--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
     <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
-    <%= javascript_importmap_tags %>
     <%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %>
   </head>

最后,我将取消链接其他 javascript 文件夹,只在清单中留下 builds 文件夹和 images 文件夹。

--- a/app/assets/config/manifest.js
+++ b/app/assets/config/manifest.js
 //= link_tree ../images
-//= link_tree ../../javascript .js
-//= link_tree ../../../vendor/javascript .js
 //= link_tree ../builds

安装 Bootstrap3

以上命令默认会安装最新的 Bootstrap, 如果像我一样需要安装旧版本,则按照以下步骤:

首先安装 Bootstrap 3jquery

yarn add bootstrap@3
yarn add jquery

之后创建一个 js 文件 app/javascript/add_jquery.js :

import jquery from 'jquery'
window.jQuery = jquery
window.$ = jquery

最后在 app/javascript/application.js 中引入即可:

...
import './add_jquery'  

import "jquery/dist/jquery"  
import "bootstrap/dist/js/bootstrap"
...

css 则是在 app/assets/stylesheets/application.bootstrap.scss 中写入:

+ @import 'bootstrap/dist/css/bootstrap';
@import 'bootstrap-icons/font/bootstrap-icons';

链接 debugger

以上操作后就可以使用 bin/dev 启动项目,会自动起来三个服务,这时如果使用 debugger 启动调试,就可以使用以下命令链接:

rdbg --attach

References

Ruby 多版本管理工具 rbenv

rbenv (Simple Ruby Version Management) 允许您在 Ruby 的多个版本之间轻松切换。它简单、不引人注目,并遵循 UNIX 的传统,即只做一件事的单一用途工具。

安装方法

安装 rbenv

# Archlinux
sudo pacman -S rbenv
# macOS
brew install rbenv
# Debian/Ubuntu
sudo apt install rbenv
# Fedora/RHEL
sudo dnf install rbenv

安装 ruby-build

使用 rbenv 安装 ruby 版本需要用到 install 命令,但是该 rbenv install 命令不是开箱即用的 rbenv 提供的,而是由 ruby-build 插件提供的,下面一同安装:

# Archlinux
sudo pacman -S ruby-build
# macOS
brew install ruby-build

使用方法

# 首先初始化
rbenv init

# 查看可安装版本
rbenv install -l # list latest stable versions
rbenv install -L # list all local versions

# 安装某个版本
rbenv install 3.1.2

# 使用某个版本
rbenv global 3.1.2 # set the default Ruby version for this machine
rbenv local 3.1.2  # set the Ruby version for this directory

References