Главная » Статьи » Меньше абсолютного позиционирования с современным CSS

Меньше абсолютного позиционирования с современным CSS

Меньше абсолютного позиционирования с современным CSS

От автора: каждый раз, когда я работаю над компонентом, которому требуется абсолютное позиционирование, я спрашиваю себя: действительно ли это необходимо? Я заметил несколько вариантов использования, в которых нет необходимости в position:absolute. Мне показалось это интересным, и захотел, задокументировать варианты использования, с которыми я обычно сталкивался, работая над проектами.

В этой статье я рассмотрю несколько вариантов использования, в которых абсолютное позиционирование не требуется.

Вступление

Если мы вернемся на 5 лет назад, CSS flexbox был все еще новым и не мог использовать надлежащих отступов. CSS-grid тогда даже не поддерживалась. В конце концов, мы использовали позиционирование CSS для достижения желаемого макета. Однако в наши дни некоторые из этих вариантов использования можно решить с помощью CSS flexbox или grid.
На днях мы работали над фронтендом целевой страницы, и мой партнер спросил меня о проблеме с макетом, с которой он столкнулся. Проблема возникла из-за position:absolute, я попытался помочь, и мы исправили эту проблему, даже не используя позиционирование CSS.

Случаи использования с примерами

Наложение в карточке

Когда у нас есть карточка, содержащая текст поверх изображения, мы часто используем position:absolute для размещения содержимого поверх изображения. В CSS-сетке это больше не требуется.

Меньше абсолютного позиционирования с современным CSS

Это типичная карточка с текстом поверх изображения. Вот HTML:

<article class="card"> <div class="card__thumb"> <img src="assets/mini-cheesecake.jpg" alt=""> </div> <div class="card__content"> <h2><a href="#">Title</a></h2> <p>Subtitle</p> </div>
</article>

Чтобы разместить контент поверх изображения, нам нужно позиционировать .card__content абсолютно.

