html - 尽管有 `line-height: 1` 和 `overflow: hidden`,仍保持悬挂字符可见
问题描述
目标
<div class="Card">
<div class="Card-FullNameLabel">Gregg Sims</div>
<div class="Card-OrganizationNameLabel">Compubotics</div>
</div>
.Card-FullNameLabel
有font-size: 16px
和line-height: 1
。_.Card-OrganizationNameLabel
有font-size: 12px
和line-height: 1
。_.Card-FullNameLabel
和之间的垂直空间.Card-OrganizationNameLabel
必须恰好是6px
。- 以下 CSS 规则必须有效且不得更改。
.Card-FullNameLabel + .Card-OrganizationNameLabel {
margin-top: 6px;
}
- 两者
.Card-FullNameLabel
和都.Card-OrganizationNameLabel
必须具有溢出容限(例如,如果此内容类似于等ÀÇĤjgpfhjklbĜiEstosTreMalfaci
,则它不能从父对象悬垂)。 - 尽管有 ,所有字母都必须完全可见
line-height: 1
。 - 不允许在 CSS 代码中使用心算(幻数和/或硬编码偏移量和其他必须预先计算的值)。
可以做什么:使用 Pug 预处理器的功能进行标记和 CSS 预处理器的样式。
初始小提琴不满足条件编号5:当前卡不具有溢出容错性。
关于line-height: 1
,不好的做法
我一再被告知我必须将line-height
值设置为超过1
.
很明显,设置 line-height: 1 是一种不好的做法。我提醒你,无单位值是相对于字体大小的,而不是相对于内容区域的,处理小于内容区域的虚拟区域是我们许多问题的根源。
好吧,我不会为此争论。我想要的只是实现我的目标的工作解决方案(如上所述)。使用它是我的责任,如果您同意line-height
必须超过1
.
但是为什么我不想line-height
那么执着地增加呢?
原因一:精确定义两个元素之间的垂直空间会变得过于复杂
该规则.Card-FullNameLabel + .Card-OrganizationNameLabel { margin-top: 6px; }
清晰、直观,并通过 CSS 表达了准则(如上图所示)。“.Card-OrganizationNameLabel
必须退出.Card-FullNameLabel
6 个像素”,仅此而已。
但是,如果我们需要在行高大于 1(或者它们具有顶部和底部填充).Card-FullNameLabel
之间定义相同的垂直空间怎么办?.Card-OrganizationNameLabel
规则的值margin-top
(由下图中未覆盖的粉红色区域可视化).Card-FullNameLabel + .Card-OrganizationNameLabel
现在是:
- 所需范围(6px)
- 下面的额外垂直空间
.Card-FullNameLabel
(指定为l_b
) - 上面的额外垂直空间
.Card-OrganizationNameLabel
(指定为l_a
)
正如我上面所说,心算是不允许的,因为它会贬低编程(CSS 案例中的 CSS 预处理器功能)并产生灵活性/可维护性影响(如果我们更改标签之间的line-height
或font-size
或所需的垂直空间,一切都需要在心理上重新 -计算)。
虽然预处理器的变量(今天在原生 CSS 中可用)可以解决这个问题,但维护起来太复杂了。要计算上图中不相交的红色粉红色,我们需要:
- 变量
font-size
化.Card-FullNameLabel
- 变量
line-height
化.Card-FullNameLabel
- 计算下面的额外空间
.Card-FullNameLabel
。 - 变量
font-size
化.Card-OrganizationNameLabel
- 变量
line-height
化.Card-OrganizationNameLabel
- 计算下面的额外空间
.Card-OrganizationNameLabel
- 将所需范围可变为
.Card-FullNameLabel
和.Card-OrganizationNameLabel
(在本例中为 6 个像素)。
在此之后,我们最终可以计算margin-top
规则的.Card-FullNameLabel + .Card-OrganizationNameLabel
。每对元素都一样,比如.Card-FullNameLabel
and .Card-OrganizationNameLabel
!! 2020 年代 Web 开发的技术太差了。
原因2:不需要每种语言
在下面的示例中,日文符号完全符合line-height: 1
(16px):
我想中文、韩文和许多其他非拉丁字符的语言也是如此。
但是:在少数情况下,可能会混合使用外国符号:
如果要谈高品质,这个案子是必须要支持的。
我不想仅仅因为这个例外而增加行高。线与线之间的垂直空间实际上变成了没关系:或6px
的尾巴重量很小,不会破坏几何美学。j
À
我的努力
尝试1:使用:before
and:after
SASS-mixinTextTruncation
接受$extraSpace
添加顶部和底部填充的参数。和伪元素通过:before
负:after
边距补偿此填充。
@mixin TextTruncation($extraSpace, $displayEllipsis: false) {
overflow: hidden;
white-space: nowrap;
@if ($displayEllipsis) {
text-overflow: ellipsis;
} @else {
text-overflow: clip;
}
padding-top: $extraSpace;
padding-bottom: $extraSpace;
&:before,
&:after {
content: "";
display: block;
}
&:before {
margin-top: -$extraSpace;
}
&:after {
margin-bottom: -$extraSpace;
}
}
body {
padding: 12px;
}
* {
line-height: 1;
font-family: Arial, sans-serif;
}
.Card {
display: flex;
flex-direction: column;
align-items: center;
width: 240px;
height: 320px;
padding: 6px 12px 12px;
background: white;
box-shadow: 0 0 3px rgba(0, 0, 0, 0.5);
}
.Card-FullNameLabel {
max-width: 100%; /* Required when the flex parent has `align-items: center` */
@include TextTruncation($extraSpace: 2px, $displayEllipsis: true);
font-size: 16px;
color: #707070;
}
.Card-OrganizationNameLabel {
max-width: 100%; /* Required when the flex parent has `align-items: center` */
@include TextTruncation($extraSpace: 2px, $displayEllipsis: true);
font-size: 12px;
color: #A2A2A2;
}
.Card-FullNameLabel + .Card-OrganizationNameLabel {
margin-top: 6px;
}
不幸的是,它不起作用:效果就像没有定义边距和填充一样:
尝试2:使用包装器
如果 和 的组合overflow-x: hidden
有效overflow-y: visible
,那就是解决方案。但它不起作用,这个问题已经在问题CSS overflow-x: visible;中考虑过。和溢出-y:隐藏;导致滚动条问题。
我想尽可能地使用包装器,但在这里看起来包装器将是最后的手段。为了避免每次都写两个标签,我创建了 Pug mixin:
mixin SingleLineLabel
span.SingleLineLabel&attributes(attributes)
span.SingleLineLabel-Text
block
好吧,SingleLineLabel
现在是一个组件。除了 Pug mixin 之外,还需要定义基本样式,SASS mixin 允许单独自定义标签:
// Constant styles
.SingleLineLabel {
overflow-y: visible;
&:before,
&:after {
content: "";
display: block;
}
&-Text {
display: block;
overflow-x: hidden;
white-space: nowrap;
}
}
// Variable styles
@mixin SingleLineLabel($truncatedVerticalSpaceCompensation, $displayEllipsis: false) {
&:before {
margin-top: -$truncatedVerticalSpaceCompensation
}
&:after {
margin-bottom: -$truncatedVerticalSpaceCompensation
}
.SingleLineLabel-Text {
padding-top: $truncatedVerticalSpaceCompensation;
padding-bottom: $truncatedVerticalSpaceCompensation;
@if ($displayEllipsis) {
text-overflow: ellipsis;
} @else {
text-overflow: clip;
}
}
}
现在我们可以应用它了:
.Card-FullNameLabel {
max-width: 100%; /* Required when the flex parent has `align-items: center` */
@include SingleLineLabel($truncatedVerticalSpaceCompensation: 1px, $displayEllipsis: true);
font-size: 16px;
color: #707070;
}
.Card-OrganizationNameLabel {
max-width: 100%; /* Required when the flex parent has `align-items: center` */
@include SingleLineLabel($truncatedVerticalSpaceCompensation: 2px, $displayEllipsis: true);
font-size: 12px;
color: #A2A2A2;
}
.Card-FullNameLabel + .Card-OrganizationNameLabel {
margin-top: 6px;
}
似乎已经达到了目标:
不幸的是,它存在发生规律不清楚的错误。有时会出现小的垂直滚动条。
我真的不知道怎么重现,但是在过去的实验中出现过,例如,如果通过开发工具将浏览器切换到设备模拟模式然后退出该模式。如果在小提琴中重复相同的实验,很可能不会得到相同的效果。
最后
基于您出色答案的解决方案将包含在不断增长的@yamato-daiwa/frontend库中。
如果您有问题符号的完整列表,例如g
、p
、À
等Ĥ
,请分享它 - 我将使用它进行测试,并将它们添加到未来的 pug 功能中以进行溢出容限测试。
解决方案
我知道您明确表示您需要保留line-height: 1
and margin-top: 6px
,但是正如您在记录的溢出 CSS 问题中确定的那样,您有点受制于当前的限制。
如果完全有可能对这些限制保持灵活,我有一个在视觉上与您最初追求的解决方案相同的解决方案。
原始状态
我从您的Initial Fiddle开始,并在 html 中添加了省略号截断 CSS 和有问题的文本。
.Card-FullNameLabel,
.Card-OrganizationNameLabel {
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
结果就是这种状态,我称之为“原始”,因为它使您的line-height
值margin
保持不变。请注意,我添加了一条overflow: hidden
规则来代替有问题的overflow-x
和overflow-y
规则混合。
建议修复
我建议进行以下 CSS 更改。这增加到line-height
允许1.5
所有字体的上升和下降都可见。然后我添加了负偏移边距来补偿:
.Card-FullNameLabel,
.Card-OrganizationNameLabel {
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
/* Shows all ascenders and descenders */
line-height: 1.5;
}
.Card-FullNameLabel {
font-size: 16px;
color: #707070;
/* Compensates for line-height */
margin: -4px 0;
}
.Card-OrganizationNameLabel {
font-size: 12px;
color: #A2A2A2;
/* Compensates for line-height */
margin: -3px 0;
}
.Card-FullNameLabel + .Card-OrganizationNameLabel {
/* 6px visually (minus 3px) */
margin-top: 3px;
}
结果可以在这里看到,我将其称为“建议的修复”。我已经确认结果在 MacOS 上的最新桌面 Chrome、Firefox 和 Safari 以及 iOS 上的 Mobile Safari 中是一致的。
比较
我从“之前”和“之后”屏幕截图中制作了一个简单的动画,展示了输出在视觉上是相同的,只是建议的修复不会切断字体的上升和下降。
请注意,您可以单击动画来查看全尺寸、1:1 像素精度的版本。
我用我称之为“中间元素”的东西做了一些额外的测试,以证明即使中间有元素,建议的修复也会与原始修复相同。
更新:自动化
正如评论中明确指出的,要求之一是 CSS 中没有“硬编码”或“魔术”数字。因此,虽然上述解决方案有效,但它需要提前手动算术。
这是一个更新的Codepen,它可以通过使用一些 SCSS 逻辑自动生成与上面显示的相似的 CSS,该逻辑将根据这些输入值计算偏移量:
多变的 | 当前值 |
---|---|
$globalLineHeight |
1 |
$minLineHeight |
1.5 |
$fullNameFontSize |
16px |
$fullNameLineHeight |
$globalLineHeight |
$orgNameFontSize |
12px |
$orgNameLineHeight |
$globalLineHeight |
$orgNameMarginTop |
6px |
出于演示目的,我添加了一些额外的代码来显示“之前”和“之后”悬停效果,以便您可以看到与原始 CSS 相比 SCSS 逻辑的行为方式。正如 HTML 和 CSS 中所指出的,您可以删除以 . 开头的行以下的任何内容#DELETE-ME
。
推荐阅读
- r - 按列 ggplot2 在地图上为网格单元格着色
- java - Android ViewBinding 有时会在绑定对象处返回 null,因此在尝试访问视图时出现空指针异常
- excel - Powershell,Excel在列中查找字符串
- python - Pandas 使用 if 将值从 df 添加到新的 df
- memory-management - C/C++:减少浪费的最佳可增长缓冲区分配大小
- ios - 如何使用 AudioKit 运行自定义 DSP?
- c++ - 如何在 C++ 中获取边界框(矩形)内的像素值和坐标?有什么方法吗?
- java - JSON数据请求后的空对象
- javascript - 胜利图改变渲染顺序(从顶部渲染水平条)
- reactjs - 为什么 VS Code 从“hoist-non-react-statics/node_modules/@types/react”导入