bikle.com /Opinions/Tech Tips

Style your site with ZURB

Written by Dan Bikle on 2013-07-20

Usually when I think about launching a new site, I visualize the look of the site with pencil and paper. After 15 minutes or so, I add color to my idea with colored pencils. Once I have some drawings I like, I start the task of coding up HTML and CSS files.

Coding up HTML and CSS is a chore. An obvious short-cut I can take is to find existing HTML and CSS files from one of my past projects which are similar to what I want. Then I bend copies of them to my will. Another short-cut is to work with copies of other people's HTML and CSS which is both licensed for use and has a beautiful look.

Colored pencils

ZURB

Generally though, I find that working with other people's HTML and CSS is more difficult than working with something I wrote several months or years ago. The site you are reading now, bikle.com, uses much HTML and CSS from a framework named Foundation by ZURB. I prefer to just call it ZURB. Although it is other people's code, I find it relatively easy to work with.

Bootstrap

A similar framework is Twitter Bootstrap. Or more precisely, twitter-bootstrap-rails which is integration software to connect Twitter Bootstrap with Ruby-on-Rails. Before I found ZURB, I tried using twitter-bootstrap-rails but learned to steer clear of it after I bumped into a bug which causes Rails to frequently look for favicon.ico at a non-existent route: twitter-bootstrap-rails/issues/198

I list below the general path I followed to style bikle.com, the site you are looking at now, with ZURB.

Linux vs Mac

I started with a Linux based development environment: CentOS 6.4

In my home office I run CentOS on a small desktop server I bought from: ZaReason

Many of my friends do web development on Macs. Although I respect Apple technology, I dislike web development on Macs because Apple upgrades OS/X so often. I've seen situations where my Mac-friends are wrestling with library incompatibilities because their copy of OS/X is too old, too new, or just hosed in some strange way. CentOS 6.x is stable and is intended to stay useful until November of 2020.

Also OS/X is not at parity with the production OS which is usually Linux. I look like a clueless developer if I check in code which passes tests on my Mac but then "breaks the build" in the Linux production environment. My Mac-friends who want dev-production-parity, make use of software called Virtualbox (and VMware also) to build Rails sites on Linux running on their Macs:

https://www.virtualbox.org

http://www.vagrantup.com

Another trend I notice is the practice of writing software in a Linux environment which is hosted remotely at Amazon or DigitalOcean:

http://aws.amazon.com/free

http://www.digitalocean.com/

Ruby

The next step down this path was to install Ruby. My preference was/is to use software called rbenv to install Ruby: https://github.com/sstephenson/rbenv

The version of Ruby I currently work with is: 2.0.0-p247

I display below a mashup of a screendump and checklist I use to install Ruby 2.0.0 with rbenv:


Checklist for testing these commands on Centos 6.4 Linux running on Amazon AWS:

Get my credit card.

Use credit card to create AWS account:

http://aws.amazon.com/free

Get AWS key-file and call it bikle.pem and store it in a place where I will not lose it like ~/.ssh/

Find a link to a Centos 6.4 "AMI" which allows me to run Centos 6.4 Linux on Amazon AWS:

http://wiki.centos.org/Cloud/AWS
click: "CentOS AWS Marketplace"
click: "CentOS 6.4 (x86_64) - Release Media"
click: Continue-button
click: "Standard Small (m1.small) 1.7GB ram $0.06 / hour"
click: "Launch"
wait.

login with command like this:

ssh -i ~/.ssh/bikle.pem root@184.73.123.321

Run these shell commands from root-shell:

yum -y update

yum -y groupinstall "Development Tools"

yum -y install ntp
yum -y install zlib zlib-devel
yum -y install curl-devel
yum -y install apr-devel apr-util-devel
yum -y install mlocate 
yum -y install libxml2-devel libxslt-devel
yum -y install libffi-devel
yum -y install readline-devel
yum -y install openssl-devel

useradd -m -s /bin/bash bikle
rsync -av ~root/.ssh ~bikle/
chown bikle ~bikle/.ssh
chown bikle ~bikle/.ssh/authorized_keys

Login from other window on my laptop:

ssh -i ~/.ssh/bikle.pem bikle@184.73.123.321

git clone git://github.com/sstephenson/rbenv.git ~/.rbenv
git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build

vi .bashrc

Add 3 lines:

