[Перевод] Интересные CSS-находки в новом дизайне Facebook

Я любопытен. Мне всегда интересно открывать инструменты разработчика браузера и разбираться с тем, как сделан какой-нибудь сайт, на который я заглянул. Этот материал представляет собой мой первый рассказ о таких вот изысканиях. Дело в том, что я обнаружил некоторые интересные примеры использования CSS (по крайней мере, они показались интересными мне), о которых мне захотелось рассказать.

s08uz59fvw7hbsgwyudyosarsks.jpeg

Речь идёт о CSS-находках в новом дизайне Facebook. Этот дизайн появился сравнительно недавно. Я его увидел пару недель назад. Сначала все элементы интерфейса казались мне необычно большими, но я привык к ним буквально за несколько дней. Здесь я расскажу обо всём том интересном, что я нашёл в дизайне Facebook.

Использование SVG-графики в аватарах


1ab74d26d61ffcf715843da59ba4e3d5.png


Аватары

SVG-графика используется для изображений-аватаров, таких, как фото профиля, фото на страницах пользователя или в группах.

Вот HTML-код:


  
    
  
  
    
    
  


Когда я это увидел, я задался вопросом о том, почему используется именно такой подход. У меня на этот вопрос есть несколько ответов:

  • У аватара должна быть внутренняя рамка, имеющая полупрозрачный чёрный цвет (10%). Это нужно для того чтобы светлые аватары выглядели бы как круглые изображения. Причём, даже в том случае, если это — полностью белые изображения.
  • К HTML-элементу нельзя добавить внутреннюю тень (box-shadow) с использованием ключевого слова inset. SVG используется для решения этой задачи.
  • Для того чтобы изображение имело бы круглую форму, используются SVG-элементы и .


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

4b09038a12e1bc902ecfc6e626a17edd.png


Аватары

Внутренняя рамка настроена с помощью следующего CSS-кода:

circle,
rect {
  stroke-width: 2;
  stroke: rgba(0, 0, 0, 0.1);
  fill: none;
}


Если изображение является квадратным — используется фигура rect:


  
    
  
  
    
    
  


Интересно то, что на главной странице ленты аватары созданы с использованием тега и элемента

, используемого для настройки внутренней полупрозрачной рамки:

    


Вот стили к этому HTML-коду:

.avatar-wrapper {
    position: relative;
}

.avatar {
    display: block;
    border-radius: 50%;
}

.avatar-outline {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
    border-radius: 50%;
}


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

связана с размером страницы. Если бы в аватарах из ленты использовалась бы SVG-графика, это привело бы к увеличению объёма данных, загружаемых при прокрутке ленты.

Использование в роли разделителей элементов
, а не внешних отступов


Я не застал тех времён, когда в качестве разделителей элементов веб-страниц использовались GIF-изображения. Но тут я увидел кое-что, напоминающее эту технику. Я так думаю, то, о чём я говорю, можно назвать div-разделителями.

9dd7ef4c5f7263fec4504ea5a9abdfc3.jpg


Элементы

, используемые в роли разделителей

Позвольте мне немного пояснить вышеприведённый рисунок. Это — фрагмент раздела, в котором находятся запросы на добавление в друзья, появляющиеся на домашней странице. Перед нами — некая сетка со сведениями о людях. У этой сетки должен быть левый внешний отступ. Я обычно добавляю к элементам подобные границы так: margin-left: 16px. Но в Facebook то же самое сделали, воспользовавшись элементом

, который отделяет сетку от края элемента-контейнера.

Зачем дизайнеры поступили именно так? У меня есть несколько догадок:

  • Возможно, в созданной ими дизайн-системе нельзя добавлять отступы для элементов-контейнеров?
  • Может быть, это React-компонент, который можно использовать где угодно, задавая его ширину?


Почему тут не используется внешний отступ? Как по мне, так CSS сайта (около 100 тысяч строк), который полон вспомогательных классов, способен вместить ещё один класс, позволяющий настроить отступ у нужного элемента.

Использование CSS-фильтров


904de063994e9cb617ada553335ae5f4.png


Иконки, созданные с помощью элементов и 

Взгляните на эти четыре иконки. Иконка со значком «плюс» и иконка со стрелкой созданы с использованием элемента . А иконки мессенджера и уведомления — с использованием SVG-элементов. Причины подобного смешения технологий мне неизвестны.

Если щёлкнуть по последней иконке, то стрелка будет перекрашена в синий цвет. «Как здесь меняется цвет, ведь стрелка — это обычное изображение?», — спросил я себя. Может, при наведении указателя мыши на иконку одно изображение просто меняется на другое? Нет, всё не так. Я выяснил, что для изменения цвета значка на иконке используется CSS-фильтр:

.icon {
    filter: invert(39%) sepia(57%) saturate(200%) saturate(200%) saturate(200%) saturate(200%) saturate(200%) saturate(147.75%) hue-rotate(202deg) brightness(97%) contrast(96%)
}


