Визуализация данных посредством HTML и CSS
Wilson Miner, 10 апреля 2008
Даных в сети становиться больше и веб-разработчикам приходится все чаще сталкиваться с задачей их отображения. Вместе с тем растет и количество инструментов визуализации, хорошим примером может быть 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].

















gene 10 апреля, 2008 8:33 #
спасибо, как раз нужно было для сайта что-то подобно. инструмент от гугл просто потрясающий, правда не уверен, что большое количество данных будет удобно передавать.
только я не понял, здесь предлагается в html/css делать дизайн, а значения подставлять с помощью javascript? но ведь он может быть отключен (наверное сейчас это очень редко бывает, но все же), получается все же, что этот вариант не удачный, лучше формировать html уже с готовыми значениями.
SHAman 10 апреля, 2008 17:25 #
gene, почему же только JS? Данные можно передавать и с сервера. Здесь рассматривается верстка. А данные могут взяться хоть с сервера, хоть из воздуха:)
Автору спасибо, очень понравилось про спаркланйны (даже слова такого не знал). Делал модуль для Perl, для отображения гистограмм, писал статью у себя, но сейчас сайт недоступен:( Так бы дал ссылочку.
Сохранил в библиотечке рецептов:)
gene 10 апреля, 2008 22:50 #
SHAman, мне показалось, что автор предлагает использование js как один из вариантов, для установки значений длин столбцов.
Octane 11 апреля, 2008 20:24 #
Блин тока что прочел эту статью на английскам (((
хз, еслиб мне дали задачку средствами хтмл+ксс сделать подобное, наверное справился бы, как и любой другой верстальщик думаю... статья так пример для новичков...
yopopt 11 апреля, 2008 22:34 #
Хорошая статья, спасибо.
Шильгия 12 апреля, 2008 10:20 #
Спасибо. Тема интересная.
Но кто-нибудь может объяснить смысл использования вместо ?
Шильгия 12 апреля, 2008 10:21 #
извините, движок тэги вырезал.
я об использовании span class="label" вместо label.
Евгений 12 апреля, 2008 14:16 #
Шильгия, чтобы движок не вырезал теги, нижно использовать кнопку Код и предпросмотр на всякий случай.
Если я правильно понял, то вопрос такой: почему
<span class="label">а не<label>.Дело в том, что: The LABEL element is used to specify labels for controls that do not have implicit labels, то есть label предназначен для создания меток к контролам, в остальных случаях их использование не прибавит коду семантичности, скорее наоборот, хотя валидатор не против их использования в любом месте кода.
gene, автор предложил использовать js как один из вариантов, не более того, окончательное решение за разработчиком, к примеру, если график используется в приложении которое не работает без js, то можно использовать js и для графика, можно сделать график, обновляемый через ajax и тому подобное, главное чтобы решение было принято обдумано.
Octane, да пожалуй тут нет ничего революционного и многие справились бы самостоятельно, но как отметил SHAman — это просто готовый рецепт, можно взять и применить, сохранив свое время для чего нибудь другого. Ну и плюс сама идея хоть она и не новая, но ведь полезно не только создавать новую информацию, но и распространять, доносить до новичнов то, что уже придумано.
Vitaly 17 апреля, 2008 16:16 #
Спасибо! Интересная статья. Читаю вас постоянно. Все нравиться. Успехов.
Блог-шоу: выпуск 4 - Блог о продвижении сайтов и веб-дизайне 18 апреля, 2008 21:26 #
[...] html и css будет интересна статья на блоге DesignForMasters Визуализация данных посредством html и css. Получаются красивые графики и [...]
20 свежих интересных постов в Интернете за прошедшую неделю… « Блог Серёжи Борзова 3 мая, 2008 13:52 #
[...] Визуализация данных посредством HTML и CSS [...]