新年里 CSS 更易编写

大家好,这里是大家的林语冰。持续关注,坚持阅读,每天一次,进步一点

免责声明

本文属于是语冰的直男翻译了属于是,略有删改,仅供粉丝参考。英文原味版请传送 A Few Ways CSS Is Easier To Write In 2023

本期共享的是 ------ 去年 CSS 引入了某些前沿新功能,辅助我们编写更精简、更灵活的 CSS,从此远离"代码屎山"。

我们生活在 CSS 的"样式复兴时代",新的功能、技术和想法日新月异,此"开元盛世"自 CSS3 以来见所未见。当我们的技术一日千里时,我们很容易"挨踢蕉绿",但也很容易因为近未来的创新而感到鸡冻,而 CSS 生态的沧桑巨变只用了不到一年的时间。虽然 CSS 的复杂性是一个热度不减的谈资,但有大佬认为去年的现代化 CSS 实际上使 CSS 更易编写。

CSS 变得更易编写,而不是变得非同寻常"。

这并非因为某些令人鸡冻的新功能引发"样式革命",比如级联图层或全新的色彩空间,而是因为一大坨新功能"梦幻联动",使 CSS 的风格更精简、有弹性,甚至有点防御性编程的味道。

高效风格组

禁止直接使用逗号分隔符将 :hover/:focus 状态链式多选,推荐使用全新的 :is() 伪类,重构为更可读的单行代码:

css 复制代码
/* 今年之前的传统写法 */
a:hover,
a:focus {
}

/* 去年之后的现代化写法 */
a:is(:hover, :focus) {
}

这里的"更具可读性"并非因为该写法更高效,而是更符合读者的直觉和人体工程学。

当然了,:is() 伪类绝对可以成为更高效的选择器,已经关注的老粉不用猴急,我们日后再说。

居中

居中是一道回头率超高的前端面试题,对不?可以这样说,将元素与其父容器的中心对齐的"传统方案"水到渠成。我们使用了 margin: auto 将元素从各个方向内推,直到它垂直居中。

这仍是一个有效的居中方案,因为 margin 的简写涉及每个方向。但假设当我们处于默认的水平左写书写模式下时,我们只需要沿内联方向工作,比如左右。这就是"传统方案"鞭长莫及的盲区。

css 复制代码
/* 传统写法 */
margin-left: auto;
margin-right: auto;

也许"外边距坍塌"十分头大。更重要的是,这需要放弃通用的 margin 简写,并专门针对其两个组成属性,再多写一行代码。但是,由于逻辑属性的概念,我们可以享受 margin 类型的另外两种简写:

  • 一种用于块方向
  • 一种用于内联方向

因此,重新审视只需内联方向居中的场景,我们现在可以通过下列方案保持效率:

css 复制代码
/* 现代化写法 */
margin-inline: auto;

该示例实现了从物理属性到逻辑属性的微妙转变,这一简单事实意味着,该示例与抛出 margin: auto 一样有效,并且能够适应写入模式的变化。如果页面突然发现自己处于垂直从右到左模式,当内联方向向上下而非左右流动时,它仍然会自动将元素在内联方向居中。

一般情况下调整写作模式

我已经给逻辑属性的优点疯狂点赞。实际上,自 Flexbox(弹性盒模型)和 CSS Grid(网格布局)以来,逻辑属性对我们今天编写 CSS 方式的影响,可能比任何其他 CSS 功能都要大。

传统上,我们可能会为"正常"书写方向编写一组样式,然后使用 [dir="rtl"],或其他方案在 HTML 级别上定位书写模式。但今天,凡是过往,皆为序章,我们使用逻辑属性卷土重来。这样,布局就会遵循书写模式!

在更改写入模式时,我们通常可能需要重置物理边距,如下所示:

css 复制代码
/* 传统写法 */
body {
  margin-left: 1rem;
}

