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


Сегодня мы рассмотрим:

  • почему декоративные элементы, сделанные с помощью чистого CSS могут не отобразиться в режиме повышенной контрастности Windows;
  • чем можно заменить объявления свойства height со значением auto для изображений;
  • какой есть нюанс при установке максимальной ширины у группы элементов;
  • плавную прокрутку без неприятных ситуаций для пользователя;
  • чего не хватает при использовании фоновых изображений.

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


▍ Свойство border не позволяет пропасть линиям


Мне нравится реализовывать декоративные элементы только с помощью CSS. Чаще всего приходится делать прямолинейную линию. Например, дизайнеры любят её добавлять к заголовкам.


Раздел проекты. Перед заголовком есть сиреневая линия.

Кажется, нет ничего сложного в реализации. Свойства width, height и background-color сделают всю работу.


.heading {
  position: relative;
}

.heading::before {
  content: "";
  width: 5rem;
  height: 2px;
  background-color: #b87eef;

  position: absolute;
  left: 0;
  bottom: 1rem;   
}

Данный способ я взял с реального сайта. Внешне проблем нет. Но они есть. Кто меня читает постоянно, тот уже догадался. Включим режим повышенной контрастности Windows.


Раздел проекты. Линия не отображается перед заголовком

Линии не видно. Браузеры в данном режиме насильно добавляют значение для свойства background-color. Оно берётся из настроек операционной системы из пункта «Фон».


Окно с настройками операционной системы. Можно задать цвет фона, текста, ссылки, неактивного текста, выделенного текста, текста у кнопки. Я выбрал задать цвет фона. Отображается элемент для выбора цвета. В поле уже выбран цвет 202020

В итоге получается, что у всех элементов со свойством background-color значение будет одинаковым. По этой причине линия становится незаметной.


Можно, конечно, не париться и оставить пользователей без неё. Правда, этот подход мне не близок. Я стараюсь не ломать задумку дизайнера, если это возможно. Тем более, что в этом случае сделать линию просто. Достаточно использовать свойство border.


Есть два варианта. Первый — само свойство border. Только есть нюанс. Поскольку свойство устанавливает границу со всех сторон, то нам нужно изначальную высоту линии в 2px разделить пополам. И уже полученное значение использовать.


Другой вариант — установить границу только с одной стороны. Для этого использовать либо свойство border-top, либо — border-bottom.


Мне лень делать какие-то вычисления. Хочется сделать просто. По этой причине возьму вариант со свойством border-top. Им заменю свойства height и background-color.


.heading {
  position: relative;
}

.heading::before {
  content: "";
  width: 5rem;
  border-top: 2px solid #b87eef;

  position: absolute;
  left: 0;
  bottom: 1rem;   
}

Линия стала белой и отображается перед заголовком

Линия на месте. Задумка дизайнера сохранилась. Надеюсь, теперь при создании линий вы сохраните их для режима повышенной контрастности Windows.


▍ Да хватит уже переопределять высоту изображений


Прыжки контента — самое раздражительное явление для меня. Знаете, начинаешь читать текст, а он упрыгивает. У данного явления даже есть умное название «Cumulative Layout Shift».


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


По этой причине многие известные разработчики советуют добавлять атрибуты width и height для элемента <img>. Так браузеры узнают размеры области, где им нужно отрисовать изображение.


<body>
  <img src="eiffel-tower.webp" width="600" height="337" alt="Эйфелева башня. Вид с реки Сены">
</body>

В этом способе обязательно нужно сбросить установленное ранее значение у свойства height.


img {
  max-width: 100%;
  height: auto;
}

Я этой рекомендации не следую. Мне кажется странным сначала что-то устанавливать, а потом сбрасывать. Я любитель только устанавливать.


Мой любимый способ — это свойство aspect-ratio. Я даже стал его добавлять по умолчанию ко всем изображениям.


img {
  display: var(--ds-typography-img-display, block);
  max-width: var(--ds-typography-img-max-width, 100%);
  aspect-ratio: var(--ds-typography-img-aspect-ratio);
}

В каждом проекте я устанавливаю нужное мне значение.