.card { position: relative;
} .card__content { position: absolute; left: 0; top: 0; width: 100%; height: 100%; background: linear-gradient(to top, #000, rgba(0, 0, 0, 0) bottom/100% 60% no-repeat; padding: 1rem;
}

В приведенном выше примере нет ничего плохого, но почему бы не использовать более простое решение? Давайте исследуем это.

Первым делом нужно добавить display:grid в компонент карты. Нам не нужно устанавливать какие-либо столбцы или строки.

.card { position: relative; display: grid;
} .card__content { display: flex; flex-direction: column; justify-content: flex-end;
}

Меньше абсолютного позиционирования с современным CSS

По умолчанию сетка CSS автоматически создает строки на основе содержимого. В карте у нас есть два основных элемента, поэтому у нас есть две строки контента. Чтобы перекрыть контент с изображением, нам нужно разместить их оба в первой области сетки.

.card__thumb,
.card__content { grid-column: 1/2; grid-row: 1/2;
}

Более того, мы можем использовать сокращение grid-area:

.card__thumb,
.card__content { grid-area: 1/2;
}

Меньше абсолютного позиционирования с современным CSS

Наконец, мы также можем использовать grid-area: 1/-1. -1 представляет собой последний столбец и строку в сетке.

Card Tag

Основываясь на предыдущем примере, мы хотим расширить его и включить тег в левую верхнюю часть карты. Для этого нам нужно использовать ту же технику grid-area: 1/-1, но мы не хотим, чтобы тег заполнял всю карту, верно?

Меньше абсолютного позиционирования с современным CSS

Чтобы исправить это, нам нужно указать тегу, чтобы он выровнялся по началу своего контейнера.

.card__tag { align-self: start; justify-self: start; /* Other styles */
}

Познакомьтесь с тегом, который расположен над его родительским элементом, без использования position:absolute. Демо.

Herо-раздел

Еще один идеальный вариант использования — это hero-раздел с содержимым, перекрывающим изображение.

Меньше абсолютного позиционирования с современным CSS

Это похоже на пример карты, но с другим стилем для самого содержимого. Прежде чем погрузиться в современный подход, давайте на минутку задумаемся о том, как это сделать с помощью абсолютного позиционирования. У нас есть три слоя: изображение, градиент наложения и содержание.

Меньше абсолютного позиционирования с современным CSS

Есть разные способы реализовать это. Если изображение носит чисто декоративный характер, можно использовать background-image. В противном случае мы можем использовать элемент img.

.hero { position: relative; min-height: 500px;
} .hero__thumb { position: absolute; left: 0; top: 0; width: 100%; height: 100%; object-fit: cover;
} /* The overlay */
.hero:after { content: ""; position: absolute; left: 0; top: 0; width: 100%; height: 100%; background-color: #000; opacity: 0.5;
} .hero__content { position: absolute; left: 50%; top: 50%; z-index: 1; transform: translate(-50%, -50%); text-align: center;
}

Вот как мы можем реализовать hero-раздел, используя абсолютное позиционирование. Однако мы можем добиться большего. Давайте исследуем современный подход.

Во-первых, нам нужно добавить display:grid к hero-элементу. После этого мы применим ту же концепцию, что и в компоненте карты grid-area:1/-1, к каждому прямому дочернему элементу.

Меньше абсолютного позиционирования с современным CSS

К сожалению, нам нужно будет использовать фиксированную высоту для hero-секции, чтобы сработало правило .hero__thumb. (Дочерний элемент с height:100% требует, чтобы его родительский элемент имел явную фиксацию height, а не min-height).

.hero { display: grid; height: 500px;
} .hero__content { z-index: 1; /* [1] */ grid-area: 1/-1; display: flex; flex-direction: column; margin: auto; /* [2] */ text-align: center;
} .hero__thumb { grid-area: 1/-1; object-fit: cover; /* [3] */ width: 100%; height: 100%; min-height: 0; /* [4] */
} .hero:after { content: ""; background-color: #000; opacity: 0.5; grid-area: 1/-1;
}

Я хочу пройтись по пронумерованным строкам кода, поскольку они важны:

Мы можем использовать z-index сетки или flex элемента. Вообще не нужно добавлять position:relative.

Поскольку .hero__content это элемент сетки, использование margin:auto будет центрировать его по горизонтали и вертикали.

Не забывайте включать object-fit:cover при работе с изображениями.

Я использовал для hero-изображения min-height:0 в том случае, если использовалось большое изображение. Это сделано для того, чтобы заставить CSS-сетку учитывать height:100% и избегать увеличения размера изображения, больше чем hero-раздел, в случае, если автор использовал огромное изображение. Подробнее об этом вы можете прочитать в моей статье о минимальном размере содержимого в CSS-сетке.

Обратите внимание, как мы пришли к гораздо более чистому решению. Демо.

CSS display:contents

Я думаю, что это первый практический пример использования display:contents, который был для меня действительно полезный. Рассмотрим следующий пример, где у нас есть контент и изображение.

Меньше абсолютного позиционирования с современным CSS

<div class="hero"> <div class="hero__content"> <h2><!-- Title --></h2> <p><!-- Desc --></p> <a href="#">Order now</a> </div> <img src="recipe.jpg" alt="">
</div>

До сих пор ничего странного. На мобильных устройствах мы хотим добиться следующего макета.

Меньше абсолютного позиционирования с современным CSS

Обратите внимание, что изображение теперь вставлено между заголовком и описанием. Как можно решить эту проблему? Поначалу может показаться, что разметка HTML должна быть изменена именно так.

<div class="hero"> <div class="hero__content"> <h2><!-- Title --></h2> <img src="recipe.jpg" alt=""> <p><!-- Desc --></p> <a href="#">Order now</a> </div>
</div>

На мобильном телефоне все может работать как положено. На десктопе нам нужно расположить img с правой стороны. И хотя это работает, но есть более простое решение display:contents. Вернемся к исходной разметке.

<div class="hero"> <div class="hero__content"> <h2><!-- Title --></h2> <p><!-- Desc --></p> <a href="#">Order now</a> </div> <img src="recipe.jpg" alt="">
</div>

Обратите внимание, что содержимое завернуто внутрь .hero__content. Как мы можем сказать браузеру, что мы хотим, чтобы <h2>, <p> и <a> были наследниками того же родительского элемента, что и img? Что ж, с display:contents я могу это сделать:

.hero__content { display: contents;
}

Браузер проанализирует разметку следующим образом.

<div class="hero"> <h2><!-- Title --></h2> <p><!-- Desc --></p> <a href="#">Order now</a> <img src="recipe.jpg" alt="">
</div>

Все, что нам нужно сделать в CSS, это следующее.

.hero { display: flex; flex-direction: column;
} .hero__content { display: contents;
} .hero h2,
.hero img { order: -1;
}

При правильном использовании display:contents — это мощный метод для достижения того, что было невозможно несколько лет назад. Конечно, мы также хотим заняться стилем для десктопа.

@media (min-width: 750px) { .hero { flex-direction: row; } .hero__content { display: initial; } .hero h2, .hero img { order: initial; }
}

Демо

Изменение порядка элементов компонентов карты

Меньше абсолютного позиционирования с современным CSS

В этом примере у нас есть вариант карты, в которой заголовок помещается вверху карты. Давайте посмотрим на разметку HTML.

<article class="card"> <img src="thumb.jpg" alt=""> <div class="card__content"> <h3>Title</h3> <p>Description</p> <p>Actions</p> </div>
</article>

Обратите внимание, что у нас есть два прямых дочерних элемента: ползунок и содержимое. Как с такой разметкой мы можем расположить заголовок h3 вверху? Мы можем сделать это с помощью абсолютного позиционирования.

.card { position: relative; padding-top: 3rem; /* Accommodate for the title space */
} .card h3 { position: absolute; left: 1rem; top: 1rem;
}

Однако это решение может не сработать, если заголовок слишком длинный.

Меньше абсолютного позиционирования с современным CSS

Это происходит потому, что заголовок выходит за рамки обычного потока, поэтому браузер фактически не заботится о том, насколько он короткий или длинный. Мы можем найти гораздо лучшее решение используя display:contents:

.card { display: flex; flex-direction: column; padding: 1rem;
} .card__content { display: contents;
} .card h3 { order: -1;
}

Это позволит нам контролировать все дочерние элементы и иметь возможность записывать их по мере необходимости с помощью свойства order.

Меньше абсолютного позиционирования с современным CSS

У нас все еще есть небольшая проблема, так как мы добавили padding:1 rem родительскому элементу. Изображение должно быть приклеено к краям. Вот как мы можем это исправить:

.card img { width: calc(100% + 2rem); margin-left: -1rem;
}

Центрирование

Когда дело доходит до центрирования, вы увидите множество шуток о том, как это сложно. В наши дни центрировать элемент намного проще, чем когда-либо.

Больше не нужно использовать преобразования position:absolute. Например, мы можем использовать margin:auto для центрирования гибкого элемента как по горизонтали, так и по вертикали.

.card { display: flex;
} .card__image { margin: auto;
}

Меньше абсолютного позиционирования с современным CSS

Соотношение сторон изображения

Новое свойство CSS aspect-ratio теперь поддерживается во всех основных браузерах. Раньше мы использовали отступы, чтобы соблюдать определенное соотношение сторон.

.card__thumb { position: relative; padding-top: 75%;
} .card__thumb img { position: absolute; left: 0; top: 0; width: 100%; height: 100%; object-fit: cover;
}

С новым aspect-ratio это намного проще.

/* */
.card__thumb { position: relative; aspect-ratio: 4/3;
}

Иногда лучше использовать рosition:аbsolute

Меньше абсолютного позиционирования с современным CSS

В этом примере у нас есть контент (аватар, имя и ссылка), перекрывающий обложку карты. У нас есть два варианта реализации этого:

Использовать position:absolute для обложки карты

Использовать отрицательное поле для содержимого

Давайте рассмотрим решения и посмотрим, какое из них больше подходит для этого варианта использования.

Использование абсолютного позиционирования

Меньше абсолютного позиционирования с современным CSS

С помощью этого решения мы можем позиционировать прямоугольник абсолютно, а затем добавить padding:1rem к содержимому карты.

.card__cover { position: absolute; left: 0; top: 0; width: 100%; height: 50px;
} .card__content { padding: 1rem;
}

Таким образом, когда покрытие карты убирается, нам не нужно редактировать или изменять CSS.

Меньше абсолютного позиционирования с современным CSS

Использование отрицательных полей

В этом решении карта не будет позиционироваться абсолютно. Вместо этого контент будет иметь отрицательное поле сверху.

.card__content { padding: 1rem; margin-top: -1rem;
}

Хотя это решение работает при наличии покрытия карты, оно может вызвать проблемы, когда у нас есть вариант карты без покрытия.

Меньше абсолютного позиционирования с современным CSS

Обратите внимание, как аватар находится за пределами своего родителя (карты). Чтобы исправить это, нам нужно изменить CSS и удалить отрицательное поле.

.card--no-cover .card__content { margin-top: 0;
}

В результате — использование position:absolute оказалось лучшим решением, так как избавит нас от написания дополнительных CSS. Надеюсь, вам понравилась статья. Спасибо за чтение!

Автор: Ahmad Shadeed

Источник: ishadeed.com

Редакция: Команда webformyself.

Читайте нас в Telegram, VK, Яндекс.Дзен