För en horisontell rad med baslinjejusterade infogade bilder ligger baslinjen vid varje bilds nedre marginalkant. Den här guiden visar hur du hittar den koordinaten i Chrome på en Mac, kontrollerar den med en liten markör och avgör när metoden inte är tillämplig.
Varför har en rad som bara innehåller bilder en baslinje?
En rad med enbart bilder deltar fortfarande i CSS:ens infogade layout. En img som visas korrekt är ett ersatt element: webbläsaren lägger ut dess ruta enligt CSS i stället för att behandla bilden som text. WHATWG dokumenterar det här renderingsbeteendet i HTML-standardens regler för bildrendering.
I vanlig horisontell infogad layout använder en bild utan en inneboende textbaslinje sin nedre marginalkant för baslinjejustering. Därför kan två baslinjejusterade bilder med olika höjd dela baslinje, trots att deras överkanter ligger på olika höjd. Regeln gäller deras rutor; den undersöker inte själva bildinnehållet. Se CSS 2, vertikal justering.
Tre olika gränser är viktiga:
| Gräns | Betydelse | Lämplig referens för baslinjen? |
|---|---|---|
| Kanten på det synliga bildinnehållet | Där bildens synliga pixlar slutar | Nej; filen kan innehålla transparenta områden |
| Bildens kantbox nederkant | Nederkanten som returneras av getBoundingClientRect() |
Ja, efter att hänsyn tagits till den nedre marginalen och baslinjejusteringen bekräftats |
| Radboxens nederkant | Den nedre gränsen för hela CSS-raden | Nej; den kan sträcka sig nedanför baslinjen |
Förälderns teckensnitt och line-height spelar fortfarande roll även när inga bokstäver syns. CSS beskriver ett osynligt bidrag baserat på teckensnittet, kallat en strut, som hjälper till att fastställa radens minimihöjd och djup. Det förklarar varför en bild kan ligga på baslinjen samtidigt som raden har utrymme under den. CSS Inline Layout-specifikationen beskriver dessa teckensnittsmått och layoutgränser; den hämtade publicerade versionen är ett Working Draft, så man bör inte utgå från att dess nyare funktioner stöds universellt av webbläsare.
Hur hittar du baslinjen på en befintlig sida?
Börja med en sida som du kan inspektera i Chrome på din Mac. Högerklicka på en bild och välj Inspect. Chrome öppnar panelen Elements med det elementet markerat; rutan Styles visar tillämpad CSS. Google beskriver arbetsflödet i Öppna Chrome DevTools.
Kontrollera följande villkor innan du beräknar en koordinat:
- Bilden deltar i normalt infogat flöde på den aktuella raden.
- Dess effektiva justering är
vertical-align: baseline. - Skrivläget är horisontellt.
- Varken bilden eller dess föräldraelement har en transformering eller visuell positionsförskjutning som påverkar mätningen.
- Du mäter själva bilden, inte en omslutande behållare med ett eget baslinjebeteende.
Dessa villkor definierar beräkningens tillämpningsområde. Till exempel justerar vertical-align: bottom ett element mot radens nederkant, medan middle använder förälderns baslinje plus halva dess x-höjd. Inget av värdena innebär att bildens nederkant anger förälderns baslinje. MDN förklarar skillnaderna i sin referens för vertical-align.
När dessa villkor är uppfyllda använder du följande samband, där alla avstånd anges i CSS-pixlar:
baslinjeY = bildensKantboxNederkant + bildensNedreMarginal
getBoundingClientRect() ger kantboxens nederkant i förhållande till visningsområdet. Rektangeln inkluderar utfyllnad och kantlinjer, så de ska inte läggas till en gång till. Marginaler ligger utanför rektangeln. MDN dokumenterar den returnerade geometrin och koordinatsystemet i Element.getBoundingClientRect().
Som ett rent illustrativt räkneexempel kan vi anta att bildens kantbox nederkant är 240.5 och att dess nedre marginal är 6. Baslinjen ligger då 246.5 CSS-pixlar nedanför visningsområdets överkant. Om behållarens kantbox överkant är 200, ligger baslinjen 46.5 CSS-pixlar nedanför behållarens övre kantlinje. Det är ett avstånd från kantlinjen, inte automatiskt från innehållskanten.
Mät en annan bild på samma rad som kontroll. Dess nedre marginalkant bör ange samma baslinje även om dess höjd skiljer sig. Om resultaten inte stämmer överens bör du granska justeringen, omslutande element, positionering och radbrytning innan du ändrar CSS. Behåll bråktalen när du jämför.
Hur verifierar du resultatet med en baslinjemarkör?
En användbar diagnostisk markör är ett tomt infogat block med noll bredd, höjd, marginaler, utfyllnad och kantlinjer, justerat mot baslinjen. Eftersom det inte har några rutor för infogat innehåll i flödet är dess baslinje dess nedre marginalkant. När alla måtten är noll sammanfaller den kanten med dess uppmätta vertikala position. Detta följer CSS 2-regeln för baslinjen hos infogade block.
Följande kompletta konsolprogram skapar en tillfällig demonstration med två neutrala rektangulära bilder och en markör. Det använder en skuggrot för att hålla provets interna format åtskilda från vanliga sidselektorer. Kör det i ett dokument i standardläge utan transformeringar på dokumentet eller body-elementet. Det mäter bara sin egen syntetiska rad, inte innehållet på en befintlig sida.
Öppna Console med Command + Option + J, enligt dokumentationen om kortkommandon i Chrome DevTools, och kör programmet. Du behöver inte installera något bibliotek eller använda någon extern bildfil. Provet skapar sina rektanglar med det vanliga Canvas API.
(async () => {
if (document.compatMode !== "CSS1Compat") {
throw new Error("Use a standards-mode document for this demonstration.");
}
const host = document.createElement("div");
host.style.cssText =
"all:initial;position:fixed;top:16px;left:16px;" +
"z-index:2147483647;background:white;padding:16px;" +
"color:#222;font:16px/1.5 sans-serif;";
const root = host.attachShadow({ mode: "open" });
const label = document.createElement("div");
label.textContent = "Sample A and Sample B";
const row = document.createElement("div");
row.style.cssText =
"display:block;position:relative;width:280px;" +
"margin:0;padding:0;border:0;white-space:nowrap;" +
"writing-mode:horizontal-tb;font:16px/24px sans-serif;" +
"background:#eee;";
const close = document.createElement("button");
close.textContent = "Remove demonstration";
close.addEventListener("click", () => host.remove());
root.append(label, row, close);
document.body.append(host);
try {
const images = [];
const samples = [
{ label: "Sample A", height: 32, color: "#777" },
{ label: "Sample B", height: 48, color: "#aaa" }
];
for (const sample of samples) {
const canvas = document.createElement("canvas");
canvas.width = 64;
canvas.height = sample.height;
const context = canvas.getContext("2d");
if (!context) throw new Error("A 2D canvas context is required.");
context.fillStyle = sample.color;
context.fillRect(0, 0, canvas.width, canvas.height);
const image = document.createElement("img");
image.alt = sample.label;
image.width = 64;
image.height = sample.height;
image.style.cssText =
"display:inline;vertical-align:baseline;" +
"margin:0 12px 0 0;padding:0;border:0;";
image.src = canvas.toDataURL("image/png");
row.append(image);
images.push(image);
}
await Promise.all(images.map(image => image.decode()));
if (!host.isConnected) return;
const marker = document.createElement("span");
marker.style.cssText =
"display:inline-block;vertical-align:baseline;" +
"width:0;height:0;margin:0;padding:0;border:0;" +
"font-size:0;line-height:0;";
row.append(marker);
const baselineY = marker.getBoundingClientRect().bottom;
const rowTop = row.getBoundingClientRect().top;
console.table(images.map(image => ({
sample: image.alt,
imageBottom: image.getBoundingClientRect().bottom,
markerBaseline: baselineY,
baselineFromRowTop: baselineY - rowTop
})));
const guide = document.createElement("div");
guide.style.cssText =
"position:absolute;left:0;right:0;height:1px;" +
"background:#222;pointer-events:none;";
guide.style.top = `${baselineY - rowTop}px`;
row.append(guide);
} catch (error) {
host.remove();
throw error;
}
})();
Programmet väntar tills båda bilderna har avkodats innan det mäter. Den dokumenterade metoden HTMLImageElement.decode() returnerar ett löfte och kan misslyckas om avkodningen misslyckas. I så fall tar programmet bort den tillfälliga panelen och rapporterar felet.
Båda bilderna har noll i nedre marginal, så deras rapporterade värden för imageBottom bör motsvara markerBaseline. Den tunna horisontella linjen markerar den koordinaten. Radens bakgrund gör det också lättare att skilja baslinjen från eventuellt kvarvarande utrymme under den. Välj Remove demonstration när du är klar.
Ändra bildernas nedre marginal i provets format från 0 till 6px för ett kontrollerat experiment. Deras kantboxars nederkanter bör då ligga sex CSS-pixlar ovanför markörens baslinje. Använd den tidigare formeln för att räkna ut den gemensamma koordinaten. På så sätt får du två oberoende referenser i provet: bildens marginalkant och den tomma markören.
När behöver metoden anpassas?
En markör är en diagnostisk infogning, så den mäter layouten efter att markören har lagts till. Om du lägger till en i ett godtyckligt befintligt stycke kan den skapa en radbrytningsmöjlighet eller på annat sätt påverka layouten. Använd beräkningen utifrån den befintliga bilden när dess förutsättningar är uppfyllda. Om du infogar en markör i verkligt innehåll bör du bekräfta att samma bilder fortfarande ligger på samma rad och att deras positioner inte har ändrats.
| Situation | Lämpligt nästa steg |
|---|---|
Bilderna använder justeringen top, bottom eller middle |
Granska justeringsregeln; använd inte formeln för baslinjejusterade bilder oförändrad |
| Bilden ligger inuti en infogad blockbehållare | Granska behållarens baslinje, som kan komma från dess sista innehållsrad |
| Bilderna ligger på flera radbrutna rader | Fastställ baslinjen separat för varje rad |
| Föräldern använder flex- eller gridlayout | Granska layoutens justeringsregler innan raden behandlas som en infogad rad |
| Dokumentet använder vertikal skrift | Använd baslinjeregler som tar hänsyn till skrivläget i stället för en y-koordinat från nederkanten |
| Bilden har inte lästs in korrekt | Åtgärda dess renderingstillstånd innan du behandlar den som en visad bildruta |
Det sista villkoret spelar roll eftersom WHATWG beskriver olika renderingsvägar för visade bilder, bilder som väntar på att läsas in och alternativtext. En trasig bild som visar sin etikett kan därför behöva tolkas annorlunda än den korrekt renderade bild du tänkte mäta. Se reglerna för bildrendering i HTML.
Dra dig inte till slutsatsen att flera bildrektanglar delar baslinje enbart för att deras överkanter ligger ungefär på samma höjd. Bilder med olika höjd kan dela baslinje men ha olika överkanter. Omvänt bevisar inte justerade överkanter att bilderna är baslinjejusterade. Bekräfta vilka rutor som deltar i samma rad och vilken justeringsregel som gäller.
Kan API:er för textmätning eller formningsbibliotek ge svaret?
Webbläsarens geometrimetoder som används här returnerar rektanglar, inte ett särskilt fält för radens baslinje. Range.getClientRects() kan hjälpa till att granska de områden som ett område upptar, men de returnerade rektanglarna anger inte baslinjens koordinat direkt. MDN beskriver gränssnittet i Range.getClientRects().
Canvasens textmått besvarar en annan fråga: hur en text på canvasen förhåller sig till den valda textbaslinjen i canvasens kontext. Exempelvis beskriver actualBoundingBoxAscent och actualBoundingBoxDescent textens synliga gränser i förhållande till den referensen. De anger inte direkt positionen för en befintlig rad med bilder i DOM:en. Se MDN:s dokumentation om TextMetrics.
Ett textformningsbibliotek har också ett snävare ansvarsområde än webbläsarens radlayout. I HarfBuzz-manualen står det att biblioteket formar textsegment och tillhandahåller information om teckenlayout, medan radbrytning och justering av stycken ligger utanför dess ansvarsområde. Att installera HarfBuzz ger alltså inte ett mått på en bildrad i en webbläsare. Dess dokumenterade omfattning tydliggör gränsen.
För en horisontell rad med enbart bilder bör du först bekräfta normalt infogat flöde och baslinjejustering. Läs sedan av en lämplig bilds kantbox nederkant och lägg till dess nedre marginal. Använd markören med nollstorlek i en kontrollerad layout när du behöver en synlig kontroll, och granska formateringskontexten igen om dessa två referenser inte stämmer överens.
Källor
HTML-standarden: rendering — WHATWG.
HTML-standarden: canvas-elementet — WHATWG.
Öppna Chrome DevTools — Google Chrome for Developers.
CSS-egenskapen vertical-align — MDN Web Docs.
Element: metoden getBoundingClientRect() — MDN Web Docs.
HTMLImageElement: metoden decode() — MDN Web Docs.
Range: metoden getClientRects() — MDN Web Docs.
TextMetrics — MDN Web Docs.
Vad HarfBuzz inte gör — HarfBuzz.