旧版 CSS,新版 CSS

我是在上世纪90年代末开始接触网页设计/开发的,直到现在我才意识到那已经是很久以前的事了。

那真是糟糕透顶。虽然能制作东西并将其发布到网上供他人查看确实很酷,但当时我们能用的工具实在太有限了。

我一直以为,大多数从事网页相关工作的人都还记得那些日子,或者至少记得接下来的十年,但我想这种假设可能有点过时了。不久前,我看到一条推文,感叹我们当年没有border-radius要如何应对。我至今还记得,当时我们是多么迫切地等待它去掉前缀!

但我也怀疑,我认识的许多人只在过去尝试过网页设计,并认为自那以后一切都没有改变。

我在此告诉你们所有人:别在我家草坪上乱逛。以下是我记忆中的CSS和网页设计历史。

元素周期表

(请记住,这篇文章是记忆与研究的完美结合,所以我无法保证其中任何内容都是正确的,尤其是关于因果关系的部分。你可能想尝试W3C的CSS历史,它要短得多,更有可能与现实相符,而且包含的脏话也少得多。)

(此外,这篇文章若能加入更多图表会更好,但光是撰写就已耗时良久。)

非常早期的日子

起初,没有CSS。

这非常糟糕。

我最喜欢的那个时代的遗物是教我 HTML 的那本书:O’Reilly 的 HTML: The Definitive Guide,该书在 90 年代中后期出版了多个版本。这本书确实只讲 HTML,完全没有提到 CSS。我已经不再拥有这本书,也无法在网上轻松找到截图,但这里有一页来自《HTML & XHTML: The Definitive Guide》,这似乎是该书的修订版(我稍后会提到XHTML),风格与原版大致相同。以下便是199X年最前沿的网页设计建议:

图0:旧版 CSS,新版 CSS

用水平线明确区分标题和页脚。

不,那不是border-top。那是<hr>。页面标题几乎肯定是用<center>居中的。

页面使用了默认的文字颜色、背景色和字体。部分原因在于这是一本分步介绍概念的指南;部分原因在于该书以黑白印刷;部分原因,我敢肯定,是因为当时给任何内容上色都是一件极其麻烦的事。

假设你想让整个网站的所有<h1>标签都显示为红色。你必须这样做:

<H1><FONT COLOR=red>...</FONT></H1>

每次都得这样做。希望你永远不要决定改用蓝色!

哦,还有,当时大家都用大写字母写 HTML 标签。我不记得为什么我们都觉得这是个好主意。也许这是因为当时文本编辑器中的语法高亮还不太常见(也就是说,我当时 12 岁,用的是记事本),而大写标签更容易与正文文本区分开来。

因此,保持网站风格一致性简直是一场噩梦。一个解决方案就是干脆不做任何样式设置,很多人都这么做了。这在某种程度上挺好的,因为浏览器允许你修改这些默认设置,这样你就可以按自己喜欢的方式阅读网页。

一个巧妙的替代方案,我记得在很多Geocities网站上都出现过,就是给每个页面完全不同的视觉风格。管他呢,对吧?每个新页面随心所欲地设计。

这种趋势很可能就是网页设计的巅峰。

天啊,我怀念那些日子。那时没有大型封闭平台,没有Twitter或Facebook。如果你想对任何人说点什么,就必须自己搭建网站。那真是太棒了。没人知道自己在做什么;我敢打赌,当时绝大多数网页设计师都是毫无头绪的业余爱好者(就像我一样),都在模仿其他毫无头绪的业余爱好者。网络上有一半都是关于《变形金刚》的粉丝门户网站,配有莫名其妙的 splash 页面,警告你如果使用 640×480 屏幕,网站效果最佳。(任何分辨率不足的12岁孩子,想必应该用零花钱买个新显示器。)所有酷炫且懂行的人都使用Internet Explorer 3,这是当时最先进的浏览器,但有些落伍者还用Netscape Navigator,所以你得在 splash 页面上加个“最佳效果在IE”的动画GIF。

这也是“网页安全颜色”的时代——一种包含216种颜色的调色板,每个通道的值都是00336699ccff——因为有些人仍然使用256色显示器!我们现在习以为常的东西,比如24位颜色。

事实上,我们现在习以为常的许多东西,当时还是一个陌生而未被驯服的问题领域。你想在网站的每一页上都使用相同的导航?没问题:将导航复制粘贴到每一页。当你更新导航时,一定要记得更新每一页——但很可能你会忘记一些,整个网站就会变成一个自我挖掘的考古现场,层层叠叠的页面逐渐变得无法使用。

