# Part 2: Box Model, Display, and Positioning

## Introduction

Every element on a page is a rectangular box. Understanding how those boxes are sized, how they relate to their neighbours, and how they can be pulled out of normal document flow is the foundation of CSS layout. I have debugged more layout problems by going back to box model fundamentals than by any other means. This part covers what I know about the box model, display modes, and positioning, from daily basics to the edge cases that catch people off guard.

***

## The Box Model

Every HTML element generates a box with four layers:

```
┌─────────────────────────────────┐
│             margin              │
│  ┌───────────────────────────┐  │
│  │          border           │  │
│  │  ┌─────────────────────┐  │  │
│  │  │       padding       │  │  │
│  │  │  ┌───────────────┐  │  │  │
│  │  │  │    content    │  │  │  │
│  │  │  └───────────────┘  │  │  │
│  │  └─────────────────────┘  │  │
│  └───────────────────────────┘  │
└─────────────────────────────────┘
```

* **Content** — where text, images, and child elements live
* **Padding** — transparent space between content and border
* **Border** — visible (or invisible) line around the padding
* **Margin** — space outside the border, separating the element from neighbours

### `box-sizing`

The browser's default `box-sizing: content-box` means `width` and `height` set the content area only. Padding and border are added *on top*, making elements wider/taller than the declared size.

```css
/* content-box default */
.box {
  width: 200px;
  padding: 20px;
  border: 2px solid black;
  /* actual rendered width: 200 + 20*2 + 2*2 = 244px */
}
```

`box-sizing: border-box` includes padding and border in the declared dimensions:

```css
/* Applied globally in my reset */
*, *::before, *::after {
  box-sizing: border-box;
}

.box {
  width: 200px;
  padding: 20px;
  border: 2px solid black;
  /* actual rendered width: exactly 200px */
}
```

`border-box` matches how most people think about sizing. I apply it globally on every project.

***

## Margin, Padding, and Border

### Shorthand Syntax

All three properties follow the same shorthand pattern:

```css
/* All four sides */
margin: 1rem;

/* Top/bottom, left/right */
margin: 1rem 2rem;

/* Top, left/right, bottom */
margin: 1rem 2rem 0.5rem;

/* Top, right, bottom, left (clockwise) */
margin: 1rem 2rem 0.5rem 0.75rem;
```

### Individual Properties

```css
margin-top: 1rem;
margin-right: 2rem;
margin-bottom: 1rem;
margin-left: 2rem;

padding-top: 0.5rem;
padding-right: 1rem;
padding-bottom: 0.5rem;
padding-left: 1rem;
```

### Logical Properties (Modern CSS)

Logical properties work in terms of writing direction rather than physical sides — useful for internationalisation:

```css
/* Block axis (top/bottom in horizontal writing) */
margin-block: 1rem;          /* shorthand for block-start + block-end */
margin-block-start: 1rem;    /* equivalent to margin-top in LTR */
margin-block-end: 1rem;      /* equivalent to margin-bottom in LTR */

/* Inline axis (left/right in horizontal writing) */
margin-inline: 2rem;         /* shorthand for inline-start + inline-end */
padding-inline: 1rem;
```

### Border

```css
/* Shorthand: width style color */
border: 1px solid #e2e8f0;

/* Individual sides */
border-top: 2px solid #3b82f6;
border-bottom: none;

/* Individual properties */
border-width: 1px;
border-style: solid;         /* solid, dashed, dotted, double, none */
border-color: #e2e8f0;

/* Radius */
border-radius: 0.5rem;
border-radius: 0.5rem 0.5rem 0 0;    /* top-left top-right bottom-right bottom-left */
border-radius: 50%;                   /* circle (on equal width/height element) */
```

### Outline

`outline` is drawn outside the border and does not affect layout (no space taken). It is primarily used for focus indicators:

```css
button:focus-visible {
  outline: 2px solid #3b82f6;
  outline-offset: 2px;   /* gap between element and outline */
}
```

Never do `outline: none` without providing an alternative focus style — it removes keyboard navigation visibility.

***

## Margin Collapse

Block margins collapse in the vertical direction: when two block elements stack, their margins do not add — the larger margin wins.

