CSS: Unavoidable Bad Parts

CSS: Unavoidable Bad Parts

CSS:不可避免的糟粕

An ersatz CSS tutorial for people who need to style a web page, but aren’t web developers. I am a wrong person to write this kind of thing, as I have neither the time, nor experience. I’d much rather read a book about this. Alas, I had to learn all this stuff from trawling MDN, so perhaps it is valuable to document what I have so far. 这是一篇为那些需要美化网页但并非网页开发者的用户准备的“替代版”CSS 教程。我并不是撰写此类文章的最佳人选,因为我既没有时间,也没有经验。我宁愿去读一本相关的书。可惜,我只能通过在 MDN 上摸索来学习这些知识,所以记录下我目前所学的内容或许还有些价值。

CSS, HTML and Web APIs are truly vast, and it takes a career to become a professional. The good news is that modern web has a reasonably-sized, learnable subset which is enough for simple tasks like a programming blog or a simple GUI. I haven’t seen a resource that teaches just this subset, but it’s not too hard to figure this out. CSS、HTML 和 Web API 的内容极其庞大,成为一名专业人士需要职业生涯的积累。好消息是,现代 Web 技术中存在一个规模适中且易于学习的子集,足以应付编程博客或简单 GUI 等任务。我还没见过专门教授这个子集的资源,但自己摸索出来并不太难。

The bad news is that there’s also a nasty set of gotchas, which will mess up your page, which you won’t suspect to exist, and which will need days of debugging to figure out. Still, it’s not that bad. I am quite happy with the styling on this site, and it’s only about 200 of readable CSS. 坏消息是,其中也存在一系列棘手的“坑”。它们会搞乱你的页面,让你防不胜防,甚至需要花费数天时间调试才能解决。不过,情况也没那么糟。我对本站的样式感到相当满意,而它仅仅用了约 200 行易读的 CSS 代码。

Good: HTML5 semantic tag names

优点:HTML5 语义化标签

It’s worth looking through MDN Elements Reference. There aren’t that many elements, and things like main, article, nav, kbd make it much easier to structure your page. Less obvious: ul for any kind of list, like site’s sections in header > nav. details for table-of-contents (check the source of MDN). dl/dt for list of pairs. 值得通读一遍 MDN 的元素参考手册。元素其实并不多,像 mainarticlenavkbd 这样的标签能让页面结构化变得简单得多。一些不太明显的用法:用 ul 表示任何类型的列表(例如 header > nav 中的站点分区);用 details 表示目录(可以查看 MDN 的源码);用 dl/dt 表示键值对列表。

Bad: Wrappers

缺点:包装器(Wrappers)

If you “View Source” on any “real” website, you’ll notice that everything has layers and layers of wrapper elements, so you might be tricked into thinking that wrappers are how you solve layout problems. I can’t really agree or disagree here, as I never wrote “production” CSS, but, in my experience, it’s much easier to understand if you do the opposite — restrict yourself to using only markup-meaningful semantic tags, and then figure out CSS which works with the markup you have. 如果你查看任何“真实”网站的源代码,会发现到处都是层层嵌套的包装元素,这可能会让你误以为包装器是解决布局问题的唯一途径。我无法完全赞同或反对这一点,因为我从未编写过“生产环境”的 CSS,但根据我的经验,反其道而行之会更容易理解——限制自己只使用具有语义意义的标签,然后针对现有的标记编写 CSS。

Bad: Layout

缺点:布局

This one is not an exclusively Web problem, layout is a struggle in every GUI framework I know. Imagine a fixed sized raster image, and a paragraph of text describing it. There are many ways to arrange these two elements on the screen’s rectangle. Generally, for every given width and height, you can do a decent job, as long as the total area is enough. A typical GUI is a hierarchy of such boxes, with a lot of “layout freedom”. The problem though is that layout of each box affects the layouts of all other boxes, as you generally want all boxes to meet exactly, without gaps and overlaps. 这不仅仅是 Web 的问题,布局是我所知的每一个 GUI 框架中的难题。想象一张固定大小的位图和一段描述它的文字,在屏幕矩形区域内排列这两个元素有很多种方法。通常,只要总面积足够,对于给定的宽高,你都能做出不错的布局。典型的 GUI 是由这类盒子组成的层级结构,拥有很大的“布局自由度”。但问题在于,每个盒子的布局都会影响其他所有盒子,因为你通常希望所有盒子能严丝合缝地对齐,没有间隙或重叠。

An important negative realization is that the layout algorithm doesn’t exist. There isn’t a fully general solution to positioning and sizing GUI boxes. Rather, different systems use different sets of heuristics to do the job, from simple RectCut, to fully general constraint solvers, with everything in between. It is hard to get the mental model of how layout works, in general. So, don’t think “how can I do my layout in a given system”, think instead “what possible layouts are allowed by the system”. 一个重要的负面认知是:通用的布局算法并不存在。对于 GUI 盒子的定位和尺寸调整,没有一种完全通用的解决方案。相反,不同的系统使用不同的启发式方法来完成这项工作,从简单的矩形切割(RectCut)到完全通用的约束求解器,以及介于两者之间的各种方案。很难建立起关于布局如何运作的通用心智模型。因此,不要去想“我该如何在特定系统中实现布局”,而应该思考“该系统允许哪些可能的布局”。

