Адаптивные таблицы для адаптивных сайтов
Вступление
Верстка адаптивных макетов для нас в 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 репозиторий для этого плагина. Возможно, буду его модифицировать в процессе, так что, как говорится — следите за обновлениями!
Всем рок!