```css
.section-a { margin-bottom: 2rem; }
.section-b { margin-top: 1rem; }
/* Gap between them: 2rem (not 3rem) */
```

Margin collapse also happens between a parent and its first/last child when there is no border, padding, or content between them:

```css
/* Parent margin collapses with child margin */
.parent { margin-top: 2rem; }
.child  { margin-top: 3rem; }
/* 3rem gap above parent (child's margin "escapes" to parent) */
```

To prevent parent-child collapse, add any padding or border to the parent:

```css
.parent {
  padding-top: 1px;   /* prevents margin collapse with first child */
}
```

Margin collapse does not happen:

* Horizontally (left/right)
* On flex or grid children
* When `overflow` is not `visible` on the parent

***

## Display

The `display` property controls how an element participates in flow layout and how it lays out its children.

### `display: block`

Takes full available width, forces a line break before and after, respects width/height/margin.

```css
div, p, h1, h2, section, article, header, footer, main, nav {
  display: block; /* default */
}
```

### `display: inline`

Takes only as much width as its content, no forced line breaks, ignores width/height, vertical margin/padding does not affect surrounding layout.

```css
span, a, strong, em, code {
  display: inline; /* default */
}
```

### `display: inline-block`

Inline flow (no forced line breaks) but respects width/height and all margin/padding.

```css
.badge {
  display: inline-block;
  padding: 0.2em 0.6em;
  border-radius: 0.25rem;
  font-size: 0.75rem;
}
```

### `display: none`

Removes element from the page entirely — not rendered, takes no space, invisible to accessibility tools.

```css
.hidden { display: none; }
```

To hide visually but keep accessible to screen readers:

```css
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
```

### `display: flex`

Turns the element into a flex container. Children become flex items. Covered fully in Part 3.

### `display: grid`

Turns the element into a grid container. Children become grid items. Covered fully in Part 4.

### `display: contents`

Removes the element's box but keeps its children in the flow — useful when you need to wrap elements for semantic reasons without adding a layout box.

```css
.wrapper {
  display: contents;
  /* element acts as if it isn't there; children participate in parent's layout */
}
```

***

## Width and Height

```css
.container {
  width: 100%;           /* percentage of parent */
  max-width: 1200px;     /* cap growth */
  min-width: 320px;      /* prevent shrinking below */

  height: auto;          /* default: grows with content */
  min-height: 100vh;     /* at least full viewport height */
}
```

### `width: auto` vs `width: 100%`

* `auto` — block element fills available width minus its own margins (respects margin)
* `100%` — fills 100% of parent's content width, then adds margin on top (can overflow)

### Viewport Units

```css
.hero {
  width: 100vw;    /* 100% of viewport width */
  height: 100vh;   /* 100% of viewport height */
}

/* Dynamic viewport units (accounts for mobile browser chrome) */
.full-height {
  height: 100dvh;  /* dynamic viewport height */
}
```

### `aspect-ratio`

```css
.video-embed {
  width: 100%;
  aspect-ratio: 16 / 9;
}

.avatar {
  width: 3rem;
  aspect-ratio: 1;   /* square */
  border-radius: 50%;
}
```

***

## Overflow

Controls what happens when content exceeds the element's dimensions.

```css
.box {
  overflow: visible;   /* default: content spills out */
  overflow: hidden;    /* clips overflowing content */
  overflow: scroll;    /* always shows scrollbar */
  overflow: auto;      /* scrollbar only when content overflows */
  overflow: clip;      /* clips like hidden but no scroll even programmatically */
}

/* Control axes independently */
.horizontal-scroll {
  overflow-x: auto;
  overflow-y: hidden;
}

/* Long words/URLs that overflow their container */
.prose {
  overflow-wrap: break-word;
  word-break: break-word;
}
```

***

## Positioning

The `position` property controls how an element is placed in the document.

### `position: static` (default)

Normal document flow. `top`, `right`, `bottom`, `left`, and `z-index` have no effect.

### `position: relative`

Element stays in normal flow but can be offset from its natural position using `top`, `right`, `bottom`, `left`. The space it originally occupied is preserved.

```css
.nudged {
  position: relative;
  top: -2px;    /* shift 2px upward */
  left: 4px;
}
```

More commonly used to make an element a **containing block** for absolutely positioned children:

