Before Flexbox and Grid, it helps to know how the browser places boxes by default and how you can change that. The CSS display property decides what kind of box an element creates, and the position property lets you move an element away from its normal place, pin it to the screen or stack it on top of other content.
Normal flow
Without any layout CSS, elements follow normal flow. Block elements stack from top to bottom, each taking the full width. Inline elements sit side by side inside lines of text and wrap when the line is full. Normal flow is responsive by default, so always start with it and only change what you need.
The CSS display property
| Value | Behaviour | Typical use |
|---|---|---|
block | New line, full width, accepts width, height and all margins | <div>, <p>, sections |
inline | Flows with text; ignores width and height | <span>, <a>, <em> |
inline-block | Flows with text but accepts width, height and padding | Badges, small buttons |
none | Removes the element from the page and from screen readers | Hidden menus, tabs |
flex / grid | Turns the element into a layout container for its children | Rows, columns, page layouts |
CSS display changes how an element behaves, not what it means. A link styled as display: block is still a link to assistive technology. That is why you should choose HTML elements for meaning (see HTML Semantic Elements) and use CSS for looks.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>block, inline and inline-block</title>
<style>
body { font-family: system-ui, sans-serif; padding: 20px; }
.tag {
background: #e7f5ff;
border: 1px solid #74c0fc;
padding: 6px 10px;
margin: 4px;
width: 120px; /* ignored for inline */
}
.inline { display: inline; }
.inline-block { display: inline-block; }
.block { display: block; }
.hidden { display: none; }
</style>
</head>
<body>
<p>Inline: <span class="tag inline">Chennai</span><span class="tag inline">Mysuru</span></p>
<p>Inline-block: <span class="tag inline-block">Chennai</span><span class="tag inline-block">Mysuru</span></p>
<p>Block: <span class="tag block">Chennai</span><span class="tag block">Mysuru</span></p>
<p>There is a hidden span here: <span class="hidden">you cannot see me</span></p>
</body>
</html>Tip: To hide something visually but keep it available to screen readers, such as a label for an icon button, use a “visually hidden” utility class instead of CSS display: none. visibility: hidden hides an element but keeps its space.
The position property
Every element starts with position: static, meaning it sits in normal flow. The other values switch on the offset properties top, right, bottom and left, or the shorthand inset.
relative: the element stays in the flow, and its original space is kept, but you can nudge it with offsets. Its main job today is to become the reference point for absolutely positioned children.absolute: the element is removed from the flow and placed relative to its nearest positioned ancestor (any ancestor with a position other than static). Use it for badges, close buttons and overlays.fixed: the element is removed from the flow and pinned to the viewport, so it stays put when the page scrolls. Use it for a floating chat or “back to top” button.sticky: the element scrolls normally until it reaches an offset such astop: 0, then sticks while its parent is still on screen. Ideal for table headers and section headings.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>relative and absolute: a sale badge</title>
<style>
body { font-family: system-ui, sans-serif; padding: 30px; }
.product {
position: relative; /* reference point for the badge */
width: 220px;
padding: 20px;
border: 1px solid #ddd;
border-radius: 10px;
}
.badge {
position: absolute;
top: -10px;
right: -10px;
background: #d6336c;
color: white;
font-size: 0.8rem;
padding: 4px 10px;
border-radius: 999px;
}
.overlay {
position: absolute;
inset: 0; /* same as top/right/bottom/left: 0 */
background: rgb(255 255 255 / 70%);
display: none;
}
.product:hover .overlay { display: block; }
</style>
</head>
<body>
<div class="product">
<span class="badge">20% off</span>
<h3>Brass diya set</h3>
<p>Handmade in Moradabad.</p>
<div class="overlay"></div>
</div>
</body>
</html><!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>sticky header and fixed button</title>
<style>
body { font-family: system-ui, sans-serif; margin: 0; line-height: 1.6; }
header {
position: sticky;
top: 0;
background: #1b4332;
color: white;
padding: 12px 20px;
z-index: 10;
}
main { padding: 20px; }
main p { margin-block: 0 16px; }
.help {
position: fixed;
right: 16px;
bottom: 16px;
background: #f77f00;
color: white;
border: 0;
padding: 12px 16px;
border-radius: 999px;
font: inherit;
}
</style>
</head>
<body>
<header>Kochi Spice Market</header>
<main>
<p>Scroll down inside this preview. The header sticks to the top and the Help button stays fixed.</p>
<p>Cardamom, pepper, cloves and cinnamon are sold by weight.</p>
<p>Ask for fresh stock in the morning.</p>
<p>Most shops accept UPI payments.</p>
<p>Tea estates in Munnar are a short drive away.</p>
<p>Carry a cloth bag for your purchases.</p>
<p>Prices are usually fixed in larger stores.</p>
<p>Smaller stalls are happy to explain each spice.</p>
<p>End of the list.</p>
</main>
<button class="help">Help</button>
</body>
</html>Stacking with z-index
When positioned elements overlap, z-index decides which one is on top: a higher number appears in front. It only works on positioned elements and on flex or grid items. Values are compared within a stacking context, so a child with z-index: 9999 cannot escape a parent that sits below another element. Keep a small, documented set of values, such as 10 for headers and 100 for modals.
Watch out: Do not build whole page layouts with position: absolute. Absolutely positioned elements are taken out of the flow, so they overlap when text grows or the screen gets narrower. Use Flexbox and Grid for layout, and positioning only for small overlays.
A sticky element that will not stick usually has one of two problems: you forgot an offset such as top: 0, or an ancestor has overflow: hidden, which changes the scrolling box it sticks to.
Fixed and sticky elements on small screens
Pinned elements are useful, but they take permanent space on the screen. On a phone in landscape mode, a tall sticky header plus a fixed cookie bar can leave only a thin strip for the actual content. Keep sticky headers short, avoid stacking several fixed bars, and make sure a fixed button never covers important text or form fields.
Remember to add space for fixed elements, too. Because a fixed footer is outside the normal flow, the last lines of the page can end up hidden behind it. Adding padding-block-end to the body equal to the footer height solves this. With these tools in place, you are ready for real layout systems, starting with CSS Flexbox.
