Хочу в очередной раз рассказать о результатах исследования дизайна сайта, который привлёк моё внимание. В прошлый раз я писал о CSS-механизмах, лежащих в основе нового дизайна Facebook. А теперь мне стало любопытно исследовать CSS-код Twitter. Новый дизайн Twitter появился почти год назад. В CSS-коде Twitter я нашёл много интересного: кое-что кажется мне просто замечательным, а кое-что — странным.
Я обратил внимание на интересную реализацию аватара пользователя на странице профиля. В этой реализации используется CSS-техника сохранения соотношения сторон элемента.
Аватар пользователя на странице профиля
Ниже показан HTML- и CSS-код, иллюстрирующие реализацию аватара.
Техника сохранения соотношения сторон элемента работает благодаря тому, что, когда у элемента есть вертикальный внутренний отступ (свойство
Вычисленное значение
С аватаром что-то не так
Когда изображение не позиционировано абсолютно, аватар будет выглядеть так, как показано на предыдущем рисунке. Изображение должно быть позиционировано с использованием значения
Теперь, когда мы разобрались с идеей, лежащей в основе этого решения, вернёмся к тому, как эта идея реализована в Twitter.
Свойство
Мне очень нравится идея управления изображениями путём воздействия только на свойство
Управление шириной изображения
Здесь можно найти демонстрационный проект к этому разделу.
Для того чтобы аватар пользователя перекрывал бы фото, находящееся в верхней части страницы профиля, используется отрицательный внешний отступ, заданный в процентах:
Правда, в модальном окне Edit Profile для настройки верхнего внешнего отступа используется уже конструкция
Я обратил внимание на то, что для стилизации некоторых кнопок используется следующий CSS-код:
Зачем передавать функции
Слишком маленькая кнопка
Функция
Во многих местах сайта я обнаружил смешивание фоновых изображений, задаваемых средствами CSS, и HTML-изображений. Взгляните на следующий пример:
Я видел такое в профиле пользователя, и в компоненте, используемом при формировании сеточного макета. Интересно то, что свойство
Я попытался сделать всё наоборот, то есть — отобразить элемент
Слева — вариант, в котором используется фоновое изображение, а справа — вариант, в котором применяется HTML-изображение
Очевидно то, что изображение справа искажено! Не знаю, почему команда разработчиков не воспользовалась CSS-свойством
Я заметил один паттерн, который заключается в постоянном использовании CSS-класса, который добавляется к элементам
Этот стиль применяется буквально к каждому элементу
Некоторые из вышеописанных стилей мне вполне понятны, вроде
Значением по умолчанию свойства
Для того чтобы избежать возникновения этой проблемы, нужно сбрасывать свойство
Flex-элемент и Flexbox-обёртка
Макет, приведённый выше, показывает, что может произойти в том случае, если содержимое flex-элемента окажется слишком длинным. Обратите внимание на то, что текст выходит за пределы элемента-обёртки. А вот что получается при использовании свойства
Содержимое не выходит за пределы flex-элемента
Я заметил использование свойства
Когда страницу прокручивают вниз, свойство
Так же, как и в проанализированном мной ранее дизайне Facebook, в дизайне Twitter, во многих местах, используются элементы-разделители. Всё это — flex-элементы, ширина которых установлена с использованием свойства
Элементы-разделители
В первом элементе, приведённом на предыдущем изображении, при настройке элемента-разделителя используется свойство
Твит
Выше показан созданный мной твит. На первый взгляд может показаться, что перед нами — элемент
Оформление текста твита
Смайлик — это
Так как первое предложение обёрнуто в тег
Второе предложение
Кнопка Назад
При выполнении поиска в Twitter, или при открытии страницы профиля, можно видеть кнопку
Вышеприведённые вычисления приводят к получению значения
Навигационные ссылки
С первого дня, когда я столкнулся с панелью навигационных ссылок, я заметил, что, при наведении на них мыши, их ширина оказывается равной их содержимому. Я задался вопросом о том, почему бы не сделать так, чтобы значок и метка занимали бы всю ширину навигационного элемента.
Здесь моё внимание привлекло использование свойства
Отступ, о котором идёт речь, присутствует в дизайне для предотвращения нежелательного поведения макета страницы. Я обратил внимание на два примера использования внешних отступов, добавляемых к элементам, так сказать, «на всякий случай». Посмотрим на них.
Отступы, добавляемые к элементам «на всякий случай». Слева — обычное содержимое элемента. Справа — содержимое, которое заметно длиннее обычного
Обратите внимание на то, что происходит в том случае, когда содержимое элемента заметно длиннее, чем его обычное содержимое. А именно, тут происходит следующее:
Внешний отступ играет роль местозаполнителя, который не даёт элементу занять всё пространство. Если вовремя это учесть, можно избежать неожиданных проблем, которые могут возникнуть в процессе работы проекта. Рекомендуется всегда тестировать макеты страниц с использованием содержимого, длина которого превышает некую «обычную» длину.
Я исследовал модальное окно редактирования профиля. Оказалось, что при определённой высоте области просмотра кнопка
Недоступная кнопка Save
Так как модальное окно не поддерживает прокрутку, до кнопки
Окно, поддерживающее динамическое изменение высоты
Почему одно окно поддерживает скроллинг, а другое — нет? Интересно знать, какое из них, по мнению дизайнеров Twitter, важнее? Как по мне — так это именно то окно, которое используется для редактирования профиля.
А вы планируете ли вы взять на вооружение какие-нибудь идеи из дизайна Twitter?
Соотношение сторон аватаров пользователей
Я обратил внимание на интересную реализацию аватара пользователя на странице профиля. В этой реализации используется CSS-техника сохранения соотношения сторон элемента.
Аватар пользователя на странице профиля
Ниже показан HTML- и CSS-код, иллюстрирующие реализацию аватара.
<a href="#" class="avatar">
<div class="avatar-aspect-ratio"></div>
<img alt="" src="me.jpg">
</a>
.avatar {
position: relative;
width: 25%;
display: block;
}
.avatar-aspect-ratio {
width: 100%;
padding-bottom: 100%;
}
.avatar img {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 100%;
}
Техника сохранения соотношения сторон элемента работает благодаря тому, что, когда у элемента есть вертикальный внутренний отступ (свойство
padding-bottom
или padding-top
), отступ зависит от ширины элемента. Взгляните на следующий пример:.element {
width: 250px;
padding-bottom: 100%;
}
Вычисленное значение
padding-bottom
равняется 250px
. Это означает, что у нас имеется идеальный квадрат. Команда Twitter использовала такую же технику, но в применении к элементу <img>
, который, по отношению к родительскому элементу, позиционирован абсолютно. Почему? Вот причина.С аватаром что-то не так
Когда изображение не позиционировано абсолютно, аватар будет выглядеть так, как показано на предыдущем рисунке. Изображение должно быть позиционировано с использованием значения
100%
для ширины и высоты. При таком подходе его размер будет установлен в соответствии с размером элемента-обёртки.Теперь, когда мы разобрались с идеей, лежащей в основе этого решения, вернёмся к тому, как эта идея реализована в Twitter.
Свойство
width: 25%
основано на ширине элемента-обёртки. На моём экране это — 600px
. Я задался вопросом о том, почему была выбрана именно такая методика. После того, как я лучше изучил CSS-код, я обратил внимание на то, что тот же самый компонент используется в модальном окне Edit Profile. Правда, элемент тут имеет меньший размер из-за использования следующего стиля:.avatar {
max-width: 8rem; /* 112px вместо 150px (25%) */
}
Мне очень нравится идея управления изображениями путём воздействия только на свойство
width
. Вот видео, иллюстрирующее эту идею.Управление шириной изображения
Здесь можно найти демонстрационный проект к этому разделу.
Верхний внешний отступ, заданный в процентах
Для того чтобы аватар пользователя перекрывал бы фото, находящееся в верхней части страницы профиля, используется отрицательный внешний отступ, заданный в процентах:
.avatar {
margin-top: -18%;
}
Правда, в модальном окне Edit Profile для настройки верхнего внешнего отступа используется уже конструкция
margin-top: -3rem
. Обратите внимание на то, что отступ в модальном окне задаётся с использованием единиц измерения rem
. Те же единицы измерения применяются и для настройки свойства max-width
.Странное использование CSS-функции calc()
Я обратил внимание на то, что для стилизации некоторых кнопок используется следующий CSS-код:
.button {
min-width: calc(45.08px)
}
Зачем передавать функции
calc()
единственное значение? Не вижу в этом смысла. Может, число 45.08 хотели округлить? Но оно при таком подходе не округляется до 45. Ширина кнопки очень мала. Кнопка, при переводе приложения на RTL-язык, вроде арабского, окажется слишком маленькой.Слишком маленькая кнопка
Функция
calc()
появляется во встроенном CSS-коде. Поэтому я полагаю, что это — результат динамической стилизации кнопки средствами React.Смешивание CSS-фонов и HTML-изображений
Во многих местах сайта я обнаружил смешивание фоновых изображений, задаваемых средствами CSS, и HTML-изображений. Взгляните на следующий пример:
<div style="background-image: url(me.jpg);"></div>
<img alt="" src="me.jpg">
Я видел такое в профиле пользователя, и в компоненте, используемом при формировании сеточного макета. Интересно то, что свойство
opacity
элемента <img>
установлено в 0
. Источником активного изображения является свойство background-image
. Кроме того, тут используется и свойство background-size: cover
, которое позволяет избежать искажения изображения.Я попытался сделать всё наоборот, то есть — отобразить элемент
<img>
и скрыть CSS-фон, и сравнил сеточные макеты. Ниже показаны результаты этого сравнения. Слева — вариант, в котором используется фоновое изображение, а справа — вариант, в котором применяется HTML-изображение
Очевидно то, что изображение справа искажено! Не знаю, почему команда разработчиков не воспользовалась CSS-свойством
object-fit: cover
для предотвращения искажений. И мне хотелось бы узнать о том, почему тут используются два изображения.Сброс стилей
Я заметил один паттерн, который заключается в постоянном использовании CSS-класса, который добавляется к элементам
<div>
. Вот соответствующий CSS-код:.css-1dbjc4n {
align-items: stretch;
border: 0 solid black;
box-sizing: border-box;
display: flex;
flex-basis: auto;
flex-direction: column;
flex-shrink: 0;
margin-bottom: 0px;
margin-left: 0px;
margin-right: 0px;
margin-top: 0px;
min-height: 0px;
min-width: 0px;
padding-bottom: 0px;
padding-left: 0px;
padding-right: 0px;
padding-top: 0px;
position: relative;
z-index: 0;
}
Этот стиль применяется буквально к каждому элементу
<div>
, находящемуся на странице. Почему? Разве тут недостаточно сброса CSS-стилей?Некоторые из вышеописанных стилей мне вполне понятны, вроде
min-width: 0
, так как тут прослеживается некоторая связь с Flexbox. Но как насчёт внутренних отступов, внешних отступов, границ? Почему у некоего элемента <div>
надо сбрасывать стили, учитывая то, что у этого элемента нет соответствующих свойств?Flexbox и min-width: 0
Значением по умолчанию свойства
min-width
является auto
, которое оказывается равным нулю. Когда нечто выводится как flex-элемент, значение его свойства min-width
равно размеру его содержимого. Позволение подобного поведения может нарушить макет в том случае, если содержимое элемента больше, чем он сам.Для того чтобы избежать возникновения этой проблемы, нужно сбрасывать свойство
min-width
для потомков flex-элементов.Flex-элемент и Flexbox-обёртка
Макет, приведённый выше, показывает, что может произойти в том случае, если содержимое flex-элемента окажется слишком длинным. Обратите внимание на то, что текст выходит за пределы элемента-обёртки. А вот что получается при использовании свойства
min-width: 0
.Содержимое не выходит за пределы flex-элемента
Использование свойства position: sticky
Я заметил использование свойства
position: sticky
в правой боковой панели Twitter (там, где выводятся медиа-тренды и рекомендации, касающиеся пользователей, на которых можно подписаться). Мне показалось интересным то, как организована работа со значениями свойств bottom
и top
при скроллинге. Значения, установленные по умолчанию, выглядят так:.sidebar {
position: sticky;
width: 350px;
bottom: -470.5px;
}
Когда страницу прокручивают вниз, свойство
bottom
заменяется на свойство top: -480.5px
. Я думаю, что дизайнеры поступили так для того чтобы позволить пользователю сначала дойти до конца боковой панели. Свойство top
добавляется уже после этого.Элементы-разделители
Так же, как и в проанализированном мной ранее дизайне Facebook, в дизайне Twitter, во многих местах, используются элементы-разделители. Всё это — flex-элементы, ширина которых установлена с использованием свойства
flex-basis
.Элементы-разделители
В первом элементе, приведённом на предыдущем изображении, при настройке элемента-разделителя используется свойство
flex-grow: 1
. Во втором используется фиксированная ширина, заданная в пикселях.Оформление содержимого твитов
Твит
Выше показан созданный мной твит. На первый взгляд может показаться, что перед нами — элемент
<p>
или <span>
, в который добавлен текст. Но, как оказалось, каждый смайлик представлен отдельным тегом <span>
, а если текст находится между двумя такими элементами, он тоже оформляется в виде тега <span>
.Оформление текста твита
Смайлик — это
<span>
, в котором есть элемент <div>
, в <div>
содержатся два изображения. Одно — это CSS-фон, второе — HTML-изображение.Так как первое предложение обёрнуто в тег
<span>
, между ним и элементами одного с ним уровня должны быть разделители. Дизайнеры добавили переход на новую строку в начале второго предложения для того чтобы разделить предложения.Второе предложение
Использование вычисляемых значений для разделения элементов
Кнопка Назад
При выполнении поиска в Twitter, или при открытии страницы профиля, можно видеть кнопку
Назад
. К этой кнопке применён стиль margin-left: -4px
, задающий отрицательный внешний левый отступ. Меня заинтересовала процедура вычисления этого значения..back-button {
margin-left: calc(5px + (-1 * (39px - 1.5em)) / 2);
}
Вышеприведённые вычисления приводят к получению значения
-4px
. Почему бы не задать просто -4px
? Не лучше ли это в данном случае, чем применение функции calc()
?Ширина навигационных ссылок
Навигационные ссылки
С первого дня, когда я столкнулся с панелью навигационных ссылок, я заметил, что, при наведении на них мыши, их ширина оказывается равной их содержимому. Я задался вопросом о том, почему бы не сделать так, чтобы значок и метка занимали бы всю ширину навигационного элемента.
Здесь моё внимание привлекло использование свойства
flex-direction: column
для каждого элемента навигационной панели. Почему? Нужно ли это в ситуации, когда тут используется лишь один дочерний элемент?Внешний отступ, добавляемый «на всякий случай»
Отступ, о котором идёт речь, присутствует в дизайне для предотвращения нежелательного поведения макета страницы. Я обратил внимание на два примера использования внешних отступов, добавляемых к элементам, так сказать, «на всякий случай». Посмотрим на них.
Отступы, добавляемые к элементам «на всякий случай». Слева — обычное содержимое элемента. Справа — содержимое, которое заметно длиннее обычного
Обратите внимание на то, что происходит в том случае, когда содержимое элемента заметно длиннее, чем его обычное содержимое. А именно, тут происходит следующее:
- Текст обрезается.
- Между элементами присутствует внешний отступ.
Внешний отступ играет роль местозаполнителя, который не даёт элементу занять всё пространство. Если вовремя это учесть, можно избежать неожиданных проблем, которые могут возникнуть в процессе работы проекта. Рекомендуется всегда тестировать макеты страниц с использованием содержимого, длина которого превышает некую «обычную» длину.
Модальные окна в областях просмотра маленькой высоты
Я исследовал модальное окно редактирования профиля. Оказалось, что при определённой высоте области просмотра кнопка
Save
такого окна недоступна. Вот как это выглядит.Недоступная кнопка Save
Так как модальное окно не поддерживает прокрутку, до кнопки
Save
мне добраться не удалось. А вот окно, используемое для управления внешним видом элементов, поддерживает динамическое изменение высоты и скроллинг.Окно, поддерживающее динамическое изменение высоты
Почему одно окно поддерживает скроллинг, а другое — нет? Интересно знать, какое из них, по мнению дизайнеров Twitter, важнее? Как по мне — так это именно то окно, которое используется для редактирования профиля.
А вы планируете ли вы взять на вооружение какие-нибудь идеи из дизайна Twitter?
Get-Web
Тут вы упускаете, что em размер относительный поэтому и сам отступ в таком случае потенциально динамический.
У background-size: cover поддержка значительно выше тут и думать не о чем. Решение с невидимыми изображениями интересное, надо взять на заметку. Интересно как к этому поисковики относятся.
Эта древняя техника наверное появилась одновременно с padding, но встречается редко
Возможно там будет или было, какое-то вычисляемое значение из нескольких переменных, но сейчас компилится только одно так как не требует динамики.
Вот это смущает, поддержка ужасная, как по мне решения на js более стабильные, но наверно они что-то знают.
ХаХ. Только сейчас понял, что это перевод и отвечаю я не автору))) Но все равно спасибо, интересные наблюдения.
gorenburg
Get-Web
Может вы не заметили, но даже у Chrome, которым пользуется подавляющее большинство, поддержка частичная (~ Partial support). Полная поддержка с учетом префиксов только 26.22%. У вас не возникает диссонанса, когда применяется position: sticky в то время как отказываются от object-fit: cover у которого действительно есть поддержка?
homm
Я не заметил. Там же указано в каком имено случае не работает.
gorenburg
homm правильно указал. поддержка не 26.22%, а все 94.41%
а object-fit: cover не применяют скорее всего потому что руки еще не дошли выпилить весь говнокод и заменить на современные методы
Get-Web
Это новый дизайн и новая верстка, то есть они подумали и решили напишем-ка мы говнокод, а потом заменим на «современные методы»? Ок…