Das Box-Modell
Kurz gesagt: Das Box-Modell sagt, dass jedes Element eine Box aus Inhalt, Innenabstand, Rahmen und Außenabstand ist; mit box-sizing: border-box gehören Innenabstand und Rahmen zur Breite.
Problem
Die Karten ragen aus dem Bildschirm
Die Seite mit den Broten auf einem Handy mit 360px Breite. Jede Karte hat width: 100%: so breit wie die Spalte. Trotzdem ragen die Karten rechts heraus, und die ganze Seite rutscht zur Seite.
Konsole
Die Spalte ist 360 − 2 × 16 = 328px breit. So breit sollte die Karte sein, und sie ist 362px breit: 34px breiter als die Spalte. Diese 34px sind kein Fehler in der Zahl 100%. Sie stecken in dem, was width misst.
Die Idee
Vier Schichten
Für CSS ist jedes Element eine rechteckige Box. Sie hat vier Schichten, von innen nach außen:
- der Inhalt: der Text, das Bild, die Kinder;
padding(Innenabstand): der Platz zwischen dem Inhalt und dem Rahmen. Der Hintergrund des Elements füllt ihn;border(Rahmen): die Umrandung;margin(Außenabstand): der Platz außerhalb des Rahmens, bis zu den benachbarten Boxen. Er ist durchsichtig.
Standardmäßig ist width nur die Breite des Inhalts. Innenabstand und Rahmen kommen außen dazu, auf beiden Seiten:
.card { width: 100%; /* 328px: der Inhalt */ padding: 16px; /* + 2 × 16 */ border: 1px solid #ccc; /* + 2 × 1 = 362px */}Deshalb ist die Karte vom Anfang 362px breit. padding: 16px gilt für alle vier Seiten. Du kannst sie auch einzeln setzen: padding: 8px 16px (oben und unten, links und rechts) oder padding-left: 16px.
Sieh es dir an
Sieh dir die Box an
Die Box wird Schicht für Schicht aufgebaut. Die Zeile oben ist width: Achte darauf, was sie misst.
/* Standard: box-sizing: content-box */.card { width: 280px; padding: 24px; border: 8px solid #2b3a55; margin: 16px;}.card.bb { box-sizing: border-box;}Schritt für Schritt, in Worten
- In der Mitte steht der Inhalt: der Text der Karte. Standardmäßig ist width nur die Breite des Inhalts: 280px.
- padding ist der Platz zwischen dem Inhalt und dem Rahmen. Er liegt auf beiden Seiten: 280 + 2 × 24 = 328px. Auch der Hintergrund der Karte füllt ihn.
- border ist der Rahmen, ebenfalls auf beiden Seiten. Die Box ist jetzt 344px breit, nicht 280: width hat nicht gesagt, wie breit die Karte auf dem Bildschirm ist.
- margin ist der Platz außerhalb des Rahmens, zwischen dieser Box und der nächsten. Er hat keinen Hintergrund und gehört nicht zur Karte, nimmt aber Platz weg: 376px.
- box-sizing: border-box ändert, was width bedeutet: Es ist jetzt die Breite bis zum Rahmen. Die Karte ist 280px breit, und der Inhalt schrumpft auf 280 − 48 − 16 = 216px.
- Dasselbe CSS, zwei Bedeutungen von width. Mit content-box ist die Karte 344px breit, mit border-box 280px: so viel, wie width sagt. Deshalb setzt fast jedes Projekt border-box für alle Elemente.
Dieselben zwei Karten im Browser. Das Blaue ist der Absatz darin: Er ist so breit wie der Inhalt der Karte. Wähl in den Entwicklertools (F12) die Karte aus: Das Panel Berechnet zeichnet dieselbe Box mit den Zahlen jeder Schicht.
Konsole
Die Idee
box-sizing: border-box
Im Kopf zu rechnen erzeugt Fehler: Du willst eine Karte so breit wie die Spalte und musst Innenabstand und Rahmen abziehen. box-sizing: border-box ändert, was width bedeutet: Es ist die Breite bis zum Rahmen einschließlich. Innenabstand und Rahmen werden von innen abgezogen, und der Inhalt schrumpft.
Dann ist width: 100% wirklich die Spalte, egal wie groß der Innenabstand ist. Deshalb beginnt fast jedes Projekt mit:
*, *::before, *::after { box-sizing: border-box;}* trifft jedes Element. box-sizing wird nicht vererbt, deshalb gilt die Regel für alle Elemente, nicht nur für <html>. ::before und ::after sind Inhalte, die CSS selbst hinzufügt; auch sie sind Boxen.
Probier es aus
Lass die Karten passen
Sorg mit box-sizing: border-box dafür, dass die Karten auf den Handy-Bildschirm passen. Der Innenabstand (16px) und der Rahmen (1px) bleiben.
Konsole
Lösung
index.html<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Brote</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main>
<h1>Brote</h1>
<article class="card">
<h2>Dobrudzha-Brot</h2>
<p class="price">1,80 €</p>
<button type="button">In den Warenkorb</button>
</article>
<article class="card">
<h2>Roggenbrot</h2>
<p class="price">2,10 €</p>
<button type="button">In den Warenkorb</button>
</article>
</main>
</body>
</html>
style.css*, *::before, *::after {
box-sizing: border-box;
}
body { font-family: system-ui, sans-serif; margin: 0; }
main { padding: 16px; }
.card {
width: 100%;
padding: 16px;
border: 1px solid #ccc;
margin-bottom: 12px;
}
Mit border-box sind width: 100% zusammen mit Innenabstand und Rahmen 328px, und der Inhalt bekommt 328 − 32 − 2 = 294px. width: 90% passt auf diesem Bildschirm zufällig, aber auf einem anderen würdest du wieder rechnen. Ohne Innenabstand passt die Karte, aber der Text berührt den Rahmen.
Die Regel, mit der fast jedes Projekt beginnt:
*, *::before, *::after {
box-sizing: ;
}border-box: width und height reichen bis zum Rahmen einschließlich. Der Standardwert ist content-box.
Die Idee
Außenabstände verschmelzen
Zwei Boxen untereinander: Der untere Außenabstand der oberen und der obere Außenabstand der unteren Box addieren sich nicht. Sie verschmelzen, und der größere bleibt.
Konsole
- Die Hinweise haben 24px unten und 16px oben. Zwischen ihnen liegen 24px, nicht 40px.
- Die Überschrift im Banner hat
margin: 20px 0. Der Banner hat oben weder Innenabstand noch Rahmen, deshalb tritt der Außenabstand der Überschrift darüber heraus: Der orange Hintergrund beginnt direkt über dem Text. Mitpadding: 1px 16pxam Banner deckt der Hintergrund den Außenabstand mit ab.
Nur vertikale Außenabstände verschmelzen. Links und rechts addieren sie sich immer. In Flex und Grid, den nächsten Lektionen, verschmelzen auch vertikale nicht.
Die Idee
block, inline und inline-block
Nicht jede Box verhält sich gleich. Die Eigenschaft display sagt, wie eine Box sich zwischen den anderen einordnet.
block: beginnt in einer neuen Zeile und nimmt die volle Breite des Elternelements ein. Breite, Höhe, Außenabstand und Innenabstand gelten.div,p,h1undarticlesind so.inline: steht in der Textzeile und ist so breit wie ihr Inhalt. Breite und Höhe gelten nicht, ein vertikaler Außenabstand bewegt nichts, und ein vertikaler Innenabstand wird gemalt, schiebt die Zeilen aber nicht auseinander.span,aundstrongsind so.inline-block: steht wie inline in der Zeile, aber Breite, Höhe, Außenabstand und Innenabstand gelten wie bei block.
Konsole
Die zwei Labels haben dieselben Eigenschaften, und das zweite ist zusätzlich inline-block. Das erste ist inline: width: 64px und der Außenabstand gelten nicht, und das Rot des Innenabstands ragt über und unter der Zeile heraus, ohne sie von den anderen wegzuschieben. Das zweite ist inline-block: Es ist 64 + 2 × 8 = 80px breit (hier ist es noch content-box), und der Absatz wird höher, damit es hineinpasst.
Probier es aus
Die Labels
Die Labels −20% und Neu sollen je 64px breit sein und nebeneinander in einer Zeile stehen. Im Moment gilt die Breite nicht.
Konsole
Lösung
index.html<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Frischmilch 3%</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<article>
<h2>Frischmilch 3%</h2>
<p><span class="badge">−20%</span> <span class="badge">Neu</span></p>
<p class="price">1,92 €</p>
</article>
</body>
</html>
style.cssbody { font-family: system-ui, sans-serif; margin: 16px; }
.badge {
display: inline-block;
width: 64px;
padding: 4px 0;
text-align: center;
color: #fff;
background: #c0392b;
}
display: inline-block gibt dem Label die Maße einer Box, und es bleibt in der Textzeile. Mit block gilt die Breite, aber jedes Label steht in einer neuen Zeile. inline ist der Standard eines <span>, ändert also nichts.
Die Idee
Einheiten
Bisher stand alles in px. CSS hat noch andere Einheiten, und jede ist für etwas gut:
px: ein fester Wert. Gut für Rahmen und kleine Abstände.rem: die Schriftgröße von<html>(16px, wenn niemand sie geändert hat).1.5remsind überall auf der Seite 24px. Wenn jemand in den Browsereinstellungen die Schrift vergrößert hat, wächst rem mit und px nicht. Schriften und Abstände stehen deshalb am besten in rem.em: die Schriftgröße des Elements selbst; infont-sizedie des Elternelements. Ein Innenabstand in em wächst mit dem Text eines Buttons.%: vom Elternelement.width: 50%ist die halbe Breite des Inhalts des Elternelements.vwundvh: 1% der Breite und der Höhe des Fensters.
Konsole
Die Überschrift hat 1.5rem = 24px. Die Karte ist 50% von 320px = 160px breit. Ihre Schrift ist 18px, also sind padding: 1em 18px. 1.25rem an der Überschrift in der Karte sind 20px: rem kümmern die 18px der Karte nicht. 0.75em an <small> kommt von der Schrift des Absatzes, die 18px geerbt hat: 13,5px.
Probier es aus
Finde den Fehler
Das Menü hat 20px, das Untermenü darin 25px, und die nächste Ebene ist noch größer. Welche Zeile ist schuld?
Wähle die Zeile mit dem Fehler.
em in font-size ist die Größe des Elternelements. Jedes verschachtelte .menu multipliziert mit 1,25: 16, 20, 25, 31,25. Mit font-size: 1.25rem ist jede Ebene 20px.
Genauer, für Neugierige
Prozentwerte bei padding und margin beziehen sich auf die Breite des Elternelements, auch oben und unten. padding-top: 50% macht eine Box halb so hoch, wie ihr Elternelement breit ist.
100vw und die Bildlaufleiste. vw schließt die Bildlaufleiste ein. Wenn die Seite eine sichtbare vertikale Bildlaufleiste hat, ist ein Element mit width: 100vw breiter als die Seite und löst horizontales Scrollen aus. Für „die volle Breite“ ist width: 100% sicherer.
vh auf dem Handy. Die Adressleiste erscheint und verschwindet. 100vh ist die Höhe bei versteckter Leiste, deshalb liegt der untere Rand bei sichtbarer Leiste unter dem Bildschirm. 100dvh folgt der tatsächlichen Höhe im Moment.
outline wird wie ein Rahmen gezeichnet, nimmt aber keinen Platz weg und verschiebt nichts. Deshalb zeigt man damit den Fokus von Buttons.
min-width und max-width setzen Grenzen: max-width: 100% verhindert, dass ein Bild aus der Spalte ragt.
Formulare. In Chromium sind Buttons standardmäßig border-box, Felder (input) dagegen content-box. Die Regel mit * macht sie gleich.
Wie man das Verschmelzen verhindert. Der Außenabstand eines Kindes tritt nicht durch das Elternelement hindurch, wenn das Elternelement oben Innenabstand oder einen Rahmen hat oder display: flow-root ist. So schafft das Elternelement einen neuen Layoutkontext (Block Formatting Context).
Ein negativer Außenabstand zieht die Box nach außen und überlappt sie mit ihren Nachbarn. Du brauchst ihn selten.
Übung
Der Katalog auf dem Handy
Der Katalog auf einem Handy (360px). Setz border-box auf alle Elemente, damit die Karten auf den Bildschirm passen. Die Karte: padding 1rem, ein Rahmen 1px solid #ddd und 12px Platz unter jeder. Die Produktüberschriften haben 1.25rem. Die Labels −20% und Neu sind inline-block, mit padding 2px 8px, weißem Text und rotem Hintergrund (#c0392b). Der Button ist so breit wie das Innere der Karte: width: 100%.
Konsole
Lösung
index.html<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Brote</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<main>
<h1>Brote</h1>
<article class="card">
<h2>Dobrudzha-Brot</h2>
<span class="badge">−20%</span>
<p class="price">1,80 €</p>
<button type="button">In den Warenkorb</button>
</article>
<article class="card">
<h2>Roggenbrot</h2>
<p class="price">2,10 €</p>
<button type="button">In den Warenkorb</button>
</article>
<article class="card">
<h2>Dinkelbrot</h2>
<span class="badge">Neu</span>
<p class="price">3,40 €</p>
<button type="button">In den Warenkorb</button>
</article>
</main>
</body>
</html>
style.css*, *::before, *::after {
box-sizing: border-box;
}
body { font-family: system-ui, sans-serif; margin: 0; }
main { padding: 16px; }
.card {
width: 100%;
padding: 1rem;
border: 1px solid #ddd;
margin-bottom: 12px;
}
.card h2 { font-size: 1.25rem; }
.badge {
display: inline-block;
padding: 2px 8px;
color: #fff;
background: #c0392b;
}
.card button { width: 100%; }
*, *::before, *::after { box-sizing: border-box; } ist die erste Regel: Ohne sie sind die Karten 362px breit. margin-bottom: 12px an der Karte gibt den Platz. 1rem sind 16px und 1.25rem sind 20px, egal was darum herum ist. Der Button mit width: 100% ist 294px breit: Die Spalte hat 328px, minus 2 × 16 Innenabstand und 2 × 1 Rahmen der Karte.
Test
Teste dich
Verwandte Lektionen
Abschnitt „Verwandte Lektionen“- Baut auf: Das HTML-Dokument · Selektoren und die Kaskade
- Geht weiter in: Flexbox: Reihe und Spalte · Grid: Zeilen und Spalten · Responsive Design
- Aufgaben zum Thema: CSS: Wie die Seite aussieht