export PATH=~/.rbenv/bin:${PATH}
eval "$(rbenv init -)"
export PS1="bikle@z5 \w $ "

$ bash
bikle@z5 ~ $ rbenv
rbenv 0.4.0-49-g8b04303
Usage: rbenv  []

Some useful rbenv commands are:
   commands    List all available rbenv commands
   local       Set or show the local application-specific Ruby version
   global      Set or show the global Ruby version
   shell       Set or show the shell-specific Ruby version
   install     Install a Ruby version using the ruby-build plugin
   uninstall   Uninstall a specific Ruby version
   rehash      Rehash rbenv shims (run this after installing executables)
   version     Show the current Ruby version and its origin
   versions    List all Ruby versions available to rbenv
   which       Display the full path to an executable
   whence      List all Ruby versions that contain the given executable

See `rbenv help ' for information on a specific command.
For full documentation, see: https://github.com/sstephenson/rbenv#readme
bikle@z5 ~ $ rbenv help versions
Usage: rbenv versions [--bare]

Lists all Ruby versions found in `$RBENV_ROOT/versions/*'.

bikle@z5 ~ $ rbenv install 2.0.0-p247
Downloading ruby-2.0.0-p247.tar.gz...
-> http://ftp.ruby-lang.org/pub/ruby/2.0/ruby-2.0.0-p247.tar.gz
Installing ruby-2.0.0-p247...
Installed ruby-2.0.0-p247 to /home/bikle/.rbenv/versions/2.0.0-p247

bikle@z5 ~ $ 
bikle@z5 ~ $ rbenv global 2.0.0-p247
bikle@z5 ~ $ bash
bikle@z5 ~ $ 
bikle@z5 ~ $ rbenv version
2.0.0-p247 (set by /home/bikle/.rbenv/version)
bikle@z5 ~ $ 
bikle@z5 ~ $ which ruby
~/.rbenv/shims/ruby
bikle@z5 ~ $ 
bikle@z5 ~ $ ruby -v
ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-linux]
bikle@z5 ~ $ 
bikle@z5 ~ $ irb
irb(main):001:0> 1+1
=> 2
irb(main):002:0> quit
bikle@z5 ~ $ 
bikle@z5 ~ $ 

Postgres

After I installed Ruby I installed Postgres which is my choice of database for my Rails environments.

I display below a mashup of a screendump and checklist I used to install Postgres:


Checklist for installing Postgres on Centos 6.4 Linux:

ssh -i ~/.ssh/bikle.pem root@184.73.123.321

cd /etc/init.d/

yum install postgresql-devel
yum install postgresql-server


/etc/init.d # 
/etc/init.d # 
/etc/init.d # grep postg /etc/passwd
postgres:x:26:26:PostgreSQL Server:/var/lib/pgsql:/bin/bash
/etc/init.d # 
/etc/init.d # passwd postgres
Changing password for user postgres.
New password: 
Retype new password: 
passwd: all authentication tokens updated successfully.
/etc/init.d # 
/etc/init.d # 
/etc/init.d # ll postgresql 
-rwxr-xr-x. 1 root root 5383 Sep 13  2012 postgresql
/etc/init.d # 
/etc/init.d # 
/etc/init.d # grep initdb postgresql
		# No existing PGDATA! Warn the user to initdb it.
                echo "$PGDATA is missing. Use \"service postgresql initdb\" to initialize the cluster first."
initdb(){
	$SU -l postgres -c "$PGENGINE/initdb --pgdata='$PGDATA' --auth='ident'" >> "$PGLOG" 2>&1 < /dev/null
  initdb)
	initdb
	echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|initdb}"
/etc/init.d # 
/etc/init.d # /etc/init.d/postgresql initdb
Initializing database: [  OK  ]
/etc/init.d # 
/etc/init.d # 


/etc/init.d # /etc/init.d/postgresql start
Starting postgresql service: [  OK  ]
/etc/init.d # 
/etc/init.d # 

Login to bikle account from laptop:

ssh -i ~/.ssh/bikle.pem bikle@184.73.123.321

bikle@z5 ~ $ 
bikle@z5 ~ $ 

Login to postgres account from bikle account:

bikle@z5 ~ $ ssh postgres@localhost
Warning: Permanently added 'localhost' (RSA) to the list of known hosts.
postgres@localhost's password: 
-bash-4.1$ 
-bash-4.1$ 
-bash-4.1$ psql
psql (8.4.13)
Type "help" for help.



Next, I created a 'Role' inside of Postgres with a name which MATCHES my linux name:

postgres=# CREATE USER bikle SUPERUSER;
CREATE ROLE
postgres=# \q
-bash-4.1$ 
-bash-4.1$ 
-bash-4.1$ exit
logout
Connection to localhost closed.
bikle@z5 ~ $ 
bikle@z5 ~ $ 



I checked that my linux name matches the Postgres Role name:

bikle@z5 ~ $ id
uid=502(bikle) gid=54323(bikle) groups=54323(bikle) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
bikle@z5 ~ $ 



Then, I checked if the bikle account could connect to Postgres, create a database, and then create/drop a table:

bikle@z5 ~ $ 
bikle@z5 ~ $ which psql
/usr/bin/psql
bikle@z5 ~ $ 
bikle@z5 ~ $ createdb bikle
bikle@z5 ~ $ 
bikle@z5 ~ $ psql
psql (8.4.13)
Type "help" for help.

bikle=# CREATE TABLE dropme (mydate DATE);
CREATE TABLE
bikle=# DROP TABLE dropme;
DROP TABLE
bikle=# 
bikle=# \q
bikle@z5 ~ $ 
bikle@z5 ~ $ 

At this point I was confident that Postgres was installed.  I was ready to install the Rails-gem.

Rails

After I installed Postgres I installed Rails. The version of Rails I currently work with is: 4.0.0

I used a Ruby-utility named 'gem' to install Rails. The shell command is displayed below:

bikle@z5 ~ $ gem install rails -v 4.0.0 --no-ri --no-rdoc


I found some discussion about installing Rails at this URL:
http://guides.rubyonrails.org/getting_started.html#installing-rails

After I installed Rails 4.0.0, I used the rails-shell-command to create a Rails application:

bikle@z5 ~ $ rails new biklecom -d postgresql


If you are new to Rails you can read about the rails-shell-command here:
http://guides.rubyonrails.org/command_line.html#rails-new

Next, I studied this page: http://foundation.zurb.com/docs/rails.html

Gemfile

I edited my Rails-Gemfile so it looked like this:


ruby "2.0.0"

source 'https://rubygems.org'

# I prefer HAML over ERB:
gem 'hpricot',       '0.8.6'
gem 'sexp_processor','4.2.1'
gem 'ruby_parser',   '3.1.3'
gem 'html2haml',     '1.0.1'
gem 'haml-rails',    '0.4'
gem 'haml',          '4.0.3'

# http://foundation.zurb.com/docs/rails.html
gem 'compass-rails', :git => 'https://github.com/Compass/compass-rails.git', :branch => 'rails4-hack'

gem "zurb-foundation", "4.2.3"

# https://devcenter.heroku.com/articles/rails4-getting-started#local-workstation-setup
gem 'rails_12factor', group: :production

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '4.0.0'

# Use Postgres as database, so Rails needs pg gem:
gem 'pg','0.15.1'

# Use SCSS for stylesheets
gem 'sass-rails', '~> 4.0.0'

# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'

# Use CoffeeScript for .js.coffee assets and views
gem 'coffee-rails', '~> 4.0.0'

# See https://github.com/sstephenson/execjs#readme for more supported runtimes
gem 'therubyracer', platforms: :ruby

# Use jquery as the JavaScript library
gem 'jquery-rails'

# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
gem 'turbolinks'

# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 1.2'

group :doc do
  # bundle exec rake doc:rails generates the API under doc/api.
  gem 'sdoc', require: false
end

# Use ActiveModel has_secure_password
# gem 'bcrypt-ruby', '~> 3.0.0'

# Use unicorn as the app server
# gem 'unicorn'

# Use Capistrano for deployment
# gem 'capistrano', group: :development

# Use debugger
# gem 'debugger', group: [:development, :test]


Question: What is a gem?

Answer: A gem is a software component for Ruby software. When you work with Rails you frequently encounter gems. The shell command you use to copy a gem from rubygems.org is 'gem'. Additionally, gem is a declaration in a Rails-Gemfile. So the term, gem, is used at least three different ways.

If you are new to Rails, think of the Gemfile as a list of gems which the Rails site depends upon. If the site has fewer gems that is usually better. On the other hand, gems allow me to extend the abilities of my sites using reusable blocks of code written by developers who have more time and/or talent than I have.

After I edited the Gemfile, I used a shell command to transform the human-readable Gemfile into Gemfile.lock which is something useful for the Rails framework but less human-readable:

bikle@z5 ~/biklecom $ mkdir scripts/
bikle@z5 ~/biklecom $ mv bin/bundle scripts/
bikle@z5 ~/biklecom $ mv bin/rails  scripts/
bikle@z5 ~/biklecom $ mv bin/rake   scripts/
bikle@z5 ~/biklecom $ bundle install --binstubs


Notice that I passed '--binstubs' option to the shell command. Many Rails developers don't use '--binstubs' but I find the result to be convenient. That option creates a directory named bin and fills it with stubs which act as useful shell commands like html2haml.

Note that in Rails 4, the bin directory is already there and populated with three files: bundle, rails, rake. I prefer those files to reside in a directory named scripts so I move them to scripts before I run bundle install. Now, if I want to issue the html2haml-shell command I can do so via 'bin/html2haml' and I can be assured that I'm calling a command which is appropriate for this situation. I'm not calling an inappropriate command which has an early position in my $PATH.

If you are new to Rails, you can read more about the bundle-shell command at this URL:
http://railscasts.com/episodes/201-bundler?view=asciicast

Database/Heroku

Next I blanked out the username field in database.yml, and then I used shell commands to help my site find its database:

bikle@z5 ~/biklecom $ bin/rake db:create
bikle@z5 ~/biklecom $ bin/rake db:migrate


If you are new to Rails, you can read more about the rake-shell command at this URL:
http://guides.rubyonrails.org/command_line.html#rake

With a new site, I try to establish database connectivity as soon as possible. If I encounter database problems I like to uncover them early in the process. With that thought in mind I worked towards deploying my new Rails site to Heroku. My intent here is to see if I encounter any database connectivity problems inside Heroku.

If you are new to Heroku, perhaps this page will help you understand how to deploy a Rails site to Heroku: https://devcenter.heroku.com/articles/git

When I deploy a Rails site to Heroku I follow this checklist:

  • Create a Rails site in my laptop or desktop
  • Commit it to a local git repo
  • Create a Heroku account via: https://api.heroku.com/signup/devcenter
  • Download the Heroku-toolbelt
  • Use the toolbelt to create a blank app on Heroku
  • Use git to push my local Rails site into the blank app
  • Use the toolbelt to connect my Rails site on Heroku to its database
  • Use a browser to see if my Rails site is up on Heroku
  • Use the toolbelt and stackoverflow.com to troubleshoot problems

After I verifed that my site was behaving well on heroku, I returned to studying this page: http://foundation.zurb.com/docs/rails.html

Rails Generator

Next, I ran one shell command:

bikle@z5 ~/biklecom $ script/rails g foundation:install


If you are new to Rails, 'script/rails g' is a shell command I call the Rails Generator:
http://guides.rubyonrails.org/command_line.html#rails-generate

Anyway what is going on here is that the ZURB-people are asking me to install some ZURB related files into my Rails site using the Rails Generator.

One of the files is the 'layout':

app/views/layouts/application.html.erb

If you are new to Rails, the layout is a type of file which acts like a picture frame. The content inside the frame frequently changes but the frame stays the same. You see this behavior in most websites.

Next I created a 'route' in my new Rails site. If you are new to Rails, think of a route as a path you are allowed to type into the browser URL field. The route I created was this: /blog/index

I used a Rails Generator shell command to create my route:

bikle@z5 ~/biklecom $ script/rails g controller blog index


In addition to my route, the Rails Generator created a Ruby class called the BlogController. If you are new to Rails you can read about controllers here: http://guides.rubyonrails.org/action_controller_overview.html

I sometimes think of a controller as the 'destination' of a route. For example if I type http://ibm.com/jobs into a browser, I expect the route, /jobs, to connect my browser to some software (a controller) which has access to a database full of IBM jobs.

After I generated both the route and controller, I created a layout for them with a simple shell command:

bikle@z5 ~/biklecom $ cp app/views/layouts/application.html.erb app/views/layouts/blog.html.erb


Rails Server

Next, I did 2 things to test this route and controller in my dev-env.

First, I started my Rails Webserver:

bikle@z5 ~/biklecom $ script/rails s -p 3334


Then I loaded this URL into a browser running on the same host as the Webserver

http://localhost:3334/blog/index/


The browser rendered some HTML and the shell-window which was running the Rails Webserver on port 3334 issued no errors. Also I used view-source in the browser to verify that the layout supplied by the ZURB people was getting served to my browser from the Rails Webserver.

So, I deployed the site to Heroku and used my browser to verify that my site behaved well in that environment.

ZURB Templates

I found ZURB Templates at this URL:
http://foundation.zurb.com/templates.php

The above page suggests you download any template by pressing option/alt

I have both a standard keyboard and a laptop keyboard in front of me now. Neither has an option key. Maybe the option key is Mac-only.

Anyway, the page you are currently reading uses the 'Blog' template:
http://foundation.zurb.com/page-templates/blog.html

I used view-source in my browser to study the HTML in the above Blog-template.

In order to use this template in my Rails site, I needed to categorize HTML in the template into two types. The first type of HTML is used to render content which is relatively static. For example, the links across the top of this page are relatively static. Often content like this does not change when you navigate to various pages in a site. I see this type of content as being like a picture frame. The second type of HTML is used to render content which is relatively dynamic. For example the sentence you are reading now is relatively dynamic since you would expect it to change if you navigated to another page in bikle.com.

As a Rails developer I put relatively static HTML in a layout file. The layout file for the page you are currently reading resides at this location: app/views/layouts/blog.html.erb

And the file which contains the dynamic content you are currently reading is in this directory: app/views/blog/

Question: How is blog.html.erb related to application.html.erb?

Answer: blog.html.erb is the layout file for the blog controller. application.html.erb is the default layout file for any controller which has no layout file. So, if bikle.com is a simple site with one controller, I could remove blog.html.erb and place all my layout-syntax in application.html.erb.

Question: How does Rails combine the static and dynamic content so that it appears as a single page in your browser?

Answer: I sprinkle lines of ERB syntax at various locations in the static content which tells Rails, "Put some dynamic content here."

Question: Why is Rails designed this way?

Answer: Only the static content "knows" the relative locations of elements which make up the single page served to the browser.

CSS

According to the Zurb documentation, I should see a file named scss/app.scss

The Rails-Zurb-generator failed to install it so I used the app/assets/stylesheets/blog.css.scss file to enhance the CSS. Rails had created this file when I generated the blog-controller.

I consider the default Zurb-font to be too small. Also I inspected it with Firebug and found it to be '#222222' which is dark-grey. I added these lines to blog.css.scss:


// Default font too light and small.
// Make it bigger and darker.
article p {
  font-size: 1.2em;
  color: black;
}


Next I enhanced the screendumps. I want the text in them to be easy to read yet starkly different than the text you are now reading:


/* These declarations are mostly used in my blog to style code in screen dumps */
pre { 
  font-weight: 600;
  font-family: monospace,"Courier New",Terminal;
  font-size: 18px; 
  border-top: 1px solid black;
  border-left: 1px solid black;
  border-bottom: 1px solid black;
  background-color: #FFFFFF;
}


Then, I enhanced the links. I inspected default color of the Zurb-links and found it to have this value: '#2BA6CB' which is a light-blue. Aesthetically nice but not conforment with my rules-for-links:

  • A link should obviously look like a link
  • Link text should be underline-decorated
  • Link text should be heavy
  • Link text should be different color than surrounding content
  • Hovering link should change the color of link text
  • Hovering link should change the color of link background

If possible:

  • A link should be a shade of blue
  • Hovering a link should change the color to red
  • Hovering link should change the background to light-grey

So, I coded up this CSS for the links:


// Links should look and act like links
a, a:visited {
  color: #0000BB;
  text-decoration: underline;
  font-weight: 600;
}
a:hover { background-color: #EEEEEE; color: #BB0000; }

Summary

That wraps up this blog-post:

  • Foundation by ZURB
  • Twitter Bootstrap
  • Linux vs Mac
  • Ruby
  • Postgres
  • Rails
  • Gemfile
  • Database/Heroku
  • Rails Generator
  • Rails Server
  • ZURB Templates
  • 'Blog' Template
  • Cleave 'Blog' Template
  • CSS