Данных в сети становится больше и веб-разработчикам приходится все чаще сталкиваться с задачей их отображения. Вместе с тем растет и количество инструментов визуализации, хорошим примером может быть Google Charts API, но и кроме него, есть большое количество сервисов и инструментов для создания диаграмм и графиков в виде изображений или Flash. Есть и великолепные техники, основанные на веб-стандартах, к примеру, CSS bar graphs Эрика Мейера, использующая семантические таблицы. Все эти методы хороши когда нужно показать данные на первом плане, и все, что вам нужно это диаграмма. Но, что если вы хотите тесно интегрировать визуализацию и навигацию на сайте, к примеру как на EveryBlock?

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

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

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

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

Горизонтальная гистограмма

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

Начнем с обычного неупорядоченного списка:

<ul class="chartlist">
  <li>
    <a href="http://www.example.com/fruits/apples/">Яблоки</a>
  </li>
  <li>
    <a href="http://www.example.com/fruits/bananas/"> »
    Бананы</a>
  </li>
  <li>
    <a href="http://www.example.com/fruits/cherries/"> »
    Вишня</a>
  </li>
  <li>
    <a href="http://www.example.com/fruits/dates/">Финики</a>
  </li>
</ul>

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

<ul class="chartlist">
  <li>
    <a href="http://www.example.com/fruits/apples/">Яблоки</a>
    <span class="count">420</span>
  </li>
  <li>
    <a href="http://www.example.com/fruits/bananas/"> »
    Бананы</a>
    <span class="count">280</span>
  </li>
  <li>
    <a href="http://www.example.com/fruits/cherries/"> »
    Вишня</a>
    <span class="count">200</span>
  </li>
  <li>
    <a href="http://www.example.com/fruits/dates/">Финики</a>
    <span class="count">100</span>
  </li>
</ul>

Создавая бары, мы должны задать элементам списка display: block, чтобы они заняли всю ширину, и position: relative, чтобы позиционировать бары относительно элемента списка.

.chartlist li {
  position: relative;
  display: block;
}

Для ускорения просмотра, с помощью абсолютного позиционирования, сместим количества вправо.

.chartlist .count {
  display: block;
  position: absolute;
  top: 0;
  right: 0;
  margin: 0 0.3em;
  text-align: right;
  color: #999;
  font-weight: bold;
  font-size: 0.875em;
}

Добавим отступ к ссылкам, чтобы текст ссылки не перекрывался с количеством, а чтобы ссылка всегда была перед баром, задаем z-index больше нуля, не забыв при этом указать position: relative, чтобы свойство z-index сработало.

.chartlist li a {
  display: block;   
  padding: 0.4em 4.5em 0.4em 0.5em;  
  position: relative;   
  z-index: 2; 
}

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

<ul class="chartlist">
  <li>
    <a href="http://www.example.com/fruits/apples/">Яблоки</a>
    <span class="count">420</span>
    <span class="index">(42%)</span>
  </li>
  <li>
    <a href="http://www.example.com/fruits/bananas/"> »
    Бананы</a>
    <span class="count">280</span>
    <span class="index">(28%)</span>
  </li>
  <li>
    <a href="http://www.example.com/fruits/cherries/"> »
    Вишня</a>
    <span class="count">200</span>
    <span class="index">(20%)</span>
  </li>
  <li>
    <a href="http://www.example.com/fruits/dates/">Финики</a>
    <span class="count">100</span>
    <span class="index">(10%)</span>
  </li>
</ul>

Замечание о данных

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

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

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

<ul class="chartlist">
  <li>
    <a href="http://www.example.com/fruits/apples/">Яблоки</a>
    <span class="count">420</span>
    <span class="index" style="width: 42%">(42%)</span>
  </li>
  <li>
    <a href="http://www.example.com/fruits/bananas/"> »
    Бананы</a>
    <span class="count">280</span>
    <span class="index" style="width: 28%">(28%)</span>
  </li>
  <li>
    <a href="http://www.example.com/fruits/cherries/"> »
    Вишня</a>
    <span class="count">200</span>
    <span class="index" style="width: 20%">(20%)</span>
  </li>
  <li>
    <a href="http://www.example.com/fruits/dates/">Финики</a>
    <span class="count">100</span>
    <span class="index" style="width: 10%">(10%)</span>
  </li>
</ul>

Последний штрих

Последнее, что нам нужно сделать в этом графике, это добавить стили для баров. При этом мы скрываем текстовые значения в процентах (с помощью text-indent как и в технике  image replacement Майка Рандла). Для нас важно не точное значение, а относительный размер, и бар прекрасно его отражает. Если нужно показать точный процент то для этого можно использовать как сами бары, так и отдельный элемент.

