Заметки веб-работника
26 февраля 2007

Таблицы с вертикальным направлением текста

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

Таблица с вертикальным направлением текста

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

Задача: Дана таблица

<table class="example">
   <tr>
      <td colspan="3">Сроки наблюдения, сут</td>
      <td>3</td>
      <td>6</td>
      <td>9</td>
      <td>12</td>
   </tr>
   <tr>
      <td rowspan="12" class="vertical">Содержание основных клеточных элементов, %</td>
      <td rowspan="3" class="vertical">Нейтрофилы</td>
      <td>Хлоргексидин</td>
      <td>49.3</td>
      <td>31.5</td>
      <td>23.5</td>
      <td>24.5</td>
   </tr>
   <tr>
      <td>Левосин</td>
      <td>43.4</td>
      <td>25.3</td>
      <td>19.5</td>
      <td>19.4</td>
   </tr>
   <tr>
      <td>Левосин + прополис</td>
      <td>32.5</td>
      <td>22.3</td>
      <td>16.2</td>
      <td>13.4</td>
   </tr>
   <tr>
      <td rowspan="3" class="vertical">Макрофаги</td>
      <td>Хлоргексидин</td>
      <td>1.0</td>
      <td>1.4</td>
      <td>18.9</td>
      <td>29.5</td>
   </tr>
   <tr>
      <td>Левосин</td>
      <td>2.1</td>
      <td>1.3</td>
      <td>17.4</td>
      <td>32.1</td>
   </tr>
   <tr>
      <td>Левосин + прополис</td>
      <td>4.1</td>
      <td>3.8</td>
      <td>27.5</td>
      <td>29.5</td>
   </tr>
   <tr>
      <td rowspan="3" class="vertical">Лимфоциты</td>
      <td>Хлоргексидин</td>
      <td>1.1</td>
      <td>3.5</td>
      <td>1.1</td>
      <td>1.9</td>
   </tr>
   <tr>
      <td>Левосин</td>
      <td>1.9</td>
      <td>2.9</td>
      <td>3.2</td>
      <td>3.8</td>
   </tr>
   <tr>
      <td>Левосин + прополис</td>
      <td>6.6</td>
      <td>2.7</td>
      <td>2.1</td>
      <td>2.7</td>
   </tr>
   <tr>
      <td rowspan="3" class="vertical">Фибробласты</td>
      <td>Хлоргексидин</td>
      <td>1.0</td>
      <td>1.0</td>
      <td>11.5</td>
      <td>28.1</td>
   </tr>
   <tr>
      <td>Левосин</td>
      <td>1.8</td>
      <td>2.3</td>
      <td>15.2</td>
      <td>25.2</td>
   </tr>
   <tr>
      <td>Левосин + прополис</td>
      <td>4.1</td>
      <td>3.9</td>
      <td>23,4</td>
      <td>25.9</td>
   </tr>
</table>
необходимо, чтобы текст в ячейках с классом vertical при отображении в браузере имел вертикальное направление «снизу-вверх».

CSS-решение существует лишь для Internet Explorer. Только этот «неправильный» браузер, начиная с версии 5.5, частично поддерживает предусмотренное в CSS3 для этих целей свойство writing-mode. Содержится у IE на вооружении и пропиетарное layout-flow, однако ни с помощью первого, ни при помощи второго свойства мне так и не удалось задать тексту нужное направление «снизу-вверх». Пришлось дополнительно использовать фильтры flipH и flipV для горизонтального и вертикального поворота текста. Окончательно приходим к следующему описанию класса vertical:

td.vertical{
   writing-mode:tb-rl;
   filter:flipH flipV;
   background:#fff; /* для устранения бага с отображением текста в IE6 и ниже */
   …
}

Задав указанные стили, текст в Internet Explorer отобразится в нужном направлении.

В поисках же универсального решения в первую очередь на ум приходит очевидная идея: заменить текстовое содержимое на идентичное графическое, но повернутое на 90 градусов. Для примера, текст «Hello World!» может быть заменен на что-нибудь вроде <img src="?text=Hello+World%21">, или «Содержимое основных клеточных элементов» – на <img src="?text= %D1%EE%E4%E5%F0%E6%E8%EC%EE%E5+%EE%F1%ED%EE%E2%ED%FB%F5 +%EA%EB%E5%F2%EE%F7%ED%FB%F5+%FD%EB%E5%EC%E5%ED%F2%EE%E2">. Основная нагрузка по генерации такого псевдо-текста в этом случае ляжет на серверную часть, а значит можно говорить о кроссбраузерности.

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

В этом случае, наша задача фактически сводится к созданию SVG-разметки, которой мы заменим текст в нужных нам ячейках. Включить SVG-изображение в HTML-документ можно так:

<object type="image/svg+xml" data="filename.svg" width="100" height="100"></object>
, либо так
<object type="image/svg+xml" data="data:image/svg+xml;<svg xmlns='http://www.w3.org/2000/svg'>…(SVG-разметка)…</svg>" width="100" height="100"></object>
Ниже, пример JavaScript-кода, содержащего подходящую SVG-разметку и выполняеющего необходимую замену (функцию GetVerticalLayout() необходимо привязать к событию onload страницы):

function GetVerticalLayout()
{
   /* Параметры */
   var fontFamily = "Arial"; /* задаем шрифт */
   var fontSize = 12; /* задаем размер шрифта */
      
   var notIE = !(navigator.appVersion.indexOf("MSIE") != -1 && navigator.systemLanguage);
   var supportSVG = document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1");

   if (notIE && supportSVG)
   {
      /* Собираем все ячейки */
      var td = document.getElementsByTagName("td");
      
      /* Находим ячейки с классом vertical и заменяем в них текст svg-изображением */
      var objElement = document.createElement("object");
      
      for(i = 0; i < td.length; i++)
      {
         if (td[i].className.match(/vertical/i))
         {
            var text = td[i].innerHTML;
            var h = td[i].clientHeight;
            var w = td[i].clientWidth;
            
            var obj = objElement.cloneNode(true);
            obj.height = (h > w) ? h : w;
            obj.type = "image/svg+xml";
            obj.width = fontSize + 2;
            obj.data = "data:image/svg+xml;charset/windows-1251,<svg xmlns='http://www.w3.org/2000/svg'><text x='" + (- obj.height/2) + "' y='" + fontSize + "' style='font-family:" + fontFamily + "; font-size:" + fontSize + "px; text-anchor:middle' transform='rotate(-90)'>" + text + "</text></svg>";
            td[i].replaceChild(obj, td[i].firstChild);
         }
      }
   }
}

Если браузер поддерживает SVG, то в соответствующих ячейках текст отобразится должным образом. Так происходило в Opera 9 и в Gecko, начиная с версии 1.8. В Internet Explorer замену не производим, так как для этого веб-проводника существует упомянутое выше простое решение, кроме того, для отображения SVG в IE нужны внешние плагины, которые, скорее всего, не будут установлены у пользователя.

Рабочий пример можно посмотреть здесь.


Теги: JavaScript SVG

 

Комментарии (9)

_______

Вы можете оставить свой отзыв по данной статье:

  Имя
  E-mail (не публикуется)
  Веб-сайт

Комментарий (Теги форматирования не поддерживаются)