【CSS in Depth 2 精译_022】3.6 一招搞定容器内元素间距的问题 + 3.7 本章小结

当前内容所在位置(可进入专栏查看其他译好的章节内容)

  • 第一章 层叠、优先级与继承(已完结)
    • 1.1 层叠
    • 1.2 继承
    • 1.3 特殊值
    • 1.4 简写属性
    • 1.5 CSS 渐进式增强技术
    • 1.6 本章小结
  • 第二章 相对单位(已完结)
    • 2.1 相对单位的威力
    • 2.2 em 与 rem
    • 2.3 告别像素思维
    • 2.4 视口的相对单位
    • 2.5 无单位的数值与行高
    • 2.6 自定义属性
    • 2.7 本章小结
  • 第三章 文档流与盒模型(已完结)
    • 3.1 常规文档流
      • 3.1.1 内容水平居中
      • 3.1.2 逻辑属性
      • 3.1.3 用好逻辑属性的简写形式
    • 3.2 盒模型
      • 3.2.1 避免使用魔数
      • 3.2.2 调整盒模型
      • 3.3.3 全局设置 border-box
    • 3.3 元素的高度
      • 3.3.1 控制溢出行为
      • 3.3.2 百分比高度的备选方案
      • 3.3.3 使用 min-height 和 max-height
    • 3.4 负的外边距
    • 3.5 外边距折叠
      • 3.5.1 文字折叠
      • 3.5.2 多个外边距折叠
      • 3.5.3 向容器外折叠
    • 3.6 容器内的元素间距问题 ✔️
      • 3.6.1 当内容改变时的处理 ✔️
      • 3.6.2 更通用的解决方案 ✔️
    • 3.7 本章小结 ✔️
  • 第四章 Flexbox 布局
    • 4.1 Flexbox 布局原理(精译中 ⏳)

3.6 容器内的元素间距问题

图 3.18 间距适中的社交模块最终布局效果

图 3.18 间距适中的社交模块最终布局效果

先处理两个社交按钮的样式(译注:赞助商链接后续会添加,这里暂不用管)。页面已经预留了一个 button-link 类,用作 CSS 选择器再好不过了。

由于设计的是链接的通用样式,指定其为块级元素,不仅能让样式充满容器的整个宽度,还能让每个链接按钮独占一行。按以下代码更新页面样式:

代码清单 3.12 设置侧边栏按钮的大小、字体和颜色

.social-links {
  max-inline-size: 25em;  /* 收窄容器宽度 */
  padding: 1em 1.5rem;
  background-color: #fff;
  border-radius: 0.5em;
}
 
.button-link {
  display: block;  /* 块级元素将填满所有可用宽度,并将每个链接独占一行 */
  padding: 0.5em;
  color: #fff;
  background-color: var(--brand-color);
  text-align: center;
  text-decoration: none;
  text-transform: uppercase;
}

链接样式搞定后,还得处理好它们之间的间距。如果不指定外边距,按钮就会直接堆叠在一起,就像现在这样。备选方案有两个:在必然发生外边距折叠的两个社交按钮间,要么分别设置、要么同时设置它们的上下外边距。

然而不管采用哪种方案,都会遇到一个问题:元素外边距与所在容器的内边距将同时生效。例如给两个按钮加上样式 margin-top: 1.5em,最终效果如图 3.19 所示。

图 3.19 按钮的顶部外边距在感官上增大了容器的内边距

图 3.19 按钮的顶部外边距在感官上增大了容器的内边距

此时,第一个按钮新增的顶部外边距令容器顶部间隙过大,与其余三边一对比显得很不协调。

这个问题有很多种解决方案,代码清单 3.13 给出的是一种较简单的版本。利用相邻兄弟组合选择器(+)选中同一父元素下紧邻其他 button-link 后的 button-link 元素。此时所设置的外边距样式只对两个按钮之间的部分生效。

代码清单 3.13 使用相邻兄弟组合样式在按钮间应用外边距

.button-link {
  display: block;
  padding: 0.5em;
  color: #fff;
  background-color: var(--brand-color);
  text-align: center;
  text-decoration: none;
  text-transform: uppercase;
}
.button-link + .button-link {  
  /* 对紧跟某按钮链接的另一按钮链接应用顶部外边距 */
  margin-block-start: 1.5em;   
}                              

该方案应该是有效的。如图 3.20 所示,第一个按钮的上边距不见了,容器四周的间距都是一致的。

图 3.20 按钮周围应用了一致的间距

图 3.20 按钮周围应用了一致的间距

这种写法充分利用了 + 组合选择器,可以推广应用到需要设置容器内元素间隙的场景中。同理,该写法也适用于在一系列行内元素、或行内块级元素之间设置左外边距。相关组合选择器的汇总梳理,详见本书附录 A。

3.6.1 当内容改变时的处理

刚才的做法思路倒没问题,但只要向侧边栏添加更多内容,间距的问题就又出现了。比如按照以下内容,在页面上再加一个友情赞助的超链接,并指定一个样式类 sponsor-link 以便设置新样式。

代码清单 3.14 给侧边栏添加一个不同类型的链接

<aside class="social-links">
  <a href="/mastodon" class="button-link">
    Follow us on Mastodon
  </a>
  <a href="/facebook" class="button-link">
    Like us on Facebook
  </a>
  <!-- 给侧边栏添加一个不同类型的链接 -->
  <a href="/sponsors" class="sponsor-link">
    Become a sponsor
  </a>
</aside>

