How to fold table columns into rows on mobile devices? - responsive-design

I'm developing a website featuring a restaurant's menu. Each item is available in different sizes, each at a different price. This is displayed on medium and large devices using a table, with a column for each price:
On mobile devices, the screen is too narrow to properly display up to 4 different sizes per product.
So I would like to fold columns into rows, having each row starting with the column name:
Is there anything like this possible using a responsive design? I'm trying to avoid maintaining two different HTML versions of the content, one visible only on mobile, and one visible only on larger screens.
I'm using Foundation 5, so I'm ideally looking for a solution using this grid system, but I'm open to any solution really.

The solution involves making table cells display: block on mobile devices, and adding a data-* attribute to each cell, matching the column name.
This data attribute is injected in the cell's ::before pseudo-element with content: attr().
Example:
<table>
<thead>
<tr>
<th>Pasta</th>
<th>Small</th>
<th>Regular</th>
</tr>
</thead>
<tbody>
<tr>
<td>Spaghetti Bolognese</td>
<td data-th="Small">£5.00</td>
<td data-th="Regular">£7.00</td>
</tr>
<tr>
<td>Lasagna</td>
<td data-th="Small">£5.00</td>
<td data-th="Regular">£7.00</td>
</tr>
</tbody>
</table>
CSS:
#media only screen and (max-width: 40em) {
thead th:not(:first-child) {
display: none;
}
td, th {
display: block;
}
td[data-th]:before {
content: attr(data-th);
}
}
You'll need to add some extra float to make it pretty.
Working example: http://codepen.io/anon/pen/medrZo

CSS changes for the above results
table {
border-spacing: 0;
}
td,
th {
padding: 0.5em;
}
th {
font-weight: bold;
text-align: left;
}
thead th {
background-color: #999;
color: white;
}
td > div {
float: right;
}
#media screen and (max-width: 885px) {
thead th:not(:first-child) {
display: none;
}
thead th:first-child:after {
content: "'s";
}
td, th {
display: block;
width: 100% !important;
}
td:first-child {
font-weight: bold;
}
td[data-th]:before {
content: attr(data-th);
border-radius: 10px 0px 0px 10px;
font-weight: bold;
min-width: 10rem;
display: inline-block;
}
}

Related

layout design suggestion for modal popup

I am looking for layout design suggestion for one of my screens.
I have a modal popup window which displays the customers information in tabbed layout which means one tab per customer. each tab has 3 accordions out of which 2 accordions have tables(grid).
Now the requirement is to compare the customer data side by side instead of using tabs. we can have maximum of 4 customers.
I assume this is what you are going for:
Layout diagram
I suggest you use the <table> tag for that. Each table column (<td>) will represent one customer.
I provided you with my example below.
body {
background-color: #ccc;
}
#modal {
width: 80%;
min-width: 100px;
height: 80%;
min-height: 100px;
background-color: white;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
padding: 15px;
text-align: center;
}
#customer_table {
position: absolute;
bottom: 10px;
width: 100%;
height: 75%;
vertical-align: top;
border-spacing: 0;
}
tr:first-child td {
height: 20px;
background-color: #5a5a5a;
color: white;
}
td {
border-left: solid #5a5a5a 1px;
border-right: solid #5a5a5a 1px;
border-bottom: solid #5a5a5a 1px;
}
<html>
<body>
<div id="modal">
<h2>Customer table</h2>
<table id="customer_table">
<tr>
<td>Customer 1</td>
<td>Customer 2</td>
<td>Customer 3</td>
<td>Customer 4</td>
</tr>
<tr>
<td>Customer data</td>
<td>Customer data</td>
<td>Customer data</td>
<td>Customer data</td>
</tr>
</table>
</div>
</body>
</html>

Accordian in angularjs

