exporting static sites from tiddlywiki

Part 3: Adding Bootstrap

Using a CSS Framework

Here we part ways with the CSS purists.

There are good reasons to write everything for yourself in CSS - you get to control every aspect of how your page looks.

But there are also good reasons to use a framework - ars longa vita brevis!

By 'dropping in' Bootstrap, we get lots of goodness for free.

Dropping in the Bootstrap CSS

Now I can do this without much trepidation.

{{$:/rs/normalise.css||$:/core/templates/plain-text-tiddler}}
{{$:/rs/static_styles.css||$:/core/templates/plain-text-tiddler}}
{{$:/rs/bootstrap.min.css||$:/core/templates/plain-text-tiddler}}

where into $:/rs/bootstrap.min.css I've copied the css for Bootstrap.

This gives me instant Bootstrap goodness, which means that if I add a div inside the body tags on $:/rs/templates/static.tiddler.html I get a properly padded, responsive container.

And I get decent defaults for the formatting of everything else too.

If I can add a useful header element (and, trivially, a footer) and have the page content generated out of Tiddlywiki then I'm close to achieving my goals.

The main motivation for wanting to stick bootstrap in there is that it handles responsive for us.

Adding a Site Header

We're going to try and lean on that to make our site look great on mobile and desktop.

To show interoperability of the two technologies, ideally we'd like to be able to generate the content of Navigation drop-downs programmatically within Tiddlywiki ie; the last 10 articles tagged "Live" on a drop-down.

Steps towards that?

I know that to get any kind of drop down, I'm going to need to get the bootstrap js into my static pages.

I'm guessing this will be quite straightforwards.

Once I've got that then the collapsing should work.

Then we can look at how to customise the list content.

At the moment, I've got the word 'test' appearing at the top of every page, because it's in the tiddler $:/rs/StaticBanner. This page http://getbootstrap.com/examples/sticky-footer-navbar/# has an example of just what we're looking for - a top navbar and a sticky footer (at leat, that's a good thing to aim for - we can say we have it under control when we get to there.

I'll open the page source (in Firefox for Mac, press command-U to open the source in a new tab, otherwise hunt through the menus on your browser for "page source". Usually there is a keyboard-shortcut listed in the menu for this item and it will save you time in future....

and find the bit of code that makes the navbar.

Then I'm going to try sticking this in that tiddler.


    <!-- Fixed navbar -->
    <nav class="navbar navbar-default navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Project name</a>
        </div>
        <div id="navbar" class="collapse navbar-collapse">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">Home</a></li>
            <li><a href="#about">About</a></li>
            <li><a href="#contact">Contact</a></li>
            <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
              <ul class="dropdown-menu">
                <li><a href="#">Action</a></li>
                <li><a href="#">Another action</a></li>
                <li><a href="#">Something else here</a></li>
                <li role="separator" class="divider"></li>
                <li class="dropdown-header">Nav header</li>
                <li><a href="#">Separated link</a></li>
                <li><a href="#">One more separated link</a></li>
              </ul>
            </li>
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </nav>

So far, so good. Looks nice but doesn't actually work. If we narrow the window, it will collapse, but then the dropdown menu won't work.

That's obviously because we need to load the bootstrap javascript code.

Also, the bootstrap code relies on jQuery.

In the example page source we just looked at, the scripts for these resources are loaded externally. I think if I pull the code into a pair of tiddlers, I should be able to load them both inline at the bottom of my HTML template.

Using a CDN for Better Performance

But wait! Do I really need to do that? I sometimes get a bit carried away with trying to bring everything in. I always think - it won't work if the cdn is down. But, in practice the cdn is hardly ever down. And anyway, my ultimate target for deployment is a cdn itself.

The advantage to using cdn is that a user may already have the resource in their browser cache (if they recently visited another page using bootstrap). The same applies if they go from page to page throughout our site.

There are designers, I'm sure, who would think nothing of asking the browser to reload the same code again and again for each page but it seems wasteful to me, even if the amounts of data are pretty trivial compared to the workload of an average browser.

We could host the resource externally ourselves but this is actually harder than using the off-site cdn.

To test with the cdn, we can just copy the lines right out of the example source code.

This is the bootstrap starter template

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
    <title>Bootstrap 101 Template</title>

    <!-- Bootstrap -->
    <link href="css/bootstrap.min.css" rel="stylesheet">

    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <h1>Hello, world!</h1>

    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <!-- Include all compiled plugins (below), or include individual files as needed -->
    <script src="js/bootstrap.min.js"></script>
  </body>
</html>

and this is the cdn code for the bootstrap parts

<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">

<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>

And this is the first one with the second one mashed into it.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
    <title>Bootstrap 101 Template</title>

    <!-- Bootstrap -->
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">

    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
      <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
      <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
    <![endif]-->
  </head>

  <body>
    <h1>Hello, world!</h1>

    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>

    <!-- Include all compiled plugins (below), or include individual files as needed -->
    <!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
  </body>
</html>

When we use that to modify our page template, this is what we get...

Note that now we can remove the reference to our bootstrap tiddler, but we'll keep the tiddler around in case we need it later.

Very good. Now the menus are operational.

Also, our own stylesheet has kicked back in because it's now loading after bootstrap. We probably don't want a red background, so we'll clear that.

I also noticed that the styles aren't quite right and I think it's because the example is using a little stylesheet of its own.

We'll find that and put it in our static styles sheet to get us started.

Some pages appear to not be getting formatted right and the shiv is for the footer, not the header.

It's here.

/* Sticky footer styles
-------------------------------------------------- */
html {
  position: relative;
  min-height: 100%;
}
body {
  /* Margin bottom by footer height */
  margin-bottom: 60px;
}
.footer {
  position: absolute;
  bottom: 0;
  width: 100%;
  /* Set the fixed height of the footer here */
  height: 60px;
  background-color: #f5f5f5;
}


/* Custom page CSS
-------------------------------------------------- */
/* Not required for template or sticky footer method. */

body > .container {
  padding: 60px 15px 0;
}
.container .text-muted {
  margin: 20px 0;
}

.footer > .container {
  padding-right: 15px;
  padding-left: 15px;
}

code {
  font-size: 80%;
}

Here's a good article about 'measure' (line length)

https://www.smashingmagazine.com/2014/09/balancing-line-length-font-size-responsive-web-design/

Here's a tweak for the maximum column width in bootstrap.

http://stackoverflow.com/questions/15884102/bootstrap-how-do-i-change-the-width-of-the-container

Next

This is all very well, it's 'kind of' responsive, but when the menus collapse, we can't get them at all.

On the bootstrap demo that we looked at, doing the same thing gives us a neat drop down menu. Where's ours?

Doing that requires that we also load the Bootstrap Javascript and in the next part of our tutorial we'll see how to do just that.

NEXT: Part 4, Including Javascript