И это, кстати, продакшн-код facebook.com. Мне этот код кажется очень странным. Разве сложно заменить этот элемент на SVG-изображение и просто поменять цвет, задаваемый атрибутом fill?

То же самое используется и при создании значка для верифицированных аккаунтов.

3d47baa191084129cbf064157811cbaf.png


Значок верифицированного аккаунта

Нечто подобное применяется и для ссылок из профиля пользователя:

.icon {
    filter: invert(59%) sepia(11%) saturate(200%) saturate(135%) hue-rotate(176deg) brightness(96%) contrast(94%);
}


Вот как это выглядит

99310bd6e66b75d6479b4c5e85b004e3.png


Ссылки в профиле пользователя

Если вам интересно узнать о том, как с помощью CSS-фильтров окрасить в любой цвет изображение, выполненное чёрным цветом, — взгляните на этот ответ на Stack Overflow. Там же можно найти инструмент для создания CSS-фильтров. Кроме того — взгляните на этот твит.

Использование изображений для создания теней


9c0d4b50682e07f4a2133369308aea86.png


Тень, созданная с помощью background-image

У главного заголовка окна имеется тень. Можно предположить, что она создана с использованием CSS-свойства box-shadow. Но на самом деле это не так. Тут использован элемент

с фоновым изображением, которое повторяется по оси x.

Я загрузил использованное здесь изображение, что позволяет рассмотреть его поближе.

16b258c6a642ad505cda3dc82ea9535c.png


Изображение, используемое для создания тени

Это — изображение размером 2×14 пикселей, которое, для создания эффекта тени, многократно повторяется. В формировании эффекта тени участвует не только изображение, но и специальный элемент

. Почему тень была создана именно так?

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

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

Ну что же, если тень вызывает такие проблемы — не вижу ничего плохого в том, чтобы заменить её на соответствующее изображение.

Широкое использование CSS-переменных


Мне нравится то, что дизайнеры Facebook используют CSS-переменные. Судя по тому, что я видел, к элементу :root добавлено более 320 переменных. Эти переменные используются и в светлой, и в тёмной темах сайта.

Когда включена тёмная тема, к HTML-элементу добавляется класс __fb-dark-mode. Потом он переопределяет все переменные, объявленные в элементе :root:

:root {
    /* Переменные светлой темы */
    -fds-active-icon:  #3578E5;
    --fds-attachment-footer-background:  #F2F3F5;
    --fds-blue-05:  #ECF3FF;
    --fds-blue-30:  #AAC9FF;
    --fds-blue-40:  #77A7FF;
}

.__fb-dark-mode:root, .__fb-dark-mode {
    /* Переопределение переменных светлой темы */
    --fds-active-icon:  black;
    --fds-attachment-footer-background:  black;
    --fds-blue-05:  black;
    --fds-blue-30:  black;
    --fds-blue-40:  black;
}


Вот видео, в котором демонстрируется то, что происходит после переключения на тёмную тему. Советую смотреть его в полноэкранном режиме.

Использование CSS-свойства line-clamp для обрезки многострочного текста


49a83fd7436aee1ea3b0d8633896d84a.png


В подписях используется обрезка многострочного текста

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

.element {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
}


Это — встроенные стили, которые, кроме того, меняются в зависимости от браузера.

612b5a0b464ea8c0501588063246120e.png


Код обрезки текста в Chrome и Firefox

Эта возможность CSS пользуется довольно хорошей браузерной поддержкой. CanIUse сообщает о том, что это свойство поддерживают (хотя и с префиксом) все ведущие браузеры. Подробности об этом свойстве можно почитать здесь.

Использование div для создания элементов, реагирующих на наведение на них указателя мыши


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

.element:hover {
    background: #ccc;
}


Однако возникает такое ощущение, что на больших сайтах, вроде сайта Facebook, такой подход непрактичен. В процессе исследования сайта я обратил внимание на элемент, который выводится только при наведении на него указателя мыши (назовём его «hover-элемент»). В этом заключается его основная задача. Вот его стиль:

.hover-div {
    position: absolute;
    right: 0;
    left: 0;
    top: 0;
    bottom: 0;
    pointer-events: none;
    border-radius: 6px;
    inset: 4px 0px;
    background-color: var(--hover-overlay);
    transition-property: opacity;
    transition-timing-function: var(--fds-animation-fade-out);
    cursor: pointer;
}


Значение свойства opacity этого элемента меняется средствами JavaScript с 0 на 1. Я поэкспериментировал с ним и выяснил, что он используется для множества компонентов. Ниже приведён набор скриншотов, демонстрирующих использование этого элемента.

264a41ea7c736c09a1e41394385a5dfb.png


Использование hover-элемента

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

Использование свойства inset


Речь идёт о сокращённой записи значений свойства, подразумевающей воздействие на верхнюю, правую, нижнюю, и левую часть элемента. Пользоваться свойством inset можно так:

.element {
    inset: 4px 0;
    /* Это эквивалентно следующему: top: 4px, bottom: 4px, left: 0, right: 0 */
}