I want to add accordian in my angularjs app. I have to show some details on button click "Additional Information". Not sure how to toggle class panel with button click.
Here is my html:
<button ng-click="showPanel()" class="accordian">Additional Information</button>
<br>
<div class="panel" style="width: 750px;">
<div class="panel-heading">Attributes</div>
<table class="table table-bordered">
<tbody>
<tr >
<td>{{room.allowFecc}}</td>
</tr>
</tbody>
</table>
</div>
CSS:
button.accordian {
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
width: 100%;
border: none;
text-align: left;
outline: none;
font-size: 15px;
transition: 0.4s;
}
button.accordion.active, button.accordion:hover {
background-color: #ddd;
}
div.panel {
padding: 0 18px;
display: none;
background-color: white;
}
div.panel.show {
display: block;
}
You can drop the class that simply does a display: block - Angular has built in directives like ngShow and ngHide which will take care of this for you. Basically in Angular, you want to manipulate the data, and then let the view bind back to the data.
For your basic example above, you want to toggle a variable from true to false to show the accordian or hide it, and then based on the variable, add a class:
The Angular:
$scope.toggleAccordian = function() {
$scope.showAccordian = !$scope.showAccordian; //our toggle variable
}
The HTML:
<button ng-click="toggleAccordian()" class="accordian">Additional Information</button>
<br>
<div class="panel" ng-show="showAccordian" ng-class="{'accordianActiveClass': showAccordian }" style="width: 750px;">
<div class="panel-heading">Attributes</div>
<table class="table table-bordered">
<tbody>
<tr >
<td>{{room.allowFecc}}</td>
</tr>
</tbody>
</table>
</div>
The ng-class="{'accordianActiveClass': showAccordian }" is the class magic, replace accordianActiveClass with the class you want to show, and when the condition is satisfied (showAccordian) the class will be added.

angular directive's content not rendered, unless you force page reflow manually

