Статьи

Плитки SitePoint: пример использования компонентов, тематики и Flexbox

Плитка SitePoint

Примечание редактора: домашняя страница SitePoint была перезапущена вскоре после публикации этой статьи. Прости Хьюго!

Я уже давно пишу для SitePoint, и я всегда находил их фрагменты статей довольно привлекательными с точки зрения дизайна. Они предоставляют всю необходимую информацию о статьях: название, автор, дата, категория и даже метрики сообщества (количество комментариев и лайков).

Я подумал, что такая плитка, вероятно, является интересным компонентом для построения, как с точки зрения HTML, так и с точки зрения CSS. В этой статье мы создадим этот компонент шаг за шагом, стараясь сделать его как можно лучше: доступным, поддерживаемым, поддерживаемым и оптимизированным для SEO.

Начиная с контента

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

 

Оттуда мы можем начать оборачивать наш контент HTML. Весь контейнер будет элементом <article> так как для него это правильный вариант использования. Внутри него у нас будет контейнер для верхней части, контейнер для заголовка (хотя это не совсем обязательно) и нижний колонтитул для метаданных.

 <article class="c-article-tile"> <div class="c-article-tile__header"> HTML & CSS 8 comments </div> <div class="c-article-tile__body"> A Tale of CSS and Sass Precision </div> <footer class="c-article-tile__footer"> by Hugo Giraudel May 12, 2016 </footer> </article> 

Примечание: мы используем соглашение BEM со вкусом для именования классов с пространствами имен ; не стесняйтесь использовать все, что вы предпочитаете.

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

 <article class="c-article-tile"> <!-- Tile header --> <div class="c-article-tile__header"> <a class="c-article-tile__category" href="https://www.sitepoint.com/html-css/"> HTML & CSS </a> <a class="c-article-tile__comment-count" href="https://www.sitepoint.com/a-tale-of-css-and-sass-precision/#comments"> 8 comments </a> </div> <!-- Tile body --> <div class="c-article-tile__body"> <h2 class="c-article-tile__title"> <a href="https://www.sitepoint.com/a-tale-of-css-and-sass-precision/"> A Tale of CSS and Sass Precision </a> </h2> </div> <!-- Tile footer --> <footer class="c-article-tile__footer"> <span class="c-article-tile__author"> by <a href="https://www.sitepoint.com/author/hgiraudel/"> Hugo Giraudel </a> </span> <time class="c-article-tile__date" datetime="2016-05-12T12:00"> May 12, 2016 </time> </footer> </article> 

Это выглядит хорошо! Несколько интересных вещей для заметки:

  • Мы не используем элемент <header> для верхней части, поскольку заголовок обычно содержит заголовок, что здесь не так.
  • Мы используем элементы <span> а не элементы <p> как здесь ничто не является абзацем контента.
  • Мы используем правильный элемент <time> и его атрибут datetime а не <span> для описания даты.

Давайте теперь заменим слово «комментарии» соответствующим доступным значком. Мы не будем слишком углубляться в объяснения, не стесняйтесь читать Рабочий рабочий SVG для доступных значков, чтобы узнать больше об этом методе.

 <svg style="display: none"> <symbol id="icon-bubble" viewBox="0 0 32 32"> <path class="path1" d="M16 2c8.837 0 16 5.82 16 13s-7.163 13-16 13c-0.849 0-1.682-0.054-2.495-0.158-3.437 3.437-7.539 4.053-11.505 4.144v-0.841c2.142-1.049 4-2.961 4-5.145 0-0.305-0.024-0.604-0.068-0.897-3.619-2.383-5.932-6.024-5.932-10.103 0-7.18 7.163-13 16-13z"></path> </symbol> </svg> <!-- … --> <a class="c-article-tile__comment-count" href="https://www.sitepoint.com/a-tale-of-css-and-sass-precision/#comments"> 8 <svg class="icon icon-bubble" aria-label="comments"> <use xlink:href="#icon-bubble"></use> </svg> </a> 

Обратите внимание, как мы используем атрибут aria-label чтобы сделать значок доступным для пользователей вспомогательных технологий.

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

 <article class="c-article-tile" itemscope itemtype="http://schema.org/Article"> <!-- Tile header --> <div class="c-article-tile__header"> <a class="c-article-tile__category" href="https://www.sitepoint.com/html-css/" itemprop="keywords"> HTML & CSS </a> <a class="cc-article-tile__comment-count" href="https://www.sitepoint.com/a-tale-of-css-and-sass-precision/#comments" itemprop="commentCount"> 8 <svg class="icon icon-bubble" aria-label="comments"> <use xlink:href="#icon-bubble"></use> </svg> </a> </div> <!-- Tile body --> <div class="c-article-tile__body"> <h2 class="c-article-tile__title" itemprop="headline"> <a href="https://www.sitepoint.com/a-tale-of-css-and-sass-precision/"> A Tale of CSS and Sass Precision </a> </h2> </div> <!-- Tile footer --> <footer class="c-article-tile__footer"> <span class="c-article-tile__author"> by <a href="https://www.sitepoint.com/author/hgiraudel/" itemprop="author"> Hugo Giraudel </a> </span> <time class="c-article-tile__date" datetime="2016-05-12T12:00" itemprop="datePublished"> May 12, 2016 </time> </footer> </article> 

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

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

Вот как это может выглядеть:

 <ul class="c-tile-list"> <li class="c-tile-list__item"> <article class="c-article-tile"></article> </li> <li class="c-tile-list__item"> <article class="c-article-tile"></article> </li> <li class="c-tile-list__item"> <article class="c-article-tile"></article> </li> </ul> 

На этом этапе мы полностью закончили с разметкой. Это чистый, доступный и SEO-дружественный; не намного больше мы можем сделать. Пришло время стилизовать это!