Bad: Browser defaults

缺点:浏览器默认样式

Let’s start with a bare (but still semantic) HTML markup of a blog article, without any CSS. If you open it in a browser, it will show something. The content isn’t unstyled — the text is of a certain color, font and size. Headers are bigger than the main text, links are underlined, etc. These are the default styles of your browser. They are helpful! The problem is that these styles differ between the browsers. So, even when you add your own CSS, and the end result looks fine in your browser, I might see something different, because you might rely on a browser default, without knowing it. 让我们从一个没有任何 CSS 的纯净(但语义化)的博客文章 HTML 标记开始。如果你在浏览器中打开它,它会显示出内容。内容并非没有样式——文本有特定的颜色、字体和大小。标题比正文大,链接有下划线等等。这些是浏览器的默认样式。它们很有用!但问题在于,不同浏览器之间的这些样式存在差异。因此,即使你添加了自己的 CSS,并且在你的浏览器中看起来很完美,我看到的可能却是另一番景象,因为你可能在不知不觉中依赖了某个浏览器的默认样式。

The last bit is the killer here — the problem is in something you didn’t write. The general solution here is a CSS reset, or normalization — starting your CSS with an explicit set of rules, overriding defaults. Not because defaults are inherently bad, because they are inconsistent. I don’t know which set of rules you need to override in practice, it’s a good idea to compare several existing CSS resets. 最后一点是致命的——问题出在你没写的东西上。通用的解决方案是 CSS 重置(reset)或标准化(normalization)——在 CSS 开头使用一组明确的规则来覆盖默认值。这并不是因为默认样式本身很糟糕,而是因为它们不一致。我不知道你在实践中具体需要覆盖哪些规则,建议对比几种现有的 CSS 重置方案。

This touches on the big question: should you style your web page? There are two competing views of the Web platform — some people treat it as a flexible, adaptive, primarily visual medium for expressing design, others would prefer if the Web focused on delivering the content, allowing each user to customize the presentation. My personal answer here is pragmatic — by default, an unstyled page is poorly usable and looks bad. I would have preferred the world where CSS-less pages were readable as is, but, in this world, I think it is helpful to style the content. At the same time, it’s a good idea to allow advanced users to bring their own CSS. Make sure that your HTML markup is reasonable, that you don’t overfit your HTML to CSS (vice-versa is fine), and that your page functions in reader mode. 这触及了一个大问题:你应该美化你的网页吗?关于 Web 平台有两种相互竞争的观点——有些人将其视为一种灵活、自适应、主要用于表达设计的视觉媒介;另一些人则希望 Web 专注于内容交付,允许每个用户自定义呈现方式。我个人的回答是务实的——默认情况下,没有样式的页面可用性差且外观糟糕。我更希望生活在一个没有 CSS 的页面也能直接阅读的世界,但在现实中,我认为美化内容是有帮助的。同时,允许高级用户使用他们自己的 CSS 是个好主意。确保你的 HTML 标记合理,不要为了 CSS 而过度拟合 HTML(反之则没问题),并确保你的页面在阅读模式下功能正常。

Good: Classless CSS

优点:无类名 CSS (Classless CSS)

You can’t reset styles to true neutral nothing: if you make the text invisible (white or transparent), it is still a style. So you might as well embrace it: after reset, style common HTML elements directly. For example, to set your favorite font for all code snippets: code { font-family: "JetBrains Mono", monospace; }. If you use main, header, footer, nav tags you can set the overall page layout without writing any CSS selectors. This of course requires making assumptions, in CSS, about the structure of your HTML, but, like, this is your HTML and your CSS, you can do whatever, and, if you don’t like the result, you can always change it! 你无法将样式重置为真正的“虚无”:如果你让文本不可见(白色或透明),那依然是一种样式。所以不如拥抱它:在重置之后,直接为常见的 HTML 元素设置样式。例如,为所有代码片段设置你喜欢的字体:code { font-family: "JetBrains Mono", monospace; }。如果你使用了 mainheaderfooternav 标签,你无需编写任何 CSS 选择器即可设置整体页面布局。这当然要求你在 CSS 中对 HTML 结构做出假设,但毕竟这是你自己的 HTML 和 CSS,你可以随心所欲;如果不喜欢结果,随时可以修改!

Bad: CSS selectors

缺点:CSS 选择器

In programming, we collectively came around to distrust inheritance and prefer composition. Default CSS is like supercharged inheritance, each design element on your web page is affected by multiple rules, and you can always “monkey patch” existing elements by appending to your CSS. There’s an unfortunate gap between CSS affordances, and what you actually want to do. The two reasonable approaches are: Conclude that CSS selectors add abstraction capability along the wrong axis, and stick to classless CSS and inline styles, using something like Tailwind to mak… 在编程领域,我们逐渐达成共识:不信任继承,更倾向于组合。默认的 CSS 就像是“超级增强版”的继承,网页上的每个设计元素都会受到多条规则的影响,而且你总是可以通过在 CSS 中追加代码来“猴子补丁”(monkey patch)现有元素。CSS 提供的功能与你实际想做的事情之间存在令人遗憾的鸿沟。两种合理的做法是:得出结论认为 CSS 选择器在错误的维度上增加了抽象能力,从而坚持使用无类名 CSS 和内联样式,或者使用类似 Tailwind 的工具来……