body[dir='rtl'] {
  margin-left: 0; /* 重置左边距 */
  margin-right: 1rem; /* 应用右边距 */
  text-align: right; /* 文本排列到另一边 */
}

只要我们使用逻辑属性,就不再出现一大坨"代码屎山":

css 复制代码
/* 现代化写法 */
body {
  margin-inline-start: 1rem;
}

修剪多余的间距

我确信大家已经在 <nav> 导航标签里使用过无序列表的链接,来实现项目的主要或全局导航。

html 复制代码
<nav>
  <ul>
    <li><a href="/follow">关注</a></li>
    <li><a href="/like">点赞</a></li>
    <li><a href="/star">收藏</a></li>
  <ul>
</nav>

在这种需求下,我确信您大概率被要求并排显示这些链接,而不是像无序列表那样顺其自然地垂直堆叠。我们中某些已经编写多年样式的老玩家可能已经形成肌肉记忆,可以将这些列表项的 display 属性从默认的 block 元素更改为 inline-box 元素,同时保留块元素的盒模型属性:

css 复制代码
/* 传统写法 */
li {
  display: inline-block;
}

这些列表项之间需要空间。毕竟,它们不再占用其父级的全部可用宽度,因为 inline-block 元素的宽度只与它们包含的内容、以及边框、填充、边距和偏移量一样宽。传统上,这意味着,像我们对居中所做的那样应用 margin,但只有在我们想要的内联方向上应用 margin 属性,可能是 margin-left/margin-right/margin-inline-end

假设我们正在使用逻辑属性,并希望在内联方向的项目列表末尾有一个边距:

css 复制代码
/* 传统写法 */
li {
  display: inline-block;
  margin-inline-end: 1rem;
}

粉丝请注意,现在我们对所有列表项都有 margin。最后一个列表项实际上不需要 margin,因为它后面没有其他项目了。

大多数情况下,这简直酷毙了,但该方案使布局变得容易受到影响。如果产品经理让我们在 <nav> 标签旁边显示另一个元素,总不能打一架吧?突然间,我们正在处理多余的间距,这可能会影响我们决定如何设计新元素的样式。这是技术负债的一种形式。

最好搞定此问题,并不留后患地解决间距问题。我们可以使用更现代化的功能,比如 :not() 伪类。这样,我们就可以将最后一个列表项排除在 margin 需求之外。

css 复制代码
/* 现代化写法 */
li {
  display: inline-block;
}

li:not(:last-of-type) {
  margin-inline-end: 1rem;
}

粉丝请注意,以后我们还有更精简的现代化写法。我们可以使用 margin-trim 属性,当应用于父元素时,它会像做头发一样剪掉多余的间距,有效地折叠边距,防止子元素与父元素的边缘齐平。

css 复制代码
/* 更精简的现代化写法 */
ul {
  margin-trim: inline-end;
}

li {
  display: inline-block;
  margin-inline-end: 1rem;
}

粉丝请注意,margin-trim 目前是实验性功能,在我疯狂码字的此时此刻,该功能能且仅能被 Safari 浏览器支持。是的没错,这些最前沿的现代化特性,可能不完全是您想直接交付甲方、落地生产的东东。仅仅因为某些东东很"时髦",并不意味着它是 KPI 的"银弹"!

事实上,可能有一个更好的解决方案,没有任何大坑,而且它就在近在眼前:Flexbox。将无序列表转换为灵活的容器,会覆盖列表项的默认块级流式布局,而不更改其显示,为我们提供所需的并排布局。另外,我们还可以读写 gap 属性,我们可能会将其视为内置 margin-trimmargin,因为它只应用子级之间的空间,而不是应用它们的方方面面。

css 复制代码
/* 不是最时髦,但是最精简 */
ul {
  display: flex;
  gap: 1rem;
}

