Position utilities set position (static, relative, absolute, fixed, sticky) and place absolute children with top-*, bottom-*, start-* and end-* at 0, 50 or 100. translate-middle, translate-middle-x and translate-middle-y centre an element on its point, which is how badges and status indicators sit on buttons and avatars.
1Edge positions
top-0, top-50, top-100 with start-0, start-50, start-100 place absolute children on a grid of nine points.
<div class="position-relative bg-body-tertiary border rounded-3" style="height:180px">
<span class="position-absolute text-bg-primary rounded-2 px-2 small top-0 start-0">1</span> <span class="position-absolute text-bg-primary rounded-2 px-2 small top-0 end-0">2</span> <span class="position-absolute text-bg-primary rounded-2 px-2 small top-50 start-50">3</span> <span class="position-absolute text-bg-primary rounded-2 px-2 small bottom-50 end-50">4</span> <span class="position-absolute text-bg-primary rounded-2 px-2 small bottom-0 start-0">5</span> <span class="position-absolute text-bg-primary rounded-2 px-2 small bottom-0 end-0">6</span>
</div>2Centre with translate-middle
translate-middle shifts an element back by half its size so its centre sits on the point.
<div class="position-relative bg-body-tertiary border rounded-3 m-3" style="height:180px">
<span class="position-absolute text-bg-primary rounded-2 px-2 small top-0 start-0 translate-middle">TL</span> <span class="position-absolute text-bg-primary rounded-2 px-2 small top-0 start-50 translate-middle">T</span> <span class="position-absolute text-bg-primary rounded-2 px-2 small top-0 start-100 translate-middle">TR</span> <span class="position-absolute text-bg-primary rounded-2 px-2 small top-50 start-0 translate-middle">L</span> <span class="position-absolute text-bg-primary rounded-2 px-2 small top-50 start-50 translate-middle">C</span> <span class="position-absolute text-bg-primary rounded-2 px-2 small top-50 start-100 translate-middle">R</span> <span class="position-absolute text-bg-primary rounded-2 px-2 small top-100 start-0 translate-middle">BL</span> <span class="position-absolute text-bg-primary rounded-2 px-2 small top-100 start-50 translate-middle">B</span> <span class="position-absolute text-bg-primary rounded-2 px-2 small top-100 start-100 translate-middle">BR</span>
</div>3Notification badge on a button
position-relative on the button, translate-middle on the counter at top-0 start-100.
<div class="d-flex gap-4 pt-2">
<button type="button" class="btn btn-primary position-relative"><i class="bi bi-envelope-fill" aria-hidden="true"></i> Inbox <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">61<span class="visually-hidden"> unread messages</span></span> </button>
<button type="button" class="btn btn-outline-secondary position-relative" aria-label="Alerts"><i class="bi bi-bell-fill" aria-hidden="true"></i> <span class="position-absolute top-0 start-100 translate-middle p-1 bg-danger border border-light rounded-circle"><span class="visually-hidden">New alerts</span></span> </button>
</div>4Online indicator on an avatar
The indicator sits at bottom-0 end-0 of a position-relative wrapper.
<div class="d-flex gap-3">
<span class="position-relative d-inline-block"><img src="../assets/img/avatar-1.svg" alt="Mason Rossi" width="64" height="64" class="rounded-circle"><span class="position-absolute bottom-0 end-0 bg-success border border-3 border-white rounded-circle" style="width:18px;height:18px"><span class="visually-hidden">Online</span></span></span> <span class="position-relative d-inline-block"><img src="../assets/img/avatar-2.svg" alt="Ella Ortega" width="64" height="64" class="rounded-circle"><span class="position-absolute bottom-0 end-0 bg-warning border border-3 border-white rounded-circle" style="width:18px;height:18px"><span class="visually-hidden">Busy</span></span></span> <span class="position-relative d-inline-block"><img src="../assets/img/avatar-3.svg" alt="Amara Lindqvist" width="64" height="64" class="rounded-circle"><span class="position-absolute bottom-0 end-0 bg-secondary border border-3 border-white rounded-circle" style="width:18px;height:18px"><span class="visually-hidden">Offline</span></span></span>
</div>5Count badge on an avatar
A number badge at top-0 start-100 with translate-middle on a square avatar.
<span class="position-relative d-inline-block mt-2"> <img src="../assets/img/avatar-4.svg" alt="Jonah Okafor" width="56" height="56" class="rounded-3"> <span class="position-absolute top-0 start-100 translate-middle badge rounded-pill text-bg-primary border border-2 border-white">8</span> </span>6Ribbon on a card
An absolutely placed label at top-0 end-0 of a card.
<div class="position-relative border rounded-4 overflow-hidden" style="max-width:18rem">
<img src="../assets/img/product-9.svg" alt="Explainer animation" class="w-100 d-block"> <span class="position-absolute top-0 end-0 text-bg-danger px-3 py-1 small fw-semibold" style="border-bottom-left-radius:var(--ui-border-radius)">-45%</span>
<div class="p-3">
<div class="fw-medium">
Explainer animation
</div>
<div class="small text-body-secondary">
$86.92
</div>
</div>
</div>7Stretched link
stretched-link on the link makes the whole position-relative card clickable.
We keep things simple, so you can focus on what matters to you.
Read the story<div class="position-relative border rounded-3 p-3" style="max-width:22rem">
<div class="fw-semibold">
Design that earns attention
</div>
<p class="small text-body-secondary">We keep things simple, so you can focus on what matters to you.</p>
<a href="#" class="stretched-link small">Read the story</a>
</div>8Sticky top inside a scroll area
sticky-top keeps a header visible while its scroll container moves.
We test early with real users, so the final design works on the first day. Friendly people answer your questions quickly, by phone, chat or email.
Thousands of clients already trust us, and we work hard to keep it that way. Clients stay with us for years because we treat their brand like our own.
We combine strategy, design and technology to build brands that grow. Our motion team turns complex ideas into short films people actually watch.
Websites we build are fast, accessible and easy for your team to update. We measure success in sign-ups, sales and brand recall, not just awards.
<div class="border rounded-3 overflow-auto" style="height:170px">
<div class="sticky-top bg-body-secondary px-3 py-2 fw-semibold small">
Section A (sticky-top)
</div>
<p class="px-3 small">We test early with real users, so the final design works on the first day. Friendly people answer your questions quickly, by phone, chat or email.</p>
<p class="px-3 small">Thousands of clients already trust us, and we work hard to keep it that way. Clients stay with us for years because we treat their brand like our own.</p>
<p class="px-3 small">We combine strategy, design and technology to build brands that grow. Our motion team turns complex ideas into short films people actually watch.</p>
<p class="px-3 small mb-0">Websites we build are fast, accessible and easy for your team to update. We measure success in sign-ups, sales and brand recall, not just awards.</p>
</div>9position-sticky with a custom offset
position-sticky plus top-0 on a table header row inside a scroll box.
| Item | Price |
|---|---|
| UX audit | $76.19 |
| Launch campaign | $14.25 |
| Brand sprint | $6.01 |
| Landing page | $31.16 |
| Brand sprint | $53.85 |
| Logo refresh | $74.11 |
<div class="border rounded-3 overflow-auto" style="max-height:170px">
<table class="table table-sm mb-0">
<thead class="position-sticky top-0">
<tr>
<th scope="col" class="bg-body-tertiary">Item</th>
<th scope="col" class="bg-body-tertiary text-end">Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>UX audit</td>
<td class="text-end">$76.19</td>
</tr>
<tr>
<td>Launch campaign</td>
<td class="text-end">$14.25</td>
</tr>
<tr>
<td>Brand sprint</td>
<td class="text-end">$6.01</td>
</tr>
<tr>
<td>Landing page</td>
<td class="text-end">$31.16</td>
</tr>
<tr>
<td>Brand sprint</td>
<td class="text-end">$53.85</td>
</tr>
<tr>
<td>Logo refresh</td>
<td class="text-end">$74.11</td>
</tr>
</tbody>
</table>
</div>10Caption over an image
position-absolute bottom-0 start-0 with margin places a label on the photo corner.
<div class="position-relative d-inline-block rounded-4 overflow-hidden" style="max-width:24rem">
<img src="https://images.unsplash.com/photo-1753162658449-e0f19e1a4cfc?auto=format&fit=crop&w=1200&h=800&q=70" alt="Seoul" class="w-100 d-block"> <span class="position-absolute bottom-0 start-0 m-3 badge text-bg-light"><i class="bi bi-geo-alt-fill" aria-hidden="true"></i> Prague</span>
</div>11Play button centred on a video
top-50 start-50 translate-middle centres the play button on the poster image.
<div class="position-relative rounded-4 overflow-hidden" style="max-width:26rem">
<img src="https://images.unsplash.com/photo-1753162657329-beced5a7f63f?auto=format&fit=crop&w=1600&h=700&q=70" alt="Video poster" class="w-100 d-block">
<button type="button" class="btn btn-light rounded-circle position-absolute top-50 start-50 translate-middle shadow fs-3 d-flex align-items-center justify-content-center" style="width:64px;height:64px" aria-label="Play"><i class="bi bi-play-fill" aria-hidden="true"></i></button>
</div>12Step progress with positioned dots
A line with translate-middle steps positioned at start-0, start-50 and start-100.
<div class="px-3 py-4">
<div class="position-relative" style="height:4px">
<div class="bg-body-secondary w-100 h-100 rounded-pill">
</div>
<div class="position-absolute top-0 start-0 bg-primary h-100 w-50 rounded-pill">
</div>
<span class="position-absolute top-50 start-0 translate-middle btn btn-sm btn-primary rounded-pill" style="width:2rem;height:2rem">1</span> <span class="position-absolute top-50 start-50 translate-middle btn btn-sm btn-primary rounded-pill" style="width:2rem;height:2rem">2</span> <span class="position-absolute top-50 start-100 translate-middle btn btn-sm btn-secondary rounded-pill" style="width:2rem;height:2rem">3</span>
</div>
</div>13Close button in the corner
A btn-close at top-0 end-0 with a small margin.
<div class="position-relative border rounded-3 p-3 pe-5 bg-body-tertiary">
<button type="button" class="btn-close position-absolute top-0 end-0 m-2" aria-label="Close"></button>
<div class="fw-semibold">
Bold ideas, beautifully executed
</div>
<div class="small">
Every project starts with a workshop, so we understand your audience before we design.
</div>
</div>14Icon inside an input
An icon at top-50 translate-middle-y on the start of a padded input.
<div class="position-relative" style="max-width:22rem">
<span class="position-absolute top-50 start-0 translate-middle-y ms-3 text-body-secondary"><i class="bi bi-search" aria-hidden="true"></i></span>
<label class="visually-hidden" for="ut-q-1254">Search</label>
<input id="ut-q-1254" type="search" class="form-control ps-5" placeholder="Search Motion">
</div>15Tooltip arrow label
A label positioned above an element with bottom-100 start-50 translate-middle-x.
<div class="pt-5 text-center">
<span class="position-relative d-inline-block"> <span class="position-absolute bottom-100 start-50 translate-middle-x mb-2 text-bg-dark rounded-2 px-2 py-1 small text-nowrap">12 saved</span>
<button type="button" class="btn btn-outline-primary"><i class="bi bi-bookmark-fill" aria-hidden="true"></i> Save</button>
</span>
</div>16Fixed and sticky classes (preview)
fixed-top, fixed-bottom and sticky-top attach bars to the viewport; here they are previewed as static boxes with position-static.
fixed-top - pins a bar to the top of the viewportsticky-top - sticks after scrolling to itfixed-bottom - pins a bar to the bottomsticky-md-top - sticky from md up<div class="d-grid gap-2 small">
<div class="position-static text-bg-dark rounded-2 p-2">
<code class="text-reset">fixed-top</code> - pins a bar to the top of the viewport
</div>
<div class="position-static text-bg-secondary rounded-2 p-2">
<code class="text-reset">sticky-top</code> - sticks after scrolling to it
</div>
<div class="position-static text-bg-dark rounded-2 p-2">
<code class="text-reset">fixed-bottom</code> - pins a bar to the bottom
</div>
<div class="position-static text-bg-secondary rounded-2 p-2">
<code class="text-reset">sticky-md-top</code> - sticky from md up
</div>
</div>17Overlay covering a card
position-absolute top-0 start-0 w-100 h-100 covers the card with a loading layer.
Fixed prices and weekly demos keep you in control from start to finish. We have helped more than a hundred companies launch, rebrand and grow online.
<div class="position-relative border rounded-3 p-3 overflow-hidden" style="max-width:22rem">
<div class="fw-semibold">
Why motion matters for modern brands
</div>
<p class="small mb-0">Fixed prices and weekly demos keep you in control from start to finish. We have helped more than a hundred companies launch, rebrand and grow online.</p>
<div class="position-absolute top-0 start-0 w-100 h-100 bg-body bg-opacity-75 d-flex align-items-center justify-content-center">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading</span>
</div>
</div>
</div>18Map pin
A pin positioned at percentage offsets with bottom-50 and translate-middle-x.
<div class="position-relative rounded-4 overflow-hidden" style="max-width:26rem">
<img src="https://images.unsplash.com/photo-1787647559705-d2ad3322020e?auto=format&fit=crop&w=1600&h=700&q=70" alt="Map of Copenhagen" class="w-100 d-block"> <span class="position-absolute top-50 start-50 translate-middle text-danger fs-2 lh-1"><i class="bi bi-geo-alt-fill" aria-hidden="true"></i></span> <span class="position-absolute bottom-0 end-0 m-2 badge text-bg-light">Austin</span>
</div>19Vertical centre on one side
top-50 end-0 translate-middle-y places a next arrow on the side of a slider.
<div class="position-relative rounded-4 overflow-hidden" style="max-width:26rem">
<img src="https://images.unsplash.com/photo-1752650736677-94fe8cdb9d5c?auto=format&fit=crop&w=1200&h=800&q=70" alt="We make good brands great" class="w-100 d-block">
<button type="button" class="btn btn-light btn-sm rounded-circle position-absolute top-50 start-0 translate-middle-y ms-2" aria-label="Previous"><i class="bi bi-chevron-left" aria-hidden="true"></i></button>
<button type="button" class="btn btn-light btn-sm rounded-circle position-absolute top-50 end-0 translate-middle-y me-2" aria-label="Next"><i class="bi bi-chevron-right" aria-hidden="true"></i></button>
</div>20Corner tag on a pricing card
A badge at top-0 start-50 translate-middle sits on the top border.
<div class="pt-3">
<div class="position-relative border border-2 border-primary rounded-4 p-4 text-center" style="max-width:16rem">
<span class="position-absolute top-0 start-50 translate-middle badge rounded-pill text-bg-primary px-3">Best value</span>
<div class="small">
Yearly
</div>
<div class="fs-3 fw-bold">
$242.89
</div>
</div>
</div>