I experience the following strange behavior in ui-bootstrap and angular 1.4. When I put a footable table directive inside a customized bootstrap panel, called hpanel, the footable initially takes more place than the panel itself:
But if I resize the screen (e.g. by collapsing the Developer Tools panel here), the footable directive draws itself and fits within panel:
Importantly, I've experienced similar problems with angular-c3 charts directives (they load incorrectly, exceeding the size of hpanel, but upon page resize behave fine), so it's probably not just a broken directive.
Have you seen anything similar?
DETAILS:
Below is an HTML template that represents the non-functional part of page. There we have an hpanel and within it a table with angular-footable directive ^1.0.3, applied to it.
Here's the template (toolList.html):
<div class="content">
<div class="row">
<div class="col-lg-12">
<div class="hpanel">
<div class="panel-heading">
<div class="panel-tools">
<a class="showhide"><i class="fa fa-chevron-up"></i></a>
<a class="closebox"><i class="fa fa-times"></i></a>
</div>
Available tools.
</div>
<div class="panel-body">
<input type="text" class="form-control input-sm m-b-md" id="filter" placeholder="Search in table">
<table id="example1" class="footable table table-stripped toggle-arrow-tiny" data-page-size="8" data-filter=#filter>
<thead>
<tr>
<th data-toggle="true">Id</th>
<th>Class</th>
<th>Label</th>
<th>Description</th>
<th data-hide="all">Owner</th>
<th data-hide="all">Contributor</th>
<th data-hide="all">Inputs</th>
<th data-hide="all">Outputs</th>
<th data-hide="all">Base command</th>
<th data-hide="all">Arguments</th>
<th data-hide="all">Requirements</th>
<th data-hide="all">Hints</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="tool in vm.tools">
<td><a ui-sref="tool-detail({id: tool.id})">{{tool.id}}</a></td>
<td>{{tool.tool_class}}</td>
<td>{{tool.label}}</td>
<td>{{tool.description}}</td>
<td>{{tool.owner}}</td>
<td>{{tool.contributor}}</td>
<td>{{tool.baseCommand}}</td>
<td>{{tool.arguments}}</td>
<td>{{tool.requirements}}</td>
<td>{{tool.hints}}</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="5">
<ul class="pagination pull-right"></ul>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</div>
The footable directive is meant to hide some columns of the table and show them upon click on a table row. It also provides pagination. It doesn't seem to work upon page load, but when I resize the page and the size of screen crosses the media-type margin (so that from medium-size screen it becomes large screen in bootstrap css terms), pagination buttons appear and columns that are meant to be hidden are hidden.
Here's how I import the footable directive in my main module app.js:
require("footable/js/footable");
require("footable/js/footable.filter");
require("footable/js/footable.striping");
require("footable/js/footable.sort");
require("footable/js/footable.paginate");
require("footable/css/footable.core.css")
require("angular-footable");
angular.module("app", [
...,
"ui.footable",
])
I use webpack to load all those modules and bower to install the dependencies.
hpanel is just a scss class, here is its definition:
/* Panels */
.hpanel > .panel-heading {
color: inherit;
font-weight: 600;
padding: 10px 4px;
transition: all .3s;
border: 1px solid transparent;
}
.hpanel .hbuilt.panel-heading {
border-bottom: none;
}
.hpanel > .panel-footer, .hpanel > .panel-section {
color: inherit;
border: 1px solid $border-color;
border-top: none;
font-size: 90%;
background: $color-bright;
padding: 10px 15px;
}
.hpanel.panel-collapse > .panel-heading, .hpanel .hbuilt {
background: #fff;
border-color: $border-color;
border: 1px solid $border-color;
padding: 10px 10px;
border-radius: 2px;
}
.hpanel .panel-body {
background: #fff;
border: 1px solid $border-color;
border-radius: 2px;
padding: 20px;
position: relative;
}
.hpanel.panel-group .panel-body:first-child {
border-top: 1px solid $border-color;
}
.hpanel.panel-group .panel-body {
border-top: none;
}
.panel-collapse .panel-body {
border: none;
}
.hpanel {
background-color: none;
border: none;
box-shadow: none;
margin-bottom: 25px;
}
.panel-tools {
display: inline-block;
float: right;
margin-top: 0;
padding: 0;
position: relative;
}
.hpanel .alert {
margin-bottom: 0;
border-radius: 0;
border: 1px solid $border-color;
border-bottom: none;
}
.panel-tools a {
margin-left: 5px;
color: lighten($color-text, 20%);
cursor: pointer;
}
.hpanel.hgreen .panel-body {
border-top: 2px solid $color-green;
}
.hpanel.hblue .panel-body {
border-top: 2px solid $color-blue;
}
.hpanel.hyellow .panel-body {
border-top: 2px solid $color-yellow;
}
.hpanel.hviolet .panel-body {
border-top: 2px solid $color-violet;
}
.hpanel.horange .panel-body {
border-top: 2px solid $color-orange;
}
.hpanel.hred .panel-body {
border-top: 2px solid $color-red;
}
.hpanel.hreddeep .panel-body {
border-top: 2px solid $color-red-deep;
}
.hpanel.hnavyblue .panel-body {
border-top: 2px solid $color-navy-blue;
}
.hpanel.hbggreen .panel-body {
background: $color-green;
color: #fff;
border:none;
}
.hpanel.hbgblue .panel-body {
background: $color-blue;
color: #fff;
border:none;
}
.hpanel.hbgyellow .panel-body {
background: $color-yellow;
color: #fff;
border:none;
}
.hpanel.hbgviolet .panel-body {
background: $color-violet;
color: #fff;
border:none;
}
.hpanel.hbgorange .panel-body {
background: $color-orange;
color: #fff;
border:none;
}
.hpanel.hbgred .panel-body {
background: $color-red;
color: #fff;
border:none;
}
.hpanel.hbgreddeep .panel-body {
background: $color-red-deep;
color: #fff;
border:none;
}
.hpanel.hbgnavyblue .panel-body {
background: $color-navy-blue;
color: #fff;
border:none;
}
.panel-group .panel-heading {
background-color: $color-bright;
}
.small-header .hpanel {
margin-bottom: 0;
}
.small-header {
padding: 0 !important;
}
.small-header .panel-body {
padding: 15px 25px;
border-right: none;
border-left: none;
border-top: none;
border-radius: 0;
// background: $color-bright;
}
.panel-body h5, .panel-body h4 {
font-weight: 600;
}
.small-header .panel-body h2 {
font-size: 14px;
font-weight: 600;
text-transform: uppercase;
margin: 0 0 0 0;
}
.small-header .panel-body small {
color: lighten($color-text, 10%);
}
.hbreadcrumb {
padding: 2px 0px;
margin-top: 6px;
margin-bottom: 0px;
list-style: none;
background-color: #fff;
font-size: 11px;
> li {
display: inline-block;
+ li:before {
padding: 0 5px;
color: $color-navy-blue;
}
}
> .active {
color: lighten($color-text,20%);
}
}
.wrapper {
padding: 10px 20px;
}
.hpanel.collapsed .panel-body, .hpanel.collapsed .panel-footer {
display: none;
}
.hpanel.collapsed .fa.fa-chevron-up:before {
content: "\f078";
}
.hpanel.collapsed .fa.fa-chevron-down:before {
content: "\f077";
}
.hpanel.collapsed.panel-collapse .panel-body {
border-width: 0 1px 1px 1px;
border-color: $border-color;
border-style: solid;
}
.hpanel.collapsed .hbuilt.panel-heading {
border-bottom: 1px solid $border-color;
}
body.fullscreen-panel-mode {
overflow-y: hidden;
}
.hpanel.fullscreen {
z-index: 2030;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
overflow: auto;
margin-bottom: 0;
}
.hpanel.fullscreen .showhide {
display: none;
}
.hpanel.fullscreen .panel-body {
min-height: calc(100% - 77px);
}
Here's tool.module.js file, which animates the template:
import angular from "angular";
var ToolResource = require("workflow/tool/tool.service");
class ToolListController {
// #ngInject
constructor($location, $stateParams, $state, tools) {
this.$location = $location;
this.$state = $state;
this.$stateParams = $stateParams;
this.tools = tools;
}
}
// #ngInject
function routesList($stateProvider) {
$stateProvider.state("tool-list", {
url: "/tool",
parent: "layout",
templateUrl: "/app/workflow/tool/toolList.html",
controller: "ToolListController",
controllerAs: "vm",
data: {
pageTitle: "Tool",
pareDesc: "List of tools, available for workflow construction.",
},
resolve: {
ToolResource: "ToolResource",
tools: function(ToolResource) {
return ToolResource.query().$promise;
}
}
});
}
module.exports = angular.module("tool", [])
.service('ToolResource', ToolResource)
.controller('ToolListController', ToolListController)
.config(routesList);
tool.service.js:
module.exports = function ToolResource($resource) {
return $resource('/api/tool/:id', {id: '#id'});
}
ANSWER:
Community is awesome!
1.5 years ago this directive was created
12 days ago this bug was fixed by Alexryan in his fork
10 days ago I posted this question on StackOverflow
8 days ago I placed a bounty on this question
7 days ago ziscloud approved pull request
in the morning today the bounty expired and in the nick of time Walfrat found out that the bug was fixed
So, yes, it was a bug in the directive that made it draw itself before getting the data from server. With the bugfix I just added load-when="vm.tools" attribute to the directive and it works fine now.
Thank you, Alexryan, ziscloud, Walfrat and other commenters/answerers. StackOverflow and Github just made my day!
Are you using this directive ? https://github.com/ziscloud/angular-footable/blob/master/src/angular-footable.js. It's an homemade (meaning not done by the editor of the footable) directive so it can be not rightly implemented to works with Angularjs.
Looking at the code it seems that you have to use an attribute load-when if you want to delay the initialization of the grid even though you use the resolve attribute in your state, it can be worth to test it.load-when shall be an empty array at start an will trigger the load after the array won't be empty anymore, but the data binded won't be used for the initialization from what i saw.
Note : i wasn't able to set a proper plnkr myself, i don't know the version you're using (and with which jQuery version) and online links doesn't seems available.
Since you are asynchronously loading data (as was mentioned in the comments) your html is rendered prior to it having any data in it. This means the directive may be fired too early (if it is attempting to adapt based on data). Typically, in this scenario, you'll want to throw an ng-if on the portion of your html that is dependent on the data loading (and show a loading gif or something in its place). You can either run the ng-if off of the data itself being defined, or maintain a separate boolean that you set once the promise is resolved.

