Адаптивные таблицы для адаптивных сайтов

Ильдар Сарибжанов | 15.03.2017

Вступление

Верстка адаптивных макетов для нас в Sawtech и для меня в частности давно не является проблемой. Сложности возникают с конечными (по слогам КО-НЕЧ-НЫ-МИ, не перепутайте порядок букв) пользователями.

Вот дизайнеры нарисовали крутой макет, я его круто сверстал (ага-ага, а ещё я очень скромный) — всё очень очень круто выглядит, а потом вся эта красота разбивается о железобетонную действительность. А именно, заказчик берет и в текст новости добавляет таблицу: «Так информация лучше структурирована». С этим доводом сложно спорить. Это проблема и её нужно решать.

Варианты решения

Я вижу пока 2 основных варианта решения.

Вариант № 1. Озадачим пользователей

Создаем в админке сложную структуру полей: одно поле — одна ячейка, а может и что-то сложнее, выбор за тобой. В эти поля  администратор, контент-менеджер или просто пользователь будет добавлять данные, а мы уже при выводе со своей стороны обрабатываем эти поля и выводим в блочной версии.

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

Вариант №2. Творите что хотите или кнопка «сделать красиво»

Тут есть 2 концептуальных направления.

Путь наименьшего сопротивления. Обернуть таблицу в div-блок, который будет автоматически добавлять полосу прокрутки, если таблица уже не помещается в ширину родителя. Много где видел такую реализацию. Вполне жизнеспособно, требует минимальных вложений со стороны разработки. Если решать задачу на уровне php, то регуляркой или еще как-то ищем по тексту таблицу и оборачиваем её в div. Только может быть сложность в работе с DOM или regexp отработает не совсем так как хочется. А можно исполнить решение на js, лично мне кажется, это вообще простым вариантом. Но об это чуть ниже сначала про концепции.

Второй концептуальный путь — пересобрать таблицу на div’ах. На выходе потребуется больше навыков от верстальщика, придется в стилях определить поведение блоков на разных разрешениях — адаптивность как она есть. Так же решается как на php, так и на js. Я пойду путем jquery.

Ой, всё! Я знаю, что jquery фу-фу-фу, но мне так проще, не хочешь не пользуйся.

Программируем

Хочу в одном плагине реализовать оба подхода, чтобы было.

Допустим имеем такую структуру

<div class="main-content">
	
	<h3>Обернутая таблица</h3>
	<table class="js-add-wrap">
		<tr>
			<th>Заголовок таблица 2, колонка 1</th>
			<th>Заголовок таблица 2, колонка 2</th>
			<th>Заголовок таблица 2, колонка 3</th>
			<th>Заголовок таблица 2, колонка 4</th>
		</tr>
		<tr>
			<td>А тут может быть очень длинный текст, например машиностроительный</td>
			<td>Строка 1, запись 2</td>
			<td>Строка 1, запись 3</td>
			<td>Строка 1, запись 4</td>
		</tr>
		<tr>
			<td>Строка 2, запись 1</td>
			<td>Строка 2, запись 2</td>
			<td>Строка 2, запись 3</td>
			<td>Строка 2, запись 4</td>
		</tr>
	</table>
	
	<br />
	<br />
	
	<h3>Преобразованная таблица</h3>
	<table class="js-convert-table">
		<tr>
			<th>Заголовок таблица 1, колонка 1</th>
			<th>Заголовок таблица 1, колонка 2</th>
			<th>Заголовок таблица 1, колонка 3</th>
			<th>Заголовок таблица 1, колонка 4</th>
		</tr>
		<tr>
			<td>А тут может быть очень длинный текст, например машиностроительный</td>
			<td>Строка 1, запись 2</td>
			<td>Строка 1, запись 3</td>
			<td>Строка 1, запись 4</td>
		</tr>
		<tr>
			<td>Строка 2, запись 1</td>
			<td>Строка 2, запись 2</td>
			<td>Строка 2, запись 3</td>
			<td>Строка 2, запись 4</td>
		</tr>
	</table>
</div>

Первую таблицу будем оборачивать в блок, а вторую будем пересобирать.

Много букв, для вот такого плагина:

(function ( $ ) {
	$.fn.adaptiveTable = function ( options ) {
		options = $.extend({
			addWrap: false
		}, options);

		var make = function () {
			var self = this;

			$(document).ready(function () {

				if( options.addWrap === true ) {
					$(self).wrap('<div class="table-adaptive-wrap"></div>');
					return true;
				}

				// пересоберем
				var new_table = $('<div class="table-adaptive"></div>');

				$(self).find('tr').each(function () {
					new_table.append('<div class="table-adaptive__row">');

					$(this).find('td, th').each(function () {
						new_table.find('.table-adaptive__row').last().append('<div class="table-adaptive__cell">' + $(this).html() + '</div>');
					});
				});

				$(self).replaceWith(new_table);
			})
		};

		return this.each(make);
	};
})(jQuery);

Для общего случая надо еще добавить такие стили

/*****************************************************************************/
/********************* Обертка для обычной таблицы ***************************/
.table-adaptive-wrap {
	position: relative;
	overflow: auto;
}

/*****************************************************************************/
/******************** Стили для адаптивной таблицы ***************************/
.table-adaptive {
	width: 100%;
	position: relative;
	display: table;
	border: 1px solid #ccc;
	box-sizing: border-box;
}

.table-adaptive__row {
	width: 100%;
	position: relative;
	display: table-row;
	
}

.table-adaptive__cell {
	position: relative;
	padding: 10px;
	display: table-cell;
	border-top: 1px solid #ccc;
	border-left:  1px solid #ccc;
	box-sizing: border-box;
}

.table-adaptive__row:first-child .table-adaptive__cell {
	border-top: none;
}

.table-adaptive__cell:first-child {
	border-left: none;
}

@media all and (max-width: 800px) {
	.table-adaptive, .table-adaptive__cell, .table-adaptive__row {
		display: block;
	}
	
	.table-adaptive {
		border: none;
	}
	
	.table-adaptive__row {
		border-bottom: 1px solid #ccc;
	}
	
	.table-adaptive__row:first-child {
		display: none;
	}
    
    .table-adaptive__cell {
	    border: none;
    }
}

Вот так незамысловато =) Вызывается как и любой плагин:

$(document).ready(function(){

	// Просто обертка
	$('.js-add-wrap').adaptiveTable({addWrap:true});

	// Сложная структура на дивах
	$('.js-convert-table').adaptiveTable();
});

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

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

See the Pen vxeBJY by Ildar Saribzhanov (@ildar_r_saribzhanov) on CodePen.

Завел на github репозиторий для этого плагина. Возможно, буду его модифицировать в процессе, так что, как говорится — следите за обновлениями!

Всем рок!