img:not([class]) {
  --ds-typography-img-aspect-ratio: 1.78;
}

В моём решении атрибут height больше использовать не нужно.


<body>
  <img src="eiffel-tower.webp" width="600" alt="Эйфелева башня. Вид с реки Сены">
</body>

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


Давайте вернёмся к изначальному способу и посмотрим в инструменты разработчика.


Отображается правило с селектором по атрибуту. В нем добавлено свойство aspect-ratio. Значение auto 600 / 337

Браузеры сами устанавливают свойство aspect-ratio, если установлены атрибуты width и height. Получается, я придумал то, что уже было сделано. Надо было только посмотреть в инструменты разработчика.


▍ К какому элементу надо устанавливать максимальную ширину блока


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


Для примера возьмём блок с приветствием на сайте разработчика.


Заголовок, краткий рассказ о себе и кнопка для связи

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


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


Для демонстрации заменю текст заголовка «Стас Мельников» на «Ростислав Михальниченко».


Заголовок стал шире, чем краткий текст с рассказом о себе

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


Работая над макетом, дизайнер сразу показывает, какой блок занимает максимальную ширину. Правильным решением будет взять ширину такого блока и добавить её к родительскому блоку. В нашем случае к блоку, где находится заголовок, текст с рассказом о себе и кнопка «Связаться с нами».


Заголовок отображается в две строки. На первой Ростислав, на второй Михальниченко. Он уже, чем блок с кратким рассказом о себе

Подводя итог, сформулирую правило. Максимальную ширину нужно устанавливать родительскому элементу. Значение нужно брать по максимально широкому дочернему элементу.


При таком варианте текст в нашей вёрстке всегда будет сохранять ту ширину, какая есть в макете. Так мы соблюдём все требования.


▍ Сниппет для создания плавной прокрутки без проблем для пользователя


Я постоянно замечаю образовательный контент, в котором авторы используют свойство scroll-behavior. Они используют его для элемента <html> для добавления плавной прокрутки на странице.


html {
  scroll-behavior: smooth;
}

Это очень опасная штука. Существуют пользователи, у которых движение объектов вызывает тошноту, головокружение и головную боль. Если он воспользуется плавной прокруткой, то такой сайт запомнится ему надолго.


По этой причине существует медиафункция prefers-reduced-motion. Она помогает браузерам определить, выключил ли пользователь анимацию движения в настройках операционной системы. Если он это сделал, то медиафункция поможет браузерам не показывать её.


В итоге если используется плавная прокрутка, то свойство scroll-behavior нужно обвернуть медиафункцией prefers-reduced-motion.


@media (prefers-reduced-motion: no-preference) {

  html {
    scroll-behavior: smooth;
  }
}

Отдельно хочу предупредить. Если объекты двигаются, плавают, уменьшаются, увеличиваются и так далее, анимацию нужно также обвернуть медиафункцией.


▍ Свойство background-color не даёт тексту и кнопке спрятаться


Выбирал я однажды себе квартиру на сайте застройщика. У него были классные фотографии. Знаете такие, чтобы вызвать желание купить. Только их я видел после десятка секунд матюгов. Конечно, после этого всё желание купить квартиру пропадало напрочь.


Моя боль — я не умею читать белый текст и идентифицировать белые элементы на белом фоне страницы. Не смог я прокачаться в этих навыках. Поэтому приходится ожидать загрузку изображений для начала взаимодействия с интерфейсом.


Правда есть и плюс. Эта ситуация зародила в моей голове памятку. Она звучит так: «Если есть фоновое изображение, всегда делай контрастный к тексту фон». По этой причине в моём коде всегда рядом со свойством background-image, есть свойство background-color.


.my-awesome-screen {
  background-image: image-set(
    url("eiffel-tower-1x.webp") type("image/webp") 1x,
    url("eiffel-tower-2x.webp") type("image/webp") 2x
  );
  background-color: #919191;
}

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


▍ Заключение