Responsive href different images for browser and mobile emails

I am designing a mobile template. In that, Header is linked to the home page for the website. But the problem is there are two different headers for desktop and mobile. I want to link both the images to the home page of the website.Initially I tried
.Header {
width: 320px;
display: block;
height: 100px;
background: url('Images/mobile.jpg') no-repeat;
}
.headerimg img {
display: none !important;
}
<tr>
<td width="500"><a class="headerimg" href="http://www.google.com/" target="_blank"><img src="Images/desktop.png" alt="Google" height="160" width="500" border="0" style="display:block;"></a></td>
</tr>
Then I tried to do it placing two images size by size and hiding one based on the view
.MobileHeaderImg {display: none !important;}
.HeaderImg {display: block !important;}
.HeaderImg a{display: block !important;}
#media handheld, screen and (max-width: 500px) {
.MobileHeaderImg {
position: relative;
display: block !important;
width: 320px !important;
height: 100px !important;
}
<tr>
<td width="500"><img src="Images/header.png" class="HeaderImg" alt="" height="160" width="500" border="0" style="display:block;"><a class="headerimg" href="http://www.google.com/" target="_blank"><img src="Images/mobile.png" class="MobileHeaderImg" alt="" height="160" width="500" border="0" style="display:block;"></a></td>
Any Idea
Thanks in Advance
I forget where I picked this up from (somewhere in Email on Acid), but the below code should solve your issue. It will likely take some tweaking to fit into your template.
<!doctype html>
<html>
<head>
<style>
#media only screen and (min-device-width: 500px) and (max-device-width: 1024px) {
span[id=switcher] {display:block;
background-image: url(http://www.emailonacid.com/images/blog_images/Emailology/2013/tablet.jpg) !important;
background-repeat: no-repeat !important;
background-position: center !important;
width: 300px !important;
height: 250px !important; }
img[id=houdini] {display: none !important; }
}
#media only screen and (max-device-width: 489px) {
span[id=switcher] {display:block;
background-image: url(http://www.emailonacid.com/images/blog_images/Emailology/2013/mobile.JPG) !important;
background-repeat: no-repeat !important;
background-position: center !important;
width: 300px !important;
height: 250px !important; }
img[id=houdini] {display: none !important; }
}
</style>
<body>
<span id="switcher"><img id="houdini" src="http://www.emailonacid.com/images/blog_images/Emailology/2013/Desktop.jpg" alt=""></span>
</body>

