position: absolute убирает элемент из обычного потока документа и позиционирует его относительно ближайшего предка с непустым position - а если такого предка нет, относительно всей страницы. Место под ним не резервируется, а размер по умолчанию - по содержимому, а не на весь родитель.
В этом уроке
Попробуй прямо сейчас: убери у .card строку position: relative - оба absolute-блока "выпрыгнут" из карточки и спозиционируются уже относительно всей страницы.
Точка отсчёта: как ищется позиционированный предок
Как уже говорилось в обзорном уроке про position и уроке про relative, absolute-элемент ищет точку отсчёта, поднимаясь вверх по дереву предков, пока не найдёт первый с непустым position (relative, absolute, fixed или sticky). Если такого предка нет вообще - точкой отсчёта становится вся страница. Но есть менее очевидное исключение: даже обычный, "непозиционированный" предок (со static) станет точкой отсчёта, если у него задан transform, filter или perspective, отличный от none - это частая причина неожиданного поведения absolute в реальных проектах.
.card { position: relative; } - явный и предсказуемый способ сделать родителя точкой отсчёта.
.card { transform: scale(1); } без осознания последствий - такой transform "случайно" превращает .card в точку отсчёта для всех absolute-потомков, даже если сам разработчик хотел просто применить трансформацию, а не менять контекст позиционирования.
Место не резервируется, размер - по содержимому
Как и у fixed, место absolute-элемента в обычном потоке НЕ резервируется - соседи ведут себя так, будто его там никогда не было (в отличие от relative, где место остаётся). А без явных width и height absolute-элемент по умолчанию занимает размер по своему содержимому, а не растягивается на всю ширину или высоту родителя, как это делает обычный блочный элемент.
Есть удобное исключение: если задать ОБА противоположных отступа на одной оси - например, и top, и bottom - а размер по этой оси оставить auto, элемент растянется и заполнит всё расстояние между ними.
position: absolute; top: 0; bottom: 0; width: 40px; - высота элемента растянется на всю доступную высоту родителя, а ширина останется 40px.
position: absolute; без width, ожидая, что элемент растянется на всю ширину родителя, как обычный div - absolute без явных offset'ов на обеих сторонах оси остаётся по размеру содержимого.
margin: auto и все отступы в 0 - центрирование
Классический приём для центрирования absolute-элемента с известными width и height: задать все четыре отступа в 0 (короткая запись - inset: 0, то есть top/right/bottom/left: 0 сразу) и margin: auto. Браузер распределит свободное место поровну со всех сторон - элемент окажется точно по центру родителя, причём по обеим осям сразу, без вычисления точных пикселей вручную.
position: absolute; inset: 0; margin: auto; width: 100px; height: 60px; - элемент 100×60px окажется точно по центру родителя.
position: absolute; top: 0; margin: auto; без right/bottom/left - для этого трюка нужны отступы со ВСЕХ четырёх сторон (или хотя бы противоположной пары на каждой оси), иначе margin: auto не сработает как центрирование.
Частые ошибки новичков
| Ошибка | Что происходит | Как исправить |
|---|---|---|
| Не подозревают, что transform/filter у предка тоже создаёт точку отсчёта | absolute-потомок неожиданно позиционируется не от страницы, а от предка с transform | Проверять, нет ли у предков transform/filter/perspective, если позиционирование "странно" работает |
| Ждут, что absolute без width растянется на весь родитель | Элемент остаётся по размеру содержимого, а не растягивается | Задать width явно или использовать offset'ы с обеих сторон оси (например, left и right) |
| Пытаются центрировать через margin: auto без всех нужных отступов | Центрирование не срабатывает - margin: auto нужно распределяемое свободное место | Задать все четыре отступа (inset: 0) вместе с явными width и height |
| Забывают, что место absolute-элемента в потоке не резервируется | Соседние элементы "не видят" absolute-элемент и сдвигаются, как будто его нет | Использовать position: relative, если нужно сохранить место в разметке |
Шпаргалка
| Что нужно | Как сделать |
|---|---|
| Точка отсчёта для absolute-потомков | position: relative; у родителя |
| Растянуть по одной оси между двумя краями | top: 0; bottom: 0; (height остаётся auto) |
| Центрировать по обеим осям | inset: 0; margin: auto; + явные width/height |
| Позиционировать в углу карточки | position: absolute; top: 8px; right: 8px; |
| Случайная точка отсчёта, о которой легко забыть | transform/filter/perspective ≠ none у предка |
Коротко: отвечаем на вопросы
Почему у absolute-элемента без width он не растягивается на весь родитель?
По умолчанию absolute-элемент занимает размер по своему содержимому, а не по родителю - это отличает его от обычного блочного элемента. Растянуть можно, задав явный width/height или offset'ы с обеих сторон одной оси (например, left: 0 и right: 0 растянут элемент по ширине).
Как отцентровать absolute-элемент через margin: auto?
Нужно задать все четыре отступа в 0 (inset: 0, то есть top/right/bottom/left: 0) вместе с явными width и height, и добавить margin: auto - браузер распределит свободное место поровну со всех сторон, и элемент окажется точно по центру родителя по обеим осям.
Может ли непозиционированный элемент стать точкой отсчёта для absolute-потомка?
Да, если у него задан transform, filter или perspective, отличный от none - даже при position: static такой предок становится точкой отсчёта, как будто у него был relative. Это частая причина неожиданного поведения absolute в реальных проектах.