更简单的方法是使用_框架_,即浏览器窗口被划分为网格,每个区域加载不同的页面……但如果用户通过搜索引擎(如AltaVista)直接进入某个页面时没有框架,他们就会感到困惑。(我不敢相信我还在解释框架,但自2001年以来几乎没人再使用它们了。你知道iframe吗?那个“i”代表“内联”,用来区分它们与占满整个视口的“常规”框架。

PHP当时甚至还没被称为PHP,也没人听说过它。这个奇怪的“Perl”和“CGI”东西真的很奇怪且难以理解,而且它无法在你的电脑上运行,错误也难以查找和诊断,而且无论如何Geocities都不支持它。如果你真的很幸运且聪明,你的网络主机使用Apache,你可以使用它的“服务器端包含”语法来做类似这样的事情:

<BODY>
    <TABLE WIDTH=100% BORDER=0 CELLSPACING=8 CELLPADDING=0>
        <TR>
            <TD COLSPAN=2>
                <!--#include virtual="/header.html" --> 
            </TD>
        </TR>
        <TR>
            <TD WIDTH=20%>
                <!--#include virtual="/navigation.html" --> 
            </TD>
            <TD>
                (actual page content goes here)
            </TD>
        </TR>
    </TABLE>
</BODY>

Mwah. 漂亮。Apache会识别这些特殊注释,将引用文件的内容插入其中,你就可以开始工作了。缺点是,当你想修改网站时,所有导航都消失了,因为你在没有Apache的普通电脑上操作,而你的网页浏览器认为这些只是普通的HTML注释。当然,你无法安装Apache,因为你拥有的只是一台“电脑”,而不是“服务器”。

遗憾的是,这一切都已成为过去——被同质化的时间线所覆盖,任何不是本周制作的内容都已成为旧闻并被遗忘。网络本应让信息永恒,但实际上,其中大部分都变得转瞬即逝。我怀念几乎我认识的每个人都有自己网站的时代。仅凭Twitter和Instagram作为整个在线存在,实在是个糟糕的替代品。

那么,让我们看看《太空大灌篮》的网站。

案例研究:太空大灌篮

《太空大灌篮》,如果你不知道的话,是史上最伟大的电影。它讲述了兔八哥短暂的篮球生涯,与真人版迈克尔·乔丹并肩作战,以某种原因拯救地球免受外星人入侵。随后,一系列非常成功且备受好评的RPG衍生作品问世,这些作品描述了《太空大灌篮》事件的后续影响,且极具正统性。

我们真是幸运,因为这部电影上映24年后,其官方网站至今仍可访问。我们现在就可以探索1996年网页设计的巅峰之作。

首先,请注意该网站的每一页都是静态页面。不仅如此,这些页面以.htm而非.html结尾,因为在Windows 95之前的版本中,用户仍需遵守8.3文件名规范。我不确定这在URL中为何重要,毕竟没人会在Web服务器上运行Windows 3.11,但事实就是如此。

splash 页面的 CSS 代码如下:

<body bgcolor="#000000" background="img/bg_stars.gif" text="#ff0000" link="#ff4c4c" vlink="#ff4c4c" alink="#ff4c4c">

哈哈,开玩笑的!CSS 是什么鬼?《太空大灌篮》比它早一个月上映。(我在页面源代码中确实看到了一行 CSS,但肯定是在后来添加的,用于样式化一些法律要求的政策链接。)

注意这些导航链接的极度精确定位。这一成就与1996年所有人做事情的方式相同:使用表格。

事实上,表格在布局方面比CSS有一个功能优势,这在当时非常重要,而不仅仅是因为CSS尚未存在。你看,你可以通过Ctrl+点击选择一个表格单元格,甚至拖动选择所有单元格,这显示了单元格的排列方式,并作为一个超级复古的布局调试器。这非常棒,因为第一个有意义的网页调试工具Firebug直到2006年才发布——整整十年后!

图1:旧版 CSS,新版 CSS

这个表格的标记中充满了无法解释的空白行,但去除这些空白行后,它看起来是这样的:

<table width=500 border=0>
<TR>
<TD colspan=5 align=right valign=top>
</td></tr>
<tr>
<td colspan=2 align=right valign=middle>
<br>
<br>
<br>
<a href="cmp/pressbox/pressboxframes.html"><img src="img/p-pressbox.gif" height=56 width=131 alt="Press Box Shuttle" border=0></a>
</td>
<td align=center valign=middle>
<a href="cmp/jamcentral/jamcentralframes.html"><img src="img/p-jamcentral.gif" height=67 width=55 alt="Jam Central" border=0></a>
</td>
<td align=center valign=top>
<a href="cmp/bball/bballframes.html"><img src="img/p-bball.gif" height=62 width=62 alt="Planet B-Ball" border=0></a>
</td>
<td align=center valign=bottom>
<br>
<br>
<a href="cmp/tunes/tunesframes.html"><img src="img/p-lunartunes.gif" height=77 width=95 alt="Lunar Tunes" border=0></a>
</td>
</tr>
<tr>
<td align=middle valign=top>
<br>
<br>
<a href="cmp/lineup/lineupframes.html"><img src="img/p-lineup.gif" height=52 width=63 alt="The Lineup" border=0></a>
</td>
<td colspan=3 rowspan=2 align=right valign=middle>
<img src="img/p-jamlogo.gif" height=165 width=272 alt="Space Jam" border=0>
</td>
<td align=right valign=bottom>
<a href="cmp/jump/jumpframes.html"><img src="img/p-jump.gif" height=52 width=58 alt="Jump Station" border=0></a>
</td>
</tr>
...
</table>

这是前两行,包括徽标。你明白我的意思。所有内容都使用 alignvalign 属性对表格单元格进行布局;rowspancolspan 属性被频繁使用;此外还加入了一些 br 标签,以每次调整一行高度的方式来调整垂直位置。

该页面上还有其他值得注意的元素,例如这个包含Apache SSI语法的标题!这在网站迁移过程中可能悄然损坏;目前该页面托管在亚马逊S3上。你知道亚马逊吗?就是那个书店?

<table border=0 cellpadding=0 cellspacing=0 width=488 height=60>
<tr>
<td align="center"><!--#include virtual="html.ng/site=spacejam&type=movie&home=no&size=234&page.allowcompete=no"--></td>
<td align="center" width="20"></td>
<td align="center"><!--#include virtual="html.ng/site=spacejam&type=movie&home=no&size=234"--></td>
</tr>
</table>

好的,让我们来看看Jam Central。我使用浏览器开发工具将视口缩小至640×480以获得真实体验(尽管这样会因标题栏、任务栏以及五六个IE工具栏而损失部分垂直空间)。

注意这些框架:左上角的标志链接回登录页面,巧妙地节省了重复显示所有导航元素的屏幕空间,而右上角是一个该死的广告横幅,已经被七种不同方式屏蔽。这三个部分都是独立的页面。

图2:旧版 CSS,新版 CSS

还注意那个在纹理背景上完全无法阅读的红色文字,这是90年代网页设计的真正标志之一。“为什么不把那段文字放在更易读的背景上?”你可能会问。你这个白痴。我怎么可能做到呢?只有<body>标签有background属性!我可以使用表格,但表格只支持纯色背景,那看起来会很无聊!

但等等,这个新的导航小工具是什么?为什么链接都排列得这么不齐?这是又一个表格吗?嗯,不是,尽管用表格填充切片图像的块并不罕见。但这是个_图像地图_,一个被遗忘已久的HTML功能。我直接给你看源代码:

<img src="img/m-central.jpg" height=301 width=438 border=0 alt="navigation map" usemap="#map"><br>

3<map name="map">
<area shape="rect" coords="33,92,178,136" href="prodnotesframes.html" target="_top">
<area shape="rect" coords="244,111,416,152" href="photosframes.html" target="_top">
<area shape="rect" coords="104,138,229,181" href="filmmakersframes.html" target="_top">
<area shape="rect" coords="230,155,334,197" href="trailerframes.html" target="_top">
</map>

我认为这基本上不言自明。usemap属性用于关联图像地图,该地图定义了一系列可点击区域,以难以理解的坐标列表形式编码。

而且这些内容至今仍可正常工作!这是HTML!你现在就可以使用它!不过最好别用!

缩略图网格

再来看看另一个随机页面。我希望能看到一些电影的剧照。(等等,剧照?难道我们还不知道“截图”是什么吗?)

图3:旧版 CSS,新版 CSS

另一个框架集,但这次排列方式不同。

<body bgcolor="#7714bf" background="img/bg-jamcentral.gif" text="#ffffff" link="#edb2fc" vlink="#edb2fc" alink="#edb2fc">

他们在这里做了一件重要的事:既然指定了背景图像(不透明的),他们也指定了背景颜色。如果没有背景颜色,当背景图像加载失败时,页面会显示白色文字在默认白色背景上,这将无法阅读。

(这仍然是一个需要记住的重要事项。我感觉现代网页开发往往假设一切都会加载,或者将加载视为某种需要绕过的不便,但并非所有人都能在距离骨干网仅20英尺的旧金山办公室使用有线连接。)

但关于页面本身。缩略图网格是网页设计中的经典问题,可以追溯到……嗯……至少可以追溯到《太空大灌篮》。主要问题在于,你希望将元素_并排放置_,而HTML默认会将所有内容堆叠成一列。你可以将所有缩略图以行内方式排列,形成一行(换行)文本,但这并非真正的网格——而且通常每个缩略图都需要某种形式的标题。

《太空大灌篮》的解决方案是使用当时工具箱中唯一可用的工具:表格。其结构如下:

<table cellpadding=10>
<tr><td align=center><a href="..."><img src="..."></a></td>...</tr>
<tr>...</tr>
<tr>...</tr>
<table>

一个 3×3 的缩略图网格,由浏览器自行排列。(最后一张图片单独在一行,实际上并不属于表格。)这种布局无法适应屏幕大小,但当时大家的屏幕都比较小,所以这个问题_稍微_不那么严重。他们没有在这里添加说明文字,但由于每个缩略图都包裹在表格单元格中,他们本可以轻松添加。

这是1996年缩略图网格的最新技术。我们将多次回顾这个小界面难题;您可以在单独页面上查看实时示例(并查看源代码以获取示例标记)。

但让我们花点时间欣赏一下我当前显示器上“全尺寸、全彩色、互联网质量”的电影截图大小。

图4:旧版 CSS,新版 CSS

不过,它们不到16KB!这只需要九秒钟就能下载。

(这让我想起了嵌入式视频的问题,直到几年后HTML5的<video>标签出现才得到解决。在此之前,你必须使用二进制插件,而它们全都糟糕透顶。)

(哦,顺便说一句:链接中的图片默认会带有链接颜色的边框。图像链接通常是显而易见的,因此这在很大程度上令人烦恼,而在CSS出现之前,你必须为每个图像使用<img border=0>来禁用边框。)

早期阶段

这就是我们起步的地方,情况糟糕透顶。如果你希望在超过几个页面上实现任何一致性,你的选择非常有限,基本上只能靠大量复制粘贴。Space Jam 网站大多选择完全不理会——许多其他网站也是如此。

然后CSS出现了,这简直是个奇迹。所有那些内联重复都消失了。你想让所有一级标题都是一种特定颜色?没问题:

H1 {
    color: #FF0000;
}

砰!大功告成。无论你的文档中包含多少个<h1>标签,每一个都会变成刺眼的红色,而且你再也不用为此操心了。更棒的是,你可以将这段代码放在一个单独的文件中,然后只需几乎不费吹灰之力,就能将这个有争议的美学选择应用到你整个网站的每一页!同样的原理也适用于你那精美的瓷砖背景图像、链接的颜色以及表格中的字体大小。

(只需记住将<style>标签的内容包裹在HTML注释中,否则不支持CSS的旧浏览器会将其显示为纯文本。)

你也不僅限於批量樣式化標籤。CSS 引入了「類別」和「ID」來僅針對特定標記的元素。一個如 P.important 的選取器僅會影響 <P CLASS="important">,而 #header 僅會影響 <H1 ID="header">。(两者的区别在于,ID 在文档中应保持唯一性,而类可以被多次使用。)借助这些工具,你可以有效地创建自己的标签,从而为你的网站打造一个定制版的 HTML!

这无疑是一次巨大的飞跃,但当时(可能)没有人想到要用 CSS 来实际“布局”页面。当CSS 1于1996年12月成为推荐标准时,它几乎完全没有涉及布局。它所做的只是将HTML的现有功能与它们所关联的标签分离。我们拥有字体颜色和背景色,是因为<FONT COLOR><BODY BACKGROUND>标签存在。唯一一个在一定程度上影响元素位置的特性是float属性,它相当于<IMG ALIGN>,可以将图像拉到一侧并让文本围绕其流动,就像杂志文章中的布局一样。这远不足以令人满意。

这并不令人意外。HTML除了表格外,没有其他真正的布局解决方案,而表格属性过于复杂,无法在CSS中泛化,且与标签结构过于纠缠,因此CSS 1无法继承任何内容。它只是减少了我们在使用如<FONT>标签时重复的工作——使网页设计少些繁琐、少些错误、少些冗余,且更易于维护。这是一个相当不错的进步, everyone都乐于采用它,但表格仍旧是页面布局的王者。

不过这没关系;你的博客真正需要的只是一个标题和一个侧边栏,而表格完全可以胜任,而且你也不会经常彻底改造这个基本结构。复制粘贴几行 <TABLE BORDER=0><TD WIDTH=20%> 并不是什么大不了的事。

有一段时间——我想大概是两三年吧,但小时候时间过得特别慢——这就是网络的状态。表格用于布局,CSS用于……嗯,样式。颜色、大小、加粗、下划线。甚至还有一个很酷的技巧,你可以让链接在鼠标悬停时才显示下划线。太棒了!

(有趣的事实:HTML 邮件至今仍基本上停留在那个时代。)

(而我就是在那个时候加入的,当时我才11岁,对自己在做什么一无所知,主要是从其他同样一无所知的11岁孩子那里学习。但这没关系;网络上很大一部分都是11岁孩子在制作自己的网站,而这很美妙。既然可以一窥地球另一端某人非常具体的爱好,为什么还要去访问一个_商业_网站呢?)

黑暗时代

一年半后,在1998年年中,我们迎来了CSS 2。(顺便说一句,我非常喜欢这页面的背景。)这是一个相对温和的升级,解决了多个领域的不足,但最有趣的是新增了几个定位原语:position属性,允许将元素精确定位到指定坐标;以及inline-block显示模式,允许将元素像图片一样嵌入文本行中。

如此诱人的功能,却遥不可及!使用position属性看似不错,但像素级精确定位与HTML的流式设计严重冲突,且难以制作出在其他屏幕尺寸下不会崩溃或存在其他严重缺陷的内容。这个 humble 的 inline-block 特性看起来足够有趣;毕竟,它解决了 HTML 布局的核心问题,即“将元素并排放置”。但至少在当时,没有浏览器实现它,它基本上被忽视了。

我无法确定究竟是定位功能的引入还是其他因素,但大约在这个时候,某种因素激发了人们尝试用CSS进行布局设计。理想情况下,你应该完全将页面的结构与外观分离。甚至有一个网站将这一原则推向极致——CSS Zen Garden至今仍存在,展示了通过应用不同的样式表,相同的HTML如何被彻底转化为完全不同的设计。

问题是,早期CSS的支持非常不稳定。回想起来,我怀疑浏览器厂商只是简单地从HTML标签中提取了行为,然后就草草了事。我很高兴地看到,RichInStyle 仍然维护着一份 早期浏览器 CSS 错误的详尽列表;以下是我最喜欢的几个:

  • IE 3 会忽略文档中除最后一个 <style> 标签之外的所有标签。
  • IE 3 忽略伪类,因此 a:hover 会被视为 a
  • IE 3 和 IE 4 将 auto 边距视为零。实际上,我认为这个 bug 可能一直存在到 IE 6。但这没关系,因为 IE 6 还错误地将 text-align: center 应用于块级元素。
  • 如果将背景图像设置为绝对 URL,IE 3 会尝试在本地程序中打开该图像,仿佛您已下载了它。
  • Netscape 4 理解类似 #id 的 ID 选择器,但会忽略 h1#id 作为无效选择器。
  • Netscape 4 不会将属性(包括字体和文字颜色!)继承到表格单元格中。
  • Netscape 4 将 <li> 上的属性应用于列表标记,而非内容。
  • 如果同一个元素同时具有 floatclear 属性(这并不合理),Netscape 4 for Mac 会崩溃。

这就是我们不得不面对的现实。人们竟然想用 CSS 来布局整个页面?哈哈。

然而这个想法逐渐流行起来。它甚至成为了一种精英主义的口号,被用作最佳实践来压制他人。“用表格进行布局就是糟糕的!”你会听到这样的说法。它们会混淆屏幕阅读器,它们在语义上是错误的,它们与CSS定位的交互效果很差!所有这些都是事实,但当替代方案是——

嗯,我们稍后再谈这个。首先,让我们回顾一下2000年左右的网络环境。

浏览器战争的结束与随后的发展停滞

简而言之:这家名为网景的公司一直在向企业出售其导航器浏览器(个人用户可免费使用),随后微软以完全免费的Internet Explorer浏览器进入市场,并且_还_胆敢将IE与Windows捆绑销售。你能想象吗?一个操作系统自带浏览器?这可是件大事,微软因此被起诉,他们输了,但后果基本上没什么影响。

但无论如何都无所谓,因为他们已经这么做了,而且奏效了。IE几乎彻底摧毁了网景的市场份额。两款浏览器都漏洞百出,而且是_不同类型_的漏洞百出,因此专为其中一款设计的网页在另一款浏览器中查看时很可能一团糟——这意味着当网景的市场份额下降时,网页设计师越来越不关注它,越来越多的网页无法在其中正常运行,其市场份额进一步下降。

如果你不使用Windows,那你可就倒霉了,我想。这很有趣,因为当时有IE for Mac 5.5,而且它通常比IE 6更少bug。(顺便说一句,比尔·盖茨并非什么天才极客,而是一位 agresive 和无情的商人,他通过刻意努力消灭任何阻碍他前进的竞争对手来积累财富,结果导致整体计算体验变差,仅此而已。)

到2001年年中Windows XP发布时,内置了Internet Explorer 6,网景已经从行业巨头沦为一个微不足道的利基玩家。

然后,在完全垄断市场后,微软停下了脚步。自IE诞生以来,它每年都会发布新版本,但IE 6是五年多来最后一个版本。它仍然存在许多漏洞,但由于没有竞争对手,这些漏洞并不那么明显,而且它“足够好”。Windows XP同样“足够好”以至于占据了桌面市场,而接下来很长一段时间内都不会有新的Windows系统发布。

万维网联盟(W3C,负责制定标准的组织,与涉嫌从事SEO欺诈的W3Schools无关)也停止了更新。HTML 在 90 年代中期经历了多次修订,随后冻结为 HTML 4。CSS 在一年半内获得了一次更新,之后便再无进展;次要更新 CSS 2.1 直到 2004 年初才达到候选推荐状态,并又花了七年时间才最终定稿。

随着IE 6的统治地位,整个网络仿佛被定格在时间中。标准不再重要,因为实际上只有一个浏览器,而它所做的一切都成为了事实上的标准。随着网络的普及,IE的垄断地位也使得使用除Windows以外的其他平台变得困难,因为IE仅限于Windows系统,而一个网站是否能在其他浏览器上正常运行则完全取决于运气。

(人们开始怀疑垄断是坏事。应该有一条法律来禁止它!)

与此同时,网景公司(Netscape)通过决定对浏览器引擎进行大规模重写,将自己置于更糟糕的境地,最终推出了符合标准程度远高于之前的网景6(Netscape 6)——但为此付出了数年时间远离市场的代价,而IE则在这一期间占据了绝对优势。其市场份额从未突破10%,而IE的峰值则达到96%。另一方面,新引擎以Mozilla应用套件的形式开源,这在几年后将变得至关重要。

在探讨这一话题之前,还有其他一些事情正在发生。

怪异模式

早期所有CSS实现都存在大量漏洞,但其中一个或许是最臭名昭著的CSS漏洞:盒模型漏洞

你看到,一个盒子(元素占用的矩形空间)有几个测量值:它自己的宽度和高度,然后是周围的空白区域称为 padding,然后是可选的边框,然后是与相邻盒子分离的 margin。CSS 规定这些属性都是累加的。一个具有以下样式的盒子:

    width: 100px;
    padding: 10px;
    border: 2px solid black;

…因此宽度为 124 像素,从边框到边框。

而IE 4和Netscape 4则采取了不同的方法:它们将widthheight视为从边框到边框的测量值,并通过_减去_边框和内边距来计算元素本身的宽度。在这些浏览器中,同一盒子的宽度为100像素(从边框到边框),其中76像素用于内容显示。

这种与规范的冲突并不理想,IE 6 试图解决这个问题。不幸的是,仅仅做出这一改变将意味着完全破坏大量此前在 IE 和 Netscape 均能正常运行的网站设计。

因此,IE 团队提出了一个非常奇怪的折中方案:他们将旧行为(连同其他几个重大 bug)定义为“兼容模式”,并将其设为默认模式。新的“严格模式”或“标准模式”必须通过在文档开头(<html>标签之前)添加“doctype”声明来主动启用。它看起来会像这样:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">

多年来,每个人都不得不将这段混乱的代码粘贴到每个HTML文档的顶部。(HTML5后来将其简化为<!DOCTYPE html>。)回过头来看,这确实是一种非常奇怪的启用正确CSS行为的方式;文档类型声明自HTML规范还是RFC时代起就已存在。我猜想,由于_没有人_真正包含一个,这是一种方便的方式,允许选择加入而无需使用专有扩展,仅仅是为了避免从一开始就错误的行为。IE团队做得很好!

有趣的是,二十年后,怪异模式仍然存在_并且仍然是默认设置_在所有浏览器中!奇异模式的具体实现随时间而变化,特别是 Chrome 和 Firefox 即使在奇异模式下也不使用 IE 的盒模型,但仍然存在相当多的其他模拟错误

你好!我是Eevee,距离上次更新已近两年。你可能会发现前面的链接已失效。嗯, Mozilla做出了一个令人费解的决定,即从MDN中删除所有Mozilla特有的信息,理由是这些内容本应属于Firefox文档,但随后又未能将其添加到Firefox文档中。因此,一些具有重要技术意义且具有深远历史价值的信息,比如Firefox中的quirks模式究竟做了什么,现在已经丢失,除了一个无法阅读的存档副本。这也将 MDN 上关于怪异模式的唯一提及缩减为 这篇孤立的文章,该文章仅模糊地描述了其定义,却未提供任何关于实际差异的具体说明。真是个该死的闹剧。

现代浏览器还提供了“几乎符合标准”模式,该模式仅模拟单一怪异行为,或许是最臭名昭著的第二大怪异行为:若表格单元格仅包含单张图片,则基线下方空间会被移除。根据常规CSS规则,图片会嵌入到一行(否则为空)文本中,这需要为字母如“y”的下伸部分预留空间。早期浏览器未能正确处理此问题,因此一些2000年左右的严格模式网站依赖于此——例如,通过将大型图片分割成多个部分并排列在表格单元格中,期望它们紧密相邻显示——因此需要中间模式来维持其运行。

但回到过去:虽然这无疑对标准(以及兼容性)有利,却引发了新问题。由于IE 6占据主导地位,且文档类型声明是可选的,因此几乎没有必要使用严格模式。其他浏览器最终不得不模拟严格模式,而非标准行为反而成了事实上的标准。关心这类问题的网页设计师(值得一提的是,我们中确实有很多人)将启用严格模式视为口号,因为这是确保与其他浏览器兼容性的绝对最低标准。

XHTML的兴衰

与此同时,W3C对HTML失去了兴趣,转而致力于开发XHTML,试图用XML的语法而非SGML来重新设计HTML。

(什么是 SGML?你可能会问。我不知道。没人知道。它是 HTML 的语法基础,这也是人们听说过它的唯一原因。)

公平地说,当时这样做确实有其合理性。HTML 通常是手动编写的(至今仍是如此),而手动编写的内容难免会出现一些错误。浏览器并不习惯直接拒绝有错误的HTML,因此它们采用了各种错误纠正技术——而与其他一切一样,不同浏览器处理错误的方式也各不相同。略微格式错误的HTML可能在IE 6中看起来运行正常(这里的“运行正常”意味着“实现你期望的功能”),但在其他浏览器中却可能变成一团糟。

W3C的解决方案是XML,因为在21世纪初,他们解决一切问题的方案都是XML。如果你不了解,XML对错误处理采取了更加明确和激进的方法——如果文档中存在解析错误,整个文档都将被视为无效。这意味着如果你依赖XHTML并在某个地方出现一个拼写错误,什么都不会渲染。只会显示错误。

这很糟糕。表面上听起来还不错,但想想看:通用XML通常是通过库动态组装的,这些库将文档视为可操作的树结构,完成后再将其转换为文本。这对于XML作为数据序列化的常见用途来说很棒,因为你的数据本身就是树结构,而XML结构大多简单重复,容易封装在函数中。

HTML 并非如此。HTML 文档几乎没有可靠的重复结构;即使这篇博客文章主要由 <p> 标签构成,其中也包含意外的 <em> 标签和偶尔出现在段落间的 <h2> 标签。用树形结构来表达这并不有趣。而这很重要,因为服务器端渲染正变得流行,生成的 HTML 仍然是通过将它视为文本流的模板来组装的。

如果 HTML 只被写成完整的静态文档,那么 XHTML 可能行得通——你写一个文档,在浏览器中看到它,知道它正常工作,没问题。但动态生成HTML并冒着特定边界情况可能导致整个网站被不可理解的浏览器错误替换的风险?这太糟糕了。

更糟糕的是,当时我们刚开始听说这个新奇的Unicode概念,而如何让它正常工作仍不明确,一个错误的UTF-8序列就足以让整个XML文档被视为格式错误!

因此,经过一番尝试后,XHTML 大多被遗忘。它的遗产以两种方式延续:

  • 它让我们所有人都停止使用大写标签名称!再见 <BODY>,你好 <body>。XML 是区分大小写的,而所有 XHTML 标签都以小写定义,因此大写标签根本无法工作。(有趣的事实:时至今日,JavaScript API 仍以大写形式报告 HTML 标签名称。)语法高亮功能的普及可能也与此有关;我们不再像 1997 年那样普遍使用记事本了。
  • 仍有不少人认为自闭合标签是必要的。你看到,HTML 有两种类型的标签:容器标签如 <p>...</p> 和标记标签如 <br>。由于 <br> 本身无法包含任何内容,因此不存在 </br> 这种形式。作为通用语法的 XML 没有这种区分;每个标签都必须闭合,但作为快捷方式,你可以写 <br/> 来表示 <br></br>。XHTML 已经死亡多年,但不知为何,我仍然看到有人在普通 HTML 文档中使用 <br/>。在 XML 之外,这个斜杠没有任何作用;HTML5 为了兼容性而定义了它,但它会被静默忽略。它甚至可能带来危害,因为它可能会让你误以为 <script/> 是空的 <script> 标签——但在 HTML 中,它绝对不是!

我唯一怀念 XHTML 的地方是,你可以将其与 XSLT(XML 模板元语言)结合,实现无需脚本的浏览器内模板化(即在整体网站布局中插入页面特定内容)。这是迄今为止唯一可能实现的方式,当它正常工作时确实酷毙了,但当它不工作时,缺点过于严重。此外,XSLT 完全令人费解。

CSS 布局的开端

回到 CSS!

你是一位有志于成为网页设计师的人。出于某种原因,你想尝试使用 CSS 来布局整个页面,尽管它显然只是用于颜色等内容。你会怎么做?

如我之前所提,你的核心问题是“将元素并排放置”。将元素“叠加”放置则不是问题——这是 HTML 的正常行为。大家使用表格的根本原因在于,你可以将内容随意放入表格单元格中,并使其以列的形式并排布局。

然而,表格似乎已不再流行。CSS 2 添加了一些与表格各部分对应的元素显示模式,但要使用它们,你必须像真实表格一样拥有三层嵌套结构:表格本身、行,然后是单元格。这似乎并不是一个巨大的进步,而且无论如何,IE 直到遥远的未来才支持它们。

还有那个 position 属性,但它似乎让内容更经常地重叠。嗯。

那还剩下什么?

只有一个工具:float

我曾说 float 原本是为杂志风格的“拉出”图片设计的,这没错,但 CSS 对它的定义相当通用。从原则上讲,它可以应用于任何元素。如果你想创建一个侧边栏,可以让它向左浮动并占用页面宽度的 20%,这样就会得到类似以下效果:

+---------+
| sidebar | Hello, and welcome to my website!
|         |
+---------+

唉!浮动元素有一个次要行为,即文本会绕其排列。如果页面文本比侧边栏更长,文本会绕到侧边栏的下方,从而破坏视觉效果。但别担心,CSS规定浮动元素之间不会相互绕排,因此只需将主体内容也设置为浮动即可!

+---------+ +-----------------------------------+
| sidebar | | Hello, and welcome to my website! |
|         | |                                   |
+---------+ | Here's a longer paragraph to show |
            | that my galaxy brain CSS float    |
            | nonsense prevents text wrap.      |
            +-----------------------------------+

这种方法虽然有效,但其局限性比表格更明显。例如,如果您添加了页脚,它会尝试将页脚放在正文文本的右侧——请记住,所有这些都是“拉”浮动,因此就浏览器而言,“光标”仍然位于顶部。因此,你需要使用clear属性,将元素置于所有浮动元素下方以解决此问题。如果你将侧边栏设置为20%宽度、正文设置为80%宽度,那么两者之间的边距会累加到100%,导致页面宽度超过视口,从而出现难看的水平滚动条,这时你还得做一些奇怪的数学计算来修复这个问题。如果两部分有边框或背景,那么它们高度不同会显得非常明显,因此你需要做一些真正荒谬的事情来修复这个问题。而更认真的作者注意到,屏幕阅读器会在到达正文文本之前先读取整个侧边栏,这对视障访客来说是一种相当不礼貌的行为,因此他们想出了更复杂的设置,以实现三栏布局,其中中间一栏在 HTML 中首先出现。

结果是一个看起来不错、工作良好且正确缩放的设计,但背后是一团奇怪的CSS混乱。你所写的任何内容都与你想实现的内容不对应——这些是设计的主要部分,而不是一次性引用!很难理解布局相关CSS与屏幕上显示内容之间的关系,而这种情况在好转之前会变得更糟。

缩略图网格 2

借助新工具,我们可以改进这个缩略图网格。原有的基于表格的布局,即使你不关心标签语义,也极其繁琐。现在我们可以做得更好!

<ul class="thumbnail-grid">
    <li><img src="..."><br>caption</li>
    <li><img src="..."><br>caption</li>
    <li><img src="..."><br>caption</li>
    ...
</ul>

这是CSS的理想状态:HTML以某种合理形式包含页面数据,而CSS则描述其实际呈现方式。

遗憾的是,由于我们只能使用float作为工具,结果显得有些粗糙。这个新版本确实能更好地适应各种屏幕尺寸,但需要一些技巧:单元格必须设置为固定高度,整个网格的居中对齐相当复杂,而且当元素更宽时,网格效果会完全失效。很明显,我们想要的是更像表格的东西,但列数要灵活。这只是伪造的。

你还需要这个奇怪的“clearfix”东西,这是一个在这个时代臭名昭著的咒语。请记住,浮动不会移动“光标”——这是我使用的虚假概念,但非常接近。这意味着这个仅包含浮动元素的<ul>标签完全没有高度。它在开始处结束,所有浮动缩略图都溢出到其下方。更糟糕的是,由于后续元素没有浮动“兄弟”元素,它们会完全忽略缩略图,并从空“网格”下方正常渲染——从而产生重叠的混乱!

解决方法是在列表末尾添加一个不占用空间的占位元素,并为其设置 CSS clear: both 属性——将其置于所有浮动元素下方。这有效地将 <ul> 的底部推至所有单独缩略图下方,使其紧密贴合。

后来浏览器支持了 ::before::after “生成内容”伪元素,这让我们可以完全避免使用占位元素。2000年代中期的样式表中常常充斥着类似的代码:

.thumbnail-grid::after {
    content: '';
    display: block;
    clear: both;
}

尽管如此,这总比使用表格好。

DHTML

作为对 JavaScript 世界的简要介绍,新的 position 属性确实赋予了我们动态布局的能力。我坚决反对这种异端行为,不仅因为没有人真正做对过,但它确实为一些小玩意儿提供了便利。

由此开启了“动态HTML”时代——即受JavaScript影响的HTML,这一术语如今已完全过时,因为我们甚至无法再用纯静态代码搭建一个博客了。在早期,它还比较无害,青少年们会在鼠标光标后面添加闪光效果,或者添加实时滴答作响的小型模拟时钟。

这些东西最受欢迎的来源是 Dynamic Drive,这个网站奇迹般地仍然存在,可能还有许多自 21 世纪初以来就没有更新过的玩具。

但如果你不想费劲寻找,这里有一个例子:每年(除了今年我忘了,抱歉),我喜欢在生日那天给我的博客添加彩带和其他无聊的东西。我非常懒惰,所以这个传统是从使用我从某个地方找到的这个脚本开始的,该脚本最初是为雪花效果设计的。它的工作原理是在页面上放置大量图像,赋予它们position: absolute属性,并反复精确调整其坐标。

与之对比的是我几年前从头开始编写的版本(https://c.eev.ee/PARTYMODE/),它仅需一点点 JavaScript(https://c.eev.ee/PARTYMODE/partymode.js)来设置图片,然后让浏览器通过 CSS 进行动画处理。虽然功能稍逊一筹,但让浏览器承担全部工作,甚至可能借助硬件加速。我们已经走了多远。

Web 2.0

黑暗时代不会永远持续。多种因素推动我们走向光明。

其中最大的因素是Firefox——或者,如果你够酷,最初是Phoenix,然后是Firebird——它在2004年11月达到1.0版本,并开始对IE造成严重冲击。这个重新编写的Netscape 6浏览器核心,Mozilla套件的核心,被提取出来成为一个独立的浏览器。它速度快,操作简便,符合更多标准,但这些都不重要。

不,Firefox真正站稳脚跟是因为它拥有_标签页_。IE 6没有标签页;如果你想打开第二个网页,就得打开另一个窗口。那简直糟糕透顶,兄弟。Firefox堪称奇迹。

当然,Firefox 并不是第一个支持标签页的浏览器;完整的 Mozilla 套件浏览器就支持标签页,而那个鲜为人知(但充满斗志!)的 Opera 浏览器早已支持标签页多年。但正是 Firefox 取得了成功,原因多种多样,其中最重要的是它没有像 Opera 那样在顶部有一个巨大的广告栏。

设计师们当然也以标准为由力推Firefox;只是这种论调主要吸引的是其他设计师,而非他们的父母。其中最受欢迎且最引人注目的演示之一是Acid2测试,旨在测试当时现代网络标准的多种功能。它有一个优势,即在正确渲染时会显示一个可爱的笑脸,而在IE 6中则会变成一个令人发指的噩梦场景。早期版本的Firefox并不完美,但它无疑更接近标准,而且你可以_看到_它在不断进步,直到Firefox 3发布时完全通过测试。

此外,Firefox还拥有更快的JavaScript引擎,即使在JIT技术普及之前也是如此。快得多。据我所记得,IE 6在实现getElementById时会遍历整个文档,尽管ID是唯一的。看看一些旧版jQuery发布公告; 它们通常会附带一些性能图表,而其他所有浏览器在性能上都远超 IE 6 至 8。

哦,还有那件事——IE 6 简直是个巨大的安全漏洞,尤其是它对任意二进制组件的原生支持,只需在某个晦涩的对话框上点击“是”,就能获得对系统的不受限制访问权限。这肯定没能提升它的声誉。

无论如何,随着其他浏览器开始占据重要市场份额,就连最固执的设计师也无法再只针对 IE 6 进行优化就草草了事。现在使用严格模式有了理由,关注兼容性和标准也有了理由——而 Firefox 正在不断努力更好地遵循这些标准,而 IE 6 却停滞不前。

(我认为这种影响为OS X打开了市场,也为iPhone的诞生铺平了道路。我不是开玩笑!想想看,如果iPhone浏览器因为所有人都还在针对IE 6进行优化而无法与任何内容兼容,它基本上就是一个更昂贵的Palm。记住,最初苹果甚至不想要原生应用;它押注于网络。)

(说到这里,Safari于2003年1月发布,基于KDE的Konqueror浏览器所使用的KHTML引擎的分支。我当时可能正在使用KDE,所以这非常令人兴奋,但其他人并不关心OS X及其2%的市场份额。)

另一个重大因素出现在2004年4月1日,谷歌宣布推出Gmail。哈哈!一个有趣的玩笑。不是糟糕的网页邮件?谷歌,这真是个好主意。

哦。哦,该死。哦,他们不是开玩笑的。这到底是怎么工作的

答案,正如每位网页开发者现在所知,是XMLHttpRequest——之所以这样命名,是因为没有人曾经用它来请求XML。显然它是微软为Exchange开发的,后来被Mozilla早期克隆,但我只是从维基百科上读到的,你可以自己去查。

关键在于,它允许你从JavaScript中发起HTTP请求。现在你可以只更新页面的一部分,用新数据在后台完成,无需重新加载。_没人_听说过这个东西,所以当谷歌推出一个基于它的完整邮件客户端时,简直就像魔法一样。

可以说,整个事情是一个错误,导致了一个地狱般的未来,静态页面在后台使用XHR加载三段文本,而没有任何理由,但这是另一个帖子。

沿着类似的思路,2006年8月发布了jQuery,另一个奇迹。它不仅弥合了IE的“JScript”API与其他人采用的标准方法之间的差异(此前已有其他库实现过这一点),还使得一次性处理整个元素组变得非常容易,而这在历史上一直是个大麻烦。现在你可以相当轻松地从JavaScript中应用CSS到各个地方!这是一个糟糕的主意!但一切都太糟糕了,我们还是这么做了!

等等,我听到你大喊。这些内容是关于 JavaScript 的!这不是一篇关于 CSS 的文章吗?

你完全正确!我提到JavaScript的崛起,是因为我认为它直接导致了CSS的现代状态,这得益于一个重要因素的提升:

雄心

Firefox 向我们展示了浏览器可以真正实现改进——每次在 Acid2 测试中的进步都令人兴奋。Gmail 向我们展示了网络可以做更多事情,而不仅仅是显示带有雪花图案的纯文本。

人们开始渴望实现更复杂的功能。

问题是,浏览器当时还没有真正变得更好。Firefox 在某些方面更快,且更严格地遵循 CSS 规范,但它并未在根本上实现浏览器本不应具备的功能。唯一改进的是工具链,而这主要影响了 JavaScript。CSS 是一种静态语言,因此无法通过编写库来提升其性能。虽然可以使用 JavaScript 生成 CSS,但这绝对是个糟糕的主意。

另一个问题是,CSS 2 仅擅长样式化矩形。这在 90 年代尚可接受,当时每个操作系统都采用矩形嵌套矩形的视觉风格。但如今我们已进入 Windows XP 和 OS X 时代,一切都变得光滑闪亮,采用曲线塑料设计。在文件浏览器中拥有圆角和整齐阴影的弧线,而网页上却没有,这多少有些尴尬。

于是,一个新的黑暗时代开始了。

CSS 技巧的时代

设计师们想要很多 CSS 无法提供的功能。

  • 圆角是一个大问题。方形角已经过时,现在每个人都想要带有圆角的按钮,因为它们是未来。 (原生按钮也因某种原因过时了。)遗憾的是,CSS无法实现这一点。你的选择是:
    1. 制作一个固定大小的圆角矩形背景图像,并将其应用于固定大小的按钮。或许干脆放弃文字,直接将整个按钮做成图片。真糟糕。
    2. 制作一个通用背景图片并缩放以适配。更巧妙,但角落可能无法完美圆角。
    3. 制作圆角矩形,裁剪角落和边缘,然后将它们放入一个 3×3 的表格中,按钮标签置于中间。更好的方法是使用 JavaScript 实时实现。
    4. 算了,干脆把整个网站做成一个大 Flash 应用吧,哈哈

    另一个问题是 IE 6 不支持 8 位 alpha 通道的 PNG 图片;它只能正确显示 1 位 alpha 通道的 PNG 图片,即每个像素要么完全不透明,要么完全透明,就像 GIF 图片一样。你只能接受锯齿边缘,将纯色背景嵌入图像,或应用各种围绕这个该死的垃圾实现的修复方案:

    filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='bite-my-ass.png');
    
  • 类似地:渐变和阴影!没有这些,你就无法制作出炫酷的塑料按钮。但这里你基本上只能再次制作图像。
  • 半透明效果也一团糟。大多数浏览器从很早开始就支持CSS 3的opacity属性……除了IE,它需要另一个微软专有的filter属性。如果你只想让背景半透明,就需要使用半透明PNG,而……你知道的。
  • 从一开始,jQuery 就内置了 fadeIn 等动画效果,这些效果开始在各处流行。这有点像网络版的 00 年代中期(包括我在内)每个 Linux 用户都使用的那个该死的 Compiz 立方体效果。显然,在大多数有趣的场景中,你需要 JavaScript 来触发元素的消失,但用它来控制实际的动画效果有点过于繁琐,给浏览器带来了负担。标签式浏览加剧了这个问题,因为浏览器大多是单线程的,而且出于各种原因,每个打开的页面都在同一个线程中运行。
  • 哦!表格行交替背景颜色。这种设计如今已过时,但我认为这很可惜,因为它确实让表格更易于阅读。但CSS对此没有解决方案,因此你只能给每隔一行添加类名如<tr class="odd">(希望表格是通过代码生成的!)或使用一些jQuery技巧。
  • CSS 2 引入了 > 子元素选择器,因此你可以编写类似 ul.foo > li 的代码来样式化特殊列表,而不会破坏嵌套列表,但 IE 6!不!支持!它!

不过,这些都只是美学问题。如果你对布局感兴趣,那么 Firefox 的崛起让你的生活既变得容易又变得困难。

还记得 inline-block 吗?Firefox 2 实际上支持它!虽然它有 bug 且隐藏在厂商前缀后面,但它基本上能用,这让设计师开始尝试使用它。然后 Firefox 3 基本上完全支持它,这感觉就像奇迹一样。我们缩略图网格的第3版只需设置宽度和inline-block即可:

.thumbnails li {
    display: inline-block;
    width: 250px;
    margin: 0.5em;
    vertical-align: top;
}

inline-block 的基本原理是,其内部内容行为类似于块级元素,但块级元素本身会被放置在常规的文本流中,就像一张图片一样。每个缩略图都包含在一个盒子中,但这些盒子彼此相邻,由于它们具有相同的宽度,因此会形成一个网格。由于功能上相当于一行文本,因此无需像使用浮动布局时那样处理对页面其他部分的异常影响。

当然,这种方法也有一些缺点。例如,你无法利用剩余空间,因此在极端屏幕尺寸下,右侧可能出现大片空白区域。宽单元格仍可能破坏网格布局。但至少这不是浮动布局。

一个小问题:IE 6。它在技术上支持 inline-block,但仅限于天然为 inline 的元素——如 <b><i>,而非 <li>。也就是说,你实际上不想(或不会想到)在这些元素上使用 inline-block。唉。

幸运的是,某位天才发现了 hasLayout,这是 IE 中的一个内部优化,用于标记元素是否……嗯……具有……布局。我也不知道具体原理。总之它会改变元素的渲染路径——使其以不同方式出现 bug,就像按元素启用怪异模式!关键是,只要添加几行代码,上述方法在 IE 6 中就能生效:

.thumbnails li {
    display: inline-block;
    width: 250px;
    margin: 0.5em;
    vertical-align: top;
    *zoom: 1;
    *display: inline;
}

前导星号会使属性无效,因此浏览器应忽略整行……但出于某种我无法理解的原因,IE 6会忽略星号并接受规则的其余部分。(几乎任何标点符号都有效,包括连字符或——我个人最喜欢的——下划线。) zoom 属性是微软的扩展属性,用于缩放内容,其副作用是赋予元素“布局”属性。而 display: inline 本应使每个元素的内容溢出到一行文本中,但 IE 将具有“布局”属性的 inline 元素大致视为 inline-block

在此我们看到了 CSS 混乱的真正潜力。针对特定浏览器的规则,采用故意错误的语法(某一浏览器会忽略该语法),以实现一种仍无法通过所写内容明确描述的效果。整套教程专门用于解释如何实现一个简单的网格布局,但要确保它在大多数浏览器上都能正常工作。你还会看到* htmlhtml > /**/ body以及各种其他乱七八糟的代码。完整列表在此!还记得之前提到的“clearfix”技巧吗?其完整版本,兼容所有浏览器,却更糟糕:

.clearfix:after {
  visibility: hidden;
  display: block;
  font-size: 0;
  content: " ";
  clear: both;
  height: 0;
}
.clearfix { display: inline-block; }
/* start commented backslash hack \*/
* html .clearfix { height: 1%; }
.clearfix { display: block; }
/* close commented backslash hack */

难怪人们开始抱怨CSS?

这是一个盲目复制粘贴的时代,人们怀着沮丧的希望试图让该死的东西正常工作。典型案例:有人(我曾找到过原始来源但现在找不到)提出了这个愚蠢的主意,总是设置 body { font-size: 62.5% },这是因为“相对单位很好”以及想要覆盖浏览器默认的16px字体大小(结果发现, 是正确的),以及处理IE浏览器的漏洞。他后来很快收回了这一做法,但为时已晚,如今成千上万的网站都以这种方式作为“最佳实践”开始。这意味着如果你想调整浏览器的默认字体大小,无论增大还是缩小,都会遇到问题——缩小后网页内容会变得微小,增大后内容仍会比预期小得多,进一步增大以补偿时,那些真正尊重你设置的网站内容又会变得异常巨大。至少现在我们有了更好的页面缩放功能,我想。

哦,还有一点要记住:Stack Overflow当时还不存在。这些内容完全是通过口口相传传播的。如果你够幸运,可能会知道一些关于网站的网站,比如quirks modeEric Meyer的网站

事实上,你可以看看Meyer的css/edge网站,那里有一些令人惊叹的例子,展示了人们在2002年甚至只使用CSS 1时所做的事情。我仍然认为complexspiral是纯粹的天才之作,尽管如今你可以用opacity和一张图片就能实现。raggedfloat 中的方法直到几年前才在 CSS 中获得原生支持,借助 shape-outside 属性!他还为我们带来了CSS重置,消除了不同浏览器默认样式之间的差异。

(我无法强调埃里克·迈耶(Eric Meyer)在CSS领域是多么具有开创性的人物。六年前,他的小女儿丽贝卡(Rebecca)去世后,她以自己独特的CSS颜色名称rebeccapurple被永恒纪念。这就是网络社区对他评价之高的原因。我得先去为这个故事哭一会儿。)

未来正逐步到来

设计师和开发者一直在突破浏览器能力的边界。浏览器处理这些功能时表现得相当糟糕。所有修复方案、变通方法和库都显得晦涩难懂、脆弱易碎、错误频发且/或资源消耗过大。

显然,浏览器需要一些新功能。但随意添加功能并不能解决问题;微软已经做过太多类似尝试,结果大多一团糟。

几项艰难的尝试开始了。由于万维网联盟(W3C)仍固步自封——甚至明确拒绝了对HTML的改进提案,转而推崇XML——来自苹果、Mozilla和Opera等活跃浏览器厂商的开发者决定自立门户。WHATWG于2004年6月成立,并开始着手开发HTML5。(它最终对错误处理进行了非常明确的定义,这完全消除了对XHTML的需求,并消除了在处理任意HTML时的一些安全问题。此外,它还为我们带来了一些新功能,如原生音频、视频和用于日期、颜色等控件的表单控件,这些功能之前一直由JavaScript驱动的自定义控件笨拙地处理。而且,嗯,现在仍然经常如此。)

然后是CSS 3。我不确定它何时开始存在。它缓慢地、艰难地出现,就像一只小鸡从蛋中孵化出来,花了好长时间才在任何地方真正实现。

我不得不多做一些有根据的猜测,但我认为它始于border-radius。具体来说,是-moz-border-radius。我不知道它何时首次被引入,但Mozilla的错误跟踪器中最早的记录可以追溯到1999年。

你看,Firefox的用户界面是通过CSS渲染的。如果Mozilla想做一些无法通过CSS实现的事情,他们会添加一个自己的属性,并用-moz-前缀来表明这是他们的发明。而当这样做不会造成实际危害时,他们会将该属性对网站开放。

因此,我推测 CSS 3 的推动真正开始于 Firefox 流行起来,设计师们发现了 -moz-border-radius。突然间,内置的圆角变得可用!无需在 Photoshop 中折腾;只需写一行代码即可!几乎在一夜之间,到处都是圆角设计。

从那时起,事情开始滚雪球般发展。新的CSS特性逐一解决了常见问题,这些特性被整合到一个新的CSS版本中:CSS 3。其中最重要的特性是解决之前提到设计问题的方案:

  • 圆角,由border-radius提供。
  • 渐变,由linear-gradient()及其相关特性提供。
  • 多个背景,虽然这不是一个紧迫的问题,但它使其他一些事情变得更容易。
  • 透明度,由 opacity 和带有 alpha 通道的颜色提供。
  • 盒阴影。
  • 文本阴影,虽然在 CSS 2 中存在,但在 2.1 中被删除,而且从未实现过。
  • 边框图像,让你可以实现比单纯的圆角边框更复杂的效果。
  • 过渡和动画,现在无需 jQuery(或任何 JavaScript)即可轻松实现。
  • :nth-child(),纯粹通过 CSS 解决了交替行问题。
  • 变换。等等,什么?这其实是从 SVG 泄露过来的,而浏览器也被期望实现 SVG,而 SVG 就是围绕变换构建的。代码已经存在,所以,嘿,现在我们可以使用 CSS 旋转东西了!以前可做不到这一点。酷。
  • 网络字体,虽然 CSS 中已经存在一段时间,但仅在 IE 中实现,且使用的是带有 DRM 的奇怪字体格式。现在我们不再局限于Windows自带的四种糟糕字体,而其他人也没有这些字体!

这些功能相当不错!它们并未解决布局问题,但确实解决了设计师此前不得不通过大量图片和/或JavaScript来笨拙解决的美学问题。这意味着需要下载的内容更少,且更多文本替代图片,这两点对网络都相当有利。

讽刺的是,这些功能所能实现的各种效果几乎立即过时,如今我们又回到了平淡的矩形时代。

浏览器前缀地狱

唉!世界仍未恢复正常。

我认为,这些新功能中的部分最初是由浏览器厂商开发的并添加了前缀。后来的一些功能则由CSS委员会设计,但在设计尚未定型时就被浏览器实现,因此也添加了前缀。

于是,_前缀地狱_就此开始,并一直延续至今。

Mozilla 拥有 -moz-border-radius,因此当 Safari 实现该属性时,将其命名为 -webkit-border-radius(“WebKit” 是苹果公司对 KHTML 的分支名称)。随后 CSS 3 规范对其进行了标准化,并将其简化为 border-radius。这意味着,若要使用圆角边框,实际上需要指定 条规则:

element {
    -moz-border-radius: 1em;
    -webkit-border-radius: 1em;
    border-radius: 1em;
}

前两条规则确保当前浏览器能正常显示效果,而最后一条则是为未来做准备:当浏览器实现标准规则并放弃前缀规则时,它将自动生效。

你必须每次都这样做,因为CSS不是编程语言,没有宏或函数之类的东西。有时Opera和IE会有自己的实现,使用-o--ms-前缀,使总数达到五个版本。渐变的情况更糟糕;语法经历了多次重大不兼容的修订,因此你甚至无法依赖复制粘贴并更改属性名称!

而且很多人,嗯,搞砸了。我不能太怪他们;我的意思是,这太糟糕了。但足够多的页面只使用了带前缀的形式,而没有使用最终形式,因此浏览器不得不继续支持带前缀的形式,时间比他们希望的要长,以避免破坏现有内容。如果带前缀的形式仍然有效,而且这是你习惯使用的形式,那么你可能仍然不会去使用不带前缀的形式。

更糟糕的是,有些人只会使用在他们偏好的浏览器中有效的那种形式。随着移动网页浏览器的兴起,这种情况变得尤为严重。iOS 和 Android 系统的内置浏览器分别是 Safari(WebKit)和 Chrome(最初基于 WebKit,现为分支版本),因此你只需使用 -webkit- 属性即可。这给 Mozilla 发布 Firefox for Android 带来了困难。

还记得IE 6的那场闹剧吗?我们又回到了那个时代!情况糟糕到Mozilla最终决定实现一系列-webkit-属性,这些属性至今仍在桌面版Firefox中得到支持。情况已经够荒谬了,Firefox现在只能通过这些属性支持某些效果,比如-webkit-text-stroke,而这个属性并未被标准化。

更妙的是,Chrome 当前的分支引擎名为 Blink,因此从技术上讲它也不应使用 -webkit- 属性。然而,事实就是如此。至少它不像 用户代理字符串混乱 那样糟糕。

浏览器厂商基本上已经放弃了前缀,现在他们将实验性功能隐藏在标志背后(因此它们只会在开发者的机器上工作),而新功能在理论上设计得更小、更容易稳定。

这种混乱可能是推动SassLESS这两种生成CSS的语言发展的主要动力。或者……可能是两种 CSS 预处理器。它们的目标非常相似:都为 CSS 添加变量、函数和某种形式的宏,让你能够消除样式表中的大量重复代码、浏览器兼容性 hack 和其他无用内容。天啊,这个博客仍然使用SCSS,尽管其使用频率随时间推移逐渐降低。

Flexbox

但随后,就像天使从天而降……Flexbox

Flexbox已经存在了很长时间——据称它在2006年的Firefox 2中就已部分支持!它经历了多次不兼容的修订,花了很长时间才稳定下来。然后IE花了很长时间才实现它,而你真的不想依赖只对一半受众有效的布局工具。直到相对较近的时期(2015年?更晚?),Flexbox才获得了足够广泛的支持,可以安全使用。我敢肯定,我仍然会遇到一些人,他们的当前版本的Safari在没有前缀的情况下完全不识别Flexbox,尽管据说Safari五年前就已取消了前缀……

总之,Flexbox 是 CSS 对一种常见 GUI 布局工具的实现:父元素包含多个子元素,父元素拥有一定可用空间,并自动将该空间分配给子元素。你知道的,它就是让元素“并排排列”。

基本原理是:浏览器计算父元素的可用空间和每个子元素的“初始大小”,确定剩余空间的大小,并根据每个子元素的灵活性进行分配。以工具栏为例:你可能希望每个按钮具有固定大小(弹性为0),但希望添加一些间隔元素来平等分配剩余空间,因此你会给它们设置弹性为1。

完成上述操作后,您还可以使用一系列提升用户体验的选项:您可以将额外空间分配到子元素之间,可以让子元素拉伸到相同高度或以各种方式对齐,甚至可以让它们折行排列以适应屏幕空间!

借助这一功能,我们可以再次尝试实现那个缩略图网格

.thumbnail-grid {
    display: flex;
    flex-wrap: wrap;
}
.thumbnail-grid li {
    flex: 1 0 250px;
}

这简直是奇迹。我一夜之间就忘了inline-block,一直对这个功能垂涎三尺,直到它被广泛支持。它甚至非常清楚地表达了我想要的效果。

……几乎如此。它仍然存在一个问题,即过宽的单元格会破坏网格,因为它仍然是一个水平行,被折行到多个独立的行中。不过,它确实非常酷,并且解决了许多其他布局问题。这显然已经足够好了。除非……?

我认为 flexbox 的广泛采用标志着 CSS 现代时代的开始。但还有一个挥之不去的问题……

IE 的缓慢而痛苦的消亡

IE 6消失得非常、非常、非常缓慢。直到2010年初左右,其市场份额才降至10%以下(仍占相当大的比例)。

Firefox在2004年底达到1.0版本。IE 7直到两年后才发布,它仅提供了有限的改进,与为IE 6开发的应用程序存在兼容性问题,而坚持使用IE 6的用户(其中许多人并非IT专业人士)通常看不到升级的必要性。Vista预装了IE 7,但Vista本身并不成功——我认为它从未在整个生命周期内接近超越XP。

其他因素包括企业 IT 政策,这些政策常常以“永远不要升级任何东西”的形式存在——而且往往有充分的理由,因为我听到了无数关于内部应用程序只能在 IE 6 上运行的可怕故事。还有整个韩国,他们法律上被要求使用IE 6,因为他们通过法律规定了一些安全要求 写入法律,而这些要求只能通过 IE 6 的 ActiveX 控件实现。

因此,如果你维护的网站被企业员工或居住在其他国家的人使用——更糟糕的是,被他们“强制要求”使用——那么你几乎别无选择,只能继续支持IE 6。制作小型个人工具和网站的人们很早就放弃了对IE 6的兼容性,并在他们的网站上贴满了越来越令人讨厌的横幅,嘲笑任何敢于使用IE 6的人……但如果你是某人的老板,为什么你会告诉他们可以放弃20%的潜在受众?只要更努力工作就行了!

随着时间的推移,这种紧张局势愈演愈烈,因为CSS变得越来越强大,而IE 6仍然是一个拖累。它甚至无法理解PNG alpha,除非使用工作around,而与此同时,我们开始获得更多关键功能,如HTML5中的原生视频。工作around变得越来越复杂,而你基本上无法使用的功能列表也越来越长。(我本想展示我的博客在IE 6中的样子,但我想它甚至无法连接——它支持的TLS协议如此陈旧且存在漏洞,以至于大多数服务器都已禁用!)

顺便提一下,要感谢YouTube团队中的某些人,他们在2009年7月 添加了一个警告横幅,敦促IE 6用户切换到任何其他浏览器——而无需征得任何人批准。“一个月内……全球IE 6流量下降了超过10%。” 并非所有英雄都身着斗篷。

我认为IE 6支持终结的起点是YouTube正式停止支持IE 6的那一天——2010年3月13日,距其发布已近九年。我不知道YouTube对企业用户或韩国政府的影响有多大,但一家大型互联网公司放弃支持整个浏览器,无疑释放了强烈的信号。

当然,IE还有其他版本,其中许多版本本身就是一团糟。但每个后续版本都变得越来越不麻烦,如今你甚至不需要过多考虑在IE(现为Edge)上的测试。恰逢微软放弃自己的渲染引擎,将浏览器改造成Chrome克隆版。

现在

CSS 现在相当不错。你不需要使用奇怪的 hack 技巧来让元素并排显示。浏览器开发工具现在内置其中,而且非常出色——Firefox 甚至开始专门警告你,当某些 CSS 属性由于其他属性的值而无法生效时!像“堆叠上下文”(不管那是什么)这样的隐含副作用现在可以显式设置,使用属性如 isolation: isolate

事实上,让我列出我能想到的所有现在可以在CSS中实现的功能。这并不是一份关于CSS样式所有可能用途的指南,但如果你自2008年以来就没有更新过CSS知识,我希望这能激发你的兴趣。而这些内容仅仅是CSS!过去那些曾经不可能实现、令人头疼或需要笨拙插件的功能,现在都已原生支持——音频、视频、自定义绘图、3D渲染……更不用说JavaScript在易用性方面的大幅提升。

布局

一个Grid容器几乎可以完成表格能做的一切,甚至更多,包括自动确定能容纳多少列。这简直太棒了。下面会详细介绍。

一个Flexbox容器可以将子元素以行或列的形式排列,允许每个子元素声明其“默认”大小以及希望占用剩余空间的比例。弹性盒可以折行、重新排列子元素而不改变源顺序,并以多种方式对齐子元素。

Columns 将文本填充到多个列中。

box-sizing 属性允许您按元素basis启用 IE 盒模型,当您需要整个元素占用固定空间并需要 padding/borders 从该空间中_减去_时。

display: contents 将元素的内容直接输出到其父元素中,仿佛该元素不存在一样。display: flow-root 基本上是一个自动的清除浮动方案,只是来得晚了十年。

width 现在可以设置为 min-contentmax-contentfit-content() 函数,以实现更灵活的行为。

white-space: pre-wrap 保留空白,但在必要时断行以避免溢出。同样有用的还有 pre-line,它将连续的空格压缩为单个空格,但保留字面上的换行符。

text-overflow 在文本溢出时使用省略号(或自定义字符)截断文本,而非简单截断。规范中还规定了文本淡出功能,但目前尚未实现。

shape-outside 用于修改浮动元素周围文本的包裹形状。甚至可以使用图像的 alpha 通道作为形状。

resize 为任意元素添加缩放手柄(只要该元素具有 overflow 属性)。

writing-mode 设置文本流动的方向。如果您的设计需要支持多种书写模式,一些提及左/右/上/下的 CSS 属性有替代方案,这些替代方案以书写模式为基础描述方向:inset-blockinset-inline 用于位置,block-sizeinline-size 用于宽度/高度,border-blockborder-inline 用于边框,以及类似的用于填充和边距。

美学

过渡会在值发生变化时平滑地插值,无论是由于:hover等效果,还是例如通过JavaScript添加类。动画 与过渡类似,但会自动播放预定义的动画。两者均可使用多种不同的缓动函数

border-radius 可将盒子的角落进行圆角处理。所有角落的大小可以不同,且可以是圆形或椭圆形。该曲线也适用于边框、背景以及任何盒子阴影。

box-shadow 可用于实现明显的投射阴影效果。您还可以使用多个阴影和 inset 阴影来实现各种巧妙效果。

text-shadow 顾名思义,用于为文本添加阴影,不过您也可以叠加多个阴影以粗略模拟文本轮廓。

transform 允许您对元素应用任意矩阵变换——即您可以进行缩放、旋转、倾斜、平移以及透视变换,且不会影响布局。

filter(与 IE 6 中的不同)提供了一系列特定的视觉滤镜,您可以将其应用于元素。其中大部分影响颜色,但也有 blur()drop-shadow()(与 box-shadow 不同,它应用于元素的外观而非其包含的盒子)。

linear-gradient()radial-gradient(), 新的且支持较少的 conic-gradient(),以及它们的 repeating-* 变体,均可生成渐变图像,并可在 CSS 中任何预期使用图像的位置使用,最常见的是作为 background-image

scrollbar-color 用于更改滚动条颜色,但其缺点是在当前浏览器中会将滚动条简化为非常简单的滑块和轨迹。

background-size: covercontain 会按比例缩放背景图像,使其要么足够大以完全覆盖元素(即使被裁剪),要么足够小以精确适配元素内部(即使未覆盖整个背景)。

object-fit 是一个类似的概念,但适用于非背景媒体,如 <img>。相关的 object-positionbackground-position 类似。

支持多个背景,这在使用渐变时特别有用——你可以叠加多个渐变、其他背景图像以及底部的一层纯色。

text-decoration 比以前更丰富;现在你可以设置线条的颜色,并使用多种不同类型的线条,包括虚线、点线和波浪线。

CSS 计数器 可用于以任意方式为任意元素编号,将 <ol> 的计数功能扩展到任何你想要的元素集合。

::marker 伪元素允许您样式化列表项的标记框,甚至可以直接用自定义计数器替换它。浏览器支持情况参差不齐,但正在逐步改善。类似地,@counter-style 规则可实现全新的计数器样式(如 1 2 3、i ii iii、A B C 等),您可在任何位置使用,但目前仅 Firefox 支持该功能。

image-set() 提供了一组候选图像,并允许浏览器根据用户屏幕的像素密度选择最合适的图像。

@font-face 定义可下载的字体,但您可通过使用 Google Fonts 避免研究其正确用法。

pointer-events: none 使元素完全忽略鼠标操作;它无法被悬停,点击会直接穿过它作用于下层元素。

image-rendering 可强制图像以最近邻方式缩放而非插值缩放,但浏览器支持仍不完善,可能需要同时添加一些厂商专有属性。

clip-path 可将元素裁剪为任意形状。还有 mask 用于任意 alpha 遮罩,但浏览器支持情况参差不齐,而且这个属性可真够复杂的。

语法与其他

@supports 允许你根据浏览器支持的情况显式编写不同的 CSS,不过如今它的实用性远不如 2004 年时那么高。

A > B 选择直接子元素。A ~ B 选择兄弟元素。A + B 选择直接(元素)兄弟节点。方括号可以用于基于属性进行选择;最常见的是 input[type=checkbox],但你也可以通过匹配 <a href> 的部分来实现有趣的功能。

现在有大量伪类。其中许多用于表单元素::enabled:disabled:checked:indeterminate(也适用于单选按钮和 <option>); :required:optional; :read-write:read-only; :in-range/:out-of-range:valid/:invalid(用于 HTML5 客户端表单验证); :focus:focus-within; 以及 :default(用于选择默认表单按钮以及任何预选的复选框、单选按钮和 <option> 选项)。

对于在同级元素中定位特定元素,我们有::first-child:last-child:only-child:first-of-type:last-of-type:only-of-type(其中“type”指标签名); 以及 :nth-child():nth-last-child():nth-of-type(),以及 :nth-last-of-type()(用于选择每第二个、第三个等元素)。

:not() 用于反转选择器。:empty 用于选择没有子元素且没有文本内容的元素。:target 选择通过 URL 片段跳转到的元素(例如,如果地址栏显示 index.html#foo,则选择 ID 为 foo 的元素)。

::before::after 现在应使用两个冒号,以表明它们创建伪元素,而非仅仅作用于所附着的选择器。::selection 自定义选中文本的显示方式;::placeholder 自定义文本字段中占位符文本的显示方式。

媒体查询 能够实现多种功能,使页面能够根据查看方式进行适配。prefers-color-scheme 媒体查询可告知用户系统是否设置为浅色或深色主题,从而无需询问即可进行相应调整。

您可以使用 #rrggbbaa#rgba 格式编写半透明颜色,也可以使用 rgba()hsla() 函数。

角度 可以使用 turn 单位表示为圆周的分数。当然,degrad(以及 grad)也同样可用。

CSS 变量(官方名称为“自定义属性”)允许您指定任意命名的值,这些值可以在任何需要值的地方使用。您可以利用此功能减少 JavaScript 中对 CSS 的手动调整(例如,通过设置 CSS 变量而非手动调整多个属性来重新着色页面复杂部分),或创建一个可响应祖先设置的变量的通用组件。

calc() 计算任意表达式并自动更新(尽管其功能在一定程度上被 box-sizing 属性所替代)。

vwvhvminvmax 单位 允许您将长度指定为视口宽度或高度的百分比,或者两者中较大的/较小的那个。


呼!我肯定还有很多内容没提到,大家在评论中肯定会有更长的有趣细节列表。感谢大家帮我节省了时间!现在我可以停止浏览 MDN,开始做这个最后的有趣部分了。

最先进的缩略图网格

终于,我们来到了构建缩略图网格的最终且客观正确的方法:使用CSS Grid。你可以通过其名称中的“Grid”一词判断这是正确的选择。现代CSS特性非常出色,能够让你直接表达需求并实现效果,而非通过隐式方式强行实现。

而且它简单至极:

.thumbnail-grid {
    display: grid;
    grid: auto-flow / repeat(auto-fit, minmax(250px, 1fr));
}

完成!这为你提供了一个网格。你还可以像使用 flexbox 一样,对其他属性进行各种调整,但这就是基本原理。你甚至不需要为元素本身添加样式;大部分布局工作都在容器中完成。

grid 缩写属性 看起来有点令人望而生畏,但只是因为它非常灵活。它的意思是:按行填充网格,生成所需的行数;创建尽可能多的 250px 列,并平等地分配剩余空间。

CSS 网格布局对于布局 <dl> 也很方便,而历史上这曾是一个令人头疼的问题——一个 <dl> 包含任意数量的 <dt> 元素,随后是任意数量的 <dd> 元素(包括零个),而网格出现之前,唯一能对这种布局进行样式设置的方法是让 <dt> 元素浮动,这意味着它们必须具有固定宽度。现在,你只需告诉 <dt> 标签放在第一列,<dd> 标签放在第二列,网格布局会自动处理剩下的部分。

至于页面布局?那个侧边栏部分?看看这有多简单:

body {
    display: grid;
    grid-template:
        "header         header          header"
        "left-sidebar   main-content    right-sidebar"
        "footer         footer          footer"
        / 1fr           6fr             1fr
    ;
}
body > header {
    grid-area: header;
}
#left-sidebar {
    grid-area: left-sidebar;
}
/* ... etc ... */

完成。简单。标记中各部分的出现顺序也不重要。

另一方面

网络仍然有点混乱。很多人甚至不知道 flexbox 和 grid 现在几乎普遍支持 几乎普遍;但考虑到从早期规范到广泛实现所花费的时间,我不能怪他们。我昨天刚看到一个全新的网站,主要由各种宽度的“缩略图”列表组成,而且它使用了浮动布局!甚至没有使用inline-block!我不知道我们是如何让 everyone 了解所有实现这种布局所需的 hack 的,但不知为何,关于 flexbox 的信息却没有广泛传播。

但更糟糕的是:我仍然经常遇到使用JavaScript进行整个页面布局的网站。如果你使用uMatrix,你的第一印象就是一堆文字覆盖在另一堆文字上。这难道不是倒退吗?你到底在做什么,以至于你的页眉和侧边栏只能通过执行代码才能正确布局?页面加载时并不是没有CSS——纯HTML默认情况下不会发生文本重叠!你必须告诉它这样做!

然后是移动网页,尽管 everyone 的初衷都是好的,但它基本上已经失败了。最初的想法是,你可以使用CSS媒体查询将正常网站适配到手机屏幕上,但实际上,大多数大型网站都有完全独立的移动版本。这意味着,要么移动网站缺少大量重要功能,我不得不尴尬地在手机上操作,要么桌面网站充斥着没人真正需要的功能。

(与此同时,谷歌自己的Android版本的Docs/Sheets等应用,其功能仅为网页版本的5%?对此我也不太清楚该如何评价。)

嗯。正在认真考虑撰写一篇更详细探讨自Firefox 3时代以来CSS改进的文章,类似于我为JavaScript撰写的那篇。但这篇文章已经够长了。

那些从未实现的未来

我不知道CSS接下来会有什么新发展,尤其是现在Flexbox和Grid已经解决了我们所有的问题。我隐约听说有人在研究更全面的数学支持,以及可能类似 Sass 中用于修改颜色的函数。有一个 绘画 API,它允许你使用 canvas API 通过 JavaScript 实时生成背景,这真是……相当厉害。据说现在规范中允许将attr()(用于获取 HTML 属性的值)作为任何属性的值,这听起来很酷,甚至可能让你完全用 CSS 实现 HTML 表格,但你也可以用变量做到同样的事情。我是说,嗯,自定义属性。我更兴奋的是:is(),它可以匹配一组选择器中的任何一个,以及 subgrid,它允许你在网格中添加一些嵌套,同时保持孙元素仍与网格对齐。

更容易的是列出一些曾经被视为未来功能但最终未能实现的特性。

  • display: run-in 自 CSS 2 版本(1998 年)起便已存在,但基本上未被支持。该想法是将一个“run-in”框以行内方式插入到下一个块中,因此:
    <h2 style="display: run-in;">标题</h2>
    <p>段落</p>
    <p>段落</p>
    

    将显示为:

    标题 段落

    段落

    嗯,我开始明白为什么它不被支持了。它曾经存在于WebKit中,但显然由于无法正常工作,六年前就被移除了。

  • “替代样式表”在21世纪初很流行,至少在我的一些朋友的网站上是这样。该想法是,你可以为网站列出_多个_样式表(可能是为了不同主题),浏览器会向用户显示这些样式表的列表。遗憾的是,该列表始终被隐藏在菜单中,且没有明显提示何时实际加载,因此最终,所有希望使用多个主题的人都自行实现了页面内的主题切换器。该功能仍被支持,但显然Chrome从未实现过它,因此该功能实际上已名存实亡。
  • 更普遍地说,原始的CSS规范明确假设用户能够为网站编写自己的CSS——在第2段中它写道

    …读者可能有一个个人样式表,用于调整人类或技术上的障碍。

    嘿,这听起来很酷。但它从未作为浏览器功能实现。Firefox 提供了 userContent.css 以及一些 URL 选择器,用于编写针对特定网站的规则,但这一功能相对不为人知。

    尽管如此,这一概念显然存在需求,这从 Stylish 扩展程序的流行程度即可看出——该扩展程序正是实现了这一功能。(可惜它被一些混蛋收购了,他们开始利用它收集浏览器数据并出售给广告商。 建议使用Stylus替代。)

  • 一个常见问题(至少对我来说)是根据复选框的状态来样式化其标签。使用:checked伪类选择器对复选框本身进行样式化相对简单。但如果你以显而易见的方式排列复选框及其标签:
    <label><input type="checkbox"> Description of what this does</label>
    

    …那么CSS无法定位<label>元素或文本节点。jQuery的(最初自定义的)选择器引擎提供了一个自定义的:has()伪类,可以用来表达这一点:

    /* checkbox label turns bold when checked */
    label:has(input:checked) {
        font-weight: bold;
    }
    

    早期 CSS 3 选择器讨论似乎希望避免这种情况,我猜可能是出于性能考虑?一个相对新颖的替代方案是写出整个选择器,但可以通过“主体”指示符来修改规则影响的选择器部分。最初这是一个伪类:

    label:subject input:checked {
        font-weight: bold;
    }
    

    后来,他们引入了 ! 前缀作为替代:

    !label input:checked {
        font-weight: bold;
    }
    

    幸运的是,这被认为是个糟糕的主意,因此当前规范中实现此功能的方式是… :has()! 遗憾的是,它仅在从 JavaScript 查询时允许使用,而非在实时样式表中,而且目前没有任何实现。20 年过去了,我仍在等待一种为复选框标签设置样式的方法。

  • <style scoped> 是一个属性,它本可以让 <style> 元素的 CSS 规则仅适用于其直接父元素内的其他元素,这意味着你可以插入任意(可能是用户编写的)CSS,而无需担心影响页面其他部分。遗憾的是,这个属性早已被悄然取消,而 shadow DOM 被提议作为一个完全不合适的替代方案。
  • 我似乎记得,当我第一次听说Web Components时,它们是可以在纯HTML中使用以减少重复的模板?但现在我找不到这个概念的任何痕迹,而当前的实现需要使用 JavaScript 来定义它们,因此没有声明性地将新标签与其实现关联。这使得它们对于没有充分理由依赖 JavaScript 的任何场景都完全无法使用。唉。
  • <blink><marquee>。安息吧。不过两者都可以通过CSS动画轻松实现。

就是这样

你还在这里?结束了。回家吧。

也许可以抵制Blink的垄断,使用 Firefox,包括在你的手机上,除非你出于某种原因使用iPhone,而iPhone禁止使用其他浏览器引擎,这比微软曾经做过的任何事情都糟糕得多,但我们出于某种原因就接受了它。

本文文字及图片出自 Old CSS, new CSS

共有 111 条讨论

  1. 快进几年,

    > <H1><FONT COLOR=red>...</FONT></H1> …每次都这样。

    又流行起来了!只是现在它被称为 class="text-red-500" :o)

    1. 我仍然觉得奇怪的是,CSS在网页开发中被视为二等公民,而大量的人似乎对学习它毫无兴趣,除了能够复制粘贴的内容。

      这种情况在其他编程语言中是不可想象的。

      1. 对我来说,很大一部分原因是全局CSS与组件化网页应用的匹配度不高。协调全局类名很快就会变得麻烦。然后你转向作用域CSS,突然间CSS就不再有太多价值了。

        1. > 协调全局类名很快就会变得麻烦。

          换句话说,CSS类名就是新的全局变量。我喜欢这种表述。一切旧事物确实又变得新颖了。

        2. 最好不要将其视为全局变量,而更像是跨关注点的注释。

          不过,不要因为 React 将 CSS 视为二等公民就责怪 CSS。试试 Svelte。它与那里的组件完美匹配。使用一个不讨厌其运行平台的 Web 框架真的令人惊叹。

        3. >协调全局类名很快就会变得麻烦。

          然而,作用域 CSS 变量确实增添了不少便利。所以我想这可能不是你所指的作用域?

      2. 随着更多基于 JavaScript 的网页开发逐渐远离任何类似继承的机制,CSS 的层叠特性开始显得格格不入。这或许是微妙的,但在我看来是个值得注意的区别。

        我正因这个原因而难以割舍传统的 CSS。我已经使用它数十年,对其了如指掌,但它在前端栈中越来越显得格格不入。

        1. > 随着越来越多的网页开发(使用 JavaScript)逐渐远离任何类似继承的机制,CSS 中的层叠规则开始显得有些格格不入。

          我对这一陈述感到困惑。层叠规则是用于解决多个规则应用于同一 HTML 元素时冲突的算法(基于 CSS 规则的位置、特异性、来源和重要性)。CSS 中的继承是另一个主题,其中父元素定义的一组属性会自动应用于子元素。如果没有继承,你将不得不为每个子元素重新定义相同的属性(例如,body 的字体大小、字体家族或颜色必须在每个子元素上重复定义)。如果没有级联,浏览器将无法解决冲突规则。这些内容有何不妥?

          1. 是的,层叠和(CSS)继承都是有价值且必要的。

            你回复的不是这位评论者,但我猜他们指的是“继承”作为编程实践,而非CSS特有的含义。

            CSS 规则在 DOM 树中的继承对 CSS 的正常工作至关重要,即使你使用了某种作用域。

            作用域是关于限制 CSS 规则应用的 DOM 子树,因此它确实与 CSS 规则继承相关。

            但即使你使用 Tailwind、(Vue)作用域样式或样式组件,你仍然需要 CSS 继承。

            没有人旨在仅对每个元素应用CSS,尽管其中很大一部分正是如此。换句话说,Tailwind的作者仍然期望“text-red-500”能够继承到子元素。

            关于继承,再谈谈级联:

            可维护CSS的核心在于保持级联扁平化,避免多级覆盖或使用非常具体的选择器。

            1. > 不是你回复的评论者,但我猜他们指的是“继承”作为编程实践,而非 CSS 特定含义。

              是的,这就是我的意思。感谢你跳出来澄清。:)

            2. 随着越来越多的人从事网页开发,我常常惊讶于其中有多少人对他们所开发的平台缺乏足够的理解。

              1. 我们中的许多人已经在这个平台上开发了数十年,只是愿意直言不讳。 ;P

      3. 在其他语言中构建 UI 时,你不需要使用三种语言。

        1. 当非基于网络的UI框架省略CSS时,它们通常不会优雅地将其整合到UI标记和/或语言中,而是根本不具备CSS所具备的功能,或者迫使你在编程语言中声明它,这在我看来往往看起来很丑陋(尤其是当它们试图在命令式编程语言中创建某种声明式DSL时)。

        2. 大型 UI 框架拥有 UI 定义 DSL 的情况并不少见。

            1. 我使用过的其他大多数前端技术都是通过自身进行主题化的

    2. 不过这可能是在一个可复用的组件中,因此重复的问题并不存在。

    3. > 又流行起来了!

      但这不应该 🙁

      1. 猜测父评论指的是 Tailwind(以及类似的“工具优先”CSS 框架)。

        1. 人们真的在手动编写 Tailwind,而不是作为模板引擎的一部分吗?

  2. 我在想,我们是否会看到Houdini最终被浏览器采用。其核心理念是:浏览器不再提供现代CSS,而是为布局引擎的各个部分提供一系列钩子。开发者可以编写自定义代码,利用这些钩子实现任意布局系统。

    CSS 庞大而复杂,且仍需支持自互联网诞生以来积累的全部遗留应用程序。大多数应用程序仅使用 CSS 的极小部分。Houdini 可能允许使用更小、更快的布局引擎,且无需处理任何遗留问题。由于你的应用程序会自带布局引擎,如果你需要某个功能,只需将其添加到布局引擎中,它就能立即在所有浏览器中生效。

    不过我不知道它现在进展如何。如今,Flexbox、Grid、Sticky 等特性已普遍支持于所有浏览器,CSS 似乎已足够完善。但或许我缺乏想象力。

    https://developer.mozilla.org/en-US/docs/Web/API/Houdini_API

    哦,看来Chrome和Safari都已经支持了大量Houdini功能:https://houdini.glitch.me/

    1. 我最希望在网页布局中实现的是一项名为“伸缩单位”的功能,其工作原理与CSS网格中的fr单位类似,即“在其他兄弟元素被定位后,占用可用空间的比例”,但有以下区别:

      – 它没有自动最小值,因此实际上等同于 minmax(0, 1fr)(这将使其性能大幅提升,避免现有许多 CSS 布局模式的指数级时间复杂度)。

      – 它可用于宽度/高度属性(以及潜在的其他位置,如边距/填充/内边距)

      如果结合一个简化的1维显示模式(即类似于flexbox但禁用了弹性布局),我认为在大多数情况下,大多数人可能不会需要更多功能。

      Houdini 很有趣,但作为过去一年致力于实现网页布局引擎的人 [0],我对 JavaScript 是否能快到足以与内置布局模式竞争持怀疑态度。如果能解决将数据廉价地传递到 WASM 虚拟机(或许通过引用)的问题,这可能是一个有趣的 WASM 应用场景。

      [0]: https://github.com/DioxusLabs/taffy

      1. > 如果能够以低成本的方式将数据传递到 WASM 虚拟机(例如通过引用),这可能是一个有趣的 WASM 应用场景。

        WASM 引用类型应该能够解决这个问题。WASM 工作组似乎进展顺利,因此我希望这一规范(或类似的替代规范)能够尽快落地。

        https://github.com/WebAssembly/reference-types/blob/master/p

      2. >“在其他兄弟元素被调整大小后,占用可用空间的一部分”和 >- 它可以用于宽度/高度属性(以及潜在的其他位置,如边距/填充/内边距)

        对我来说,这本质上就是clamp所做的,尽管它不能在兄弟元素被调整大小后占用大小。

        如果 clamp 未来能像 inherited 一样获取值,那将非常酷,但这恐怕难度不小。

        1. > 尽管它无法在兄弟元素被调整大小后占用空间

          关于提议的新单位的关键点是:

          1. 它在兄弟元素被调整大小后占用空间(即为 flexbox 90% 的使用场景提供专用语法)

          2. 它防止同一节点被“自动”调整大小(即根据其子元素的大小进行调整)。这是重要的优化措施,可大幅提升布局性能。

          综合来看,这既能显著简化布局代码,又能显著提升布局性能。

          1. 嗯,我认识的一个家伙最近花了数周时间尝试实现一个设计,但如果将设计中隐含的所有想法都赋予同等权重,这个设计实际上是无法实现的,而这本可以让他实现他试图做的事情。

    2. 我被告知我是第一个在Houdini中尝试WebAssembly的人,结果导致浏览器崩溃。我提交了错误报告,但因缺乏进展而被关闭。

      目前似乎没有人再处理这个问题。

    3. 我真心希望Houdini永远不会成为最终规范。演示用例虽然有趣,但我们最不需要的就是在网页开发中增加更多复杂性。

      当今的浏览器已经更像操作系统而非文档查看器。Houdini基本上更进一步,允许每个应用程序携带自己的渲染器。Linux目前对此依赖甚深,这使得诸如全局主题设置等日常任务变得异常繁琐。

      1. > 我们最不需要的就是让网页开发变得更加复杂。

        这是其中一种思考方式。另一种是,Houdini 让浏览器变得更简单——因为 CSS(以当前形式存在)可以被移入一个可重用的库,并在浏览器之间共享。理论上,如果所有浏览器都支持 Houdini,它们就无需维护自己的 CSS 实现。

        1. 作为跨浏览器共享代码的内部实现细节,这听起来足够有吸引力。Web 开发者无需了解这些细节,因为这只是浏览器渲染流程中的一部分,恰好被浏览器厂商共享。

          但实际上,我认为浏览器厂商不会在这一层面合作。共享规范已够缓慢,共享渲染代码将是一场噩梦。

          除此之外,我通常看到 Houdini 的演示都聚焦于开发者功能,本质上是在 CSS 渲染中添加少量自定义逻辑。这将它从共享库中提取出来,进入用户空间。

        2. 我迫不及待想看到纯CSS的加密挖矿 ^W Houdini

          1. 我们已经在Wasm中有了加密挖矿。Houdini不会改变任何事情。

    4. Houdini需要JavaScript,这是它普及的重大障碍。

      1. JQuery、React、Vue、Svelte等都需要JavaScript,但它们都普及了。

        1. JQuery、React、Vue、Svelte等确实做了一些用户需要的基本功能。

          Houdini 不同。它更侧重于布局和样式。

          1. 有些人会关闭 JavaScript

          2. 它会减慢页面渲染速度

    5. 你能分享一些如果没有遗留网站,可能会被废弃的 CSS 功能示例吗?我几乎知道的每个 CSS 特性都有用处,但我只知道它们是因为在需要时查阅过,所以可能遗漏了一些特性。

    6. 我认为即使没有这些特性,也能实现合理的紧凑布局系统。这里可能存在机会,即创建一个涵盖所有现代需求的 CSS 子集,并通过文档规范和代码检查工具来强制执行。

    7. 是的,唯一缺失的是对网页动画规范的完整支持。例如,iOS和Firefox中缺少scrolltimelines。这一功能对于在网页应用中实现与原生应用相似的性能至关重要。

  3. > 它 [Firefox] 速度快,简单,符合标准,但这些都不重要。

    >

    > 不,Firefox 真正站稳脚跟是因为它有 标签

    文章没有提到,但当时与标签同样吸引人的是弹出窗口拦截器!真正首个广告拦截器类功能。而且它也非常棒 :)。

  4. 这让我想起1995年时的想法,我曾想开发一个浏览器,通过菜单选项展示不同浏览器下的输出效果(那时开发浏览器几乎等同于开发操作系统)。我记得在CSS出现前的一些糟糕的样式尝试,最糟糕的是

        <font size=+1><ol></font> item text
    

    用来更改列表项目符号的大小(当然,这只在Netscape上有效,而在其他浏览器上会完全破坏渲染)。

  5. > 假设你想让整个网站的所有 <h1> 标签都显示为红色。你必须这样做:<H1><FONT COLOR=red>...</FONT></H1> …每次都得这样做。希望你永远不要决定改用蓝色!

    这对我来说从来不是大问题,因为那时候我用 Perl 脚本生成网页。我只需定义 $h1_color = ‘red’,然后运行脚本生成静态 HTML 页面。老板(就是我 :))想把颜色改成蓝色?只需把 ‘red’ 改成 ‘blue’,然后重新运行脚本。

    1. 你自己的、更糟糕的CSS,需要一个构建工具链。你真是个先驱者!

      1. 这并不容易:

          - 没有构建工具链
          - 没有 JavaScript
          - 只有单一的配置点
        
      2. 公平地说,像 SASS 和 LESS 这样的工具已经存在一段时间了。Tailwind 在生产环境中需要构建。

        1. 我认为我们讨论的是1995年至2000年期间,而不是2006年(Sass出现时)、2009年(Less出现时)或2018年(Tailwind出现时)

  6. 我清楚地记得曾在一家公司工作,当时我需要上传我们圆角按钮的新资源,这些按钮是由3×3的图像元素组成的网格。

    LOL clearfix。

    我从未真正需要与IE 6兼容性作斗争,但当我与它作斗争时,它会激烈地反击。

    我还需要向设计师解释为什么我们不能使用半透明背景(也是IE 6的问题)。

    1. 啊,是的,3×3。每当这个话题出现,我就会想起早期前端开发时期的许多美好回忆。我曾在https://brajeshwar.com/2005/splice9-bitmap-window-resizer-co…中写过关于我们的经历。

      我记得在Photoshop中对曲线进行“羽化”处理,以获得更平滑的圆角效果。我的团队,尤其是新成员,会说——嘿,这个技巧,这个技巧,我们学到了一个技巧。 😉

      那些挣扎是真实的,乐趣虽短暂且间歇性,但每一刻都值得。

      1. 好时光啊。

        A List Apart、Yayhooray……你的文章帮助我学习了网页设计。

      2. 在使用阴影效果之前,我们还得手动裁剪阴影的静态图像。希望你永远不需要更改阴影所在的背景!

    2. 有一种方法可以以非标准方式使用包图像(据我所记得,使用Photoshop中的偏移量),并通过负背景位置模拟3×3网格图像,使用更少的元素。这是一种高级技术。

      1. 你是指CSS精灵图,还是有其他技术是我这些年错过的?

        1. 是的,这是另一种技术。我现在找不到它了(这是老一辈大师的技术)。它与精灵图或边框半径不同,因为它需要在Photoshop中通过滤镜->偏移对图像进行预处理,这基本上相当于负背景位置。这样可以将原始图像的左上角指针移至其中心。之后在CSS中,你可以使用负背景位置来抵消图像的变换。这有效地帮助创建了灵活元素的右边缘,而在此之前,背景位置无法锚定到右侧。

          你仍然需要多个元素,但你可以使用单张图像(这对HTTP延迟/压缩更有利)。

  7. 我几乎在所有地方都使用“display:flex”,正如你所说,Flexbox 几乎适用于所有情况。对于那些在 Flexbox 上遇到困难的人,我使用这个工具来简化流程:https://flexboxcss.com

    1. 我只是对HTML略知皮毛,但对于我经常处理的布局类型,网格布局比Flexbox更常用。子网格布局在某些任务中是必要的,但目前支持仍不完善。

      容器查询是媒体查询的更灵活替代方案。

      在为他人网站编写自定义规则(使用Stylus扩展)时,elem[attr=value]及其变体(如^=等)非常有用。:has() 用于为具有特定属性的元素的父元素应用样式,但目前并非所有浏览器都支持。

      据我所知,目前在实际应用中仍无法实现完全自动的深色模式(等)主题(使用 HSL),尽管相关函数的规范中已包含颜色空间。

      1. > 我只是对 HTML 有所涉猎,但就我所做的布局类型而言,网格布局比弹性布局更常用。

        这取决于内容是固定在桌面显示器上还是对移动屏幕响应。网格布局在移动设备上显示时,无法提供与弹性布局相同的响应灵活性。

        在我对网格与 Flexbox 的实验中,每次使用网格时,只要需要内容在移动屏幕上显示,我不得不立即切换到 Flexbox。

        我对网格的使用最终只是表格的另一种形式,而表格在移动屏幕上表现不佳(甚至无法正常工作)。

        1. 我对网格布局的处理方式是使用媒体查询(或容器查询,这样在顶层调试更方便,且在嵌套布局时必不可少)来为同一DOM结构实现完全独立的布局,当视口(或父容器)的水平宽度过小时。弹性布局的问题在于,它意味着“相邻”元素可能会随机折行到任何位置,即使它们实际上应该紧邻排列,而使用网格布局时,我可以针对每个可用的水平尺寸单独安排元素的紧密排列。

          1. > 弹性布局的问题在于,它意味着“相邻”元素可能会随机折行到任何位置,即使它们实际上应该紧邻在一起,而使用网格布局,我可以为每个可用的水平尺寸单独安排元素的紧密排列。

            我不会仅仅使用 flex 并就此作罢;我会使用媒体查询在 flex-horizontal 和 flex-vertical 之间切换。这意味着我可以在桌面端在特定宽度处换行,或在移动端在每个单元格处“换行”。

            当然,这并不完美,因为它只支持两种屏幕尺寸类别——桌面或移动端 🙂

    2. 我最近开始了一份新工作,需要做很多前端开发(可惜)。

      Flexbox是救星,除非它不是(我直到昨晚才知道网格布局的存在,但它确实解决了我在Flexbox上挣扎已久的一个用例)

    1. 需要注意的是,“所有”主流浏览器指的是 Chrome、Chrome、Chrome、Chrome、Firefox、Chrome、Chrome、Safari 和 Chrome。

      1. 而且还有很多用户仍在使用旧版浏览器。而 :has 没有简单的 polyfill 解决方案。

        1. 其实没有你想象的那么多。Chrome 十多年前的自动更新功能彻底改变了游戏规则,因为过去用户需要手动升级。IE 11 的安装量已经非常小,通常由企业 IT 团队提供支持。

          我确信还有一些可怜的人仍在使用Windows XP,祝他们好运,但我不会为此投入任何工程时间。就像开着一辆1957年的雪佛兰一样,你可以继续使用,但从现在起,你必须自行负责其维护、保养和道路适航性。如果你想这样度过你的时间,祝你好运。只是别抱怨蓝牙不工作。

          1. 这与IE11无关。:has()在Safari 15.4之前和Firefox 121之前不可用,三星在20之前也不可用。这些都是相对较新的版本,许多人,尤其是移动用户,无法更新。

      2. 我觉得这里有《蒙提·帕顿》的恶搞元素。

  8. 变量未被提及。如果你想在这里使用相同的背景色、那里使用相同的边框色、那里使用相同的文字色,该怎么办?CSS 目前可以通过 var(–my-color) 实现这一点。

    对我来说,这使得 CSS 构建变得多余。抱歉,Sass 和其他工具。

    1. 自定义属性很棒,直到你需要从 JavaScript 访问它们,然后发现这不可能,不得不回到绘图板重新设计。

      在使用 CSS/SCSS/Tailwind/Svelte/SASS/PostCSS 等构建了无数设计系统后,我坚信作为独立语言并存储在独立文件中的 CSS 需要被淘汰。

      我正在用纯 Typescript 构建一个实验性设计系统,终于感觉能让 UI 摆脱石器时代了。

      我确信很快又得回到绘图板重新设计。

    2. 确实,你可以使用备用值如var(–my-color, #B22222),并结合calc()函数,在纯CSS中实现一些惊人的效果。

  9. 感谢CSS。我的意思是,看看其他替代方案。真的没有其他东西能像CSS这样拥有如此强大的功能和灵活性。每次我回到原生领域,总有一种纯粹的自由和愉悦感,回到网络平台。

    1. Flutter 是一个不错的替代方案,我发现它在设计 UI 框架时确实投入了大量思考,利用了我们多年来关于什么有效、什么重要的所有知识,无需担心向后兼容性,而是可以采取一种全新的方法。

      除了这一点,我基本上同意,CSS 尤其是在 2024 年,实际上在大多数情况下使用起来非常不错。

      1. 令我感到可笑的是,即便拥有 25 年的工程经验,你只能指出一个框架,其实现效果足以被视为优于 CSS。

        在已有 20 年技术积累的情况下,新选项本应默认更优。当绝大多数“替代方案”都未能达到这一标准时,这反映了我们行业怎样的现状?

  10. 有趣的是,IE 和 NN 的默认行为都是 `box-sizing: border-box;`,而对我来说,这种行为是合理的。当时更好的决定可能是更新规范并以另一种方式添加兼容模式。

    1. border-box 是规范早期草稿中的原始行为,但在最终发布前被改为 content-box。那些抢先发布并采用草案行为的浏览器搞错了。而且这并非“默认”行为,而是“唯一”行为——允许网页开发者控制此行为的 box-sizing 属性是在很久之后才出现的。

  11. > 哦,还有,当时大家都用大写字母写 HTML 标签。我不记得为什么我们都觉得这是个好主意。也许这是因为当时文本编辑器中的语法高亮功能并不常见(也就是说,我当时12岁,使用的是记事本),而全大写标签更容易与正文文本区分开来。

    早期使用全大写HTML标签的主要原因并非出于内存考虑。更多是出于可读性和一致性的考虑。随着HTML的演进,小写标签因其更好的可读性和与XML的兼容性而成为标准。

    另一个值得注意的点是,在计算机早期,内存是宝贵的资源,每个字节都至关重要。一些开发者认为使用大写字符可以节省内存,因为大写字母在ASCII中的表示更简单,占用的位数更少。然而,这种差异极其微小,几乎不会对内存使用产生明显影响。

    1. 什么?大写和小写字母占用的位数相同。ASCII为所有字符分配7位(尽管实际使用8位)。

      1. 如今部分开发者认为CSS-in-JS是个好主意。网页开发者希望HTML在结构和解析上与XML一致。后端开发者也认为基于XML封装的RPC(SOAP)是未来方向。

        各个时期的开发者都曾提出过一些在事后看来荒谬的观点。

        1. 使用大写字母节省空间的说法客观上是错误的。

          1. 作为过去一直使用大写标签的人,这并非为了节省空间,而是为了提升人类可读性。全大写标签在以小写为主的文本背景下更具辨识度。此外,DOM API 在检查 HtmlElement 对象名称时会将大小写折叠为大写。

            说实话,这是我第一次听说有人认为这有节省空间的优势。

      2. 在计算机早期,ASCII 并非普遍使用,字符集空间常小于 8 位且缺乏小写字母,或采用混合字符集如 PETSCII(包含大写字母),额外字符空间则填充图形。对于纯文本系统,可使用 6 位字符存储文档,因可忽略填充图形的上方字符空间。

        1. 这在HTML出现之前很久就是这样了。HTML一直至少使用ASCII。

          1. 确实如此,但许多早期编写HTML的人来自那个时代,因此这些习惯常常保留下来。

            1. 你是说他们用全大写字母编写网页吗?我怀疑这种做法从未普遍存在。

  12. 我从事CSS编写已超过10年,至今仍需不断应对某些难题(主要涉及Flexbox、图像和定位)。

    CSS易于学习但几乎不可能精通。

    1. 布局一直以来都容易学习但难以掌握。这一情况在CSS和网页出现之前就已存在。你以为那些在权威报纸工作的编辑们从未需要过修改布局以确保内容恰好出现在折叠线以上吗?而他们的输出目标是静态的!

  13. 有人知道《太空大灌篮》网站的历史吗?我很好奇是谁创建了它,以及哪些幸运儿一直维护它至今。(愿它的存在永不被归档到Wayback Machine……)

  14. > 一年半后,即1998年中期,我们迎来了CSS 2。(顺便说一句,我喜欢这页面的背景。) 这是一个小幅升级,解决了多个领域的不足,但最有趣的是新增了几个定位原语:position属性,允许将元素精确定位到指定坐标;以及inline-block显示模式,允许将元素像图片一样嵌入文本行中。

    inline-block实际上是在CSS 2.1中引入的,该版本比CSS 2晚了几年。

  15. > 使用 JavaScript 生成 CSS 虽然可行,但天啊,这绝对是个糟糕的主意。

    哈哈。

    作为一名自诩为全栈开发者的后端开发者,我读这篇文章时乐在其中。CSS 就像一个混乱的战场,几乎不可能找到一份关于它为何会发展成现在这样的总结。此外,我对过去几次带着新鲜的后端思路来面对这个问题时,问前端开发者“嗯,我们为什么这样做?”而他们只能发出尴尬的回应,感到一种奇怪的认同感。

    1. 作为一个在CSS出现之前就从事前端开发的人(我大概是在<center>标签引入的时候开始的),我可能可以回答你们任何问题。

      大多数答案——尤其是关于早期功能的——归根结底是桌面出版领域的人希望保留他们一直使用的功能,使用程序员鲜少听过的术语,并希望采用他们社区中已熟练掌握的布局方式。

      有些东西在翻译过程中丢失了,但很多只是因为桌面出版没有开发人员习惯的相同目标或对算法优雅的渴望。当然还有权衡。记住,当CSS首次在Internet Explorer中引入时,16-32MB的内存是典型的,甚至算是先进的。用户在好日子里可能只有512MB的硬盘空间。当时并不存在我们今天所理解的GPU。有一些2D加速器(如经典的Diamond显卡),它们将原本极其缓慢的渲染速度提升到了相对较慢的水平。800×600的分辨率是网页开发时的典型目标。

      没有人真正知道自己在做什么,但每个人都有自己的看法,而这些看法往往相互矛盾。许多临时解决方案只是为了解决当天的难题,结果却成了我们今天的技术债务。

      ActiveX和Flash(以及<applet>)解决了实际问题,但从未被设计为整体架构的一部分。SVG耗时过长,进展被委员会的决策拖累。XML触及一切,并被普遍认为是未来发展的粘合剂……直到它不再被认可。我们仍然称它们为 XHR 调用,尽管它们很少再获取 XML 资源。

      布局很困难。非常困难。要做到正确布局简直难如登天,而这还是在你有周密的计划和普遍共识的情况下。微软和网景显然没有这些。两者都没有一个坚实的参考点。正确的行为大多取决于“当前浏览器版本的渲染方式”。

      我们确实走了很远。应该预料到会有瑕疵和伤疤。总的来说,我对现代CSS的成果非常满意。它可能很复杂,但它所产生的输出也是如此。那些渴望某种实质上更简单的东西的人,我认为他们对问题空间的理解有所欠缺。

    2. 作为一个主要从事前端工作且对CSS相当熟悉的人,我仍然对事物为何会以这种方式发展以及为何某些事情(如布局)有如此多的实现方式感到困惑。布局选项的数量及其固有的怪癖使得从头开始设计任何网站或应用程序成为一场噩梦。这就是为什么大多数现代应用程序使用布局引擎如Bootstrap或Foundation(尤其是因为它们为你完成了大部分响应式设计工作)。

      1. 在布局方面,有没有什么具体的问题可以指出?根据我的经验,大多数情况下,你只需要使用display: flexdisplay: grid(然后调整子元素的必要属性),通常就能很好地工作。

    3. 作为一名希望转向后端开发的全栈开发者:我完全同意你的观点。前端对我来说比后端麻烦得多,因为其中很多部分在可用性方面似乎毫无理由地糟糕。

      1. 在前端,用户控制执行环境。在后端,开发者控制执行环境。这正是为了让网络能够以这种方式扩展。

        大多数开发者都是控制狂。“我输入指令,计算机就按我的要求执行。”我认为这种情况在开发者群体中比普通人群更为普遍。前端缺乏这种控制权,必然会让许多同行感到不满。我认为那些对环境控制力较弱的人,往往更适应前端开发——更接受现状,而非追求某种优雅且可验证到极致的理想状态。

        我们在后端塑造了尽可能可预测和可控的世界。可以说,前端更贴近现实世界及其妥协。

  16. 在评论中,发明怪异模式的人实际上解释了它的历史!请有人更新维基百科……我做不到。

  17. 感谢分享。我完全忘了“网页安全颜色”这件事!

  18. 有趣的是,这里完全没有提到SASS或SCSS。

  19. 其他一些回忆:

    网景浏览器4.0的“缺失闭合表格标签致命错误”,即缺少闭合表格标签会导致整个文档无法渲染。https://www.webmasterworld.com/css/234.htm

    尤其值得一提的是,在缺乏任何其他布局或样式控制的情况下,常见的解决方法是通过嵌套表格、valign=center(你从未如此幸运!)来实现布局,如果运气好,还可以通过命令行调用 html-tidy 进行调试。

    另一个“本可以、应该”的例子在这里被提及,大约在2004年左右,CSS被称为“JSS”。https://levelup.gitconnected.com/a-brief-history-of-css-in-j

    …相关资料难以查找,但我认为Mozilla/NS曾试图推广(并短暂尝试过一个分支)基于JS的样式语言。例如:body.style.background = “white”,并将其作为编写“样式表”的唯一语言。

    据我所记得:微软基本上直接拒绝了,因为他们有 MS-Word 团队,他们设想了“CSS 作为书籍”的宇宙(并且有 effectively 无限的资深程序员来实现“级联”),而网景则规模较小、更具创新精神,并且更关注一个 _有效_ 的网络,而不是一个 _完美_ 的网络。

    由于当时没有搜索引擎,且网页内容不断衰减,要找到原始资料非常困难,因为相关网站并未被引用。

    微软通过“拥抱、扩展、消灭”(EEE)策略至少让网络发展倒退了十年,但又意外地通过忘记已实现的XHR(异步同步资源)技术,推动了网络向前发展,该技术使得AJAX及其他交互技术成为可能。

    你未曾真正经历过,直到你遇到一个被定罪的垄断者,他们拥有满屋子的律师,坐在会议室里辩论是否要通过诉讼将你的公司逼入绝境,只因你开发了与他们的浏览器兼容的产品(一旦你成长到足够大的规模,并目睹同行公司在跨越某个门槛后被摧毁)。这就是为什么人们对微软始终怀有如此持久而深沉的厌恶。他们故意破坏了互操作性互联网,并用“法律”和“财务”这两把双头棍子故意摧毁了创新技术。

    在互联网早期,其他有趣的竞争技术包括:带有ANSI图形的大型机系统(BBS),然后是作为SVG原型的“RipScript”。接着是Prodigy,它实际上是一个原型浏览器(具有自己的矢量渲染能力)。

    甚至以文本为主的浏览体验Gopher,也曾是Mosaic 1.0的竞争对手,因为当时没人知道互联网应该是什么样子。还有Lynx和Links,这些概念上非常棒的工具,只是CSS(布局与层次结构)和JS(交互与声明)的出现(哈哈)让它们变得过时了。

    不能忘记提及AOL-server(带TCL)和NSS… Netscape Secure Server,它发明了SSL,并一度是唯一提供安全流量的途径。对于业余爱好者来说,它绝对不可用,因为它是一个非常昂贵的产品。

    很少有其他结果,但开源和垄断者的财务控制扭曲了我们现在所拥有的网络。

    如果我有一根魔法棒,我会选择402-Payment-Required,并且会犹豫是否鼓励真正全球(普适)的内容聚合用于搜索。

    我们处于一种二元对立中:“只有谷歌”能够每天下载并索引整个互联网,而“只有脸书”能够访问“脸书数据”。

    Facebook出于商业动机,将事件数据和商家/待售数据锁定在登录要求之后,这对开放互联网而言是巨大损失。

    谷歌作为“守门人”掌控导航(通过万能搜索框+广告取代DNS),同样对开放互联网构成损失。不相信我?试试在Chrome中设置浏览器主页。它只会在一开始打开浏览器时打开一次,不会在新标签页、新窗口中打开,除非使用一个不稳定的扩展程序。

    1. > 但他们不小心再次启动了它,因为他们忘记了已经实现了XHR,这使得AJAX和其他交互技术成为可能。

      公平地说,微软引入了一个ActiveX控件,可以加载外部资源而无需离开页面。事实上,有几个版本彼此不兼容。

      正是网景/Mozilla团队为其提供了独立于ActiveX的固定API,微软和其他公司后来在数年后采纳了这一API,并最终成为标准,包括其古怪的大小写规则。

      该API由Chris Blizzard在2000年Mozilla开发者大会上应我的请求迅速实现并交付。(需明确的是,我并未参与该项目开发,也无意居功。当时团队正向与会者征集反馈,而我们当时的规模相对较小。此处仅为说明我曾亲眼见证相关事件。)

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

你也许感兴趣的: