Створюємо адаптивну зведену таблицю

35

Від автора: не так давно твіт Smashing Magazine привернув увагу до моєї статті по створенню елегантною таблиці з допомогою OpenType. Спасибі, Smashing Magazine. Один коментатор справедливо зауважив, що таблиця була неадаптівной: при звуженні вікна браузера дані відсівалися. Я не міг змінити таблицю, як в попередніх прикладах: порядок і напрямок даних в ній важливі і не повинні обрізатися. Проте є інше рішення.

В Microsoft Excel та інших табличних додатках є функція під назвою «зведені таблиці», яка змінює рядки і стовпці місцями. Подібний ефект можна реалізувати на веб-сторінках за допомогою JavaScript для таблиць певного виду. Наприклад, для таблиці зверху.

Починаємо з розмітки

Макет таблиці схожа на таблицю з прикладу з OpenType, тільки тут додаються id й клас (необов’язкові закриваючі теги були видалені для спрощення коду).

2014 Greenhouse gas emissions, per country

China

USA

EU

India

Russia

CO2 (mt)

10,540

5,334

3,415

2,341

1,766

Emission per capita (t)

7.6

16.5

6.7

1.8

12.4

CSS теж дуже схожий. Я написав цей приклад на Sass:

table {
margin: 2rem auto;
font-size: 1.6 rem;
border-collapse: collapse;
@all media and (max-width: 636px) {
font-size: 1.4 rem;
}
@all media and (max-width: 522px) {
font-size: 1.2 rem;
}
table td {
text-align: right;
padding: .5rem;
width: 5rem;
}
table thead th {
border-bottom: 1px solid #777;
font-weight: 400;
}
table tbody th {
font-weight: 400;
text-align: right;
padding-right: 1rem;
}
table caption {
font-weight: 600;
margin-bottom: 1rem;
}
table tbody td {
color: #444;
}

Поворот рядків і стовпців

Поточна структура таблиці записана в JS в змінну fulltable. Без JS таблиця буде відображатися, але не буде повертатися.

var fullTable = document.querySelector(«.large»).innerHTML,
caption = gg.getElementsByTagName(«caption»),
ggHead = gg.querySelector(«thead tr»),
ggBody = gg.querySelector(«tbody»),
ggColHeaders = ggHead.querySelectorAll(«th»),
ggDataHeaders = ggBody.querySelectorAll(«tr th»),
ggDataRows = ggBody.querySelectorAll(«tr»),
matchPoint = window.matchMedia(«(max-width: 600px)»),
slimTable;

У всіх змінних зберігається частина таблиці.

function pivotTable() {
if (matchPoint.matches && gg.matches(«.large»)) {
if (typeof slimTable === ‘undefined’) {
ggHead.innerHTML = «

 

«;
for (var i = 0; i < ggDataHeaders.length; i++) {
var scoped = ggDataHeaders;
scoped.scope = «col»;
ggHead.appendChild(scoped);
}
var totalCols = ggDataRows[0].getElementsByTagName(«td»).length;
ggBody.innerHTML = «»;
for (var j = 0; j < totalCols; j++) {
var newRow = document.createElement(«tr»);
var newRowHeader = document.createElement(«th»);
newRowHeader.scope = «row»;
newRowHeader.innerHTML = ggColHeaders[j].innerText;
newRow.appendChild(newRowHeader);
for (var k = 0; k < ggDataRows.length; k++) {
var currentRowData = ggDataRows[k].getElementsByTagName(«td»);
var newCell = document.createElement(«td»);
newCell.innerHTML = currentRowData[j].innerText;
newRow.appendChild(newCell);
}
ggBody.appendChild(newRow);
}
} else {
gg.innerHTML = slimTable;
}
gg.classList.remove(«великий»);
gg.classList.add(«small»);
slimTable = document.querySelector(«.small»).innerHTML;
}
if (gg.matches(«.small») && !matchPoint.matches) {
console.log(«Upsize»);
gg.innerHTML = fullTable;
gg.classList.remove(«small»);
gg.classList.add(«великий»);
}
}

Функція pivotTable змінює рядка і колонки місцями. Клітинки заголовків, які були ліворуч, переміщуються вгору. Чисто семантично (і з точки зору перспективи) нічого не змінюється, змінюється тільки вигляд.

Після перевороту таблиці клас змінюється з large на small. Перевернута версія структури таблиці записується в змінну slimTable, щоб таблиця ще раз не перекинулася при зміні розміру вьюпорта.

Функція pivotTable запускається після завантаження сторінки:

pivotTable();

Нам не потрібно перевіряти виклик функції pivotTable щоразу при зміні розміру вьюпорта (це сильно вдарить по продуктивності), тому я примусово знизив час повторного запуску до 200 мілісекунд при спрацьовуванні події resize:

window.addEventListener. («resize», throttle( pivotTable, 200 ));

Уповільнення робиться через функцію:

function throttle (callback, limit) {
var wait = false;
return function () {
if (!wait) {
callback.call();
wait = true;
setTimeout(function () {
wait = false;
}, limit);
}
}
}

Висновок

Техніка не підходить для всіх таблиць у яких занадто багато стовпців і рядків), але може стати в нагоді для таблиць, як у нашому прикладі.