Alignment basics: what CSS “align” really means

“Alignment” sounds like one thing, but in CSS it depends on what you’re aligning:

  • Text and inline content (words, inline links, inline icons) → usually text-align or vertical-align.
  • Boxes (divs, cards, layouts) → usually margin: auto, flexbox, or grid.
  • Single elements that should be perfectly centered → grid/flex centering, or absolute+transform tricks.

One beginner rule that explains 80% of “why won’t this align?”: alignment needs extra space. If the container is only as big as the thing inside it, there’s nothing to “center within”.

Text-align: aligning inline content

text-align aligns inline content inside a block container: text, inline links, inline icons, and also inline-level elements like img (by default).

text-align: left / center / right / justify

text-align:
 .demo { text-align: left; } 
 *, ::before, ::after { box-sizing: border-box; } .demo { border: 3px solid #111; padding: 18px; max-width: 560px; font-family: ui-monospace, system-ui; line-height: 1.45; } .demo a { text-decoration: underline; } 
 

This is a paragraph with a link and some text. Try switching text-align values.

Notice how we didn’t align the .demo box itself, only the content inside it. If you want to center the whole box, that’s a different technique (we’ll do that soon).

Centering images and buttons with text-align

A very common beginner trick: if an element is inline (or inline-block), text-align can center it. Images are inline by default, buttons are often inline-block-ish.

text-align:
 .demo { text-align: center; } 
 *, ::before, ::after { box-sizing: border-box; } .demo { border: 3px solid #111; padding: 18px; max-width: 560px; font-family: system-ui, ui-monospace; } .demo img { width: 220px; height: auto; } .button { display: inline-block; margin-top: 14px; padding: 10px 14px; border: 2px solid #111; text-decoration: none; font-family: ui-monospace, system-ui; } 
  

Centering block elements with auto margins

To center a block element horizontally, the classic move is: margin-inline: auto. But it only works when the block has a constrained width (like width or max-width).

margin-inline: auto (the classic “center a box”)

 .card { margin-inline: auto; } 
 .card { margin-inline: auto; max-width: 410px; } 
 .card { margin-inline: auto; width: 320px; } 
 *, ::before, ::after { box-sizing: border-box; } .wrap { border: 3px dashed #111; padding: 18px; font-family: ui-monospace, system-ui; } .card { border: 3px solid #111; padding: 16px; background: #f2f2f2; } 
 

Centered card (when it has a width or max-width).

Try the different snippets.

If the element is naturally width: 100%, there is nothing to “center” because it already fills the row. That’s why adding max-width or width makes the centering visible.

vertical-align: inline alignment and baselines

vertical-align is often misunderstood because it does not vertically center block elements. It aligns inline or inline-block elements relative to the line box (baseline, middle, top, etc.).

Fixing the “icon sits too low” problem

vertical-align:
 .icon { vertical-align: baseline; } 
 *, ::before, ::after { box-sizing: border-box; } .demo { border: 3px solid #111; padding: 18px; font-family: system-ui, ui-monospace; font-size: 20px; } .icon { display: inline-block; width: 22px; height: 22px; border: 2px solid #111; background: #f2f2f2; margin-right: 8px; } 
 
Icon next to text

For inline icons/images next to text, vertical-align: middle is a very common “feels right” choice.

Flexbox alignment: the layout workhorse

Flexbox aligns items inside a flex container. It has two axes:

  • Main axis (default: horizontal) → controlled by justify-content.
  • Cross axis (default: vertical) → controlled by align-items.

If you change flex-direction, the axes swap. (Sneaky, but useful.)

justify-content (main axis)

justify-content:
 .flex { display: flex; justify-content: flex-start; } 
 *, ::before, ::after { box-sizing: border-box; } .flex { border: 3px solid #111; padding: 12px; font-family: ui-monospace, system-ui; } .item { border: 2px solid #111; padding: 10px 12px; background: #f2f2f2; } 
 
One
Two
Three
Four

align-items (cross axis)

To see cross-axis alignment clearly, we need the container to have some height.

align-items:
 .flex { display: flex; align-items: stretch; } 
 *, ::before, ::after { box-sizing: border-box; } .flex { border: 3px solid #111; padding: 12px; height: 160px; font-family: ui-monospace, system-ui; gap: 10px; } .item { border: 2px solid #111; padding: 10px 12px; background: #f2f2f2; } .item.tall { padding-top: 22px; padding-bottom: 22px; font-size: 22px; } 
 
Small
Taller
Small

stretch is the default for align-items. It stretches items to fill the container’s cross size when the item’s cross size is auto.

align-content (only when wrapping)

This one gets people: align-content does nothing unless there are multiple flex lines. That means you need flex-wrap: wrap and enough items to wrap.

align-content:
 .flex { display: flex; flex-wrap: wrap; align-content: flex-start; } 
 *, ::before, ::after { box-sizing: border-box; } .flex { border: 3px solid #111; height: 220px; padding: 12px; gap: 10px; font-family: ui-monospace, system-ui; } .item { border: 2px solid #111; background: #f2f2f2; padding: 10px 12px; width: 120px; } 
 
1
2
3
4
5
6
7
8

Flexbox perfect centering (two lines)

The famous recipe: justify-content: center and align-items: center.

 .center { display: flex; justify-content: center; align-items: center; } 
 .center { display: flex; justify-content: center; align-items: center; flex-direction: column; } 
 *, ::before, ::after { box-sizing: border-box; } .center { border: 3px solid #111; height: 200px; font-family: ui-monospace, system-ui; background: #f2f2f2; gap: 10px; padding: 10px; } .badge { border: 2px solid #111; padding: 8px 10px; background: #fff; } 
 
Centered
Also centered

Flexbox trick: push one item to the end with auto margins

A practical pattern for headers/nav bars: put margin-left: auto on the item you want to “push right”.

 .bar .spacer { margin-left: auto; } 
 .bar { justify-content: space-between; } 
 *, ::before, ::after { box-sizing: border-box; } .bar { display: flex; align-items: center; gap: 10px; border: 3px solid #111; padding: 12px; font-family: ui-monospace, system-ui; } .pill { border: 2px solid #111; padding: 8px 10px; background: #f2f2f2; } 
 
Logo
Docs
Blog
Account

Both snippets work, but auto margin is amazing when you want “these stay left, that one goes right” without calculating spacing.

Grid alignment: precise two-dimensional control

Grid is like flexbox’s more structured cousin. Flex is great for one-dimensional flow. Grid shines when you care about both rows and columns.

Aligning items inside their cells

Use justify-items (inline direction) and align-items (block direction), or the shorthand place-items.

 .grid { display: grid; place-items: start; } 
 .grid { display: grid; place-items: center; } 
 .grid { display: grid; place-items: end; } 
 *, ::before, ::after { box-sizing: border-box; } .grid { border: 3px solid #111; padding: 12px; height: 220px; font-family: ui-monospace, system-ui; background: #f2f2f2; grid-template-columns: repeat(3, 1fr); gap: 10px; } .item { border: 2px solid #111; background: #fff; padding: 10px 12px; width: 90px; } 
 
A
B
C
D
E
F

The grid cells are bigger than the items, so you can really see the alignment.

Aligning the whole grid inside its container

This is a different concept: justify-content and align-content control how the entire grid sits inside the container when the container is bigger than the grid tracks.

place-content:
 .grid { display: grid; place-content: start; } 
 *, ::before, ::after { box-sizing: border-box; } .grid { border: 3px solid #111; padding: 12px; height: 260px; font-family: ui-monospace, system-ui; background: #f2f2f2; grid-template-columns: repeat(2, 140px); grid-auto-rows: 60px; gap: 10px; } .item { border: 2px solid #111; background: #fff; display: grid; place-items: center; } 
 
1
2
3
4

Aligning a single item with *-self

Grid gives each item its own “override”: justify-self and align-self (or place-self).

 .featured { place-self: center; } 
 .featured { justify-self: end; align-self: start; } 
 *, ::before, ::after { box-sizing: border-box; } .grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; border: 3px solid #111; padding: 12px; height: 220px; font-family: ui-monospace, system-ui; background: #f2f2f2; } .item { border: 2px solid #111; background: #fff; padding: 10px 12px; width: 90px; } 
 
A
C
D
E
F

Absolute positioning: old-school centering (still useful)

Sometimes you don’t want layout rules; you want one thing floating on top of another. That’s where absolute positioning shines.

Center with top/left + translate(-50%, -50%)

This is the classic: set top: 50% and left: 50%, then pull back by half the element’s own size with transform: translate(-50%, -50%).

 .stage { position: relative; }

.modal {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
 .stage { position: relative; } .modal { position: absolute; inset: 0; margin: auto; height: 130px;} 
 *, ::before, ::after { box-sizing: border-box; } .stage { border: 3px solid #111; height: 240px; background: url("https://picsum.photos/900/260") center / cover no-repeat; font-family: ui-monospace, system-ui; overflow: hidden; } .modal { width: min(360px, 85%); border: 3px solid #111; background: rgba(255, 255, 255, 0.92); padding: 14px; } .modal p { margin: 0; } 
 

The second snippet (inset: 0; margin: auto;) is a neat alternative when the element has a known size. The translate version works great even when the size changes.

The easy button: place-items: center

If you can use grid, place-items: center is the “I want this centered, please and thank you” option.

 .center { display: grid; place-items: center; } 
 .center { display: grid; place-items: center; text-align: center; } 
 *, ::before, ::after { box-sizing: border-box; } .center { border: 3px solid #111; height: 220px; font-family: ui-monospace, system-ui; background: #f2f2f2; padding: 12px; } .card { border: 2px solid #111; background: #fff; padding: 14px; width: min(410px, 90%); } 
 

Centered card

Grid makes centering almost suspiciously easy.

Real-world alignment patterns

Pattern: centered page content with max-width

This is the classic blog/article layout: the page is wide, but the content is comfortable to read.

 .container { max-width: 680px; margin-inline: auto; padding-inline: 16px; } 
 .container { max-width: 680px; margin-inline: auto; padding-inline: 16px; text-align: center; } 
 *, ::before, ::after { box-sizing: border-box; } .page { border: 3px solid #111; padding: 18px; font-family: system-ui, ui-monospace; line-height: 1.5; background: #f2f2f2; } .container { border: 2px dashed #111; padding-block: 12px; } h4 { margin: 0 0 10px; font-family: ui-monospace, system-ui; } 
 

Reading width content

This container is centered with margin-inline: auto. The page can be huge, but this stays readable.

Pattern: icon + text perfectly aligned (row)

Use flexbox for little UI rows. It’s clean and predictable.

 .row { display: flex; align-items: center; gap: 10px; } 
 .row { display: flex; align-items: baseline; gap: 10px; } 
 *, ::before, ::after { box-sizing: border-box; } .row { border: 3px solid #111; padding: 14px; font-family: system-ui, ui-monospace; } .avatar { width: 52px; height: 52px; border: 2px solid #111; background: url("https://picsum.photos/120/120") center / cover no-repeat; border-radius: 50%; flex: 0 0 auto; } .name { font-family: ui-monospace, system-ui; font-size: 18px; } .meta { opacity: 0.8; } 
 
Alex
Online now

Pattern: centered modal with backdrop

Grid centering is a great “modal overlay” pattern: the backdrop is the container, the modal is the child.

 .backdrop { display: grid; place-items: center; } 
 .backdrop { display: flex; justify-content: center; align-items: center; } 
 *, ::before, ::after { box-sizing: border-box; } .backdrop { border: 3px solid #111; height: 260px; font-family: ui-monospace, system-ui; background: rgba(0, 0, 0, 0.18); padding: 14px; } .modal { width: min(410px, 90%); border: 3px solid #111; background: #fff; padding: 14px; } .modal .actions { display: flex; gap: 10px; margin-top: 12px; } .modal a { display: inline-block; padding: 8px 10px; border: 2px solid #111; text-decoration: none; } 
 

Troubleshooting: why alignment doesn’t work

Why text-align “does nothing”

  • You’re trying to align a block element, not inline content. Use margin-inline: auto, flex, or grid.
  • Your “thing” is 100% width, so centering looks identical.

Why margin: auto doesn’t center

  • The element has no width constraint. Add width or max-width.
  • You’re centering vertically with margins, but the layout doesn’t create extra vertical space.

Why align-items doesn’t seem to work

  • The container has no height (or no extra space). Give it height, or let it be taller than its children.
  • You forgot display: flex or display: grid on the container.
  • You used align-content without wrapping (flex) or without extra track space (grid).

Why translate(-50%, -50%) sometimes feels weird

  • Transforms can affect subpixel rendering and create slightly blurry text on some screens.
  • If you need pixel-crisp UI, consider grid/flex centering instead (when possible).

Quick cheatsheet: CSS alignment

  • Center text / inline stuff: text-align: center
  • Center a block horizontally: max-width: ...; margin-inline: auto
  • Center in flex: display: flex; justify-content: center; align-items: center
  • Center in grid: display: grid; place-items: center
  • Push one flex item right: margin-left: auto
  • Align inline icon with text: vertical-align: middle
  • Absolute center (overlay): top: 50%; left: 50%; transform: translate(-50%, -50%)

Conclusion: you now have CSS alignment superpowers

Alignment in CSS isn’t one feature, it’s a toolbox. Use text-align and vertical-align for inline content, use margin-inline: auto when you’re centering a block with a constrained width, and reach for flexbox or grid when you want layout-level control (especially for vertical centering). When you need overlays, absolute positioning with transform: translate(-50%, -50%) is still a perfectly valid classic.

Most alignment bugs come down to one thing: there’s no extra space to align within. So whenever something “refuses” to center, check the container size, the element’s width/height, and whether you’re using the right alignment system for the job. Once you get that habit, alignment stops being mysterious and starts being… quite satisfying.

You can learn even more in our Centering With CSS Interactive Tutorial.