How to handle tables in responsive web design, (if not the most asked question when talking about responsive sites) is definitely in the top five. With the current evolution in web design heading down the path of responsive sites, the handling of content across multiple screen sizes and devices becomes complicated, especially when dealing with tables. Many times, you will find the columns of a table within the content be cropped by the viewport of the device. Other times, you will see 6-10 columns squeezed into an area of less than 400 pixels wide, and it becomes unreadable.
One interesting method of handling tables responsively? Behold, Reflow Table Widget for jQuery Mobile. It works by collapsing the table into a vertical presentation, stacking label/data pairs in blocks. This method however, may not work for all types of data, and does need a bit of vertical scrolling to read all the data.
What I will go over is a different responsive data table technique of hiding the table on smaller screens, and opening a full view of the table in a pop out.
To view a demo see: Responsive Table Demo
The Code
The following js finds all tables within the content, wrapping each with a unique ID.
With this ID it creates a small preview of the table to show the reader that there is additional data. It will try to get the tables caption and or thead
, though if the table does not contain a thead
, it will grab the first table row. This table preview is then overlaid with a link to open the full table view. Upon clicking, the a modal box takes over the window with the table contained in scrollable div.
Disclaimer: I do not claim this code is perfect, nor super awesome (but it is pretty cool). I am a novice when it comes to js, and the following code could be improved.
jQuery(document).ready(function($) { var counter = 1, modalActive = false; $( 'table' ).wrap(function() { // Wrap the tables to be able to uniquely identify them. // This also helps with the popupout page takeover. var wrapper = '<div data-table-id="' + counter + '" id="table-' + counter + '" class="table-wrapper"></div>'; counter++; return wrapper; }); // Create preview of hidden table. Will be used to open table popout. $('.table-wrapper').before(function() { var tableId = $( this ).data( "tableId" ); // Look for a caption to use for our preview. var caption = $( this ).find( 'caption' ); if ( caption.length ) caption = caption[0].outerHTML; else caption = ''; // Look for a table header to use for our preview. var thead = $( this ).find( 'thead' ); if ( thead.length ) thead = thead[0].outerHTML; else thead = ''; // Grab first table row to use for our preview. var firstTableRow = $( this ).find( 'tr:first' ); if ( firstTableRow.length ) firstTableRow = firstTableRow[0].outerHTML; else firstTableRow = ''; if ( thead !== '' ) var tableSnippet = caption + thead; else var tableSnippet = caption + firstTableRow; var tablePreview = '<table data-table-id="' + tableId + '" id="table-' + tableId + '-preview" class="table-preview">' + tableSnippet + '</table>'; return tablePreview; }); // Open popout of table preview clicked. $( '.table-preview' ).click(function() { var tableId = $( this ).data( "tableId" ); $( '#table-' + tableId ).show(); $( '#table-' + tableId ).addClass( 'is-viewing' ); $( this ).hide(); // Helps prevent scrolling of behind the table. $( 'html' ).width(0).height(0).css( 'overflow', 'hidden' ); $( 'body' ).width(0).height(0).css( 'overflow', 'hidden' ); var modalActive = true; }); // Add link to close popout. $('.table-wrapper table').before( '<a class="close-table-modal" href="#">↵ Return to site.</a>' ); $( '.close-table-modal' ).click(function(e) { e.preventDefault(); var tableId = $( this ).parent().data( "tableId" ); $( this ).parent().hide(); $( '#table-' + tableId + '-preview' ).show(); // Helps prevent scrolling of behind the table popout. $( 'html' ).width( 'auto' ).height( 'auto' ).css( 'overflow', '' ); $( 'body' ).width( 'auto' ).height( 'auto' ).css( 'overflow', ''); // when popout is closed, bring viewer to location of table preview. document.getElementById( 'table-' + tableId + '-preview' ).scrollIntoView(); var modalActive = false; }); var mq550 = window.matchMedia("only screen and (max-width: 550px)") function whiteoutReset( mq550 ){ console.log( mq550 ); if ( mq550.matches && true === modalActive ) { $( 'html' ).width(0).height(0).css( 'overflow', 'hidden' ); $( 'body' ).width(0).height(0).css( 'overflow', 'hidden' ); } else { $( 'html' ).width( 'auto' ).height( 'auto' ).css( 'overflow', '' ); $( 'body' ).width( 'auto' ).height( 'auto' ).css( 'overflow', '' ); } if ( mq550.matches ) { $( '.table-preview' ).show(); $( '.table-wrapper' ).hide(); } else { $( '.table-preview' ).hide(); $( '.table-wrapper' ).show(); } } whiteoutReset( mq550 ); mq550.addListener( whiteoutReset ); });
Below is some CSS styling to handle the modal window the table will pop up in, as well as the preview table. I have the media query set at 550px and below, but depending on your sites contents and tabular data, you may find a wide or smaller viewport will work better.
/* * =Responsive Table */ .table-preview { display: none; } .close-table-modal { display: none; } @media only screen and (max-width: 550px) { .close-table-modal, .table-preview { display: block; box-sizing: border-box; } .close-table-modal { text-align: left; padding: 5px; } .table-preview { float: left; height: 80px; width: 100%; overflow: hidden; position: relative; background: rgba( 0, 0, 0, .05 ); } .table-preview:before { content: "View Data"; width: 100%; height: 40px; position: absolute; z-index: 999; top: 0; left: 0; background: -webkit-linear-gradient( rgba( 255,255,255, 0) 0%, rgba( 255,255,255, 1) 80% ); display: block; color: #bada55; text-align: center; font-weight: bold; padding-top: 45px; font-size: 16px; text-decoration: underline; text-shadow: 0px 0px 7px #fff; } .table-wrapper { display: none; } .table-wrapper.is-viewing { display: block; background: #fff; margin: 0; position: fixed; width: 100%; z-index: 999999; top: 0; left: 0; height: 100%; overflow: auto; } .table-wrapper.is-viewing table { width: 550px; margin: 5px; } }
Leave a Reply