Releasing IQ::Color

At SonicIQ we have a number of RubyGems used internally that we haven’t found time to open-source yet i.e. cleanup the documentation and get into state that people can find useful. I’m going to make it my mission to get some of these out there which first involves releasing some of the smaller Gems that the larger ones depend on.

IQ::Color is a really simple Gem for converting colour values to and from CSS(3) notation, this is used by a couple of our larger Gems but I can see it being of use on it’s own. A simple example:


color1 = IQ::Color.RGB.new(127, 127, 255)
color1.to_css #=> "#7f7fff"

color2 = IQ::Color.from_css('rgba(127,127,255,0.4)')
color2.red    #=> 127
color2.green  #=> 127
color2.blue   #=> 255
color2.alpha  #=> 0.4
color2.to_css #=> "rgba(127,127,255,0.4)"

More examples can be found on GitHub.

Fixing {{model}} placeholders in Rails 2.3 when Rails 3 is installed

This was causing me all kinds of grief. I am running Rails 2.3 and Rails 3 apps on the same server and on installing Rails 3, the Rails 2.3 apps started displaying {{model}} and similar strings in views.

It turns out that Rails 3 uses i18n version 0.5.0 and with this version as far as I can see, the placeholder text in translations follow the %{text} format instead of the {{text}} format in 0.4.2 which Rails 2.3 was using. The only way I found to fix this was to declare the specific i18n version before the Rails gem gets required in the “load_rails_gem” method of “config/boot.rb” in my Rails 2.3 apps:


def load_rails_gem
  gem 'i18n', '0.4.2' # Add this line

  if version...
end

Doing this specifies that we want i18n 0.4.2 exactly, whereas Rails 2.3 specifies version “>= 0.1.3″ which would obviously includes “0.5.0”.

In running Rails 2.3 and Rails 3 apps side by side, I also ran into this problem and overcame it with the fixes by “bct” and “ronin-95281” in the comments… apparently Rails Core won’t fix this.

If anyone else has a cleaner fix for this I would love to hear about it.

Completely Flattening a Git Repository

Whilst working on a recent project, I ended up with a massive git repository due to frequent commits of large-ish files. As I was the only one working on the project and I was certain I didn’t need anything from the history, I wanted to be able to flatten all the commits in the repository.

I didn’t find exactly what I was after but found a handy tip on Stack Overflow. In essence you re-initialize your local repository and force a push to your remote. A word of warning, if you have anyone else pulling or pushing to the remote repository, they will hate you for this as it will completely screw up any revision history or branches they may be working on.

Here’s my modified version of the tip on Stack Overflow to take into account .gitignore and removing the existing .git repository:


$ cd {{project-directory}}
$ rm -rf .git
$ git init
$ git add .
$ git commit -m 'Initial commit'
$ git remote add origin {{url}}
$ git push --force

p.s. Don’t say I didn’t warn you!

Ruby Causing MacBook Pro to Run Hot

The past couple of days the fan on my MacBook Pro has been constantly on and battery usage down to around a third. Launching Activity Monitor, it showed 3 Ruby processes all at 100% CPU usage. The solution was to force quit these processes and within seconds, the fan slowed up and the battery indicator went up. Force quitting these processes didn’t affect anything I was doing with Rails or IRB so I guess they were just stray processes.

If anyone else gets the same problem, just launch Activity Monitor which lives in the /Applications/Utilities folder, click the CPU tab if not already selected, select processes with a process name of “ruby”, click “Quit Process” and then select “Force Quit”. Just selecting “Quit” wouldn’t work for me hence the “Force Quit”.

I hope this saves someone else the head-scratching as to why their Mac is running hot.

Using Artifice to Stub Server Responses

In a recent project I needed a way to fake a response from a server in my Cucumber features. Specifically, I was testing integration with a payment gateway and wanted to stub it’s responses based on different requests.

In the past I have used FakeWeb, however it becomes a little hairy when you need to stub a response based on request body. I came across a couple of alternatives, firstly WebMock which looks promising but then Artifice from the mighty Yehuda Katz caught my eye…

Artifice lets you “replace the Net::HTTP subsystem of Ruby with an equivalent that routes all requests to a Rack application”. I like the simplicity of this solution as you can in essence use a Rack application to replace the responses of the service you are testing.

An Example

First we create a simple Rack application to stand in for the server we are interacting with.