Давайте подведём итог. В этой статье мы рассмотрели:

  • технику создания декоративных элементов с помощью свойства border;
  • свойство aspect-ratio, позволяющее не переопределять высоту изображений;
  • что надо устанавливать максимальную ширину для родительского элемента, а не для самого широкого элемента в макете;
  • создание плавной прокрутки без неприятных ситуаций для пользователя;
  • в чём польза свойства background-color при использовании фоновых изображений.

Оставлю ссылки на все выпуски:

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


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


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


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

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


  1. sfi0zy
    10.09.2024 09:46
    +3

    Указание атрибутов высоты и ширины для картинки в html - это решение, которое легко интегрируется и может работать на стороне сервера для каждой картинки. Сегодня у вас 337 пикселей по высоте, завтра 376, потом 334. Вариант хардкодить aspect-ratio в штатном CSS моментально теряет индивидуальный подход. Старый вариант прост и надежен. Новый же зависит от тех, кто будет заполнять сайт контентом, и может сломаться на ровном месте.


    1. melnik909 Автор
      10.09.2024 09:46

      Сегодня у вас 337 пикселей по высоте, завтра 376, потом 334. Вариант хардкодить aspect-ratio в штатном CSS моментально теряет индивидуальный подход.

      Иван, почему вы говорите "хардодить"? Через пользовательские свойства можно все изменить. Поясните, пожалуйста


      1. sfi0zy
        10.09.2024 09:46

        Т.е. вы предлагаете на стороне сервера задавать CSS custom properties в inline-стилях? Это, конечно, интересный подход, но он выглядит сложным для восприятия. Прелесть пикселей в том, что они никак не зависят от технологий и контекстов и при этом надежно решают изначальную задачу. А custom properties создаст зависимости между штуками на клиенте и сервере, которые вообще ничего про друг друга знать не должны. Магия CSS красива до тех пор, пока она не завязана на сервер.


        1. melnik909 Автор
          10.09.2024 09:46

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


          1. sfi0zy
            10.09.2024 09:46
            +1

            почему вы использовали слово "хардкодить". Ответьте, пожалуйста

            Вот это:

            img:not([class]) {
                --ds-typography-img-aspect-ratio: 1.78;
            }
            

            чистой воды хардкод.Посмотрите на картинки прям здесь, на хабре. Даже в вашей статье они все разных пропорций. Жестко заданное 1.78 тут не прокатит. Эту property можно переписать на сервере под каждое изображение индивидуально, но получим то, что описано выше.


            1. melnik909 Автор
              10.09.2024 09:46

              Спасибо. Теперь я понял. По моей практике изображения специально подготавливают. В этом случае проблем я лично не вижу. Может вы видите?

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


  1. Spaceoddity
    10.09.2024 09:46

    Не, ну рекомендация инлайновых стилей в 2024 - это, конечно, за гранью уже...

    Я, конечно, понимаю ваш восторг по поводу новых css-свойств, но привязываться к соотношению сторон и фигачить разметку в структуру кода - какой-то просто-напросто вредный совет!

    Ну есть же object‑fit...

    Вообще тема с размерами элементов настолько необъятная... Там столько подводных камней... Целый цикл статей нужен только по одной этой теме!


    1. melnik909 Автор
      10.09.2024 09:46

      Я, конечно, понимаю ваш восторг по поводу новых css-свойств, но привязываться к соотношению сторон и фигачить разметку в структуру кода

      Эту мысль совсем не понял. Поясните, пожалуйста, что вы имеете ввиду?


      1. Spaceoddity
        10.09.2024 09:46
        +1

        Что именно вам не понятно в этой фразе?

        Привязываться к соотношению сторон - некорректно. Потому что при одном разрешении картинка, например, может иметь квадратную форму, а при другом - прямоугольную.

        Вот как это понимать - В каждом проекте я устанавливаю нужное мне значение... --ds-typography-img-aspect-ratio: 1.78?

        У вас в проекте все изображения с одинаковым соотношением сторон? Серьёзно?

        Ну а про инлайновые стили вам уже выше объяснили.


        1. melnik909 Автор
          10.09.2024 09:46
          +1

          Мне не понятна эта фраза "фигачить разметку в структуру кода". Поясните?

          Вот как это понимать - В каждом проекте я устанавливаю нужное мне значение...  --ds-typography-img-aspect-ratio: 1.78?

          Как пример того, как задаются значение для свойств. Если вам не понравился мой пример, то он из моего проекта. Так я задаю стили для изображений, у которых нет атрибута class.

          У вас в проекте все изображения с одинаковым соотношением сторон? Серьёзно?

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

          Вы конкретнее сформулируйте свой вопрос. Я отвечу.

          P.S. Отдельно хочу поблагодарить вас за чтение моих статей. Вы ни одной не пропускаете. Мне приятно. Спасибо


          1. Spaceoddity
            10.09.2024 09:46

            Мне не понятна эта фраза "фигачить разметку в структуру кода". Поясните?

            Ну инлайновые стили же.

            P.S. Отдельно хочу поблагодарить вас за чтение моих статей. Вы ни одной не пропускаете. Мне приятно. Спасибо

            Немножко сарказмом пахнуло)) Ну да ладно, возможно мне показалось. А что тут удивительного? Я на тех же материях специализируюсь - разумеется у меня в ленте будут ваши статьи. Как минимум, чтобы не пропустить что-то новое/вкусное. К сожалению, статьи по вёрстке на Хабре в последнее время очень редки - вы вроде единственный кто с завидным постоянством что-то пишет по этой теме. Так что это вам респект! ;) Да, кое с чем я бываю не согласен (ну у меня свой "верстальный бэкграунд"), но кое-что и я бывает схороню))


            1. melnik909 Автор
              10.09.2024 09:46

              Ну инлайновые стили же.

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

              Немножко сарказмом пахнуло)) Ну да ладно, возможно мне показалось.

              Никакого сарказма. Вам показалось. На Хабре есть несколько человек, включая вас, постоянно читающих и комментирующих. Я ценю это.

              Так что это вам респект! ;) Да, кое с чем я бываю не согласен (ну у меня свой "верстальный бэкграунд"), но кое-что и я бывает схороню))

              Спасибо. Как раз для этого я занимаюсь контентом.


    1. ionicman
      10.09.2024 09:46
      +1

      Не, ну рекомендация инлайновых стилей в 2024 - это, конечно, за гранью уже...

      Конечно! Лучше все тащить в стили, даже если это единоразово для какого-то фикса и короче class="something", и да - обязательно SASS. Про производительность и progressive enhancement тоже надо забыть в 2024, да? ))) Любители догм.

      И хоть я и не оборяю aspect-ratio для этого тоже, object-fit, если что, вообще не про указывание высоты - так, на всякий.


      1. Spaceoddity
        10.09.2024 09:46

        Что это вас так порвало?))

        Да, лучше! Это всё обсосано было ещё лет 20 назад. И причём здесь SASS вообще? Есть такое понятие - семантика. Любители всего нового. Вот и имеем кадавров а-ля CSS-in-JS...

        И на всякий случай вам - aspect-ratio, если что, вообще не про указывание высоты ;)


        1. ionicman
          10.09.2024 09:46

          Что это вас так порвало

          Не надо мне ваше состояние приписывать)

          Про SASS был сарказм, спасибо что не поняли)

          Что такое семантика, вы, судя по тому что пишите - не знаете.

          aspect-ratio, если что, вообще не про указывание высоты

          Ага, но я отвечал про ваш object-fit, а не на автора)


          1. Spaceoddity
            10.09.2024 09:46

            Про SASS был сарказм, спасибо что не поняли)

            Вообще не понял. Тут то адепты препроцессоров, то лютые противники встречаются. Я не слепая мёртвая болгарская бабка.

            Что такое семантика, вы, судя по тому что пишите - не знаете.

            Аналогично;) Но судя по вашей "аргументации" в стиле "сам дурак" - даже распинаться не имеет смысла. Зашёл в тред, нагадил в комментах, перешёл на личности и слился)) В игнор!

            Кстати, пишЕте - это не просто орфографическая ошибка. Это как раз семантическая ошибка))

            Ага, но я отвечал про ваш object-fit, а не на автора)

            Ага, только я-то отвечал не вам. Учить он меня вёрстке будет)))