Привет, Хабр!


Общаясь с коллегами, я заметил, что они незнакомы с последними возможностями CSS. Как обычно, у всех свои причины. У кого-то много повседневной рутины. Кому-то в принципе неинтересно, что нового происходит в CSS. А кто-то по привычке использует подходы десятилетней давности и ему норм.


Как фанату CSS, мне грустно. Сколько же прикольных вещей проходит мимо них. Да и их код может быть меньше, надёжнее и проще для понимания. В общем, я собрал несколько фрагментов кода, которые были популярны давным-давно, и переписал их с помощью новых возможностей CSS.


Давайте посмотрим, что я вам подготовил.


▍ Центрирование элемента с помощью свойства transform и значения translate(-50%, 50%)


Центрирование элементов всегда было камнем преткновения. Очень долго не было простого способа реализовать эту задачу. Даже на собеседованиях всегда спрашивали: «Как можно отцентрировать элемент со свойством position и значением absolute по двум осям?».


Потом появилось свойство transform, и все массово стали его использовать.


.parent {
  position: relative;
}

.parent::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

Расскажу, что тут происходит. Сначала происходит смещение элемента с помощью свойств top и left. Важно помнить, что браузеры перемещают верхний левый угол. В итоге мы получим, что он будет находиться по центру родительского элемента.


А нам нужно, чтобы в центре была середина элемента. Для этого надо сместить его в противоположную сторону на половину ширины и высоты. Тут и помогает свойство transform.


Если для него задать значение в процентах, то итоговое значение смещения браузеры будут вычислять относительно свойств width и height. В результате мы увидим, как элемент сместится в центр родительского элемента.


Сегодня уже можно сделать проще. Нам больше не надо смещать элементы с помощью свойств top и left, а следовательно, и свойства transform. Значение center для свойства place-items сразу сделает всю магию.


.parent {
  display: grid;
  place-items: center;
}

.parent::before {
  content: "";
  position: absolute;
}

Также не надо добавлять свойство position со значением relative. Поскольку свойств top и left больше нет.


▍ Стилизация элементов на основе селекторов + или ~


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


С требованиями жестить не будем. Пусть минимальная длина пароля должна быть минимум четыре символа.


<body>
  <!-- встроенная валидация отключена, потому что чаще всего её реализуют самостоятельно --> 
  <form class="form" novalidate>
    <!-- другие элементы -->
    <div class="field">
      <label class="field__label" for="password">Пароль</label>
      <input class="field__input" id="password" type="password" minlength="4" required>
      <span class="field__hint">Пароль должен быть больше 3 символов</span>
    </div>
    <!-- другие элементы -->
  </form>
</body>

Исчезновение подсказки будем реализовывать через свойство display. Будем его добавлять со значением none к элементу с классом .field__hint, если пользователь ввёл четыре и более символов.


В разметке нужный элемент находится после поля для ввода, значит, тут надо использовать селектор + или ~.


.field__input:valid + .field__hint {
  display: none;
}

Только этот способ всегда вызывал проблемы. Кто-то случайно поменял порядок элементов, и код отваливался. Сегодня это можно побороть, заменив этот подход на решение с использованием псевдо-класса :has.


.field:has(.field__input:valid) .field__hint {
  display: none;
}

Теперь наш код фиг сломаешь. Ему всё равно на то, как располагаются элементы в разметке. Больше не будет неожиданных ошибок!


▍ Объявление стека системных шрифтов


В комментариях под статьёй «Как фронтендеру сделать интерфейс дружелюбнее к пользователю. Коллекция HTML/CSS лайфхаков» я нашёл код с использованием ключевого слова system-ui, когда его поддержкой была неидеальной. Этот комментарий помог мне вспомнить, что раньше был подход использования системных шрифтов.


Суть заключалась в том, что указывались все семейства шрифтов, которые используются в операционных системах по умолчанию. Назвали такой подход «System Font Stack». Было несколько вариантов реализации.


/* реализация Github */
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}

/* реализация Medium */
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue",sans-serif;
}

Сегодня поддержка ключевого слова system-ui позволяет нам отказаться от этих фрагментов кода. Оно же само говорит браузерам использовать системный шрифт. Больше подсказки не нужны!


Нам осталось просто добавить его в качестве единственного значения для свойства font-family.


body {
  font-family: system-ui;
}

Такой код пишу я. Но если вы хотите, можно добавить вторым значением sans-serif. Вдруг вам покажется такой код ненадёжным.


▍ Установка размеров с помощью свойств width и height для элементов с position: absolute или position: fixed


Несколько недель назад я проверил, сможет ли ChatGPT заменить меня. Одной из задач было сверстать модальное окно. Далее покажу, какой код написал ChatGPT для его стилизации.


.modal {
  display: none; 
  width: 100%;
  height: 100%;

  position: fixed;
  top: 0;
  left: 0;
  z-index: 1000;

  justify-content: center;
  align-items: center;

  background-color: rgba(0, 0, 0, 0.5);
}

Обращу внимание на свойства top, left, width и height. Браузеры, обработав их, расположат элемент в левом верхнем углу, растянув на всё пространство по ширине и высоте.