app = proc do |env|
  [200, { "Content-Type"  => "text/html" },
    ["Hello world: #{env.inspect}"]
  ]
end

Then we simply use Artifice’s “activate_with” method to wrap any requests.


Artifice.activate_with(app) do
  response = Net::HTTP.start("google.com") do |http|
    http.post("/the_url", "foo=bar")
  end
  puts response.body
end

This allows for a Rack app to be used as a stand in for a complete API, it could be a Sinatra app for example allowing for easy route handling. We could go so far as to have a series of Rack apps that can be used as stand-ins for common API’s.

The Solution to Fluid Inconsistencies and Equal Height Columns (revisited)

This is a follow on from my previous article on fluid equal height columns, please consider reading this first if you are interested on how I arrived at this solution.

I have been happily using both techniques in my previous article, however was not happy with the use of CSS expressions in the equal height solution. Paul O’Brien noted that my technique suffered the same problem as the One True Layout solution, so unless you need to link to anchors in a column, the old technique seems to be the cleanest. I very rarely have the need to link to anchors except for say comments in a blog, in which case a simpler two column solution or the use of javascript may be more applicable.

So mixing together my fix for fluid inconsistencies and the One True Layout solution for equal height columns, we end up with this:


.content        { overflow: hidden; position: relative; background: #f5f5f5;
                  height: 1%; /* IE6 hasLayout */ }
.content div    { float: left; position: relative; margin-left: -100%; width: 8.333%; padding-right: 1px;
                  padding-bottom: 32767px; margin-bottom: -32767px; /* Equal height columns */ }
                