Свойство inset настраивается для вышеописанных hover-элементов, связанных с некоторыми другими элементами. Стиль встроен в HTML. Я заметил его применение к компоненту, показанному ниже.

769054ac517b986e82125881204b2006.png


Синим цветом выделены области, на которые воздействует свойство inset

Во время написания этого материала свойство inset поддерживает лишь Firefox 66+.

Атрибут dir=«auto» и логические CSS-свойства 


На многоязычных сайтах, вроде Facebook, иногда сложно спрогнозировать то, каким именно будет контент. Например, имя пользователя в некоем компоненте имеет атрибут dir=«auto». Это означает, что направление текста будет зависеть от языка. Скажем, при использовании английского языка текст будет выводиться слева направо, а при использовании арабского — справа налево.

Более того, надо отметить, что тут имеется встроенный стиль, который меняет направление текста (возникает такое ощущение, что атрибута dir=«auto» недостаточно). Вот как то выглядит:

محتوى بالعربية


Обратите внимание на то, что к элементу добавлен стиль text-align: start. Тут используется логическое CSS-свойство. Стиль, для LTR-макетов, будет выглядеть как text-align: right.

Если вас интересуют особенности RTL-стилизации — взгляните на этот мой материал.

Динамический фон, зависящий от главной фотографии


a836735adfbb4ecd4371426313b0c068.png


Фон, зависящий от главной фотографии

Вы обратили внимание на то, что для оформления фона используется градиент и цвет, похожий на цвет главной фотографии? Этот фон формируется динамически, он основан на цвете фотографии. Как это делается?

▍1. Получение доминантного цвета


Сначала нужно получить доминантный (используемый чаще других) цвет главного фото. После того, как этот цвет найден, создаётся уменьшенный вариант главной фотографии, закрашенный только этим цветом.

a25b2b2b59fc7a1b7a12c9cfbbb27795.png


Нахождение доминантного цвета

▍2. Добавление фона, использующего доминантный цвет


122094ec6de5136b61915ffe90d07141.png


Фон, использующий найденный доминантный цвет

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

▍3. Добавление градиента поверх фона


Для добавления градиента поверх фона используется такой CSS-код:

.element {
    background-image: linear-gradient(to top, #FFFFFF, rgb(255, 255, 255), rgba(255,255,255,0.7), rgba(255,255,255,0.4), rgba(255,255,255,0));
}


435a5790cd327ae5d2237b2b37a4d255.png


Добавление градиента (в дизайне используются светлые цвета)

В том случае, если в дизайне используются тёмные цвета, применяется обратный вариант градиента:

.element {
    background-image: linear-gradient(to top, #000, rgb(0, 0, 0), rgba(0,0,0,0.7), rgba(0,0,0,0.4), rgba(0,0,0,0));
}


f7e5b39b451f4457101a9091835320fe.png


Добавление градиента (в дизайне используются тёмные цвета)

Для нахождения доминантного цвета изображения можете воспользоваться этим инструментом.

Множественные тени


23c76d6943c930dc1ac70fa252fa87b7.png


Тени

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

5ca55020207e86410ccbec1dab3e89e5.jpg


Выпадающие меню

Вот CSS-код:

.element {
    box-shadow: 0 12px 28px 0 rgba(0, 0, 0, 0.2), 0 2px 4px 0 rgba(0, 0, 0, 0.1), inset 0 0 0 1px rgba(255, 255, 255, 0.5);
}


Тут у вас может возникнуть вопрос о том, зачем тут создаётся inset-тень белого цвета с прозрачностью в 50%? Дело в том, что это — тень для тёмного режима. Ниже показан увеличенный фрагмент интерфейса, в котором используется такая тень.

3fe72e31e49c2b9ee93509d07543184e.png


Увеличенный фрагмент интерфейса с inset-тенью

Мне нравится это разумное решение.

Пустые элементы для flexbox-сеток


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

64c92e292850d6313e10268b8732490d.png


Пустые элементы в сеточном макете

Вот CSS-код:

.wrapper {
    display: flex;
    flex-wrap: wrap;
    justify-items: space-between;
}

.item {
    width: 205px;
}


Выглядит всё это интересно, правда? Использование значения space-between при настройке размещения элементов — дело рискованное. Макет будет выглядеть неправильно в том случае, если, например, имеется всего три фотографии. Ниже показан пример такого макета.

856d64af475882a171ef4c67c349ae1a.png


Опасность использования space-between

Как команда Facebook справилась с этой проблемой? Очень просто: тут имеются четыре пустых элемента

, ширина которых равна ширине фото. Вот HTML-код этого решения:

    
    
    
    
    
    
    
    


При таком подходе подобные пустые элементы

играют роль искусственных элементов. Они помогают поддерживать одинаковое расстояние между элементами.

Использование вертикальных медиа-запросов


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

@media (min-height: 700px) {
    .element {
        width: 584px;
    }
}


Итоги


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

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

iqfib45pgphfrxv--zfemt0qnmw.jpeg

© Habrahabr.ru