Target
<div class="Card">
<div class="Card-FullNameLabel">Gregg Sims</div>
<div class="Card-OrganizationNameLabel">Compubotics</div>
</div>
- The
.Card-FullNameLabel
hasfont-size: 16px
andline-height: 1
. - The
.Card-OrganizationNameLabel
hasfont-size: 12px
andline-height: 1
. - The vertical space between
.Card-FullNameLabel
and.Card-OrganizationNameLabel
must be exactly6px
. - Below CSS rule must work and must NOT be changed.
.Card-FullNameLabel + .Card-OrganizationNameLabel {
margin-top: 6px;
}
- Both
.Card-FullNameLabel
and.Card-OrganizationNameLabel
must have overflow tolerance (e. g. if this content will be something likeÀÇĤjgpfhjklbĜiEstosTreMalfaci
and so on it must not overhang from the parrent). - All letters must be fully visible despite to
line-height: 1
. - The mental arithmetic (magic numbers and/or hard coded offsets and other values which must be pre-computed) in CSS code are not allowed.
What is O'K to do: use the functionality of Pug pre-processor for markup and CSS pre-processors for styles.
Inital fiddle does not satisfied to the condition number 5: currently the card is not overflow-tolerant.
About line-height: 1
, the bad practice
I has been repeatedly told about I must set line-height
to value more than 1
.
It becomes obvious that setting line-height: 1 is a bad practice. I remind you that unitless values are font-size relative, not content-area relative, and dealing with a virtual-area smaller than the content-area is the origin of many of our problems.
Well, I don't going to dispute about it. All I want is the working solution for the reaching of my target (descripted above).
The usage of it is my responsibility and I will not reсcommend this solution if you agree that line-height
must be more than 1
.
But why I don't want increase the line-height
so persistently?
Reason 1: The precise defining of the vertical space between two elements will become too complicated
The rule .Card-FullNameLabel + .Card-OrganizationNameLabel { margin-top: 6px; }
is clear, intuitive and expresses the guidelines (represented in the picture above) by CSS. "The .Card-OrganizationNameLabel
must retire from .Card-FullNameLabel
by 6 pixels", and nothing more.
But what if we need to define the same vertical space between .Card-FullNameLabel
and .Card-OrganizationNameLabel
when line height is more than 1 (or they have the top and bottom paddings)? The value of the margin-top
(visualized by non-overlayed pink area in the picture below) of .Card-FullNameLabel + .Card-OrganizationNameLabel
rule now be the difference of:
- The desired range (6px)
- The extra vertical space below
.Card-FullNameLabel
(designated asl_b
) - The extra vertical space above
.Card-OrganizationNameLabel
(designated asl_a
)
As I told above, the mental arithmetic is not allowed because it devalues the programming (CSS preprocessors capabilities in CSS case) and makes flexibility/maintainability impact (if we change the line-height
or font-size
or desired vertical space between labels, everything need to be mentally re-computed).
Although the preprocessor's variables (today became available in native CSS) can solve this problem, it will be too complicated to maintain it. To compute the non-intersecting red pink in the image above, we need to:
- Variablelize the
font-size
of.Card-FullNameLabel
- Variablelize the
line-height
of.Card-FullNameLabel
- Compute the extra space below
.Card-FullNameLabel
. - Variablelize the
font-size
of.Card-OrganizationNameLabel
- Variablelize the
line-height
of.Card-OrganizationNameLabel
- Compute the extra space below
.Card-OrganizationNameLabel
- Variablelize the desired range between
.Card-FullNameLabel
and.Card-OrganizationNameLabel
(6 pixels in this example).
After this, we can finally compute the margin-top
for the rule .Card-FullNameLabel + .Card-OrganizationNameLabel
. And same for each pair of elements like .Card-FullNameLabel
and .Card-OrganizationNameLabel
!! Too poor technology for the web development in 2020s.
Reason 2: It does not require for each language
In below example, the Japanese symbols are perfectly fits to line with line-height: 1
(16px):
I suppose same will be for the Chinese, Korean and many other languages with non-latin characters.
But: in the small percentage of cases, there the foreign symbols could be mixed:
If to talk about high quality, this case must be supported.
I don't want increase the line height just for this exception. It's OK that the vertical space between lines actually became not 6px
: the tails of j
or À
has a small weight and it will not break the geometric aesthetics.
My efforts
Attempt 1: usage of :before
and :after
The SASS-mixin TextTruncation
accepts the parameter $extraSpace
which adding top and bottom paddings. The :before
and :after
pseudo elements compensates this paddings by negative margins.
@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;
}
Unfortunately, It does not work: the effect is same as if no margins and no paddings has been defined:
Attempt 2: usage of the wrapper
If the combination of overflow-x: hidden
and overflow-y: visible
works, it was the solution. But it does no work and this problem has been considered in the question CSS overflow-x: visible; and overflow-y: hidden; causing scrollbar issue.
I want to avid the wrappers as possible, but here it looks like the wrapper will be the last resort. To avoid of writing two tags each time, I created the Pug mixin:
mixin SingleLineLabel
span.SingleLineLabel&attributes(attributes)
span.SingleLineLabel-Text
block
Well, the SingleLineLabel
now a component. Besides the Pug mixin it's required to define the basic styles and SASS mixin allows to customize the label individually:
// 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;
}
}
}
Now we can apply it:
.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;
}
It seems like the target has been reached:
Unfortunately, it has the bug which occurrence regularity is unclear. Sometimes the small vertical scrollbar appearing.
I really don't know how to reproduce it, but in the past experiment it has occurred, for example, if to switch the browser to device simulation mode by development tools and then exit from this mode. Most likely, you will not get the same effect if repeat same experiment in fiddle.
Finally
The solution based on your great answers will be included to growing @yamato-daiwa/frontend library.
If you have the full list of the problematic symbols like g
, p
, À
, Ĥ
and so on, please share it - I'll use it for the tests and also add them to the future pug functionality for the overflow tolerance testing.