Супер решение, которое я лично использовал десять лет. Но его можно сократить до одной строки. Задайте значение 0 для свойства inset.


.modal {
  display: none; 
  position: fixed;
  inset: 0;
  z-index: 1000;

  justify-content: center;
  align-items: center;

  background-color: rgba(0, 0, 0, 0.5);
}

Ещё раз скажу, что в первом решении нет проблем. Просто второе короче. Мне кажется, чем меньше кода, тем лучше.


А также вы можете использовать свойство inset для случаев, когда используется значение absolute.


.awesome-block { 
  position: absolute;
  inset: 0;
  background-color: rgba(0, 0, 0, 0.5);
}

▍ Объявление значения для свойств margin и padding вместе со значением 0


Проводя код-ревью, я всё ещё замечаю старый подход к объявлению свойств margin и padding. Если требуется установить значение только по одной оси, разработчики вынужденно используют значение 0.


.awesome-block {
  margin: 0 auto;
  padding: 1rem 0 2rem;
}

Уже не надо так делать. Есть логические CSS-свойства. Они позволяют установить отступ только по оси.


.awesome-block {
  margin-inline: auto;
  padding-block: 1rem 2rem;
}

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


Да, логические свойства зависят от основного направления текста, которое задаётся свойством writing-mode. Но ошибка может произойти, только если вы будете использовать значения vertical-lr или vertical-rl. А это вряд ли случится — если только вы делаете интерфейс для азиатской аудитории, например, японской.


Если же вы поддерживаете японский язык, то уже точно знаете, где могут быть проблемы. И скорее всего, используете логические свойства массово. В других случаях никто не поменяет направление текста так, чтобы были проблемы.


▍ Установка ширины блочного элемента с использованием свойства display


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


<body>
  <div class="awesome-block">
    <span>Блочный элемент с текстом</span>
  </div>
</body>

.awesome-block {
  padding: 0.5rem;
  background-color: lightblue;
  /* что ещё тут нужно дописать? */
}

В инструментах разработчика подсвечен элемент. Его ширина вычислена строго по вложенному тексту


Скорее всего, вы вспомните, что можно поменять значение свойства display на inline-block, inline-flex или inline-grid. И вы будете правы.


.awesome-block {
  padding: 0.5rem;
  background-color: lightblue;
  display: inline-grid;
}

Без вопросов, это проверенный временем способ. Но он не всегда сработает, потому что не всегда можно менять значение свойства display. Лучше использовать ключевое слово fit-content.


Я сразу перейду к нашему примеру и добавлю свойство width со значением fit-content для элемента с классом .awesome-block.


.awesome-block {
  padding: 0.5rem;
  background-color: lightblue;
  width: fit-content;
}

А главный плюс нового решения заключается в том, что элементы сохранят своё расположение. Например, в случае с блочными элементами они продолжат располагаться в столбец. В первом решении такого не было бы.


▍ Расположение элементов в столбец с помощью свойства flex-direction со значением column


Давайте решим простую задачу. Нам нужно расположить несколько элементов друг под другом и задать между ними отступ. А-ля блок с карточками новостей. Сразу скажу, что мы исключаем решение с блочными элементами и свойством margin для отступов.


Часто я встречаю, что разработчики используют свойство flex-direction и gap.


