A couple of things I wanted to achieve:
- Simple layout, fitting both mobile and desktop browsers without diving into responsiveness.
- Modular document structure. For instance I have a header that should display identically on every page, but when header information changes (e.g. the day of last update), I do not want to make the correction on all the pages where it appears.
- Display other HTML pages dynamically within the page where the
user clicked some link. Of course this content can be just a
short text. But it should be an independent document maybe also
included elsewhere.
- Browse my homepage also on mobile phones.
Basic Layout and Link Buttons
"Mobile first" is what you hear everywhere. So I decided to have a
very simple layout that fits both mobile and desktop, not to get in
trouble with responsiveness. You might say the desktop looks poor now,
but I don't mind as long as one can navigate and read without problems.Mobile apps prefer horizontal push-buttons that mostly span 100 % of the page width, and "drop down" something when you push them. The reason is possibly that mobiles are mostly used in portrait orientation.
For the basic layout I decided to have just a header on top, with title info and few horizontally arranged navigation buttons, and content below, that consistently uses full-width push buttons representing links to other parts of the homepage. These link buttons sometimes lead
- to full-page documents, sometimes
- to internet pages (like this Blog), and sometimes
- to short documents that "drop down" below the link button directly within the parent page.
Here is the full-width push button's HTML
<a class="blocklink" href="Books.html">Books</a>and CSS
.blocklink {
cursor: pointer; /* show link cursor on hover */
border-radius: 0.7em; /* rounded corners */
padding: 0.3em; /* inner spacing */
margin: 0.2em; /* outer spacing */
display: block; /* makes it full width */
font-size: 1.3em; /* a little bigger for mobiles */
text-decoration: none; /* no link underline */
background-color: rgba(51, 153, 255, 0.6); /* blue */
color: white;
/* color gradient from opaqueness to transparency */
background: -webkit-linear-gradient(left, rgb(51, 153, 255), rgba(51, 153, 255, 0.2)); /* Safari */
background: -o-linear-gradient(right, rgb(51, 153, 255), rgba(51, 153, 255, 0.2)); /* Opera */
background: -moz-linear-gradient(right, rgb(51, 153, 255), rgba(51, 153, 255, 0.2)); /* Firefox */
background: linear-gradient(to right, rgb(51, 153, 255), rgba(51, 153, 255, 0.2)); /* Standard */
}
Modular document structure
The header
I chose <iframe> HTML elements to keep the header modular. Iframes offer the possibility to import an URL.So the header text and the navigation buttons are written in just one HTML document which is imported via <iframe> elements in all other documents. That way only the iframe element is duplicated, not the header text.
Moreover I like relative links, something like src="header.html" instead of src="http://server/me/homepage/header.html".
This is the section that has to be duplicated in all documents:
<div class="header">
<iframe src="header.html" width="100%" frameborder="0" scrolling="no"></iframe>
</div>
Mind that, when a document is in a sub-directory, sometimes this has to be
<div class="header">
<iframe src="../header.html" width="100%" frameborder="0" scrolling="no"></iframe>
</div>
You do not need to care about the header.css (referenced in header.html), this is found relative to the header.html.
Likewise you do not need to care about the links in header.html, they also will be found relative to their document's directory.
The only thing you have to care about is that the navigation buttons in header.html load their links into the top document and not into the iframe:
<a class="navigationitem" href="index.html" target="_top">Welcome</a>
Loading documents dynamically
This is what is called AJAX (Asynchronous JavaScript and XML): the DOM (document object model) is changed without reloading the whole page.I used JQuery.load() for this. Here is my script. It uses a CSS class "expandcontrol" to find all buttons that want to load dynamically their href URL.
Mind that on some mobile phones (Android) you need to tell the browser to redraw the page after load(), else the scrolling area is not expanded and you will not be able to scroll down to the end of the loaded document.
<head>
...
<script src="http://code.jquery.com/jquery.min.js" type="text/javascript"></script>
<script src="stackpanel.js" type="text/javascript"></script>
</head>
stackpanel.js
$(document).ready(function() {
var loading = false;
var expandcontrols = $(".expandcontrol");
$(expandcontrols).click(function(event) {
event.preventDefault(); // consume click
var nextDiv = $(this).next("div");
var visible = $(nextDiv).css("display") != 'none';
var hasContent = $(nextDiv).children().size() > 0;
if (visible && hasContent) {
$(nextDiv).css("display", "none");
}
else if ( ! loading ) { // ignore other loads while loading
$(nextDiv).css("display", "");
if ( ! hasContent ) { // not yet loaded
var trigger = $(this);
var cursor = trigger.css("cursor");
trigger.prepend("<span style='color: orange; background-color: black;'>Waiting for ... </span>");
trigger.css("cursor", "wait"); // for browsers
loading = true;
$(nextDiv).load(this.href, {}, function(response, status, xhr) {
trigger.children().first().remove(); // remove the "wait" message
trigger.css("cursor", cursor); // restore cursor
loading = false;
if (status != "success") { // there was a problem
trigger.prepend("<span style='color: red; background-color: black;'>Fehler: "+xhr.status+"</span>");
}
else {
// due to a bug on Android browser (can not scroll down to end of loaded text)
// we need to invalidate the layout
var triggerParent = trigger.parent();
triggerParent.hide(0, function() {
triggerParent.show();
});
}
});
}
}
});
});
Yes, this looks as complicated as JavaScript is.
But JQuery disburdens that. JQuery is for different browsers what Java is for different operating systems.
Essentially there is a function declared to be executed as soon as the DOM has been loaded.So also following HTML is needed for that:
That function searches all elements with class "expandcontrol" and installs a click callback on them.
That click callback then loads (when clicked) the URL of the href of the event source (button link) into a div below the event source.
<a class="expandcontrol blocklink" href="music.html">Music</a>The restrictions for such dynamically loaded pages are as follows:
<div /> <!-- will receive dynamic content on link click -->
- they must not contain relative links, JQuery does not
substitute relative links to fit the new location of the parent
page, so they would not be found
- they should not contain CSS references, as these would
merge into the parent page's CSS and possibly change the layout
as soon as they are loaded.
Browse on mobiles
Because the layout is that simple I did not need care about responsive layout (layout changes with screen dimensions).But nevertheless my homepage was "very far away" when I first looked at it on a mobile. I needed the magnifying "two-finger drag" to be able to read it.
"Far away" means the browser zoom factor was not set to be initially 1.0, as I read on the internet.
So everything I needed was to include a meta--tag named "viewport" into all my HTML head tags:
<meta name="viewport" content="initial-scale=1"/>To be on the safe side I included these also in my main CSS (recommended because the meta-tag is not a w3c standard):
@-viewport {Then the mobile browser shows the page adapted to its viewport width, and you do not need the two-finger drag.
zoom: 1.0;
width: extend-to-zoom;
}
@-ms-viewport {
width: extend-to-zoom;
zoom: 1.0;
}
P.S.
The meta-tag
initial-scale
does not work when big images or pre-formatted text sections with very long lines are in the document. An android mobile then zooms away, and the document is "far away" again.