```css
.card {
  position: relative;  /* establishes positioning context */
}

.card__badge {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
}
```

### `position: absolute`

Removed from normal flow (no space reserved). Positioned relative to the nearest ancestor with `position` other than `static`. If none, positions relative to the initial containing block (viewport).

```css
.dropdown {
  position: absolute;
  top: 100%;      /* below the parent's bottom edge */
  left: 0;
  width: 200px;
  background: #fff;
  border: 1px solid #e2e8f0;
  z-index: 100;
}
```

### `position: fixed`

Removed from flow. Positioned relative to the viewport. Stays in place as the user scrolls.

```css
.sticky-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1000;
  background: #fff;
  border-bottom: 1px solid #e2e8f0;
}
```

### `position: sticky`

Hybrid: behaves as `relative` until a threshold is reached while scrolling, then becomes `fixed` relative to its scroll container.

```css
.table-header th {
  position: sticky;
  top: 0;
  background: #f7fafc;
  z-index: 1;
}

.sidebar {
  position: sticky;
  top: 2rem;
  align-self: start;   /* needed inside flex/grid to prevent stretching */
}
```

`sticky` only works if:

* A `top` (or `bottom`) threshold is set
* The element's scroll container has scrollable overflow
* The parent is taller than the sticky element

### `z-index`

Controls stacking order for positioned elements (`relative`, `absolute`, `fixed`, `sticky`). Higher values stack on top.

```css
.modal-overlay { z-index: 400; }
.modal          { z-index: 500; }
.tooltip        { z-index: 600; }
```

`z-index` only works on positioned elements. It creates a **stacking context** — a child element cannot appear above an ancestor's stacking context peer, regardless of `z-index` value.

***

## The `float` Property

Float shifts an element to the left or right edge of its container, allowing text to wrap around it. It is the legacy layout mechanism — before Flexbox and Grid, floats were used for multi-column layouts.

```css
.article-image {
  float: left;
  margin: 0 1.5rem 1rem 0;
  max-width: 300px;
}
```

Clearing floats:

```css
/* Modern clearfix */
.clearfix::after {
  content: "";
  display: block;
  clear: both;
}

/* Or use flow-root on the container */
.container {
  display: flow-root;
}
```

I use floats only for text-wrapping around images. For page layout, I use Flexbox or Grid.

***

## `visibility` vs `display: none` vs `opacity: 0`

| Property             | Space Reserved | Accessible to Screen Readers | Events |
| -------------------- | -------------- | ---------------------------- | ------ |
| `display: none`      | No             | No                           | No     |
| `visibility: hidden` | Yes            | No                           | No     |
| `opacity: 0`         | Yes            | Yes                          | Yes    |

```css
/* Toggle visibility without layout shift */
.tooltip {
  visibility: hidden;
  opacity: 0;
  transition: opacity 0.2s;
}

.tooltip.is-visible {
  visibility: visible;
  opacity: 1;
}
```

`visibility` and `opacity` are combined here because `visibility: hidden` cannot be transitioned smoothly, but `opacity` can. The combination gives a fade effect without layout shift.

***

## Summary

| Concept                  | Key Point                                                    |
| ------------------------ | ------------------------------------------------------------ |
| `box-sizing: border-box` | Width includes padding + border — apply globally             |
| Margin collapse          | Vertical block margins collapse; flex/grid children exempt   |
| `display: block`         | Full width, forces line break                                |
| `display: inline`        | Content width only, no width/height                          |
| `display: inline-block`  | Inline flow + respects box model                             |
| `display: none`          | Removes element entirely from page and accessibility tree    |
| `position: relative`     | Creates positioning context for absolute children            |
| `position: absolute`     | Removed from flow, positioned to nearest positioned ancestor |
| `position: fixed`        | Positioned to viewport, stays on scroll                      |
| `position: sticky`       | Relative until threshold, then fixed within container        |
| `z-index`                | Stacking order — works only on positioned elements           |
| `overflow`               | Control clipping/scrolling of overflowing content            |

***

## Up Next

[Part 3](https://blog.htunnthuthu.com/getting-started/programming/css-101/css-101-part-3) covers Flexbox — the modern one-dimensional layout system.
