Mät det layoutade DOM-elementet vid den avsedda visningsbredden för att storleksbestämma en textförhandsvisning i webbläsaren. Använd Canvas för mått på text på en enda rad. Den här guiden visar hur du jämför båda på en Mac och förstår varför deras bredd och höjd skiljer sig åt.
Den praktiska uppgiften är att ta reda på hur mycket utrymme en syntetisk kortetikett behöver när webbläsarens visningsyta ändras. Ett användbart resultat registrerar visningsytan, den tillgängliga textbredden, teckensnittsinställningarna och den uppmätta rutan tillsammans. En bredd utan dessa villkor är svår att återskapa.
Vilken textbredd och texthöjd ska du mäta?
Webbläsarens API:er besvarar flera olika storleksfrågor. Välj det mått som motsvarar beslutet du behöver fatta innan du börjar beräkna.
| Din fråga | Mått | Vad det representerar |
|---|---|---|
| Hur långt sträcker sig en radbrytningfri sträng horisontellt? | Canvas measureText(text).width |
Textens framåtskjutning |
| Vilka är Canvas-glyfernas konturer? | Canvas-egenskaperna actualBoundingBox… |
Glyfernas gränser i förhållande till justeringspunkten och baslinjen |
| Hur mycket layoututrymme upptar ett kort? | Elementets getBoundingClientRect() |
Dess omslutande kantlinjeruta, inklusive utfyllnad och kanter |
| Var ligger textfragmenten efter radbrytning? | Range getClientRects() |
Rektanglar som hör till den markerade texten |
| Vilken rektangel omsluter textfragmenten? | Range getBoundingClientRect() |
Deras gemensamma omslutande rektangel |
Canvas-textens framåtskjutning och glyfbredd kan skilja sig åt: kursiva former kan sträcka sig utanför sin framåtskjutning. För glyfkonturer beräknar du bredden som actualBoundingBoxLeft + actualBoundingBoxRight och höjden som actualBoundingBoxAscent + actualBoundingBoxDescent. Måtten anges i CSS-pixlar. TextMetrics — MDN
Ett elementmått omfattar utfyllnad och kanter, medan ett textbaserat Range mäter markerad text med hjälp av teckensnittsmått. Ingetdera ska beskrivas som en exakt rektangel av de pixlar som faktiskt ritats ut. W3C-specifikationen definierar Range-textrektanglar horisontellt med hjälp av uppstapel, nedstapel och textens framåtskjutning. Element: metoden getBoundingClientRect() — MDN, CSSOM View Module — W3C
För en förhandsvisning av storleken i webbläsaren använder du elementrutan för att reservera utrymme och Range-rektanglarna för att granska textflödet. Behåll Canvas-måtten som en separat referens för den radbrytningfria strängen.
Ställ in visningsytan och textvillkoren först
Öppna DevTools i Chrome på din Mac, aktivera Toggle device toolbar och välj Responsive under Dimensions. Ange den avsedda bredden och höjden i visningsytans fält. Chrome dokumenterar både numerisk inmatning och storleksändring av visningsytan genom att dra i den. För en förhandsvisning på dator använder du enhetstypen för dator när den kontrollen finns. Simulera mobila enheter med enhetsläge — Chrome for Developers
Skilj mellan visningsytans bredd och textbredden. Ett kort kan ha en maxbredd, yttre mellanrum, utfyllnad och kanter. När kortet når sin maxbredd gör en ökning av webbläsarens bredd inte textytan större.
Anta till exempel att ett kort har en illustrativ bredd på 360px för kantlinjerutan, horisontell utfyllnad på 16px på varje sida och två kanter på 1px. Dess tillgängliga innehållsbredd är 360 − 32 − 2 = 326px. Det är den bredd som finns tillgänglig för radbrytning. Elementets omslutande rektangel rapporterar fortfarande 360px. Detta följer det dokumenterade beteendet för mätning av kantlinjerutan. Element: metoden getBoundingClientRect() — MDN
Matcha den avsedda teckensnittsfamiljen, vikten, storleken, stilen, radhöjden, avståndet och radbrytningsreglerna. I synnerhet kollapsar white-space: normal blanksteg och tillåter radbrytning, medan pre-wrap bevarar blanksteg och radbrytningar i källtexten, men fortfarande tillåter radbrytning. En förhandsvisning som använder det ena kan inte på ett tillförlitligt sätt representera det andra. white-space — MDN
Skilj också mellan teckenstorlek och radhöjd. Vid horisontell text påverkar line-height beräkningen av radhöjden; det beskriver inte bokstävernas synliga höjd. Ett teckensnitt på 16px med en radhöjd på 24px kräver därför en annan höjdberäkning än Canvas-måtten för glyfernas konturer. line-height — MDN
Kör en fullständig syntetisk textförhandsvisning
Öppna en tom flik, öppna DevTools, välj Console och kör följande fullständiga webbläsarskript en gång. Det skapar ett neutralt kort och en mätrapport. Inget bibliotek, externt teckensnitt, befintlig väljare eller HTML-fil behövs. Läs in den tomma fliken igen innan du kör en ny kopia.
Kortet följer visningsytan tills det når en bredd på 480px för kantlinjerutan. Rapporten uppdateras när fönstret eller den emulerade visningsytan ändras i storlek. Exemplet är avsiktligt begränsat till ett enkelt horisontellt textblock med enhetlig stil. Den webbläsarberoende koden har granskats; den kördes inte i en webbläsare under förberedelsen.
(async () => {
const text =
"Sample collection: round forms, soft gradients, and simple patterns.";
document.body.style.margin = "0";
const card = document.createElement("div");
card.textContent = text;
card.lang = "en";
card.dir = "ltr";
card.style.cssText = [
"box-sizing: border-box",
"width: min(480px, calc(100% - 48px))",
"margin: 24px",
"padding: 16px",
"border: 1px solid #777",
"font: normal 400 16px/24px Arial, sans-serif",
"font-kerning: normal",
"letter-spacing: 0px",
"word-spacing: 0px",
"white-space: normal",
"overflow-wrap: normal",
"word-break: normal",
"hyphens: none",
"color: #222",
"background: #f4f4f4"
].join(";");
const report = document.createElement("pre");
report.style.cssText =
"margin: 24px; white-space: pre-wrap; overflow-wrap: anywhere;";
document.body.append(card, report);
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");
if (!ctx) {
report.textContent = "A Canvas 2D context is unavailable.";
return;
}
// Establish layout before waiting for the fonts used by that layout.
card.getBoundingClientRect();
await document.fonts.ready;
const format = value =>
Number.isFinite(value) ? value.toFixed(2) : "unavailable";
function measure() {
const style = getComputedStyle(card);
const box = card.getBoundingClientRect();
const horizontalExtras =
parseFloat(style.paddingLeft) + parseFloat(style.paddingRight) +
parseFloat(style.borderLeftWidth) + parseFloat(style.borderRightWidth);
const range = document.createRange();
range.selectNodeContents(card);
const textBox = range.getBoundingClientRect();
const fragments = Array.from(range.getClientRects());
ctx.font = "normal 400 16px Arial, sans-serif";
ctx.fontKerning = "normal";
ctx.direction = "ltr";
ctx.textAlign = "left";
ctx.textBaseline = "alphabetic";
const metrics = ctx.measureText(text);
const inkWidth =
metrics.actualBoundingBoxLeft + metrics.actualBoundingBoxRight;
const inkHeight =
metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent;
report.textContent = [
"All dimensions below are CSS pixels.",
`Layout viewport: ${document.documentElement.clientWidth} x ${document.documentElement.clientHeight}`,
`Card border box: ${format(box.width)} x ${format(box.height)}`,
`Available text width: ${format(box.width - horizontalExtras)}`,
`Range bounds: ${format(textBox.width)} x ${format(textBox.height)}`,
`Range fragment count: ${fragments.length}`,
`Canvas unwrapped advance: ${format(metrics.width)}`,
`Canvas glyph bounds: ${format(inkWidth)} x ${format(inkHeight)}`,
`Computed line height: ${style.lineHeight}`
].join("\n");
}
measure();
window.addEventListener("resize", measure);
})().catch(error => console.error("Preview failed:", error));
Element- och Range-anropen använder webbläsarens faktiska layout. Canvas mäter samma syntetiska sträng som en enda rad utan radbrytning. HTML-standarden ersätter ASCII-blanksteg med mellanslag när Canvas-text förbereds; ett radbyte som skickas till measureText() skapar inte ett CSS-stycke med flera rader. HTML Standard: Canvas-elementet — WHATWG
Skriptet väntar på document.fonts.ready efter att layouten har upprättats. Enligt MDN uppfylls detta löfte när inläsningen och layoutåtgärderna för de använda teckensnitten har slutförts. Det betyder inte att alla deklarerade teckensnitt har lästs in eller att det teckensnitt som föredras från början måste vara det som visas. Document: egenskapen fonts — MDN
Läs resultaten och avgör om texten får plats
Börja med Available text width och jämför sedan kortets höjd vid två visningsstorlekar. När en radbrytning lägger till en rad ändras kortets höjd, medan Canvas-måttet för den radbrytningfria framåtskjutningen kan förbli oförändrat. Den kombinationen hjälper dig att skilja en ändring i radbrytningen från en ändring av teckensnittet.
För det här exemplet är följande bredder illustrativa beräkningar, inte uppmätta teckensnittsresultat. De förutsätter att layoutens visningsyta har angiven bredd och att skriptets stilar förblir oförändrade.
| Layoutens visningsbredd | Kortets bredd för kantlinjerutan | Tillgänglig textbredd |
|---|---|---|
360px |
312px |
278px |
800px |
480px |
446px |
1200px |
480px |
446px |
De två sista raderna förklarar varför en bredare webbläsare kan lämna textens radbrytning oförändrad: kortet har redan nått sin maxbredd. Enbart en ändring av visningsytan kan inte ge kortet mer innehållsutrymme.
För ett enkelt block med enbart enhetlig text upptar en illustrativ layout med tre rader och 24px radhöjd 72px utrymme för radhöjderna. Lägg till 32px vertikal utfyllnad och 2px för kanterna, så blir den illustrativa korthöjden 106px. Den här beräkningen hjälper dig att förstå resultatet. När innehållet eller stilen blir mer komplicerad är det uppmätta DOM-måttet det avgörande värdet. line-height — MDN
Behandla inte automatiskt Range fragment count som ett universellt antal rader. Range-API:t returnerar text- och elementrektanglar enligt sina markeringsregler. RTF, nästlade element och fragmenterad layout kan ge en mer komplicerad uppsättning rektanglar. Exemplet markerar bara en enda vanlig textnod för att göra diagnostiken begriplig. CSSOM View Module — W3C
Undvik också att uppskatta den radbrutna höjden med ceil(unwrappedWidth / availableWidth). Den formeln förutsätter att texten kan brytas vid godtyckliga horisontella positioner. Webbläsarens radbrytning måste följa de konfigurerade reglerna för blanksteg och brytning, så mät i stället det radbrutna blocket. white-space — MDN
Vad ska du kontrollera när måtten inte stämmer överens?
Kontrollera först mätgränsen. Rektangeln för ett kort med full bredd och en smalare Range-rektangel kan båda vara korrekta. Kortet reserverar layoututrymme; Range beskriver den markerade texten. Canvas-måttet för glyfhöjd ger ett tredje värde med ett annat syfte.
Kontrollera sedan att teckensnittet är redo. Om du lägger till ett deklarerat webbteckensnitt kan document.fonts.load(fontSpecification, sampleText) uttryckligen begära matchande teckensnitt innan mätningen. Hantera avvisade löften i stället för att i tysthet ersätta resultatet med ett lyckat värde. Det valfria textargumentet filtrerar efter Unicode-områden; det verifierar inte täckning av enskilda glyfer. FontFaceSet: metoden load() — MDN
Bevara formningsgränserna när du beräknar en etikettbredd. Mät hela strängen i stället för att summera separat uppmätta teckenbredder. Canvas-specifikationen förbereder en positionerad glyfkörning med det aktuella teckensnittet och textinställningarna; resultatet är rätt måttenhet för den strängen. Begränsa Canvas-jämförelsen i det här exemplet till de angivna teckensnittsinställningarna, i stället för att anta att den återger alla CSS-typografifunktioner. HTML Standard: Canvas-elementet — WHATWG
Mät den faktiska komponenten på plats för en befintlig sida. Om du flyttar text till en generisk dold ruta ändras layoutvillkoren, om du inte också återskapar de relevanta stilarna och det omgivande sammanhanget. Element utan tillhörande layoutrutor kan inte ge användbara normala rutmått, och CSS-transformeringar påverkar rektanglarna som dessa API:er rapporterar. Det syntetiska exemplet undviker båda komplikationerna. CSSOM View Module — W3C
Hur kan du upprepa förhandsvisningen vid flera webbläsarstorlekar?
För enstaka kontroller anger du varje visningsstorlek manuellt och registrerar rapporten. Jämför bredder runt den punkt där radbrytningen ändras i stället för att bara kontrollera en mycket smal och en mycket bred layout.
För upprepade kontroller stöder Playwright uttryckliga visningsmått och en separat inställning för deviceScaleFactor. Dokumentationen tillåter också att visningsytan i en enhetspreset åsidosätts. Det här ger en dokumenterad väg för automatisering: ställ in visningsytan, läs in sidan, vänta på teckensnitten och det relevanta innehållet och hämta sedan DOM-måtten i webbläsaren. Emulering — Playwright
Håll CSS-mått åtskilda från skärmens pixeltäthet. Playwright exponerar visningsyta och skalfaktor som separata inställningar, medan Canvas-textmått anges i CSS-pixlar. En skärm med högre pixeltäthet kräver inte i sig att den CSS-bredd som avsätts för en etikett fördubblas. Emulering — Playwright, TextMetrics — MDN
En användbar förhandsvisning är därför en liten sammanställning av villkoren: webbläsare, visningsyta, text, typografi, innehållsbredd och uppmätt korthöjd. Använd DOM-resultatet för att storleksbestämma den radbrutna komponenten, behåll Canvas-mått för frågor om en enda textrad och upprepa mätningen i varje webbläsare vars återgivning du behöver representera.
Källor
- CSSOM View Module — W3C.
- HTML Standard: Canvas-elementet — WHATWG.
- TextMetrics — MDN Web Docs.
- Element: metoden getBoundingClientRect() — MDN Web Docs.
- Document: egenskapen fonts — MDN Web Docs.
- FontFaceSet: metoden load() — MDN Web Docs.
- white-space — MDN Web Docs.
- line-height — MDN Web Docs.
- Simulera mobila enheter med enhetsläge — Chrome for Developers.
- Emulering — Playwright.