В стилях мы задаем высоту бара 100% и оставляем для width значение по умолчанию (0), чтобы бары не были видны пока точное значение width не указано. Цвет баров нужно подобрать так, чтобы они были достаточно заметны, при этом ссылки на их фоне должны остваться читабельными.

.chartlist .index {   
  display: block;   
  position: absolute;   
  top: 0;   
  left: 0;   
  height: 100%;   
  background: #B8E4F5;   
  text-indent: -9999px;   
  overflow: hidden; 
}

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

Гистограмма

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

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

<ul class="timeline">
  <li>
    <a href="http://www.example.com/2007/dec/1/" »
    title="1 Декабря, 2007: 40">
      <span class="label">1</span>
      <span class="count">(40)</span>
    </a>
  </li>
  <li>
    <a href="http://www.example.com/2007/dec/2/" »
    title="2 Декабря, 2007: 100">
      <span class="label">2</span>
      <span class="count">(100)</span>
    </a>
  </li>
</ul>

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

Под барами диаграммы зарезервируем место для меток:

.timeline {
  font-size: 0.75em;
  height: 10em;
}

.timeline li {
  height: 8em;
}

Теперь установим position: relative для элементов списка, чтобы потом использовать абсолютное позиционирование баров внутри них, float: left, чтобы они размещались один за другим по горизонтали, подберем размеры не забывая, что нам нужно место для метки и зададим границы по краям элемента, чтобы бары не сливались, при этом все размеры как и везде задаем в em.

.timeline li {   
  height: 8em;  
  position: relative;  
  float: left;  
  width: 1.5em;   
  margin: 0 0.1em;

}

Сделать бар и метку кликабельными можно установив для ссылки display: block и height: 100%, чтобы она заполнила пространство внутри элемента списка.

.timeline li a {    
  display: block;   
  height: 100%;  
}

Чтобы метки были кликабельными, мы разместили их внутри ссылки, теперь вынесем их под график с помощь абсолютного позиционирования, используя отрицательное значение для свойства bottom. Поскольку высота баров 8em, а всего графика 10em у нас остается 2em для размещения меток.

.timeline li .label {   
  display: block;   
  position: absolute;   
  bottom: -2em;   
  line-height: 2em;  
  left: 0;  
  width: 100%;  
  text-align: center;
}

Числа нам не нужны, поэтому скроем их с помощью text-indent и overflow. Осталось задать фон баров и разместить их подходящим образом внутри элементов списка с помощью абсолютного позиционирования.

.timeline li a .count {   
  display: block;   
  position: absolute;
  bottom: 0;
  left: 0;
  text-indent: -9999px;   
  overflow: hidden;
  width: 100%;
  height: 0;  
  background: #AAA;
}

Если в этом графике сделать,  чтобы каждый бар показывал процент от общей суммы, то из-за большого количества баров они получатся маленькими, поэтому мы пойдем другим путем, высоту самого большого бара примем за 100%, а размеры остальных будем вычислять относительно него. В окончательном примере гистограммы добавлен эффект подсветки при наведении мышки, чтобы пользователь четко видел на какой элемент графика он кликает.

Спарклайн

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

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

<span class="sparkline">
  <span class="index"><span class="count">(60, </span></span>
  <span class="index"><span class="count">220, </span></span>
  <span class="index"><span class="count">140, </span></span>
  <span class="index"><span class="count">80, </span></span>
  <span class="index"><span class="count">110, </span></span>
  <span class="index"><span class="count">90, </span></span>
  <span class="index"><span class="count">180, </span></span>
  <span class="index"><span class="count">140, </span></span>
  <span class="index"><span class="count">120, </span></span>
  <span class="index"><span class="count">160, </span></span>
  <span class="index"><span class="count">175, </span></span>
  <span class="index"><span class="count">225, </span></span>
  <span class="index"><span class="count">175, </span></span>
  <span class="index"><span class="count">125)</span></span>
</span>

Предполагается, что спарклайн можно размещать прямо в тексте, но пока не будет хорошей поддержки display: inline-block, придется ограничиться обычным float.

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

.sparkline {
  float: left;
  height: 1em;
  margin: 0 0.5em;
}

В этот раз бары содержит элемент span.index поэтому задаем для него position: relative и float:left, а ширину, равную ширине будущих баров 2px.

Примечание: Ширину баров автор почему-то указывает в px, мне кажется, стоит как и везде использовать em, масштабируемость спарклайнам не повредит.

.sparkline .index {
  position: relative;
  float: left;
  width: 2px;
  height: 1em;
}

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

.sparkline .index .count {
  display: block;
  position: absolute;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 0;
  background: #AAA;
  overflow: hidden;
  text-indent: -9999px;
}

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

Не стоит недооценивать возможности этой техники

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

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

Translated with the permission of A List Apart Magazine and the author[s].