.container {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

У меня всегда в голове вопрос: «Зачем?». Можно же просто использовать значение grid для свойства display.


.container {
  display: grid;
  gap: 1rem;
}

Это вполне рабочий приём. Так что если вам нужно расположить два элемента в столбец с отступами, то имейте в виду это решение.


▍ Заключение


Вот и всё. Я постарался показать альтернативные подходы и их плюсы. Не знаю, получилось ли хорошо, но в любом случае надеюсь, что вы нашли что-то новое для себя и захотели это использовать в своём коде.


Обязательно напишите, что я упустил, написал не так и в чём не прав. Для этого есть комментарии. А я их читаю.


Спасибо за чтение!


P.S. Помогаю больше узнать про CSS в своём ТГ-канале CSS isn't magic. Присоединяйтесь. Ссылка в профиле.


© 2025 ООО «МТ ФИНАНС»

Telegram-канал со скидками, розыгрышами призов и новостями IT ?

Комментарии (18)


  1. pnmv
    17.06.2025 09:24

    когда вижу предложение заменить одно на другое, особенно если последнее менее конкретно, встает главный вопрос - что с производительностью?


    1. melnik909 Автор
      17.06.2025 09:24

      Сколь вижу комментариев под статьями о предложениях заменить одно на другое, всегда спрашивают про производительность. Зачем?

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


      1. pnmv
        17.06.2025 09:24

        я из другой области - пишу вам с делёкого бекенда. извините, если что.

        мне правда любопытно, но что-то там пытаться самому городить не хочется. лучше спросить у специалиста.


        1. melnik909 Автор
          17.06.2025 09:24

          Уточните, пожалуйста, про какой пример вы говорите?


          1. pnmv
            17.06.2025 09:24

            выберите, пожалуйста, наиболее интересный, по вашему мнению, вариант, из числа тех, где "было много, стало мало".


          1. Gary_Ihar
            17.06.2025 09:24

            давайте там где :has вместо +, если вы не против?


            1. melnik909 Автор
              17.06.2025 09:24

              Хорошо. Попробую из этого сделать статью


  1. alexzen
    17.06.2025 09:24

    Странные советы. Для центрирования display: flex намного удобнее и читаемость кода выше.


    1. melnik909 Автор
      17.06.2025 09:24

      Ни разу за 10 лет не встречал использование флексов для позиционирования элемента с position: absolute. Надо взять на вооружение!

      .parent {
        display: flex;
        justify-content: center;
        align-items: center;
      }
      
      .parent::before {
        content: "";
        position: absolute;
      }

      Вы этот способ имели ввиду?


      1. Spaceoddity
        17.06.2025 09:24

        А зачем тут вообще позиционирование? Как все модалки во всём вебе сейчас выглядят:

        .modal-bg{
        	position: fixed;
        	top: 0;
        	left: 0;
        	right: 0;
        	bottom: 0;
        	
        	display: flex;
        	justify-content: center;
        	align-items: center;
        
        	background: rgba(0, 0, 0, 0.4);
        
        	z-index: 1000;
        }
        .modal-bg__window{
        	width: 300px; /* 50%  40vw auto и т.п.*/
        }
        


        1. melnik909 Автор
          17.06.2025 09:24

          Мне показалось, что меня спрашивал не про модалку, а про первый пример. Я попытался пофантазировать, что автор комментария имеет ввиду.


  1. cp_poonam
    17.06.2025 09:24

    Really enjoyed this post! I still come across teams using older CSS methods like translate(-50%, -50%). This article is a great reminder of how far CSS has come. I’ll definitely be referencing this when updating our internal style guides. Appreciate the practical examples!


  1. sfi0zy
    17.06.2025 09:24

    Сегодня уже можно сделать проще. Нам больше не надо смещать элементы с помощью свойств top и left, а следовательно, и свойства transform. Значение center для свойства place-items сразу сделает всю магию.

    И заодно создаст побочный эффект в виде изменения логики расположения других элементов в контейнере. Главная фишка приема с transform на 50% взад состоит в том, что этот элемент ни на что не влияет. И двигать можно по мере необходимости, не только на 50%. Это очень удобно при верске "дизайнерской дичи" в рекламе. Вся визуальная фигня вокруг контейнеров с контентом просто существует в своем абсолютно позиционированном мире, и ее не нужно ничем подпирать. А place-items меняет логику для основного контента в контейнерах. Получается лишняя связь между вещами, которые не должны быть связаны. И гибкость решения страдает. Так что новый вариант хорош, но не всегда.


  1. Spaceoddity
    17.06.2025 09:24

    Блин, наверное, пройдусь по всём пунктам попозже. А пока ответ на основной тезис "Общаясь с коллегами, я заметил, что они незнакомы с последними возможностями CSS". Почему сразу незнакомы? Возможно просто стесняются юзать. Как я. Так уж исторически повелось - что у верстальщиков выработалась некоторая инерция в освоении новых фич. И не на пустом месте ;) Потому что перед юзанием каждой подобной фичи, надо сверяться c caniuse, или того хлеще - видеть приписку "*в настройках браузера надо проставить флаг...".

    P.S. Одна из немногих фич CSS, за которую я ухватился как только о ней узнал - display: contents - как же я её ждал))


    1. melnik909 Автор
      17.06.2025 09:24

      Возможно просто стесняются юзать. Как я. Так уж исторически повелось - что у верстальщиков выработалась некоторая инерция в освоении новых фич. И не на пустом месте ;)

      Мне кажется дело кроется в том, что вы не доверяете технологиям. Вы же сами об этом пишите. И вы не одиноки. Для многих CSS это черный магический ящик. Это тоже не на пустом месте случилось.

      Я пытаюсь, как-то помочь с этим справиться. Могу я немногое. Например, подсказывать куда смотреть. Это я пытаюсь делать


      1. Heggi
        17.06.2025 09:24

        До недавнего времени большинство "революционных" или просто "новых" фич (кавычки тут не зря) тупо не поддерживались большинством браузеров. Фича, которая есть хроме, не факт что есть в каком-нибудь IE или сафари. Особенно сильно с внедрением фич тормозил IE. И лучше использовать старые, проверенные способы и костыли с гарантией работоспособности, нежели идти и проверять новинки во всей куче браузеров.
        Сейчас с этим попроще, актуальных браузеров (движков) осталось 3 штуки и теперь главный тормоз на арене - сафари.


  1. Spaceoddity
    17.06.2025 09:24

    Стилизация элементов на основе селекторов + или ~

    Но суть техники о которой вы рассказываете, совсем в другом)) Это уже полноценный siblings. Тут логика переходит уже на совершенно иной уровень.

    Ну и как я говорил ранее - настолько крутые фичи пока что откровенно ссыкотно юзать)) Лучше перестраховаться))

    Да и потребность в + и ~ не исчезнет (особенно +).


    1. melnik909 Автор
      17.06.2025 09:24

      Где бы вы использовали + и ~?