Применение некоторых стилей

Для части CSS мы будем предполагать правильную блочную модель для всех элементов . Мы также будем сильно полагаться на flexbox, потому что, почему бы и нет?

Компонент списка контейнеров

Наш компонент списка очень тонкий, поэтому там не так много стиля. Он должен обеспечить сетчатый макет для плиток, обработать расстояние между плитками и убедиться, что все плитки на одной линии имеют одинаковую высоту. Это не должно быть слишком сложно благодаря flexbox.

 /** * 1. Reset default list styles * 2. Flexbox used for a grid-like layout for the tiles. */ .c-tile-list { list-style: none; /* 1 */ margin: 0; /* 1 */ padding: 0; /* 1 */ display: flex; /* 2 */ flex-wrap: wrap; /* 2 */ } 

А теперь список пунктов:

 /** * 1. Flexbox used for equal-height tiles on a same line. * 2. Make sure a time never looks distorded. * 3. Spacing between tiles. */ .c-tile-list__item { display: flex; /* 1 */ flex-direction: column; /* 1 */ flex: 0 0 300px; /* 2 */ margin: 10px; /* 3 */ } 

Компонент плитки статьи

Давайте перейдем к настоящему зверю: компоненту статьи. Есть много элементов для стиля, начиная с самой плитки.

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

 /** * 1. Make it possible to bottom align the footer in a tile that has a minimum * height. * 2. Make sure the tile spread across the full height of the parent if inside * a flex container. */ .c-article-tile { display: flex; /* 1 */ flex-direction: column; /* 1 */ flex: 1 0 auto; /* 2 */ border: 1px solid rgba(0, 0, 0, 0.1); background-color: rgb(255, 255, 255); } 

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

 .c-article-tile__header, .c-article-tile__body, .c-article-tile__footer { display: flex; padding-left: 20px; padding-right: 20px; } 

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

 .c-article-tile__header, .c-article-tile__footer { font-size: 80%; } 

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

 /** * 1. Rely on the `color` property for the border color by not setting any color * value, making it super convenient for theming. */ .c-article-tile__header { padding-top: 15px; padding-bottom: 10px; border-bottom: 2px solid; /* 1 */ } 

Направление по умолчанию для гибкого контейнера - это row , поэтому мы явно не указали его для наших субконтейнеров. Чтобы выровнять количество комментариев справа от заголовка, есть 2 решения. Первым решением было бы установить justify-content: space-between в заголовке для размещения наших элементов. Другое решение, которое мы будем использовать, - это установить margin-left: auto на счетчике, полагаясь на лучший секрет flexbox .

 /** * 1. Right align the comment count container in the header. */ .c-article-tile__comment-count { margin-left: auto; /* 1 */ } 

Заголовок теперь работает как положено. Мы можем перейти к телу и названию статьи. Тело просто нуждается в небольшом интервале по вертикали, а плитке нужны некоторые типографские стили.

 .c-article-tile__body { padding-top: 20px; padding-bottom: 20px; } .c-article-tile__title { margin: 0; color: #333; font-size: 150%; } 

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

Во-вторых, это всегда должно быть в одной строке. К счастью, мы можем форсировать это поведение с помощью white-space: nowrap . Однако мы не контролируем длину имени автора, поэтому нам нужно убедиться, что макет не сломается, если имя слишком длинное. Я хорошо осознаю, что «усечение не является страной содержания…», но в этом случае я думаю, что это меньшее из двух зол.

 /** * 1. Bottom align the footer in the tile. * 2. Prevent any content from the footer from wrapping, effectively forcing it * on a single line at all time. */ .c-article-tile__footer { padding-top: 10px; padding-bottom: 15px; margin-top: auto; /* 1 */ white-space: nowrap; /* 2 */ color: #949494; } /** * 1. Prevent the author and the date from overlapping in case they both don't * fit on the line; add an ellipsis to the author name. * 2. Visually no effect when both the author and the date fit; however make * sure they are slightly spaced from each other if they meet on the line. */ .c-article-tile__author { text-overflow: ellipsis; /* 1 */ overflow: hidden; /* 1 */ margin-right: 5px; /* 2 */ } /** * 1. Right align the date container in the footer. */ .c-article-tile__date { margin-left: auto; /* 1 */ } 

Вот и все для макета плитки! У нас есть еще одна вещь, которую нужно завершить, прежде чем мы закончим.

Правильная тематика

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

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

 <article class="c-article-tile t-sass" itemscope itemtype="http://schema.org/Article"></article> 

Оттуда мы можем применить некоторые стили к нашей плитке на основе этого класса. Мы применяем определенный цвет к плитке и всем ее ссылкам. Это будет эффективно влиять на цвет границы из заголовка, но не на текст #949494 колонтитула, который уже имеет определенный цвет ( #949494 ).

 .c-article-tile.t-sass, .c-article-tile.t-sass a { color: #c69; } 

Все в порядке, но заголовок, который становится розовым, когда должен быть черным, только становится розовым, когда завис или активен. Решение состоит в том, чтобы заставить ссылку наследовать цвет своего родителя ( #333 ), когда последний не находится или не активен. Для этого мы можем разумно использовать псевдокласс :not() :

 /** * 1. Make the title link inherit the color only when not active / hovered, * effectively making it themed when active / hovered. */ .c-article-tile__title:not(:hover):not(:active) > a { color: inherit; /* 1 */ } 

Завершение дела

Это оно! Фу, это был долгий путь, но я надеюсь, тебе понравилось. Мне кажется, что этот небольшой пример - идеальный кандидат для правильной инкапсуляции компонентов, управления темами и игры с flexbox. Не стесняйтесь попробовать, и если вы найдете способ сделать это еще лучше, обязательно поделитесь!