这就是我大爱 CSS 的原因。CSS 就像为你写诗,因为有一大坨方案可以表达同一件事,其中某些方案比其他方案更优雅。但"最好"的方案是符合你的心智模型的方案。如果结果如你所愿,那就不用怕其他人先质疑、再质疑。

粉丝请注意,删除有序列表和无序列表上的列表样式是常见需求,比如 list-style-type: none,但这会产生副作用,Safari 浏览器剥离了列表项的默认可访问角色。一种"修复方案"是将角色添加回 HTML <ul role="list> 中。还有另一种方案,允许我们通过删除具有空引号值的列表样式类型,来保留 CSS:

css 复制代码
ul {
  list-style-type: '';
}

保持比例

我们过去几乎没有什么选择来保持元素的物理比例。举个栗子,如果我们想要一个完美的正方形,我们可以依赖元素 width/height 显式声明的固定像素单位:

css 复制代码
/* 传统写法 */
height: 500px;
width: 500px;

或者,也许我们需要元素的大小稍微弯曲,因此我们更喜欢相对单位。在这种需求下,像百分比这样的值就很头大,因为像 50% 这样的值是相对于元素的父容器的大小,而不是元素本身的大小。然后,父元素需要固定尺寸或其他完全可预测的尺寸。这几乎是一个无限循环,试图通过设置另一个包含元素的比例,来维持一个元素的 1:1 比例。

所谓的"Padding Hack"确实是一个聪明的解决方案,而不是真正的"奇技淫巧",而是 CSS 盒模型大师级命令的展示。

"如果我们将元素的高度强制为零(height: 0;),且没有任何边框,那么填充将是盒模型中影响高度的唯一部分,我们将得到正方形"。------ C.C.

无论如何,这需要一大坨巧妙的"代码屎山"才能实现。CSS 工作组提出了一个更优雅的解决方案:aspect-ratio 属性。

css 复制代码
/* 精简写法 */
aspect-ratio: 1;
width: 50%;

现在,无论元素的宽度如何响应其周围环境,我们都有一个完美的正方形,这为我们提供了更简单有效的规则集,并且更能适应变化。

卡片悬停效果

在卡片上设置悬停效果的样式传统上是一个复杂的过程,我们将元素包装在 <a> 标签中,并挂钩到其悬停时相应的卡片样式。但是 :has() 伪类现在从 Firefox 121 开始在所有主要浏览器中都普遍支持!我们可以将链接作为子元素放置在卡片中,并在卡片悬停时将其设置为父元素。

css 复制代码
/* 传统写法 */
a.card-link:hover > .card {
}

/* 现代化写法 */
.card:has(:hover, :focus) {
}

完结撒花

这些只是 CSS 去年提供的新工具,私以为这些东东对我今天编写样式的方式影响颇大。我可以想到本文尚未提及的其他功能,但日后再说。这些功能包括但不限于:

  • 字符长度单位 ch
  • text-wrap: balance
  • Cascade Layers(级联图层)
  • 容器查询
  • <selectmenu> 标签
  • CSS 嵌套语法(SCSS/LESS 已死?)
  • 更多前沿技术日后再说......

我知道有一段时间,我们中的某些人先质疑、再质疑现在的 CSS 的心智模型是否"猪脑过载",并认为 CSS 的学习曲线比万里长城还陡峭。但私以为随着 CSS 变量和 CSS 嵌套语法等原生特性的普及,我们以后即使不借助 SCSS/LESS 等工具,也能灵活地使用给力的 CSS,这某种意义上也降低了前端工程化的技术熵,将我们从技术负债中解放出来。

本期话题是 ------ 你觉得哪个 CSS 的新特性未来可期?欢迎在本文下方群聊自由言论,文明共享。

《前端 9 点半》每日更新,持续关注,坚持阅读,每天一次,进步一点

谢谢大家的点赞,掰掰~

相关推荐
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60617 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅8 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment8 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅9 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊9 小时前
jwt介绍
前端
爱敲代码的小鱼9 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax