CSS 高尔夫练习

Avatar of Alex Zaworski
Alex Zaworski

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

代码高尔夫 是一种编程类型,其目标是以尽可能少的字节数完成任务。 CSSBattle 是一个代码高尔夫战场,玩家们在其中争夺使用 CSS 和 HTML 重新创建目标图像。

规则非常简单

  • 不允许使用外部资源(抱歉,不允许使用 <img src="the-solution.png">
  • 您的解决方案必须在 Chrome 中正确渲染(仅用于评分目的)

这可能与日常的前端工作大不相同,非常有趣。您无需担心可维护性、语义、性能、可访问性或任何其他事情,只需专注于将一个东西变得非常非常小,并且仍然能够正确渲染。

12 次尝试中的高尔夫解决方案

这种思考方式与我们大多数人编写用于生产网站的前端代码的方式大相径庭(我希望如此!),因此我一直在 GitHub 上发布我所有的解决方案,以便分享一些知识并向其他人学习。作为一项意外的好处,这也意味着我提交的解决方案有一个相当详细的历史记录。

以下是我的 CSSBattle 的第 7 个目标 的尝试过程,它看起来像这样

CSSBattle 目标 #7 — 叶状轨迹

“只需将它居中”方法

一个合理的第一种方法是简单地将一个元素粘贴到页面中间,在其上添加一个框阴影和一个圆角,然后就完成了。如果我们真的要编写它,它可能看起来像这样

<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
        background: #0B2429;
        margin: 0;
      }

      .leaf {
        width: 150px;
        height: 150px;
        border-radius: 67% 0;
        background: #F3AC3C;
        margin: 75px 0 75px 175px;
        box-shadow:
          -50px 0 #998235, 
          -100px 0 #1A4341
      }
    </style>
  </head>
  <body>
    <div class="leaf"/>
  </body>
</html>

但这有 423 个字节!这对于 CSS 高尔夫来说是不行的,所以让我们看看我们可以删除什么。

尝试 1:144 个字节

<p style="margin:75 167;height:150;width:150;border-radius:67%0;box-shadow:-50px 0#998235,-100px 0#1A4341,0 0 0 5in #0B2429;background:#F3AC3C">

这是一个经过高尔夫处理的版本。这里肯定有一些奇怪的东西——没有 <!DOCTYPE>、没有 <html>、没有 <body>,什么也没有。浏览器不需要它们(实际上,它会为我们插入它们),因此通过省略它们,我们可以节省大量字节。我们使用 <p> 而不是 <div>,因为它的长度更短,而且我们根本没有关闭标签,因为渲染不需要它。

CSS 本身并没有太大区别,除了我们使用了巨大的框阴影而不是 body 元素上的背景(“background”很长,所以避免使用它可能会有益)。它也被内联在元素中,因为 <style></style> 标签会额外占用字节。

您可能已经注意到,我们在上一个框阴影中使用了 5in 作为扩展。玩弄奇怪的单位是 CSS 高尔夫的一个重要部分。在这种情况下,我们只需要阴影覆盖 400×300 的画布,而“5in”(480px)比任何像素值都更短。

尝试 2:141 个字节

<p style=margin:75+167;height:150;width:150;border-radius:67%0;box-shadow:-50px+0#998235,-100px+0#1A4341,0+0+0+5in#0B2429;background:#F3AC3C>

这引入了非常重要的一个高尔夫技巧:用加号替换空格,使我们能够删除属性周围的引号,从而节省几个字节。我不完全确定这是为什么。有人建议它可能与 HTML 规范的 这部分 相关。如果您有更好的答案,请告诉我!

此尝试还清理了上次尝试中的一些空格错误。

尝试 3:126 个字节

<body bgcolor=F3AC3C style=margin:75+75+75+175;border-radius:67%+0;box-shadow:-50px+0#998235,-100px+0#1A4341,0+0+0+5in#0B2429>

使用 <body> 标签而不是 <p> 意味着

  • 我们不再需要花费字节来设置段落的 height 或 width
  • 我们可以访问 bgcolor

bgcolor 是一个已弃用的属性,在 CSS 高尔夫解决方案中经常出现。它仅适用于少数几个标签(包括 <body>),并且可以完成两件很棒的事情

  • 为我们节省了在“background:”上花费字节
  • 通过允许我们省略十六进制颜色中的 # 来节省一个字节。此外,如果颜色以一个或两个零结尾,我们可以删除它们,它仍然可以正确渲染。例如,FFFF00FFFF 相同。

此迭代中存在高尔夫回归!你能找到它吗?

“边框”方法

至此,我已经断断续续地花了几个小时来调整这个目标,并且陷入了困境。幸运的是,CSSBattle 在 Spectrum 上拥有一个友好的社区,他们非常乐意提供帮助。

当时,Praveen 以比我少两个字节的成绩占据了第一名,所以我寻求了一些帮助。他建议利用 <body><html> 元素来定位所有内容,同时使用边框代替背景颜色。

尝试 4:126 个字节