接着,就得为该链接设置样式,但同时还得处理好它与其他按钮之间的间距。图 3.21 是处理间距 之前 的样子。

图 3.21 第二个按钮与底部链接之间缺少间距

图 3.21 第二个按钮与底部链接之间缺少间距

新链接的样式如下所示。样式更新后,您可能首先想的是再加个顶部外边距来解决间距问题。先别急,我接下来会给出另一个巧妙的替代方案。

代码清单 3.15 赞助商链接的样式

.sponsor-link {
  display: block;
  color: var(--brand-color);
  font-weight: bold;
  text-decoration: none;
}

再加一个顶部外边距固然正确,但鉴于 HTML 改动频繁的沉疴顽疾,没准下个月或来年,该侧边栏中的某些内容就得挪挪位置或者被替换掉,比如把友情赞助链接移到侧边栏的顶部,又或者需要添加一个组件来注册邮箱简讯等。

只要内容一变,相应的边距问题也只能再搞一遍,以确保每块内容之间都能间隔一致,但容器的上下边缘除外。

3.6.2 更通用的解决方案

Web 设计师 Heydon Pickering 曾表示,外边距“就像是在一个物体的某一侧抹了胶水,而你还没想好要不要把它贴到哪儿或者贴到什么东西上”。与其在当前页面反复设置同样的外边距,不如以一种更通用的方式固定写死,使得该间距任由页面结构如何调整都能生效。这就要用到一类特殊的选择器,Pickering 称之为 迟钝的猫头鹰选择器(lobotomized owl selector),因为它长这样:* + *。关于该选择器的详细用法,Pickering 还特地写了一篇博客 https://alistapart.com/article/axiomatic-css-and-lobotomized-owls/。

该选择器开头是一个可以选中任意元素的通用选择器(*),接着是一个相邻兄弟组合器(+),最后是另一个通用选择器。它因形似一只眼神呆滞的猫头鹰而得名。这只做了脑叶切除术的呆头鹰功能上与前面用过的选择器 .social-button + .social-button 差不多。区别在于它不会选中紧跟在其他按钮后的按钮,而是选中紧跟在任意元素后的任意元素。也就是说,它选中的是除首个子元素外所有同一父元素下的子元素。(也可以使用 :not(:first-child) 选择器等效替换)

接下来演示该选择器在设置页面顶部外边距的具体用法,不妨令其与一个新的“stack”类相结合,添加到需要设置子元素纵向间距的任意容器中。最终效果如图 3.22 所示。

图 3.22 所有元素间距一致

图 3.22 所有元素间距一致

按代码列表 3.16 更新样式。这里用到了另一个组合选择器:子组合器(>),让这只“呆萌猫头鹰”(lobotomized owl)只对 stack 类下的直接后代元素生效。这段代码在页面上大有用处。

代码清单 3.16 创建一个 stack 容器来纵向排布各元素间距

.stack > * + * {
  /* 指向堆栈中除第一个以外的所有子项 */
  margin-block-start: 1.5em;
}

接下来,就可以将 stack 类添加到任何需要设置子元素间距的容器中了。先加到 <body> 上,这样 <header><div class="container"> 之间就隔开了;再加到 <div class="container"> 上,这样主内容区和社交链接容器间也有了一致的间距;最后是社交链接容器,这样三个链接元素也统一隔开了。

加上该间距后,整个页面就大功告成了。完整样式如代码清单 3.17 所示:

代码清单 3.17 最终样式表

*,
*::before,
*::after {
  box-sizing: border-box;
}
 
:root {
  --brand-color: #0072b0;
  --column-width: 1080px;
}
 
body {
  margin: unset;
  background-color: #eee;
  font-family: Helvetica, Arial, sans-serif;
}
 
.page-header {
  color: #fff;
  background-color: var(--brand-color);
}
 
.page-header h1 {
  max-inline-size: var(--column-width);
  margin: 0 auto;
  padding: 1em 1.5rem;
}
 
.container {
  max-inline-size: var(--column-width);
  margin-inline: auto;
}
 
.main {
  padding: 1em 1.5rem;
  background-color: #fff;
  border-radius: 0.5em;
}
 
.social-links {
  max-inline-size: 25em;
  padding: 1em 1.5rem;
  background-color: #fff;
  border-radius: 0.5em;
}
 
.button-link {
  display: block;
  padding: 0.5em;
  color: #fff;
  background-color: var(--brand-color);
  text-align: center;
  text-decoration: none;
  text-transform: uppercase;
}
 
.sponsor-link {
  display: block;
  color: var(--brand-color);
  font-weight: bold;
  text-decoration: none;
}
 
.stack > * + * {
  margin-block-start: 1.5em;
}

3.7 本章小结

  • 在常规文档流中,行内元素并排排布,必要时换行。块级元素各自独占一行,并默认填满其容器的宽度。
  • 逻辑属性指的是元素在文档流中的各边(sides)或尺寸大小,而非其明确方位。
  • 盒模型描述了外边距、边框、内边距以及内容如何定义元素的尺寸大小。使用 box-sizing: border-box 可以让该尺寸大小的行为定义更加直观。
  • 元素的高度是根据其内容动态确定的。明确限制高度可能会导致溢出问题。
  • 元素的外边距可以与其容器外的其他外边距发生折叠,从而导致元素间的间距异常。应用 overflow: auto 可有效处理该问题。
  • 在统一设置块级元素之间的间距方面,呆头鹰选择器不失为一个好用的工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

安冬的码畜日常

您的鼓励是我持续优质内容的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值