<div class="Card"> <div class="Card-FullNameLabel">Gregg Sims</div> <div class="Card-OrganizationNameLabel">Compubotics</div> </div>.Card-FullNameLabel tiene font-size: 16px y line-height: 1 ..Card-OrganizationNameLabel tiene font-size: 12px y line-height: 1 ..Card-FullNameLabel y .Card-OrganizationNameLabel debe ser exactamente 6px . .Card-FullNameLabel + .Card-OrganizationNameLabel { margin-top: 6px; }.Card-FullNameLabel como .Card-OrganizationNameLabel deben tener tolerancia de desbordamiento (por ejemplo, si este contenido será algo así como ÀÇĤjgpfhjklbĜiEstosTreMalfaci , etc., no debe sobresalir del padre).line-height: 1 .Qué está bien hacer: usar la funcionalidad del preprocesador Pug para marcado y los preprocesadores CSS para estilos.
🌎 El violín inicial no cumple con la condición número 5 : actualmente la tarjeta no es tolerante al desbordamiento.
line-height: 1 , la mala práctica Me han dicho repetidamente que debo establecer line-height en un valor superior a 1 .
Se vuelve obvio que establecer line-height: 1 es una mala práctica. Les recuerdo que los valores sin unidades son relativos al tamaño de fuente, no al área de contenido, y tratar con un área virtual más pequeña que el área de contenido es el origen de muchos de nuestros problemas.
CSS de inmersión profunda: métricas de fuente, altura de línea y alineación vertical
Bueno, no voy a discutir sobre eso. Todo lo que quiero es la solución de trabajo para alcanzar mi objetivo (descrito anteriormente). Su uso es mi responsabilidad y no recomendaré esta solución si acepta que line-height debe ser superior a 1 .
Pero, ¿por qué no quiero aumentar la line-height manera tan persistente?
La regla .Card-FullNameLabel + .Card-OrganizationNameLabel { margin-top: 6px; } es claro, intuitivo y expresa las pautas (representadas en la imagen de arriba) por CSS. "La .Card-OrganizationNameLabel debe retirarse de .Card-FullNameLabel en 6 píxeles", y nada más.
Pero, ¿qué sucede si necesitamos definir el mismo espacio vertical entre .Card-FullNameLabel y .Card-OrganizationNameLabel cuando la altura de la línea es mayor que 1 (o tienen los rellenos superior e inferior)? El valor del margin-top (visualizado por un área rosa no superpuesta en la imagen a continuación) de .Card-FullNameLabel + .Card-OrganizationNameLabel ahora será la diferencia de:
.Card-FullNameLabel (designado como l_b ).Card-OrganizationNameLabel (designado como l_a ) Como dije anteriormente, la aritmética mental no está permitida porque devalúa la programación (capacidades de los preprocesadores CSS en el caso de CSS) y tiene un impacto en la flexibilidad/mantenibilidad (si cambiamos la line-height o font-size o el espacio vertical deseado entre etiquetas, todo necesita ser re-computado mentalmente).
Aunque las variables del preprocesador (hoy disponible en CSS nativo) pueden solucionar este problema, será demasiado complicado mantenerlo. Para calcular el rosa rojo que no se cruza en la imagen de arriba, necesitamos:
font-size de .Card-FullNameLabelline-height de .Card-FullNameLabel.Card-FullNameLabel .font-size de .Card-OrganizationNameLabelline-height de .Card-OrganizationNameLabel.Card-OrganizationNameLabel.Card-FullNameLabel y .Card-OrganizationNameLabel (6 píxeles en este ejemplo). Después de esto, finalmente podemos calcular el margin-top para la regla .Card-FullNameLabel + .Card-OrganizationNameLabel . ¡Y lo mismo para cada par de elementos como .Card-FullNameLabel y .Card-OrganizationNameLabel ! Tecnología demasiado pobre para el desarrollo web en la década de 2020.
En el siguiente ejemplo, los símbolos japoneses se ajustan perfectamente a la línea con line-height: 1 (16 px):
Supongo que lo mismo será para el chino, el coreano y muchos otros idiomas con caracteres no latinos.
Pero : en el pequeño porcentaje de casos, allí los símbolos extranjeros podrían estar mezclados:
Si para hablar de alta calidad, este caso debe ser compatible.
No quiero aumentar la altura de la línea solo por esta excepción. Está bien que el espacio vertical entre las líneas en realidad no sea de 6px : las colas de j o À tienen poco peso y no romperán la estética geométrica.
:before y :after SASS-mixin TextTruncation acepta el parámetro $extraSpace que agrega rellenos superior e inferior. Los pseudo elementos :before y :after compensan estos rellenos con márgenes negativos.
@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; }Desafortunadamente, no funciona: el efecto es el mismo que si no se hubieran definido márgenes ni rellenos:
Si la combinación de overflow-x: hidden y overflow-y: visible funciona, era la solución. Pero no funciona y este problema se ha considerado en la pregunta CSS overflow-x: visible; y desbordamiento-y: oculto; causando problema de barra de desplazamiento .
Quiero ávido de los envoltorios como sea posible, pero aquí parece que el envoltorio será el último recurso. Para evitar escribir dos etiquetas cada vez, creé el mixin Pug:
mixin SingleLineLabel span.SingleLineLabel&attributes(attributes) span.SingleLineLabel-Text block Bueno, SingleLineLabel ahora es un componente. Además del mixin Pug, se requiere definir los estilos básicos y el mixin SASS permite personalizar la etiqueta individualmente:
// 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; } } }Ahora podemos aplicarlo:
.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; }Parece que se ha alcanzado el objetivo:
Desafortunadamente, tiene el error de que la regularidad de ocurrencia no está clara. A veces aparece la pequeña barra de desplazamiento vertical.
Realmente no sé cómo reproducirlo, pero en el experimento pasado ocurrió, por ejemplo, cambiar el navegador al modo de simulación de dispositivo mediante herramientas de desarrollo y luego salir de este modo. Lo más probable es que no obtenga el mismo efecto si repite el mismo experimento en el violín.
La solución basada en sus excelentes respuestas se incluirá en la creciente biblioteca @yamato-daiwa/frontend .
Si tiene la lista completa de los símbolos problemáticos como g , p , À , Ĥ , etc., compártala. La usaré para las pruebas y también la agregaré a la futura funcionalidad pug para la prueba de tolerancia al desbordamiento.
Sé que usted declaró explícitamente que necesitaba mantener line-height: 1 y margin-top: 6px , pero como se identificó con el problema de CSS de desbordamiento documentado , está atascado con sus restricciones actuales.
Si es posible ser flexible con respecto a esas restricciones, tengo una solución que es visualmente idéntica a la que buscabas originalmente.
Comencé con su violín inicial y agregué CSS de truncamiento de puntos suspensivos y texto problemático en el html.
.Card-FullNameLabel, .Card-OrganizationNameLabel { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } El resultado es este estado que llamo "Original" ya que no modifica los valores line-height y margin . Tenga en cuenta que agregué un overflow: hidden en lugar de la mezcla problemática de las reglas de overflow-x y overflow-y .
Propongo los siguientes cambios de CSS. Esto aumenta line-height a 1.5 , lo que permite que todos los ascendentes y descendentes de la fuente sean visibles. Luego agregué márgenes de compensación negativos para compensar:
.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; }El resultado se puede ver en acción aquí , al que me refiero como "Solución propuesta". He confirmado que los resultados son consistentes en las últimas versiones de escritorio de Chrome, Firefox y Safari en MacOS y Mobile Safari en iOS.
Hice una animación simple a partir de capturas de pantalla de "antes" y "después" que demuestran que el resultado es visualmente idéntico, excepto que la solución propuesta no corta los ascendentes y descendentes de la fuente.
Tenga en cuenta que puede hacer clic en la animación para ver una versión de tamaño completo con una precisión de píxel de 1:1.
Hice algunas pruebas adicionales con lo que llamo "elementos intermedios" para demostrar que la solución propuesta se comportaría igual que la original, incluso si hubiera elementos intermedios.
Como quedó claro en los comentarios, uno de los requisitos es que no haya números "codificados" o "mágicos" en el CSS. Entonces, si bien la solución anterior funciona, requiere aritmética manual antes de tiempo.
Aquí hay un Codepen actualizado que puede producir automáticamente un CSS similar al que se mostró arriba mediante el uso de alguna lógica SCSS que calculará las compensaciones en función de estos valores de entrada:
| Variable | Valor actual |
|---|---|
$globalLineHeight | 1 |
$minLineHeight | 1.5 |
$fullNameFontSize | 16px |
$fullNameLineHeight | $globalLineHeight |
$orgNameFontSize | 12px |
$orgNameLineHeight | $globalLineHeight |
$orgNameMarginTop | 6px |
Para fines de demostración, agregué un poco de código adicional que mostrará un efecto de desplazamiento "antes" y "después" para que pueda ver cómo se comporta la lógica SCSS en comparación con el CSS original. Como se indica tanto en HTML como en CSS, puede eliminar todo lo que esté debajo de las líneas que comienzan con #DELETE-ME .