Fluid Horizontal NavBar for responsive website

Im trying to make a fluid responsive web that contains an horizontal navbar, my problem is that at a certain width of the browser window the elements of the bar start to relocate one on top each other, is there any way to avoid this behavior in order to make the navbar just stretch until a certain media query break point. I need to website to look al least decent in the ranges where the querys are not activated.
Here's how things look so far:
http://wearehellyeah.com/test/home_formacio.html
<div class="barra">
<!--Menu Principal-->
<nav class="menu-principal">
<ul class="menu">
<li class="item sub"><button type="button" id="menu-lateral" class="sb-toggle-left"><img src="img/iconos/menu.png" alt="search"></button></li>
<li class="item">Actualitat</li>
<li class="item">Activitat de l'oficina</li>
<li class="item">Vocalies</li>
<li class="item">Formació</li>
<li class="item">Serveis</li>
<li class="item">Actualitat</li>
<li class="item no-border">El Col-legi</li>
<li class="item home">Marcar com pàgina d'inici</li>
<li class="item conectados">Conectados 103</li>
<li class="item"><button type="button" id="search"><img src="img/iconos/search.png"></button></li>
</ul>
</nav>
<!--Fin Menu Principal-->
<!--Input buscador-->
<div class="buscador">
<form action="">
<input type="text" id="ip-search">
</form>
</div>
<!--Fin de Input Buscador-->
</div>
The CSS:
.barra {
background: #00b1da;
width: 100%;
padding: 0;
}
.menu-principal {
height: 36px;
line-height: 35px;
margin: 0 auto;
max-width: 1024px;
position: relative;
width: 100%;
}
.menu {
padding: 0;
margin: 0;
}
.menu .item {
float: left;
list-style: none;
}
.menu .item a {
border-right: 1px solid #008ba9;
color: #fff;
font-size: 13px;
padding: 0 .98em;
text-decoration: none;
white-space: nowrap;
}
.menu .sub {
background: #008ba9;
padding: 0 .4em;
height: 35px;
display: block;
}
.conectados {
background: #fff;
color: #4b585b;
font-size: 13px;
padding: .1em 1em 0 2.3em;
position: relative;
}
.menu .home {
background: url("../img/iconos/home.png") no-repeat 2% #00a9a1;
border-left: 1px solid #40c2d3;
padding: 0 0 0 1em;
}
You could add a min-width:
.menu-principal {
min-width:883px;
}
Then it won't go on top of each other. However there are too many options on the navigation bar, you might want to make it a drop-down box when it goes into a mobile media-query range.
e.g. http://vagish.com (as you make the browser width smaller, it changes the navigation bar)
You could have a media query which takes place between 768px and 880px, and reduces the spacing between menu items, and this should be able to make it look fine until you hit the 768px media query.
This would work (along with the CSS above):
#media all and (max-width: 768px) and (min-width: 880px) {
.menu-principal {
padding:0px;
}
.menu-med .item a {
padding:0 .69em;
}
}

Resources