.content .col3  { left: 100%;     background: #eee; z-index: 1; }
.content .col2  { left: 108.333%; background: #ddd; z-index: 2; }
.content .col1  { left: 116.666%; background: #ccc; z-index: 3; }
etc...

Notice the “padding-right: 1px;” on the columns, this will not be seen in most cases due to the column z-ordering but stops unsightly gaps caused by rounding.

View final example.

So this is a marriage of an old technique for equal height columns and a new technique for flexible column positioning. We are using no CSS hacks and it will work in Safari, Chrome, Firefox, and IE back to version 6

I will continue my search for a solution to the age old anchor problem and in the meantime, any suggestions are most welcome.

The Solution to Fluid Inconsistencies and Equal Height Columns

Update: There is a follow up article to this one addressing issues raised in the comments.

An introduction

Being an early adopter of Web Standards back in 2001 and thanks to Jeffrey Zeldman’s Designing with Web Standards released in 2003, I strived for a life without tables and 1 pixel shims and instead one filled with semantic markup and a clean separation of content from presentation. Early on in the transition to Web Standards came frustration, the things we used to do with tables without batting an eyelid became a series of CSS hacks and erroneous markup.

To this day there are two core concepts which still make us standards freaks wince. The first is equal height columns and the second is percentage width consistency across browsers. Chris Coyier of CSS Tricks recently rounded up the current solutions for Fluid Width Equal Height Columns but all have their limitations. We have a new flexible box model in CSS3, however it will be a number of years before we can use this in practice due to the slow uptake of new browsers.

A couple of weeks ago, I decided that enough was enough and that it was time to sit down and come up with a solid answer to the problem. Combining a number of CSS tricks that I have amassed over my years in the industry, I have come up with what I believe to be a solution.

Fluid Inconsistencies

Just today I read a post by Steffan Williams on his frustrations with “Fluid Inconsistencies“, so I will address this first.

As documented by John Resig, the reason for inconsistencies with percentage widths comes down to the fact that different browsers round in different ways. Webkit rounds down to the nearest pixel, IE rounds up and Firefox does a bit of both in order to spread the difference across the containing element.

Surprisingly, Webkit’s rounding causes me the biggest problem. As an example, lets say we have 12 equal width columns butted up together. When the container is at 800 pixel in width, in an ideal world each column would be 66.666 pixels, the problem being that there is no such thing as a fraction of a pixel, so Webkit rounds each column down to 66 pixels. This gives a total width of 792 pixels meaning there is a gap of 8 pixels between the right of the container and the right of the last column.

So what are our options? Absolute positioning could work as we would manually set the left edge of each column, negating the cumulative rounding problem. The obvious problem is that absolute positioning would take the columns out of the flow of the document meaning we couldn’t have anything below them and they wouldn’t force their container to grow. What we need is absolute positioning only on the x axis so that we can position each column a specific distance from the left edge. We can achieve this effect with a bit of css trickery…

Absolute positioning only on the x axis

To simulate absolute positioning on just the x axis, we will combine floats, negative margins and relative positioning. Relative positioning is like absolute positioning in that you can specify a left and top value, however it differs in that the element is positioned relative to where it would have been without relative positioning. If we could just get all the columns to start at the same x position, we could use relative positioning from there to shift the columns into the correct positions.

Given the following markup and bearing in mind that you should normally use semantic class names instead of col1, col2 etc.


<div class="content">
  <div class="col1"><p>I am column 1</p></div>
  <div class="col2"><p>I am column 2</p></div>
  <div class="col3"><p>I am column 3</p></div>
  etc...
</div>

I turns out that with the use of floats and negative margins we can get all the columns positioned at the same starting x position.


.content        { position: relative; overflow: hidden; background: #f5f5f5; }
.content div    { float: left; margin-left: -100%; position: relative; width: 8.333%; }

Note the “overflow: hidden;” on the container, this serves two purposes. The first is to ensure it expands to the height of the tallest float (a simple clearfix), the second is so that IE, who we have established rounds up, doesn’t overlap the right edge of the container. Also note that the column width is set to 8.333% (100% ÷ 12).

At this stage we have all columns stacked on top of each other and positioned at -100%. The reason that they are now all in the same place is that when the first element is shifted to the left by 100% (due to the negative margin), the second element’s x coordinate is now 0, it in turn gets shifted left by 100% and so on.

This leaves us in a great position (pardon the pun) as we can now position the columns anywhere horizontally by just adding 100% to the desired x position.


.content .col1   { left: 100%;     background: #eee; }
.content .col2   { left: 108.333%; background: #ddd; }
.content .col3   { left: 116.666%; background: #ccc; }
.content .col4   { left: 124.999%; background: #bbb; }
etc...

View example 1

The real beauty of this technique is that the column order is independent of the order they appear in the markup. You can swap 1 with 3, 9 with 2 etc. you can even span multiple columns by doubling the width. Below is an example of changing the column order.


.content .col3   { left: 100%;     background: #eee; }
.content .col2   { left: 108.333%; background: #ddd; }
.content .col1   { left: 116.666%; background: #ccc; }
.content .col4   { left: 124.999%; background: #bbb; }
etc...

Notice how all we have done here is change the class names around.

View example 2

So there you have it, we have addressed the “Fluid Inconsistencies” problem and it works in Safari, Chrome, Firefox and right the way back to IE6. The keen eyed among you will have noticed the occasional 1 pixel gap between the columns on scaling the browser window, I will address this in the next section.

Equal Height Columns

This has long been a subject for debate and is a hot topic for the “Just Use Tables!” clan. Something caught my eye when reading Chris Coyier’s Fluid Width Equal Height Columns and that was the “Nicolas Gallagher Method”. He basically uses “:before” and “:after” pseudo selectors to add blank content to the container element which can then be styled, pure genius. The only downside to his technique however, is that you are limited to 3 equal height columns.

Based on Nicolas’s method, I found that it was possible to add “:after” pseudo selectors to the columns themselves to achieve the effect of equal height columns. The benefit of this is that we can tell the styled content to inherit the background properties of it’s parent element. This way you only have to style the column itself and all will be inherited correctly.

So how do we do it I hear you shout! Well it’s almost disappointingly simple, I will show the code and then explain what is going on.


.content            { z-index: 1; }
.content div:after  { content: ""; position: absolute; z-index: -1; background: inherit;
                      left: 0; top: 0; right: -1px; bottom: -9999px; }

As with Nicolas’s method, we setup an “:after” with blank content, position it absolutely and set it’s z-index to -1 so that it appears under the column element who’s z-index is 1. The difference comes with the actual positioning. As our column is positioned relatively, we set it’s left and top to 0 so that the top left corner matches that of the column. We set the the right to -1px to solve the occasional gap between columns as promised. The bottom value is where the magic happens, we set it to -9999px. This makes it drop way below the bottom of the column and as long as the difference in height between the tallest and shortest columns is less than that value, you are fine, a pretty safe bet I would say.

View example 3

And that’s it, equal height columns with flexible widths. We could end here, as everything works in Safari, Chrome, Firefox and IE9. In IE8 and below, the page will degrade gracefully and just not have equal height columns. We can however add IE 6/7/8 support using CSS expressions and I would recommend including the fixes with conditional comments should you need to support these versions.

Fixing Internet Explorer IE6/7/8


/* IE 6/7/8 fixes */
* html .content { height: 1%; /* IE6 hasLayout */ }
.content div    { clear: expression(innerHTML += '<u class="ieafter"></u>', style.clear = 'none', 0); }
.ieafter        { width: expression(parseInt(parentNode.offsetWidth) + 1 + 'px');
                  height: expression(parseInt(parentNode.parentNode.offsetHeight) + 'px');
                  background-color: expression(parentNode.currentStyle.backgroundColor);
                  background-image: expression(parentNode.currentStyle.backgroundImage);
                  background-repeat: expression(parentNode.currentStyle.backgroundRepeat);
                  background-position: expression(parentNode.currentStyle.backgroundPosition); }

View example 4

Things to consider

When using this method, if you need padding on columns, I would suggest adding it to an element within the column as opposed to the column itself as otherwise Webkit has two more opportunities to round down (one for the left padding and one for the right). If you really need to add padding to the columns themselves then you may want to add the following Webkit fix.


/* If we have left and right padding on columns, Safari has 2 more opportunities to round down so compensate here */
@media screen and (-webkit-min-device-pixel-ratio:0) { .content div:after { right: -3px; } } 

Something else to consider is explicitly setting the z-index for each column in order from left to right as the additional width we are giving our “:after” content has the potential to overlay the next column. With the z-indexes it looks like this:


.content .col3  { left: 100%;     background: #eee; z-index: 1; }
.content .col2  { left: 108.333%; background: #ddd; z-index: 2; }
.content .col1  { left: 116.666%; background: #ccc; z-index: 3; }
etc...

View example 5

You will notice in my examples I have used divs. These can be easily substituted for more semantic HTML5 elements such as “section” but I wanted to keep the examples simple without the need for HTML5 shivs etc. My use of ‘col1, col2′ etc. class names are purely for this example, you should use more semantic class names in real development.

I hope you like my new technique, feel free to leave a comment with any questions.

Acknowledgements

Update 08/12/10: As pointed out by Paul O’Brien in the comments, the equal height column technique shown here suffers the same side effect as the One True Layout solution, in that if you have a link to an anchor in a column, that column will scroll when the link is clicked. If you need to link to anchors in your columns, this may not be the best technique and the only other option without adding additional markup is to equalise the column height with javascript. The only benefit of this technique over the One True Layout option is that it fixes gaps between columns. I will continue my search for a solution to the anchor issue.

Super simple jQuery templating

Working with jQuery, it is common to find yourself needing some kind of templating solution. There are plenty out there, however sometimes the use-case is simple enough that you don’t really need a fully blow templating plugin.

We’ll take a task list as an example (just to be original). Lets say you have the following task objects in an array:


var tasks = [
  { id: 1, name: 'A todo item' },
  { id: 2, name: 'Another todo' }
];

Now you want to display them in an unordered list with checkboxes etc. What I like to do is create a ‘templates’ object, which contains my basic templates:


var templates = {
  taskList: $('<ul class="task-list">'),
  taskItem: $('<li><input type="checkbox" /> <span /></li>')
}

With these templates in place, it’s a simple case of cloning them when required and inserting the relevant data. jQuery’s ‘text‘ and ‘attr‘ methods are ideal for this as they handle the escaping of html entities. Based on this we can iterate over our tasks array and insert the relevant items in the dom:


var list = templates.taskList.clone();
$.each(tasks, function() {
  templates.taskItem.clone()
    .attr('id', this.id)
    .find('span').text(this.name).end();
  list.append();
});

$('body').append(list);

And that’s it, by using jQuery’s ‘text‘ and ‘attr‘ functions, you have complete control over your templates, without having to remember to escape html. Your templates can be stored away in an external javascript file and everyone’s happy.

Mobile Safari text sizing woes.

Update: Modified code to use technique mentioned here.

For a while I’ve been frustrated by a rendering issue in Mobile Safari. It commonly happens in footers whereby the text gets rendered bigger than specified.

It turns out after some googling, the solution is quite simple. Using the following, Mobile Safari should leave your font sizing alone.


html { -webkit-text-size-adjust: 100%; }

Source: http://website-engineering.blogspot.com/2009/07/stop-adjusting-text-size-in-iphone-when.html