mirror of
https://github.com/suitenumerique/meet.git
synced 2026-09-05 15:16:38 +00:00
d46cf43c7d
The previous implementation centered initials by measuring `<text>`
with `getBBox()`, which returns the font's advance-width by
ascent-to-descent band, not the ink of the glyphs. On fonts with an
asymmetric band, initials rendered off-center. Marianne is a
particularly clear case: ascent 1131 / descent 256 puts the band
center 87.5/1000 above the caps' optical center, so every avatar
sat ~4.6 viewBox units (~1.5–1.8 px) too low. A follow-up rewrite
using canvas `actualBoundingBox*` metrics fixed it but pulled in a
runtime measurement rig (shared canvas, ref, state, layout effect,
`fonts.load` + `loadingdone`, plus combining-mark stripping) just
to place two uppercase letters.
Since initials are always uppercased, optical centering has a
closed form: `baseline = center + capHeight/2`. Real-world text
fonts have cap heights in a narrow ~0.66–0.73 em band (Marianne is
0.70), so:
translateY(calc(var(--avatar-cap-height, 0.7) * 0.5em))
is exact for the stock font and within ~0.4 px for any plausible
replacement. No JS, SSR-safe, no first-paint jump, no font-loading
race. Accents float above the cap box instead of dragging the
letter down.
The single font-dependent number remaining (cap height) is exposed
as a CSS variable, so self-hosters overriding the font can override
it next to the font itself, or leave the default. Once
`text-box: trim-both cap alphabetic` ships broadly, even the
variable can go.
72 lines
1.7 KiB
CSS
72 lines
1.7 KiB
CSS
:root {
|
|
--fonts-sans: 'Marianne', ui-sans-serif, system-ui, sans-serif;
|
|
--avatar-cap-height: 0.7;
|
|
}
|
|
|
|
.Header-beforeLogo {
|
|
display: block;
|
|
}
|
|
|
|
.Header-beforeLogo::before {
|
|
content: '';
|
|
display: block;
|
|
background-image: url(/assets/marianne.svg);
|
|
background-position: 0 -0.046875rem;
|
|
background-size: 2.0625rem 0.84375rem;
|
|
height: 0.75rem;
|
|
margin-bottom: 0.1rem;
|
|
width: 2.0625rem;
|
|
}
|
|
|
|
.Header-beforeLogo::after {
|
|
content: '';
|
|
display: block;
|
|
background-image: url(/assets/gouvernement.svg), url(/assets/devise.svg);
|
|
background-repeat: no-repeat, no-repeat;
|
|
background-size: 108.8px 10px, 40px 29px;
|
|
background-position: 0 3px, 0 18.9px;
|
|
width: 108.8px;
|
|
height: 48px;
|
|
margin-top: 0.25rem;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: 'Marianne';
|
|
src: url('/assets/fonts/Marianne-Regular-subset.woff2') format('woff2');
|
|
font-weight: 400;
|
|
font-style: normal;
|
|
font-display: swap;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: 'Marianne';
|
|
src: url('/assets/fonts/Marianne-Regular_Italic-subset.woff2') format('woff2');
|
|
font-weight: 400;
|
|
font-style: italic;
|
|
font-display: swap;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: 'Marianne';
|
|
src: url('/assets/fonts/Marianne-Medium-subset.woff2') format('woff2');
|
|
font-weight: 500;
|
|
font-style: normal;
|
|
font-display: swap;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: 'Marianne';
|
|
src: url('/assets/fonts/Marianne-Bold-subset.woff2') format('woff2');
|
|
font-weight: 700;
|
|
font-style: normal;
|
|
font-display: swap;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: 'Marianne';
|
|
src: url('/assets/fonts/Marianne-ExtraBold-subset.woff2') format('woff2');
|
|
font-weight: 800;
|
|
font-style: normal;
|
|
font-display: swap;
|
|
}
|