Статьи

Адаптивные решения для сравнительных таблиц

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

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

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

Анатомия сравнительной таблицы характеристик

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

На основании этих примеров мы можем обобщить структуру таблицы сравнения с помощью следующего кода:

<table> <thead> <tr> <th>&nbsp;</th> <th>Product 1</th> <th>Product 2</th> <th>Product 3</th> </tr> </thead> <tbody> <tr> <td>Feature 1</td> <td>&#10004;</td> <td>&#10004;</td> <td>&#10004;</td> </tr> <tr> <td>Feature 2</td> <td>&mdash;</td> <td>&#10004;</td> <td>&#10004;</td> </tr> <tr> <td>Feature 3</td> <td>&mdash;</td> <td>&mdash;</td> <td>&#10004;</td> </tr> <tr> <td>Feature 4</td> <td>&mdash;</td> <td>&mdash;</td> <td>&#10004;</td> </tr> </tbody> </table> 

Легко определить элементы, упомянутые ранее: названия продуктов, названия функций и метки, которые показывают, присутствует ли функция или нет. Обратите внимание, что &#10004; Код представляет символ галочки (✔).

Теперь мы подошли к корню проблемы. Чтобы таблица сохраняла оптимальную эффективность при низкой ширине экрана, необходимо выполнить несколько условий:

  • Пользователь должен иметь возможность легко дифференцировать продукты;
  • Функции должны быть легко идентифицируемыми; и
  • Должно быть ясно, присутствует ли функция для продукта или нет.

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

Первое решение: Flexbox

Как мы можем добиться этого? Один ответ — flexbox. Если вы не знаете, что такое flexbox, или вам нужен освежитель, вы можете проверить недавнюю статью Ника Саллума на эту тему . Остальные из нас могут погрузиться в решение.

Сначала мы должны убедиться, что наши изменения происходят только на маленьких экранах. Чтобы это произошло, мы нацеливаем наш код, используя медиа-запрос, используя классическую ширину 768px в качестве точки останова:

 @media screen and (max-width: 768px) { tr { display: flex; flex-flow: row wrap; justify-content: space-around; } td, th { display: block; width: 33%; } th:first-child, td:first-child { text-align: center; background: #efefef; width: 100%; } th:first-child { display: none; } } 

В этом наборе правил есть несколько важных вещей:

  • Мы изменяем отображаемое значение для строки таблицы, чтобы flex и мы говорим ее дочерним элементам течь в строке, равномерно распределенной.
  • Затем мы указываем ячейкам принять display:block чтобы нормализовать их как обычные контейнеры (оставив значение по умолчанию, вы получите помехи от правил таблицы, особенно в отношении размера).
  • Следующий шаг нацеливается на первую ячейку в каждой строке, делая ее полной ширины и изменяя цвет фона, для дополнительного контраста. Правила потока позволяют ему оставаться на вершине трех других ячеек — именно то, что нам нужно.
  • Мы заканчиваем изменение, скрывая первое, чтобы над названиями продуктов ничего не отображалось.

Демо можно посмотреть здесь .

Очевидно, что решение действительно только до тех пор, пока оно имеет достаточную поддержку. Согласно caniuse.com , поддержка flexbox составляет более 80% для самых современных вариантов и более 93%, если мы включаем версии браузера, которые требуют префиксов, или используют предыдущие версии правил. Поддержка IE начинается с IE10 (только синтаксис 2012 года), в то время как IE11 имеет полную поддержку. Поскольку мы в основном заинтересованы в поддержке на небольших экранах, мы можем игнорировать отсутствие поддержки предыдущих версий IE. На мобильном фронте поддержка начинается с Android 4.4 и iOS 7.1. Предыдущие версии требуют префиксов поставщиков и не поддерживают функцию переноса.

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

Второе решение: дополнительная разметка + роли ARIA

Если большая часть браузеров, которые вы собираетесь поддерживать, не поддерживает flexbox, есть альтернатива. Фактически это решение, которое я использовал в реальном проекте в 2013 году. Нам понадобится дополнительная разметка: нам нужно будет добавить одну дополнительную строку, дублирующую имя функции. Хотя это может показаться утомительным, чтобы делать вручную, это может быть автоматизировано, если информация считывается из источника данных. В конце код из нашего исходного примера должен выглядеть так:

 <table> <thead> <tr> <th>&nbsp;</th> <th>Product 1</th> <th>Product 2</th> <th>Product 3</th> </tr> </thead> <tbody> <tr class="visible-xs" aria-hidden="true"> <td>&nbsp;</td> <td colspan="3">Feature 1</td> </tr> <tr> <td>Feature 1</td> <td>&#10004;</td> <td>&#10004;</td> <td>&#10004;</td> </tr> <tr class="visible-xs" aria-hidden="true"> <td>&nbsp;</td> <td colspan="3">Feature 2</td> </tr> <tr> <td>Feature 2</td> <td>&mdash;</td> <td>&#10004;</td> <td>&#10004;</td> </tr> <tr class="visible-xs" aria-hidden="true"> <td>&nbsp;</td> <td colspan="3">Feature 3</td> </tr> <tr> <td>Feature 3</td> <td>&mdash;</td> <td>&mdash;</td> <td>&#10004;</td> </tr> <tr class="visible-xs" aria-hidden="true"> <td>&nbsp;</td> <td colspan="3">Feature 4</td> </tr> <tr> <td>Feature 4</td> <td>&mdash;</td> <td>&mdash;</td> <td>&#10004;</td> </tr> </tbody> </table> 

CSS также довольно прост:

 .visible-xs { display: none; } @media screen and (max-width: 768px) { .visible-xs { display: table-row; } td:first-child, th:first-child { display: none; } } 

Мы можем сделать еще один шаг ради доступности и скрыть дополнительную разметку от программ чтения с экрана с помощью aria-hidden="true" . Таким образом, те приложения для чтения с экрана, которые соответствуют спецификации aria-hidden , не будут читать дублированный контент дважды.

Вот демонстрация этого второго решения .

Вывод

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