1Normal flow
If you write no layout CSS at all, the browser still places things by a fixed rule called normal flow: block elements (div, p, h1, section, nav) stack top to bottom and each takes the full width. Inline elements (a, span, strong, img) sit side by side in a line and wrap like text.
display, flex, grid) or takes an element out of it (position). Decide which one you need before you write CSS.2display
display decides what kind of box an element is, and how its children are laid out.
| Value | Behavior |
|---|---|
block | Starts a new line, fills the full width. Width, height, margin and padding all work. |
inline | Flows inside a line of text. width and height do not apply to non-replaced inline elements, vertical margins do nothing. |
inline-block | Sits in a line like text, but accepts width, height, margin and padding. |
none | Removed completely: no space, not shown, not read by screen readers. |
flex | Children line up in a row or column and you control spacing and alignment (section 6). |
grid | Children are placed in rows and columns at the same time (section 7). |
contents | The element’s own box disappears and its children act as if they were in the parent. |
display: none vs visibility: hidden vs opacity: 0
| Takes space | Clickable | Use for | |
|---|---|---|---|
display:none | No | No | Menus, tabs, hidden panels |
visibility:hidden | Yes | No | Hide without the layout jumping |
opacity:0 | Yes | Yes | Fade animations |
3The box model
Every element is a box made of four layers, from inside out: content, padding (space inside the border), border, margin (space outside, between elements).
Always set box-sizing: border-box
By default, width: 300px plus padding: 20px makes a box 340px wide, and this is the most common reason things overflow. With border-box, padding and border are counted inside the width.
*, *::before, *::after { box-sizing: border-box; }
Margin shorthand
margin: 10px; /* all four sides */
margin: 10px 20px; /* vertical | horizontal */
margin: 10px 20px 30px; /* top | horizontal | bottom */
margin: 10px 20px 30px 40px; /* top right bottom left (clockwise) */
margin: 0 auto; /* centers a block that has a width */
margin-left: auto; /* pushes an element to the far right */
4position
position controls whether an element stays in the normal flow. Together with top, right, bottom, left it nudges or pins it.
| Value | In flow? | Offsets are measured from… | Typical use |
|---|---|---|---|
static | Yes | Offsets do nothing (default) | Everything normal |
relative | Yes (keeps its space) | Its own original spot | Small nudge, or to become an anchor for children |
absolute | No | Nearest ancestor establishing its containing block | Badges, corner buttons, dropdowns |
fixed | No | The browser window | Floating buttons, always-visible bars |
sticky | Yes | The scroll container, once you scroll past it | Headers, table headings, side menus |
absolute element looks for the closest parent that has position: relative (or absolute, fixed, sticky). If none exists, it uses the whole page. So when an absolute element “jumps to the corner”, add position: relative to the parent you want it inside.Try it
Sibling before
Set the parent to static and watch the target measure from the outer page instead of its parent. Choose relative and notice the siblings do not move, because the original space is kept. Choose absolute and the siblings close the gap, because the box left the flow.
Offset shortcuts
inset: 0; /* top, right, bottom, left all 0: stretch to fill the parent */
position: absolute; top: 0; right: 0; /* pin to top-right corner */
position: absolute; inset: 0; margin: auto; width: 200px; height: 100px; /* centered */
fixed
.chat-button { position: fixed; right: 20px; bottom: 20px; }
Stays in place while you scroll. Some ancestor properties can change its containing block; for example, if a parent has transform, filter or perspective, the fixed element measures from that parent instead.
sticky
Needs a threshold (such as top: 0) and room to move within its container. The page itself can provide the scrolling. Scroll the box below.
Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
header { position: sticky; top: 0; z-index: 10; background: #fff; }
top, that no ancestor has overflow: hidden/auto/scroll (it becomes the scroll container), and that the parent is taller than the sticky element.5z-index & stacking
z-index decides which overlapping element is on top. Higher wins. It only works on elements that are positioned (not static) or that are flex/grid children.
position with a z-index, opacity below 1, transform, filter, isolation: isolate. A child cannot escape its parent’s stacking context. Compare the parent contexts, not just the child values./* a simple scale that avoids chaos */
--z-dropdown: 100;
--z-sticky: 200;
--z-modal: 300;
--z-toast: 400;
6Flexbox
Use flexbox to lay items out along one direction: navbars, button groups, cards in a row, a label next to an input. Set display: flex on the parent; its direct children become flex items.
.row { display: flex; gap: 16px; }
Two axes matter. The main axis is the direction of the row (horizontal by default). The cross axis is the other one. justify-content works on the main axis and align-items on the cross axis. If you flip to flex-direction: column, they swap.
Try it
Container properties
| Property | What it does |
|---|---|
flex-direction | row | column | row-reverse | column-reverse |
justify-content | Distributes items along the main axis |
align-items | Aligns items on the cross axis |
flex-wrap | Lets items drop to a new line instead of shrinking |
gap | Space between items (use this instead of margins) |
align-content | Spacing between lines when items wrapped |
Item properties
| Property | What it does |
|---|---|
flex: 1 | Item grows to take the free space. Two items with flex: 1 share it equally. |
flex: 0 0 200px | Do not grow, do not shrink, start at 200px (a fixed-width item). |
flex-shrink: 0 | Never get squeezed (good for logos and icons). |
align-self | Override align-items for a single item. |
order | Change visual order without touching the HTML. |
margin-left: auto | Absorbs all free space on that side: pushes the item (and everything after it) to the end. |
min-width: 0 to the item and the text can wrap or truncate.7Grid
Use grid when you need rows and columns together: page layouts, card galleries, dashboards, forms. Set display: grid on the parent and define the columns.
.grid {
display: grid;
grid-template-columns: 1fr 2fr 1fr; /* three columns, middle twice as wide */
gap: 16px;
}
.wide { grid-column: 1 / 3; } /* from line 1 to line 3 = 2 columns */
Responsive cards with no media query
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 20px;
}
Each card is at least 240px wide, and the browser fits as many per row as it can.
Page layout with named areas
.page {
display: grid;
grid-template-columns: 240px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas:
"header header"
"side main"
"footer footer";
min-height: 100vh;
}
header { grid-area: header; }
aside { grid-area: side; }
main { grid-area: main; }
footer { grid-area: footer; }
8Centering
/* 1. Center anything, horizontally and vertically (best default) */
.parent { display: grid; place-items: center; }
/* 2. Same with flex */
.parent { display: flex; justify-content: center; align-items: center; }
/* 3. Center a block horizontally only */
.box { width: 600px; max-width: 100%; margin: 0 auto; }
/* 4. Center text */
.text { text-align: center; }
/* 5. Center an absolutely positioned element */
.box { position: absolute; inset: 0; margin: auto; width: 200px; height: 100px; }
/* 6. Center on the full screen */
.parent { min-height: 100vh; display: grid; place-items: center; }
9Tasks: how do I…?
Put the logo on the left and the links on the right (navbar)
Flex on the nav, then let the space between do the work.
<nav class="nav"><a class="logo">DECT</a><ul class="links">…</ul></nav>
.nav { display: flex; justify-content: space-between; align-items: center; padding: 16px 32px; }
.links { display: flex; gap: 24px; list-style: none; margin: 0; padding: 0; }Put the logo left, links in the center, a button right
Three-column grid, where the middle column stays truly centered.
.nav { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; }
.nav .cta { justify-self: end; }Keep the navbar at the top while scrolling
.nav { position: sticky; top: 0; z-index: 100; background: #fff; }Push one link to the far right
Auto margin on that item.
.links { display: flex; gap: 16px; }
.links .login { margin-left: auto; }Put a button in the top-right corner of a card
The card is the anchor (relative); the button is pinned (absolute).
.card { position: relative; padding: 24px; }
.close { position: absolute; top: 12px; right: 12px; }Put a notification badge on an icon
.icon { position: relative; display: inline-block; }
.badge { position: absolute; top: -6px; right: -6px; }Make a floating button stay in the bottom-right corner
.fab { position: fixed; right: 20px; bottom: 20px; z-index: 50; }Show a dropdown menu under a link
This CSS illustrates placement only. A complete dropdown also needs a keyboard- and touch-operable button, focus handling and an expanded state.
.item { position: relative; }
.dropdown { position: absolute; top: 100%; left: 0; display: none; min-width: 180px; z-index: 100; }
.item:hover .dropdown { display: block; }Build a modal with a dark overlay
This is a layout example, not a complete accessible modal. A real modal also needs focus management, a clear close action and Escape-key handling; consider the native dialog element.
.overlay { position: fixed; inset: 0; background: rgba(0,0,0,.5); display: grid; place-items: center; z-index: 300; }
.modal { background: #fff; padding: 24px; width: min(480px, 92vw); border-radius: 8px; }Keep the footer at the bottom when the page is short
body { min-height: 100vh; display: flex; flex-direction: column; margin: 0; }
main { flex: 1; } /* takes all leftover space, footer is pushed down */Make a sidebar plus main content
.layout { display: grid; grid-template-columns: 260px 1fr; gap: 24px; }
.sidebar { position: sticky; top: 16px; align-self: start; }Make cards the same height, with the button at the bottom
.cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 20px; }
.card { display: flex; flex-direction: column; }
.card .btn { margin-top: auto; }Place two buttons side by side with a space
.actions { display: flex; gap: 12px; }Make a full-screen hero with centered text
.hero { min-height: 100vh; display: grid; place-items: center; text-align: center; }Stack columns on mobile, side by side on desktop
.row { display: flex; flex-direction: column; gap: 20px; }
@media (min-width: 768px) { .row { flex-direction: row; } .row > * { flex: 1; } }Hide the menu on mobile and show a burger button
.burger { display: none; }
@media (max-width: 767px) { .links { display: none; } .burger { display: block; } }Put text over an image
.hero { position: relative; }
.hero img { width: 100%; display: block; }
.hero .text { position: absolute; left: 24px; bottom: 24px; color: #fff; }10Common problems
| Symptom | Cause | Fix |
|---|---|---|
| Absolute element jumps to the page corner | No positioned parent | position: relative on the parent |
| Parent collapses to zero height | All children are absolute or floated | Give the parent a height, or keep one child in flow |
| z-index has no effect | Element is static, or in a different stacking context | Add position: relative; raise the parent’s z-index |
| Horizontal scrollbar appears | Something is wider than the screen (padding with content-box, 100vw, long words) | box-sizing: border-box; use width: 100%; overflow-wrap: anywhere |
| Width and height do nothing | Element is inline (span, a) | display: inline-block or block |
| Margin-top on a child moves the parent | Margin collapsing | Use padding on the parent, or display: flow-root |
| Small gap under an image | Images are inline and sit on the text baseline | img { display: block; } |
| Sticky doesn’t stick | Missing top, or an ancestor has overflow set | Add top: 0; remove overflow from ancestors |
| Flex item overflows with long text | Items won’t shrink below content size | min-width: 0 on the item |
| 100vh is too tall on phones | The browser toolbar counts in 100vh | Use 100dvh |
| Fixed element not fixed | An ancestor has transform or filter | Move the element outside, or remove the transform |
| Centering fails vertically | Parent has no height | Give it min-height |
Debug routine
/* 1. Show every box */
* { outline: 1px solid rgba(255,0,0,.4); }
/* 2. In the browser: right-click → Inspect → hover the element
The colors show margin, border, padding and content.
3. Check the "Computed" tab for the real display and position. */
11Units & sizing
| Unit | Meaning | Use for |
|---|---|---|
px | Fixed pixels | Borders, shadows, small details |
% | Percent of the parent | Fluid widths |
rem | Multiple of the root font size (often 16px) | Font sizes, spacing |
em | Multiple of the element’s font size | Padding that scales with text |
vw / vh | 1% of the viewport width / height | Full-screen sections |
dvh | Viewport height that adapts to mobile toolbars | Full-height on phones |
fr | Share of free space in grid | Grid columns |
width: min(1100px, 92%); /* never wider than 1100px, never touching the edges */
font-size: clamp(1rem, 2.5vw, 1.5rem); /* min | preferred | max */
.container { max-width: 1100px; margin-inline: auto; padding-inline: 20px; }
img { max-width: 100%; height: auto; } /* images never overflow */
12Cheat sheet
| I want to… | Use |
|---|---|
| Arrange items in a row or column | display: flex + gap |
| Build rows and columns | display: grid |
| Center anything | display: grid; place-items: center |
| Center a block horizontally | margin: 0 auto + a width |
| Space items apart | gap (parent) rather than margins on children |
| Push an item to the end | margin-left: auto (flex) |
| Pin to a corner of its parent | parent relative + child absolute |
| Pin to the screen | position: fixed |
| Stick while scrolling | position: sticky; top: 0 |
| Cover an area completely | position: absolute; inset: 0 |
| Show or hide | display: none / block |
| Change which overlaps which | z-index on a positioned element |
| Keep padding inside the width | box-sizing: border-box |