Es gehört zur Philosophie des 3 Purpose Grids (Demo), dass nur wenige rudimentäre GUI- und Design-Elemente zur Verfügung gestellte werden, damit der Desinger bzw. Entwickler Freiraum für eine individuelle Gestaltung behält. Dies ist bei vielen CSS-Frameworks, wie z.B. Bootstrap anders. Dort werden viele ausgefeilte GUI-Elemente wie Tabulatoren, Buttons, Sliders, etc. implementiert, deren Verwendung dann allerdings dazu führt, dass ein damit erstelltes Produkt am Ende erkennbar auf einem Bootstrap-Framework aufsetzt. Wer also ein individualisiertes Produkt realisieren möchte, der muss entweder auf diese Elemente verzichten, was zu einem Overhead in den Sourcen führt oder aber z.B. mittels aufwändiger SASS-Modifikationen einen eigenen GUI-Style generieren, was allerdings sehr spezifische Skills erfordert und nicht ganz einfach sein dürfte. Dies soll aber mit unserem Grid-System nicht passieren.
Trotzdem können wir auf die Unterstützung weniger GUI- und Design-Komponenten nicht verzichten. Wir beschränken uns auf CSS-Unterstützung für:
- Menus,
- Medien,
- Info-Boxen,
- Formulare,
- Tabellen und
- Karten.
Andere machen daraus 6 Artikel. Ich packe hier alles in einen. Schließlich will ich ja auch mal fertig werden mit dieser Reihe.
Damit hätten wir dann den ersten Zweck unseres 3 Purpose Grid erreicht, nämlich die Verwendung als ganz normales CSS-Framework für Portale. Wir werden noch einige weitere Teile benötigen, um alle unsere Ziele zu erreichen.
Beginnen wir mit den Menus.
CSS-Menu-Ressourcen
Für unser Top-Menu hatten wir ja schon einiges geleistet. Dies hat insofern eine besondere Bedeutung, als es wahrscheinlich auch das wichtigeste Menu ist, das wir als Collapsed-Menu bei Klick auf den Navigations-Button öffnen müssen, wenn eine bestimmte Breite für Tablets und Handy unterschritten wird. Alle erforderlichen Styles hierfür finden wir in folgender CSS-Datei, die wir schon im Zusamenhang mit Header und Footer (Teil 3) und der Navigation (Teil 4) eingeführt hatten:
- assets/css/nav-resp-whr-nrw-var-1-vers-0.5.0.css
Hierauf brauchen wir also in diesem Teil 5 nicht mehr einzugehen. Wir benötigen aber CSS-Styles für weitere vertikale und horizontale Menus, die wir eventuell auf unserer Seite platzieren wollen.
Ein vertikales Menu
Das vertikale Menu unseres Grid-Systems (vgl. Abb. 1) ist zwar grundsätzlich schon hierarachisch. Es muss dann aber bei Bedarf noch nach-gestyled werden.
Abb. 1: 3 Purpose Grid: Theming / Simples vertikales Menu (Demo)
Die Demo kann sich übrigens manchmal etwas von der Abbildung hier unterscheiden, weil sich der Entwicklungsstand im Moment noch laufend ändert. An den Zusammenhängen ändert dies jedoch nichts.
Hinweis: Aus den gleichen Gründen sollte man nicht versuchen, die Skripte hier zu einem Gesamt-System zusammenzubauen. Manches ist nicht aktuell. Als Teillösung und zum Verständnis sind die Skripte aber zu gebrauchen. Wartet einfach auf die Implementierung einer Download-Möglichkeit, die es bald für eine Alpha-Version geben wird.
Hier die zugehörige CSS-Datei:
/* sideMenuSimple.css */ .menu-vert-base { width:100%; margin-bottom: 30px; } .menu-vert-base ul { list-style-type: none; margin: 0px; padding: 0px; } .menu-vert-base ul ul { list-style-type: none; margin: 0px; padding: 10px; } .menu-vert-base li { display: block; margin: 1px; width:100%; } .menu-vert-base a { font-family: "Open Sans",sans-serif; display: block; text-decoration: none; background-color: #EEEEEE; color: #555555; padding:5px 10px; } .menu-vert-base a:hover { background-color: #555555; color: #cccccc; } .menu-vert-base li p img { width: 100%; height: auto; padding: 0 5px 0 0; } /* Style */ .menu-vert-base li.current_page_item a { color: #8ab900; } .menu-vert-base li a { font-family: 'Open Sans', Arial, Helvetica, sans-serif; font-size: 14px; color: #797979; } .menu-vert-base li a:hover { color: #2F6194; text-decoration:none; } .menu-vert-base li.active a { background-color: #aaaaaa !important; color:white; }
3-Purpose-Grid - File: assets/css/menu-vert.base-whr-nrw-var-1-vers-0.5.0.css
Angewendet werden die Styles, indem hauptsächlich ein nav-Element mit der Klasse menu-vert-base versehen wird:
... <aside> <div class="aside-navigation"> <nav class='nav-aside-1 menu-vert-base vertical'> <h6 style="padding-top:3px;padding-left:12px;">Varianten</h6> <ul id="nav-aside-1" class="nav collapsible"> <li><a href="index-855.3.html">855px 3 Spalten</a></li> ...
Dabei wollen wir es belassen. Es gibt ja eine Vielzahl von Vorlagen zu solchen Menus im Internet und wir wollen die Freiheiten des Designers deshalb nicht beschränken.
Es gibt übrigens auch für diesen Menu-Typ eine Premium-Variante für das 3 Purpose Grid, welches dann auch Javascript benötigt, dafür aber beliebig viele Levels zulässt (im CSS sind 3 Level definiert) und die Möglichkeit enthält, Menu-Einträge mit zusätzlichen Bildern und Kommentaren auszustatten sowie einen Fuß- und Kopfbereich z.B. für Ads, etc. zu implementieren (vgl. Abb. 2).
Abb. 2: 3 Purpose Grid: Theming / Vertikales Menu Premium Version (Demo)
Die zusätzlichen Infos im Footer und Header sowie im Bereich der Menu-Punkte (in der Abbildung nicht zu sehen), werden auch in das Collapsible-Menu für Tablets und Handys übertragen. Tipp: Öffnet mal den Menu-Punkt Sonstige in der Demo.
Ein horizontales Menu
Ein hierarchisches horizontales Menu wäre auch nützlich. Unser Top-Menu ist ja rein linear. Da vertikales und horizontales Menu teilweise gemeinsame Ressourcen nutzen, bauen wir uns schnell eins (vgl. Abb. 3):
Abb. 3: 3 Purpose Grid: Theming / Horizontales Menu Version (Demo)
Designerisch noch stark verbesserungsbedürftig, aber es funktioniert schon richtig für mobile Endgeräte. Denn dort können wir z.B. Hover-Menus nicht nutzen. Wir öffnen das Menu durch einen Klick bzw. auf dem Touch-Screen mit einem Fingerdruck.
In der Premium-Version können solche Menus übrigens genauso wie das vertikale Menu auch in das Collapsible Menu integriert werden.
Hier zunächst die erforderliche CSS-Ressource:
/* Reset */ nav.horizontal ul, ul ul{ margin:0; padding:0; list-style-type:none; list-style-position:outside; position:relative; line-height:1.5em; } /* Design */ nav.horizontal ul a { display:block; padding:0px 2em 0px 5px; border-left:1px solid #ffffff; border-top:1px solid #ffffff; border-bottom:1px solid #ffffff; text-decoration:none; } nav.horizontal ul a, nav.horizontal ul a:link, nav.horizontal ul a:active, nav.horizontal ul a:visited{ background-color:#073563 !important; color:#fff; } nav.horizontal ul a:hover{ background-color:#fff !important; color:#333 !important; } /* Align horizontal */ nav.horizontal ul li{ float:left; position:relative; } /* Position nested lists right beyond the main menu */ nav.horizontal ul ul { position:absolute; width:12em; top:1.5em; display:none; } /* Align sub menus left and set size */ nav.horizontal ul li ul a{ width:10.2em; /* 12 em Änderung erforderlich wegen padding 2em s.o. */ float:left; } /* Define where to display submenus */ nav.horizontal ul ul ul{ top:auto; } nav.horizontal ul li ul ul { left:12em; margin:0px 0 0 10px; } nav.horizontal ul li ul ul a{ width:5em; } /* nav.horizontal ul li:hover ul ul, nav.horizontal ul li:hover ul ul ul, nav.horizontal ul li:hover ul ul ul ul{ display:none; } nav.horizontal ul li:hover ul, nav.horizontal ul li li:hover ul, nav.horizontal ul li li li:hover ul, nav.horizontal ul li li li li:hover ul{ display:block; }*/ .horizontal .plusSign { background: url("./images/icon_arrow_right.png") no-repeat scroll 98% center rgba(255, 0, 0, 0); } .horizontal .minusSign { background: url("./images/icon_arrow_down.png") no-repeat scroll 98% center rgba(0, 0, 0, 0); }
3-Purpose-Grid - File: assets/css/menu-horz.simple-whr-nrw-var-1-vers-0.5.0.css
Weil wir :hover nicht nutzen können, weil wir bei unserem Grid-System immer damit rechnen, dass wir einen Touch-Screen haben, müssen wir einen Mechanismus mit Javascript implementieren, der dazu führt, dass bei einem Druck auf einen Menu-Eintrag das Untermenu per jQuery-Skript geöffnet wird und bei einem Druck auf einen Bereich neben dem Menu das Menu wieder geschlossen wird.
Wir implementieren diesen Mechanismus unabhängig von schon bestehenden CSS-Styles für :hover sowohl für das vertikale als auch das horizontale Menu.
/* (c) Dr. Wolfgang Hauertmann, Hilden 2015, Lizenz: siehe lizenz.txt */ /* * Menu events, etc */ var naviall =(function(){ var isClicking = false; /* Horizontal and vertical nav menu */ // Set callapsible icons function setCollapsibleIcons() { $("nav ul.sub.collapsible").each(function(){ if ($(this).is(":visible")) { $(this).prev().removeClass('plusSign'); $(this).prev().addClass('minusSign'); } else { $(this).prev().removeClass('minusSign'); $(this).prev().addClass('plusSign'); } }); } /* Horizontal nav menu */ // animation function horzmenu(){ // $(" nav.horizontal ul a").removeAttr("title"); $("nav.horizontal ul ul").css({display: "none"}); // Opera Fix /* $("nav.horizontal ul li").hover( function(){ $(this).find('ul:first').css({visibility: "visible",display: "none"}).show(400, function(){ setCollapsibleIcons(); }); }, function(){ $(this).find('ul:first').css({visibility: "hidden"}); setCollapsibleIcons(); } );*/ $("nav.horizontal ul li").click( function(){ // alert('x'); } ); } function _init() { $( window ).resize(function() { // reset some automized setted styles $("nav.vertical ul.nav.collapsible").removeAttr("style"); $("nav.horizontal ul.nav.collapsible").removeAttr("style"); /* Set callapsible icons */ setCollapsibleIcons(); }); $(document).click(function(e) { if (isClicking) { isClicking = false; // event was handled by another click handler setCollapsibleIcons(); return; } // Check for left button if (e.button === 0) { $("nav.horizontal ul.sub.collapsible").slideUp(function() { setCollapsibleIcons(); }); } setCollapsibleIcons(); }); $(document).ready(function() { /* Vertical nav menu */ $("nav ul.sub.collapsible").prev().click(function(){ isClicking = true; // reset it inwith document-click-handler /* slide up all horizontal menus if another menu point (from vertical too) was clicked */ $(this).parents('ul').addClass('dontSlideUp'); $("nav.horizontal ul.sub.collapsible").each(function(){ if (!$(this).hasClass('dontSlideUp')){ $(this).slideUp(); } }); $(this).parents('ul').removeClass('dontSlideUp'); /* * Remove a possible height:312px or similar remaining from the last 'collapseUp'of the collapsed nav menu. * The unwanted effect is, that elements below the nav-menu will not be moved down on expanding. */ $("nav.vertical ul.nav.collapsible").removeAttr("style"); $("nav.horizontal ul.nav.collapsible").removeAttr("style"); //slide up all the link lists if (!$(this).next().is(":visible")) { $(this).next().slideDown(function() { setCollapsibleIcons(); }); } else { $(this).next().slideUp(function() { setCollapsibleIcons(); }); } }); /* Set callapsible icons */ setCollapsibleIcons(); /* Horizontal nav menu animation */ horzmenu(); }); } return { init: _init() }; }()); console.log('navi-all.js');
3-Purpose-Grid - File: assets/js/mod/menu-base-whr-nrw-var-1-vers.0.5.0.js
Damit verfügen wir jetzt neben der Top-Navigationsleiste über ein horizontales und ein vertikales Menu, die wir beliebig auf unserer Seite einbauen können.
Da wir im Collapsible Menu noch nicht richtig hierarchische Menus verwalten können und dort auch nur ein Menu in der Basis-Version unseres Grid unterbringen können, müssen wir uns auf ein einfaches lineares Menu im Kopfbereich beschränken. Für unsere Zwecke hier im Blog reicht das. Wer diese Einschränkung aufheben möchte, der muss entweder die hier vorgestellten Ressourcen selbst erweitern oder kann mich natürlich nach der Premium-Version fragen.
CSS-Medien-Ressourcen
Bilder
Bilder gehören zu den häufigsten Medien und können mit wenigen CSS-Handgriffen responsiv in unser System eingebunden werden:
/* (c) Dr. Wolfgang Hauertmann, Hilden 2015, Lizenz: siehe lizenz.txt */ /* * Images, responsive */ /* * Make all images responsive * * We have following image types: * - logo-img: Header 1 only, * - node-image: inserted into a text, * - col-image: content of a column */ .logo-img img, .node-image img, .col-image img { width:100%; height:auto; border-radius: 4px; } /* * An overlay-image to make a background layer logo clickable */ img.logo-transparent { width:100%; height:auto; margin: 0px 0px 0px 0px; } /* we need a margin to following content */ .col-image { margin-bottom:10px; } /* * Photos with additional icons */ .col-image #photo { border: solid 1px navy; border-radius: 4px; font-size: 2.5em; color: white; background-color: #2B67A4; background-image: url("../../assets/img/friedrichskoog-port-245664_640.jpg"); background-size: 100% 100%; /*width:100%; height:300px;*/ } .col-image #photo img{ border: none; border-style: none; display: block; } .col-image .icon { float:right; margin-top:3px; padding-right:10px; right:3px; }
3-Purpose-Grid - File: assets/css/resp-img-whr-nrw-var-1-vers-0.5.0.css
Der Einfachheit halber wird alles, was irgendwie mit Bildern zu tun hat, in dieser Datei gestyled, damit wir es immer schnell wiederfinden können. Ausnahmen davon bestätigen die Regel.
Wir machen erst einmal grundsätzlich alle Typen von Bildern, die wir verwenden wollen responsive (width:100%; height:auto;). Natürlich gibt es ausgefeiltere Techniken, die man hier einsetzen kann, aber wir wollen es ja so einfach wie möglich halten und wir kommen damit schon sehr weit.
Für Bilde, die in Texte eingebettet sind, haben wir die Regel .node-image img definiert (vgl. Abb. 4).
Abb. 4: 3 Purpose Grid: class node-image img für Bilder in Texten (Demo)
Für Bilder, die ganze Spalten ausfüllen sollen, gibt es den Style .col-image img (vgl. Abb. 5):
Abb. 5: 3 Purpose Grid: class col-image img für Bilder in Spalten(Demo)
Außerdem werden noch Styles für ein spezielles Feature zur Verfügung gestellt, nämlich Bilder mit Icons auszustatten (in diesem Falle aus dem Font icomoon), die oben in das Bild integriert werden. Diese Icons kann man dann später mit Javascript-Funktionalität hinterlegen, z.B. um ein Foto hochzuladen oder ähnliches (vgl. Abb. 6):
Abb. 6: 3 Purpose Grid: class .col-image #photo für Bilder mit Icons (Demo)
Bilder, bzw. Bildere mit Icons sowie ggf. ein erforderliches transparantes Overlay-Image (in Abb. 6 rosa opaque angedeutet), werden wie folgt eingebunden:
... <!-- Header variant x.y --> <div class="left col2"> <div class="container"> <div class="logo-img"><a href="#"><img src="./assets/img/logo.png" /></a></div> <div class="logo-text"> <h1>3 Purpose Grid</h1> ... ... <div class="node-image"><img src="..." /></div> ... <div class="col1"> <div class="container"> <div class="col-image"><img src="..." /></div> .... </div> </div> ... <div class="col-image"> <div class="icon-camera icon" aria-hidden="true" onclick="javascript:alert('Vögelchen!');"></div> <div class="icon-mobile icon" aria-hidden="true" data-id-mappos="341"></div> <div id="photo"><img src="./assets/img/transparent_640x460.png"/></div> </div> ...
3-Purpose-Grid - File: index..xy...html
Der Style .logo-img img wird hier nur im Header 1 verwendet und hat dort keinen Einfluß auf dessen Aussehen, da in der zugehörigen CSS-Datei für diesen Header speziellere Styles definiert sind.
Allerdings sollte man aufpassen. Die CSS-Datei für Images sollte in der Reihenfolge oberhalb der CSS-Dateien spezieller Strukturen wie Header und Footer liegen.
Videos
Auch die responsive Einbindung von Videos erfordert etwas Styling-Aufwand, wenn auch nicht sehr viel:
/* * Videos, responsive */ .resp-video { position: relative; padding-bottom: 55%; padding-top: 15px; height: 0; overflow: hidden; } .resp-video iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
3-Purpose-Grid - File: assets/css/resp-vid-whr-nrw-var-1-vers-0.5.0.css
Wie ein Video eingebunden wird, wird im Zusammenhang mit den Info-Boxen diskutiert.
CSS-Info-Boxen-Ressourcen
Info-Boxen sind auch nichts anderes als UL-Listen, die entsprechend gestyled werden. Im folgenden wird die Einbindung von Videos in eine Info-Box dargestellt.
... <div class='two-columns'> <div class="col2"> <div class="container"> <nav> <ul id="card-index"> <li><a href="#">Nordsee</a></li> <li class="active"><a href="#">Ostsee</a></li> <li><a href="#">Bahrentssee</a></li> <li><a href="#">Balearen</a></li> </ul> </nav> <div class='clearfix'></div> <section> <div class="content-video"> <!--video height="288" width="512" controls="" poster="video/maus-maus-aus-3.jpg" src="http://www.html-seminar.de/video/maus-maus-aus-3.ogg"> <div>Hier wäre ein Video zu sehen, wenn Ihr Browser HTML5 Unterstützung hätte, wie z.B. der aktuelle Firefox</div> </video--> <div class="resp-video"> <iframe width="536" height="315" src="https://www.youtube.com/embed/RF66ZXZEcYE" frameborder="0" allowfullscreen></iframe> </div> </div> </section> </div> </div> </div> ...
3-Purpose-Grid - File: index...xy...html
Das Ergebnis soll so aussehen (vgl. Abb. 7):
Abb. 7: 3 Purpose Grid: Info-Box (Demo)
Für dieses recht ansprechende Feature, das auch responsive ist, benötigen wir neben der oben schon erwähnten Datei für responsive Videos noch folgende Styles:
/* (c) Dr. Wolfgang Hauertmann, Hilden 2015, Lizenz: siehe lizenz.txt */ /* * Card index */ /* Info-Box */ ul#card-index { font: bold 11px Verdana, Arial, sans-serif; list-style-type: none; margin: 0; padding: 0 0 24px 30px; /*border-bottom: 1px solid #333333;*/ } ul#card-index li, #card-index a { -webkit-border-top-left-radius: 10px; -webkit-border-top-right-radius: 10px; -moz-border-radius-topleft: 10px; -moz-border-radius-topright: 10px; border-top-left-radius: 10px; border-top-right-radius: 10px; } ul#card-index li { float: left; height: 21px; background-color: #333; margin: 2px 2px 0 2px; border: 1px solid #333333; } #card-index a { float: left; display: block; color: #ffffff; text-decoration: none; padding: 4px 10px; } #card-index a:hover { background: #FFF; color:#333333; } #card-index li.active { border-bottom: 1px solid #FFF; background-color: #FFF; } #card-index li.active a { color: #000; } .content-video { border-width: 0 1px 1px 1px; border-color: #0099FF; border-style: solid; padding: 10px; background-color: #ffffff; border-radius: 4px; }
3-Purpose-Grid - File: assets/css/card-index-whr-nrw-var-1-vers-0.5.0.css
CSS-Formular-Ressourcen
Ein weiterer wichtiger Theming-Bereich ist das Stylen von Formularen, wichtig z.B. für unser Ziel, dieses Grid-System als NodeJS-Konsole einsetzen zu können.
Wir brauchen dafür ein System, dass responsiv ist, aber auch für den Einsatz in Spalten unterschiedlicher Breite geeignet ist. Z.B. können sich meist relativ große Formulare im Hauptbereich einer Seite befinden oder in einem relativ schmalen Seitenbereich. Bei verkürzter Breite im Falle eines mobilen Endgerätes (Tablet, Handy) sollten sich die Formulare dann gleich verhalten bzw. gleich aussehen.
Hierfür habe ich folgende Styles definiert:
/* (c) Dr. Wolfgang Hauertmann, Hilden 2015, Lizenz: siehe lizenz.txt */ /* * Forms, responsive */ .form-header { margin: 0 0 20px 0; } .form-header div { font-size: 90%; color: #333333; } .form-header h2 { margin: 0 0 5px 0; } form > div { clear: both; overflow: hidden; padding: 1px; margin: 0 0 10px 0; } form > div > fieldset > div > div { margin: 0 0 5px 0; } form > div > label, legend { width: 33%; float: left; padding-right: 10px; } form > div > div, form > div > fieldset > div { width: 65%; float: right; } form > div > fieldset label { font-size: 90%; } fieldset { border: 0; padding: 0; } input[type=text], input[type=email], input[type=url], input[type=password], textarea { width: 100%; border-top: 1px solid #ccc; border-left: 1px solid #ccc; border-right: 1px solid #eee; border-bottom: 1px solid #eee; } input[type=text], input[type=email], input[type=url], input[type=password] { width: 50%; } input[type=text]:focus, input[type=email]:focus, input[type=url]:focus, input[type=password]:focus, textarea:focus { outline: 0; border-color: #4697e4; } form.thin > div { margin: 0 0 15px 0; } form.thin > div > label, form.thin legend { width: 100%; float: none; margin: 0 0 5px 0; } form.thin > div > div, form.thin > div > fieldset > div { width: 100%; float: none; } form.thin input[type=text], form.thin input[type=email], form.thin input[type=url], form.thin input[type=password], form.thin textarea, form.thin select { width: 100%; } form.big > div > label, form.big legend { text-align: right; } @media (max-width: 814px) { /* special adjustment, not identical with resp855.css */ form.big > div > label, form.big legend { text-align: left; } /* thin -> big */ form.big > div { margin: 0 0 15px 0; } form.big > div > label, form.big legend { width: 100%; float: none; margin: 0 0 5px 0; } form.big > div > div, form.big > div > fieldset > div { width: 100%; float: none; } form.big input[type=text], form.big input[type=email], form.big input[type=url], form.big input[type=password], form.big textarea, form.big select { width: 100%; } } /* following could be modified or defined in style-all...xy..css */ form { background-color:#A9CDE5; padding:10px; border: 1px solid #333333; margin-bottom:10px; border-radius: 4px; }
3-Purpose-Grid - File: assets/css/resp-forms-whr-nrw-var-1-vers-0.5.0.css
In dieser Datei stehen unten die Media-Queries, die für zwei Typen von Formularen die Responsivität herstellen. Die beiden Typen haben die Klassen:
- form-thin und
- form-big.
Formulare werden mit der Klasse form-thin ausgestattet, wenn sie in einer Spalte untergebracht werden, z.B. in einer rechten Seitenspalte (vgl. Abb. 8).
Abb. 8: 3 Purpose Grid: Einspalten-Formular mit der Klasse form-thin (Demo)
Formulare werden mit der Klasse form-big ausgestatten, wenn sie über mehrere Spalten breit sein sollen. In diesem Fall werden bei Desktop-Breite bis Tablet-Landscape bzw. solange der Platz reicht die Labels über die Input-Felder geschrieben (vgl. Abb. 9).
Abb. 8: 3 Purpose Grid: Mehrspalten-Formular mit der Klasse form-big (Demo)
Damit kommen wir schon ziemlich weit. Spezielle Form-Eigenschaften können dann z.B. in unserer Datei style-all-......css definiert werden.
CSS- Tabellen-Ressourcen
Natürlich gehören auch Tabellen zu den Standard-CSS-Aufgaben, weshalb wir hier ansatzweise eine responsive Lösung vorstellen. Allerdings muss man bei Tabellen sehr inhaltsorientiert vorgehen. Je nach Content benötigt man eventull ein anderes Prinzip für die Implementierung. Eine Übersicht über verschieden Ansätze bietet dieser Artikel. Dort werden sowohl reine CSS- als auch Javascript-Lösungen diskutiert.
Ich habe mich hier für einen eigenen Lösungsansatz basierend auf CSS entschieden, den man später aber mittels jQuery gut erweitern kann. Der Ansatz sieht vor, eine Tabelle in Html zu verdoppeln, in der zweiten Tabelle dann einige erste Spalten zu löschen und diese Tabelle zunächst unsichtbar zu machen. Unterhalb einer definierten Breite wird dann mittels Media-Queries in der ersten Tabelle einige letzte Spalten unsichtbar und die zweite Tabelle sichtbar gemacht. Das Ergebnis sieht dann so aus (vgl. Abb. 10-11):
Abb. 10: 3 Purpose Grid: Tabelle großes Display (Demo)
Abb. 11: 3 Purpose Grid: Tabelle kleines Display (responsiv) (Demo)
Dafür benötigen wir folgende CSS-Datei:
table.standard { border-spacing: 0; border-collapse: separate; background-color:#ffffff; } table.standard th { background: #2B67A4; color: #ffffff; text-align: left; } table.standard tr:nth-child(even) { background: #eeeeee; } table.standard tr:nth-child(odd) { background: transparent; /* don't set a color here. In FF you will get white edges! Set a table background-color in table */ } table.standard td, table.standard th { padding: 5px 12px; border-bottom: 1px solid green; border-right: 1px solid #255789; } table.standard tr:last-child td:first-child { border-bottom-left-radius:10px; } table.standard tr:last-child td:last-child { border-bottom-right-radius:10px; } table.standard tr th:first-child, table.standard tr td:first-child { border-left: 1px solid #255789; } table.standard tr:first-child th, table.standard tr:first-child td { border-top: 1px solid #255789; } table.standard tr:first-child th:first-child/*, table.standard tr:first-child td:first-child*/ { border-top-left-radius:10px } table.standard tr:first-child th:last-child/*, table.standard tr:first-child td:last-child*/ { border-top-right-radius:10px } /* * An invisible copy of the last column as one-column-table * for small displays */ table.standard.responsive.second { display:none; } @media (max-width: 767px) { table.standard tr th, table.standard tr td { font-size:small; padding: 5px 6px; } } @media (max-width: 480px) { table.standard tr:first-child th:first-child/*, table.standard tr:first-child td:first-child*/ { border-top-left-radius:0px } table.standard tr:first-child th:last-child/*, table.standard tr:first-child td:last-child*/ { border-top-right-radius:0px } table.standard tr:last-child td:first-child { border-bottom-left-radius:0px; } table.standard tr:last-child td:last-child { border-bottom-right-radius:0px; } } /* * you can support this system with a javascript perhaps later * which creates table.responsive.second and more automatically. */ @media (max-width: 366px) { table.standard tr th:nth-child(3), table.standard tr td:nth-child(3) { display:none; } table.standard.responsive.second { display:table; width: 100%; } }
3-Purpose-Grid - File: assets/css/table-resp-whr-nrw-var-1-vers-0.5.0.css
Die Tabellenstruktur aus den der sichtbaren und unsichtbaren Tabelle sieht dann etwa so aus:
<div class='two-columns'> <div class="col2"> <div class="container"> <h4>Garnelen, Heringe</h4> <p>Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.</p> <div class="blue-table"> <table id="skills-table" class="table table-striped table-bordered table-condensed standard responsive first"> <thead> <tr> <th>Frontend</th> <th>Backend</th> <th>Projektmanagement</th> </tr> </thead> <tbody> <tr> <td>Javascript</td> <td>PHP</td> <td>Projektmanagement</td> </tr> <tr> <td>Html5 / CSS3</td> <td>MySql</td> <td>Agile Programmierung</td> </tr> <tr> <td>jQuery</td> <td>MongoDB (NoSql, Cloud-Computing)</td> <td>Beratung</td> </tr> <tr> <td>Responsive Design</td> <td>Typo3 / Extbase</td> <td></td> </tr> <tr class="warning"> <td></td> <td>Drupal (bevorzugt)</td> <td></td> </tr> <tr> <td></td> <td>Zend-Framework</td> <td></td> </tr> <tr> <td></td> <td>cakePHP</td> <td></td> </tr> </tbody> </table> <table id="skills-table" class="table table-striped table-bordered table-condensed standard responsive second"> <thead> <tr> <th>Projektmanagement</th> </tr> </thead> <tbody> <tr> <td>Projektmanagement</td> </tr> <tr> <td>Agile Programmierung</td> </tr> <tr> <td>Beratung</td> </tr> </tbody> </table> </div> </div> </div> </div>
3-Purpose-Grid - File: index..xy...html
Wichtig sind die Klassen standard responsive first und standard responsive second. Die übrigen Klassen sind Bootstrap-Klassen, die in unserem System zunächst mal keine Verwendung haben.
Wie schon erwähnt, kann die zweite Tabelle unter Umständen mit jQuery generieren. Bei größeren Tabellen würde sich diese Lösung dann anbieten. Ein kleines Script dafür wäre relativ schnell entwickelt. Dabei könnte die hier gewählte CSS-Struktur die Grundlage bilden.
CSS-Karten-Ressourcen
Als letztes spendieren wir noch ein paar Ressourcen für das Einbinden von Karten in unser Grid-Layout und zwar auf Basis von OpenLayers 3. Dafür müssen wir unsere index..xy...html um folgende Snipptes erweitern:
... <!-- Theming --> <!-- Maps --> <link href="./assets/css/resp-map.all-whr-nrw-var-1-vers-0.5.0.css" rel="stylesheet" type="text/css" /> <link href="./assets/css/resp-map.dir-whr-nrw-var-1-vers-0.5.0.css" rel="stylesheet" type="text/css" /> <link href='http://ol3js.org/en/master/css/ol.css' rel="stylesheet" type="text/css" /> .... </head> <body> ... <div class='two-columns'> <div class="col2"> <div class="container"> <div class="locations"> <h4>Unser Kutter (aktuelle Position)</h4> <div class="compass-map"> <div id='map'></div> <div id='compass'> <img id="compassImg" alt="Compass" src="./assets/img/compass.png"/> <h4 id="compassInfo" style="text-align:center;"></h4> </div> </div> </div> </div> </div> </div> <!-- Maps --> <script type="text/javascript" src='http://ol3js.org/en/master/build/ol.js'></script> <script type="text/javascript" src='./assets/js/maps.js'></script> </body> </html>
3-Purpose-Grid - File: index...xy...html
Wir finden oben eigene CSS-Styles, die wir weiter unten vorstellen, sowie Styles von OpenLayers 3, die wir per Hot-Link laden.
In der Mitte sehen wir dann den Container für zwei Spalten, der folgendes enthält:
- eine h4-Überschrift,
- die Karte mit der ID map,
- ein Image, das eine Grafik für die Richtungsanzeige enthält und
- eine weitere unsichtbare h4-Überschrift für eine später geplante Kompassangabe in Grad.
Die beiden Elemente für die Kompass-Funktion benötigen wir erst später, wenn wir unser System um Funktionen für hybride Apps erweitern.
Um unteren Bereich der Index-Datei verlinken wir per Hot-Link die OpenLayers-API und wir benötigen natürlich auch ein eigenes Javascript, mit dem wir unsere Karte initalisieren. Daraus geht auch der Pfad hervor, in dem wir dieses vorläufig ablegen. Wenn wir es später erweitern wollen, sollte man das Modul-Pattern verwenden und das Skript dann im Ordner mod ablegen.
Das Ergebniss soll dann so aussehen (vgl. Abb. 9):
Abb. 12: 3 Purpose Grid: Kartenfunktionen (Demo)
Unser Haupt-CSS-Datei für Karten sieht so aus:
.locations { margin-bottom:20px; width:100%; height:300px; } .compass-map { position:relative; width:100%; height:100%; } #map { width:100%; height:100%; position:absolute; top:0; left:0; } #compass { position:absolute; bottom:0px; right:50px; } #compass img{ margin-bottom:10px; } .ol-attribution { z-index:10000; }
3-Purpose-Grid - File: assets/css/map-resp.all-whr-nrw-var-1-vers-0.5.0.css
Für den Richtungskompass legen wir eine eigene CSS-Datei an:
.compass-map canvas { border-radius: 4px; }
3-Purpose-Grid - File: assets/css/map-resp.dir-whr-nrw-var-1-vers-0.5.0.css
Dazu noch etwas Javascript gemixt:
var map; function initMap(){ // http://jsfiddle.net/6RS2z/4/ var vectorSource = new ol.source.Vector({ //create empty vector }); var iconFeature = new ol.Feature({ geometry: new ol.geom.Point( // geographic EPSG:4326 // mercator = EPSG:3413 // ????? = EPSG:900913 e.g. 748863, 7092072 // ????? = EPSG:3857 ol.proj.transform([750863, 7093072], "EPSG:900913", "EPSG:900913" ) ), name: 'Unser Kutter', laenge: '12m', jahresfang: '5000t' }); vectorSource.addFeature(iconFeature); //create the style var iconStyle = new ol.style.Style({ image: new ol.style.Icon(/** @type {olx.style.IconOptions} */ ({ // anchor: [0.5, 46], anchor: [0, 0], anchorXUnits: 'fraction', anchorYUnits: 'pixels', opacity: 0.75, // src: 'http://ol3js.org/en/master/examples/data/icon.png' src: './assets/css/images/fishing_boat3.ico' // Converting photos: http://www.online-convert.com/result/05431bb4414794bce97cb7f70fde5b8d })) }); //add the feature vector to the layer vector, and apply a style to whole layer var vectorLayer = new ol.layer.Vector({ source: vectorSource, style: iconStyle }); map = new ol.Map({ layers: [new ol.layer.Tile({ source: new ol.source.OSM() }), vectorLayer], target:'map', renderer:'canvas', interactions: ol.interaction.defaults({mouseWheelZoom:false}), view: new ol.View({ projection: 'EPSG:900913', center:[748863,7092072], zoom:12 }) }); /* var newLayer = new ol.layer.Tile({ source: new ol.source.OSM() }); map.addLayer(newLayer);*/ } $(document).ready(function() { initMap(); });
3-Purpose-Grid - File: assets/js/maps.js
In der Document-Ready-Funktion wird die Karte beim Laden der Seite initalisiert. Dargestellt wird eine mögliches Postition eines Kutters mit Hilfe eines Icons, das ich mir irgendwie aus einem Pixabay-Foto gebastelt habe mit einem Online-Iconizer. Dieses muss natürlich am richtigen Ort gespeichert werden. Wo, geht aus dem Skript hervor.
Fazit
Das war's. Mehr Theming gibt es nicht. Keine Buttons, keine Slider, außer für unsere Info-Box keine Tabulatoren-Systeme. Das überlassen wir alles dem Designer. Es gibt ja genug Inspirationsquellen mit fast fertigen Lösungen im Netz, die man leicht in unser System integrieren kann.
Trotzdem war es bisher schon eine Menge Holz.
Als Ausgangspunkt für ein Portal-System liefert es alles, was man mindestens braucht. Die Idee war ja Copy&Paste für grundlegende Strukturen und dann die eigenen Ideen umsetzen.
Aber wir wollten noch mehr. Wir haben noch einen langen Weg vor uns:
- Purpose 2 war der Einsatz des Systems als Konsole. Damit beschäftigen wir uns im nächsten Teil 6 dieser Reihe.
- Purpose 3 war der Einsatz für Hybride Apps. Dies erfordert noch einige weitere Teile mehr.