<style>*{border-radius:67%+0;border:75px solid#F3AC3C;margin:0 50;box-shadow:-50px 0#998235,-100px 0#1A4341,0 0 0 5in#0B2429

这与我们上次的策略大相径庭。我们的 body 标签消失了,我们使用 <style>*{ 来定位浏览器为我们插入的 <html><body> 标签。marginborder 的组合将我们的形状精确地推到了需要的位置,而 <body> 上的 box-shadow 覆盖了从 <html> 上的样式中看到的任何多余内容。

这对我来说很难理解,但 Praveen 绘制了一张图,很好地解释了这些内容。这是一个美化的版本

<html><body> 上的边距和边框

ab<html> 上的边距和边框,c<body> 上的边距。<body> 上的右侧边距没有任何作用,因为没有空间将 <body> 推到左侧,并且它已经具有零宽度。

应用框阴影后,b 被覆盖,剩下的就是我们的目标图像。

这里仍然缺少一些优化。 Dorus van den Oord 能够将边框方法缩减到 121 个字节,并提供了以下神秘的建议

实现 121 的一个小提示:如果您能将元素移动四分之一……?

尝试 5 和 6:122 个字节

<style>*{border-radius:67%+0;border:75px solid#F3AC3C;margin:0 50;box-shadow:-53q 0#998235,-25vw 0#1A4341,0 0 0 5in#0B2429

事实证明,我们只需要一个几乎没有人听说过的单位(q)(以及谦逊的 vw)。在 CSS 高尔夫中,很少会正确地写出“px”,所以这是一个需要注意的地方。在这里,我们可以用 25vw 替换 100px,用 53q 替换 50px

q 或四分之一毫米,正是如此——1/4 毫米,或略小于一个像素。q 单位是 CSS 高尔夫的主力军,因为它与 % 是两个只需一个字节就能表达的单位之一。我在这里结合了我的第 5 次和第 6 次尝试,因为它们都是单位调整。但我们仍然离 121 个字节差一个字节!

尝试 7:121 字节

<style>*{border-radius:67%0;border:75px solid#F3AC3C;margin:0 50;box-shadow:-53q 0#998235,-25vw 0#1A4341,0 0 0 5in#0B2429

我们终于修复了第三次尝试中的回归问题,感谢 Praveen 的拉取请求。 百分比不需要在其与后续值之间添加空格,因此我们可以在 border-radius 中节省一个字节。这是一个很好的例子,说明了代码共享如何帮助所有相关人员。我在这上面卡了相当长的一段时间。

“奇特边距”方法

不过,边框并不是唯一的方法!让我们看看Rasmus Fløe的奇特边距

我在 #7 中使用 box-shadow 和奇特的 margin:75 400 75-150 获得了 123 个字符 :)

尝试 8:120 字节

<body bgcolor=0B2429 style=border-radius:67%0;margin:75+400+75-150;box-shadow:86mm+0#F3AC3C,73mm+0#998235,75vh+0#1A4341>

以下是 Rasmus 解释的工作原理

正向右外边距将其从画布推到左侧——负向左外边距将元素拉伸到所需的宽度 :)

这是绘制出来的

Rasmus Fløe 的“奇特边距”方法

右外边距 (b) 将 <body> 元素完全推到左侧,使其宽度折叠为零。然后,负向左外边距 (a) 将其拉伸回 150px 宽(叶形宽度),然后我们的盒阴影 (c) 偏移足够大以显示出来。这很棒,因为我们不再需要处理负盒阴影才能使所有内容正确分层。

我们也回到了 bgcolor 并可以利用背景颜色的一个很好的特性:因为 <html> 没有自己的背景颜色,所以它会从 <body> 继承一个。

尝试 9 和 10:118 字节

<body bgcolor=0B2429 style=border-radius:67%0;margin:75+340+75-90;box-shadow:7cm+0#F3AC3C,57mm+0#998235,55vh+0#1A4341>

通过更多地调整单位,我们能够再节省两个字节(感谢 Dorus,他是第一个发现此优化的)。调整边距可以节省一位数字(150 变为 90),并且作为额外的好处,我们可以将 86mm 转换为 70mm,后者变为 7cm。我在这里再次结合了两个尝试,它们只是微小的单位修复。(我不好意思地说,我最初错过了 mmcm 的转换。)

尝试 11:117 字节

<body bgcolor=0B2429 style=border-radius:67%0;margin:75+85%75-90;box-shadow:7cm+0#F3AC3C,57mm+0#998235,55vh+0#1A4341>

Romain Deltour 是第一个找到这个 117 字节解决方案的人。将 340 更改为 85% 意味着我们可以在其中一个值之后省略空格(就像我们在 border-radius 中所做的那样),从而节省另一个字节。

尝试 12:115 字节

<body bgcolor=0B2429 style=border-radius:67%0;margin:75+85%75-90;box-shadow:7cm+0#F3AC3C,57mm+0#998235,55vh+0#7fd2>

在 Romain 的 117 字节解决方案发布两周后,Viacheslav Popov 能够通过Alpha 合成并使用4 位十六进制代码将字节数减少到 115。

我真的很喜欢这个,因为它不仅非常巧妙,而且很多人(包括我自己)都认为目标已经完全优化了。Viacheslav 的坚持不仅引发了新一轮的讨论,还为我们未来的目标增添了另一个 CSS 技巧™。

尝试 13:<115 字节?

在我看来,这似乎非常接近最优,但这肯定不意味着它无法被超越——为什么不试一试呢?有一些先前成果可以帮助你入门,有很多人愿意提供帮助,甚至有一些工具。祝你代码高尔夫愉快⛳️