Bij een horizontale regel met inline-afbeeldingen die op de basislijn zijn uitgelijnd, ligt de basislijn bij de onderrand van de marge van elke afbeelding. Deze handleiding laat zien hoe je die coördinaat in Chrome op een Mac bepaalt, controleert met een kleine markering en herkent wanneer deze methode niet van toepassing is.
Waarom heeft een regel met alleen afbeeldingen een basislijn?
Een regel met alleen afbeeldingen neemt nog steeds deel aan de inline-opmaak van CSS. Een afbeelding die correct wordt weergegeven, img, is een vervangen element: de browser maakt de opmaak van de box volgens CSS, in plaats van de afbeelding als tekst te behandelen. WHATWG documenteert dit weergavegedrag in de regels voor afbeeldingsweergave van de HTML-standaard.
Bij gewone horizontale inline-opmaak gebruikt een afbeelding zonder intrinsieke tekstbasislijn de onderrand van de marge voor uitlijning op de basislijn. Daardoor kunnen twee op de basislijn uitgelijnde afbeeldingen met verschillende hoogtes dezelfde basislijn delen, terwijl hun bovenranden op verschillende hoogtes liggen. Deze regel geldt voor hun boxen; er wordt niet gekeken naar de afbeelding zelf. Zie CSS 2, verticale uitlijning.
Drie verschillende grenzen zijn van belang:
| Grens | Betekenis | Geschikt als verwijzing naar de basislijn? |
|---|---|---|
| Rand van de zichtbare afbeelding | Waar de zichtbare pixels van de afbeelding eindigen | Nee; het bestand kan transparante ruimte bevatten |
| Onderkant van het kader van de afbeelding | De onderkant die door getBoundingClientRect() wordt geretourneerd |
Ja, na verrekening van de ondermarge en bevestiging van de uitlijning op de basislijn |
| Onderkant van de regelbox | De ondergrens van de volledige CSS-regel | Nee; deze kan onder de basislijn doorlopen |
Het lettertype en line-height van het bovenliggende element zijn nog steeds van belang wanneer er geen zichtbare letters zijn. CSS beschrijft een onzichtbare bijdrage op basis van het lettertype, een strut genoemd, die helpt de minimale hoogte en diepte van de regel vast te stellen. Dat verklaart waarom een afbeelding op de basislijn kan staan terwijl er onder de afbeelding ruimte overblijft. De specificatie CSS Inline Layout beschrijft deze lettertypemetrieken en opmaakgrenzen; de opgehaalde gepubliceerde versie is een werkdocument, dus je mag niet aannemen dat nieuwere functies ervan in alle browsers worden ondersteund.
Hoe vind je de basislijn op een bestaande pagina?
Begin met een pagina die je in Chrome op je Mac kunt inspecteren. Klik met de rechtermuisknop op een afbeelding en kies Inspect. Chrome opent het paneel Elements met dat element geselecteerd; het deelvenster Styles toont de toegepaste CSS. Google documenteert deze werkwijze in Chrome DevTools openen.
Controleer de volgende voorwaarden voordat je een coördinaat berekent:
- De afbeelding neemt deel aan de normale inline-flow op de betreffende regel.
- De effectieve uitlijning is
vertical-align: baseline. - De schrijfrichting is horizontaal.
- Noch de afbeelding, noch een voorouder ervan heeft een transformatie of visuele positioneringsverschuiving die de meting beïnvloedt.
- Je meet de afbeelding zelf, niet een omliggende wrapper met eigen basislijngedrag.
Deze voorwaarden bepalen wanneer de berekening geldt. vertical-align: bottom lijnt een element bijvoorbeeld uit met de onderkant van de regel, terwijl middle de basislijn van het bovenliggende element gebruikt, plus de helft van de x-hoogte ervan. Geen van beide waarden betekent dat de onderrand van de afbeelding de basislijn van het bovenliggende element aangeeft. MDN licht deze verschillen toe in de vertical-align-referentie.
Als aan deze voorwaarden is voldaan, gebruik je de volgende relatie, waarbij alle afstanden in CSS-pixels zijn uitgedrukt:
baselineY = imageBorderBoxBottom + imageMarginBottom
getBoundingClientRect() geeft de onderkant van het kader ten opzichte van de viewport. De rechthoek omvat opvulling en randen, dus die mag je niet nogmaals optellen. Marges liggen buiten die rechthoek. MDN documenteert de geretourneerde geometrie en het coördinatenstelsel in Element.getBoundingClientRect().
Neem voor een expliciet illustratieve berekening aan dat de onderkant van het kader van de afbeelding 240.5 is en dat de ondermarge 6 bedraagt. De basislijn ligt dan 246.5 CSS-pixels onder de bovenkant van de viewport. Als de bovenkant van het kader van de container 200 is, ligt die basislijn 46.5 CSS-pixels onder de bovenrand van het kader van de container. Dit is een afstand vanaf de rand van het kader, niet automatisch vanaf de rand van het inhoudsgebied.
Meet als controle een andere afbeelding op dezelfde regel die aan de voorwaarden voldoet. De onderrand van de marge ervan moet dezelfde basislijn aangeven, ook als de hoogte anders is. Bij een afwijkende uitkomst is het verstandig de uitlijning, wrappers, positionering of regelafbreking te inspecteren voordat je CSS wijzigt. Behoud de waarden achter de komma tijdens de vergelijking.
Hoe controleer je het resultaat met een basislijnmarkering?
Een handige diagnose is een lege inline-block met nulbreedte, nulhoogte, geen marges, opvulling of randen, uitgelijnd op de basislijn. Omdat deze geen regelboxen in de normale flow heeft, is de basislijn de onderrand van de marge. Omdat al deze afmetingen nul zijn, valt die rand samen met de gemeten verticale positie. Dit volgt de CSS 2-regel voor de basislijn van inline-blocks.
Het volgende volledige consoleprogramma maakt een tijdelijke demonstratie met twee neutrale rechthoekige afbeeldingen en een markering. Het gebruikt een shadow root om de interne stijlen van het voorbeeld gescheiden te houden van gewone paginaselectors. Voer het uit in een document in standaardenmodus, zonder transformaties op het document of de body. Het meet alleen de eigen synthetische regel, niet de inhoud van een bestaande pagina.
Open de Console met Command + Option + J, zoals beschreven in sneltoetsen voor DevTools van Chrome, en voer het programma uit. Er is geen bibliotheekinstallatie of extern afbeeldingsbestand nodig. Het voorbeeld genereert de rechthoeken met de standaard-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;
}
})();
Het programma wacht tot beide afbeeldingen zijn gedecodeerd voordat het metingen uitvoert. De gedocumenteerde methode HTMLImageElement.decode() retourneert een promise en kan worden afgewezen als het decoderen mislukt; in dat geval verwijdert het programma het tijdelijke paneel en geeft het de fout weer.
Beide afbeeldingen hebben een ondermarge van nul, dus de gerapporteerde waarden van imageBottom moeten overeenkomen met markerBaseline. De dunne horizontale lijn markeert die coördinaat. Met de achtergrond van de regel kun je bovendien eventuele resterende ruimte eronder zien. Kies Remove demonstration als je klaar bent.
Wijzig voor een gecontroleerd experiment de ondermarge van de voorbeeldafbeeldingen in de afbeeldingsstijl van 0 naar 6px. Hun onderkanten van het kader moeten dan zes CSS-pixels boven de basislijn van de markering liggen. Pas de eerdere formule toe om de gedeelde coördinaat te bepalen. Zo heb je binnen het voorbeeld twee onafhankelijke verwijzingen: de margerand van de afbeelding en de lege markering.
Wanneer vraagt deze methode om een andere aanpak?
Een markering is een diagnostische invoeging en meet dus de resulterende opmaak. Als je er een toevoegt aan een willekeurige bestaande alinea, kan dat een afbreekmogelijkheid introduceren of de opmaak op een andere manier beïnvloeden. Geef de voorkeur aan de berekening op basis van de bestaande afbeelding als aan de voorwaarden daarvoor is voldaan. Controleer bij het invoegen van een markering in echte inhoud of dezelfde afbeeldingen op dezelfde regel blijven staan en of hun posities niet zijn veranderd.
| Situatie | Geschikte vervolgstap |
|---|---|
Afbeeldingen gebruiken de uitlijning top, bottom of middle |
Inspecteer die uitlijningsregel; pas de formule voor op de basislijn uitgelijnde afbeeldingen niet ongewijzigd toe |
| De afbeelding staat in een inline-block-wrapper | Inspecteer de basislijn van de wrapper; die kan afkomstig zijn van de laatste inhoudsregel |
| Afbeeldingen staan op meerdere afgebroken regels | Bepaal de basislijn afzonderlijk voor elke regel |
| Het bovenliggende element gebruikt flex- of grid-opmaak | Inspecteer eerst de uitlijningsregels van die opmaak voordat je de rij als een inline-regel behandelt |
| Het document gebruikt verticale schrijfrichting | Gebruik regels voor basislijnen die rekening houden met de schrijfrichting, in plaats van een y-coördinaat van de onderrand |
| De afbeelding is niet succesvol geladen | Los de weergavestatus op voordat je de afbeelding behandelt als een weergegeven afbeeldingsbox |
De laatste voorwaarde is van belang omdat WHATWG verschillende weergavepaden beschrijft voor weergegeven afbeeldingen, afbeeldingen die nog worden geladen en alternatieve tekst. Een kapotte afbeelding die het bijbehorende label weergeeft, vraagt daarom mogelijk om een andere interpretatie dan de succesvol weergegeven afbeelding die je wilde meten. Zie de regels voor afbeeldingsweergave van de HTML-standaard.
Leid niet af dat er één gedeelde basislijn is alleen omdat meerdere afbeeldingsrechthoeken ongeveer dezelfde bovenkant hebben. Afbeeldingen met verschillende hoogtes kunnen dezelfde basislijn delen en verschillende bovenkanten hebben. Omgekeerd bewijzen uitgelijnde bovenkanten niet dat de afbeeldingen op de basislijn zijn uitgelijnd. Controleer welke boxen aan dezelfde regel deelnemen en welke uitlijningsregel van toepassing is.
Kunnen tekstmeet-API's of vormgevingsbibliotheken het antwoord geven?
De browsermethoden voor geometrie die hier worden gebruikt, retourneren rechthoeken en geen speciaal veld voor de basislijn van een regel. Range.getClientRects() kan helpen de gebieden te inspecteren die een bereik inneemt, maar de geretourneerde rechthoeken geven de basislijncoördinaat niet rechtstreeks. MDN beschrijft die interface in Range.getClientRects().
Canvas-tekstmetrieken beantwoorden een andere vraag: hoe een stuk canvas-tekst zich verhoudt tot de geselecteerde tekstbasislijn van de canvascontext. actualBoundingBoxAscent en actualBoundingBoxDescent beschrijven bijvoorbeeld de inktgrenzen van de tekst ten opzichte van die referentie. Ze bepalen niet rechtstreeks de positie van een bestaande DOM-regel met afbeeldingen. Zie de TextMetrics-documentatie van MDN.
Een tekstvormgevingsbibliotheek heeft ook een beperktere taak dan de regelopmaak van een browser. De HarfBuzz-handleiding vermeldt dat de bibliotheek tekstsegmenten vormgeeft en informatie over glyphopmaak levert, terwijl het afbreken en uitvullen van alinearegels buiten haar taak valt. HarfBuzz installeren levert dus geen meting op van een afbeeldingsregel in een browser. De gedocumenteerde reikwijdte verduidelijkt die grens.
Controleer bij een horizontale regel met alleen afbeeldingen eerst of deze in de normale inline-flow staat en op de basislijn is uitgelijnd. Lees vervolgens de onderkant van het kader van een afbeelding die aan de voorwaarden voldoet en tel de ondermarge erbij op. Gebruik de markering van nulformaat in een gecontroleerde opmaak als je een zichtbare controle nodig hebt. Beoordeel de opmaakcontext opnieuw wanneer deze twee verwijzingen niet overeenkomen.
Bronnen
HTML-standaard: weergave — WHATWG.
HTML-standaard: het canvas-element — WHATWG.
Chrome DevTools openen — Google Chrome for Developers.
CSS-eigenschap vertical-align — MDN Web Docs.
Element: de methode getBoundingClientRect() — MDN Web Docs.
HTMLImageElement: de methode decode() — MDN Web Docs.
Range: de methode getClientRects() — MDN Web Docs.
TextMetrics — MDN Web Docs.
Wat HarfBuzz niet doet — HarfBuzz.