Navigation bar About Projects Clients Contact Blog

Author Archive

CSS3 and Graceful Degradation

posted August 20th, 2010 by ClaraClara

While we’ve previously discussed issues of browser compatibility in terms of trying to make websites look identical in all popular browsers, this isn’t the best strategy in 100% of cases. Web design is exciting partly because unlike print design, it’s not just a static image in a known medium — websites will be viewed from all kinds of browsers and devices, interacted with, resized, searched, downloaded, and printed. So rather than striving for pixel-perfect control over the display of every site, we sometimes work for a different but still positive experience with each browser instead of an identical experience.

One great example of this is features supported by CSS3. The CSS3 specification is still under development by the W3C. But a lot of modern browsers support some or all of its features. We take advantage of this by writing code that creates fancy visual effects — like custom fonts, rounded corners, and drop shadows — for users whose browsers support these features, but degrades gracefully into a simpler display for users with older browsers. This enables us to create simple, search-engine-friendly markup for everyone and display these visual features to some without adding a lot of cruft to the code — and then, as users upgrade, more and more of them will be able to see our visual effects!

Here we show a few popular CSS3 features and how they display on different browsers. In some cases, the feature in its standard form doesn’t work in some browsers, but the browsers have implemented proprietary versions of the feature with the same functionality — in that case, we just list both the standard features (for browsers that support it, and browsers of the future that will support it) and the proprietary versions in our stylesheet.

For our sample here, we’re trying to display an h2 heading in a custom font, with a drop shadow, and we want our text box to have rounded corners on just the top left and bottom right corners. We’ll use the text-shadow and border-radius properties for the drop shadow and rounded corners.

For a custom font, things are a little bit more complicated. Using the @font-face declaration, we’re able to embed our font in the webpage and then simply use the font-family property on our h2 as usual. The drawbacks of this method are that the custom font won’t display for users of older browsers, and that the font’s licence has to allow embedding (in this case, we got it from FontSquirrel, a great resource that publishes free fonts licensed for commercial use and keeps track of which licenses allow embedding and thus can be used with @font-face). When it’s important that the same font display even for users of older browsers, and the font’s license allows embedding, we like to use Cufon (a JavaScript-based solution); when the font’s license doesn’t allow embedding, we use the Flash-based sIFR solution.

Our HTML is simple:

<h2>Hello World</h2>
<div class="rounded-box">
Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
</div>

And then with CSS, we load the embedded font with the initial @font-face declaration, and use both standard and proprietary attributes to describe the rounded corners to the browser:

h2, .rounded-box { font-family: sans-serif; }

@font-face {
font-family: 'HeavyDataRegular';
src: url('heavy_data-webfont.eot');
src: local('☺'), url('heavy_data-webfont.woff') format('woff'), url('heavy_data-webfont.ttf') format('truetype'), url('heavy_data-webfont.svg#webfontPAbKscLj') fo\
rmat('svg');
font-weight: normal;
font-style: normal;
}

h2 { color: #00c; text-shadow: 2px 2px 2px #222; font-family: 'HeavyDataRegular'; font-size: 50px; }
.rounded-box {
-moz-border-radius-topleft: 15px;
-moz-border-radius-bottomright: 15px;
-webkit-border-top-left-radius: 15px;
-webkit-border-bottom-right-radius: 15px;
border-top-left-radius: 15px;
border-bottom-right-radius: 15px;
-moz-box-shadow: 6px 6px 5px #222;
-webkit-box-shadow: 6px 6px 5px #222;
box-shadow: 10px 10px 5px #222;

background: #00cc00;
padding: 10px;
width: 500px;
}

The HTML and CSS don’t change at all between browsers, but how much of the visual effects a user can see depends on their browser.

  • Users with the oldest browsers don’t see any of the effects (shown: Opera 8):

    opera8

  • In Firefox 2, users see the rounded corners, but not the drop shadow or custom font:

    ff2

  • In all recent versions of IE (shown: IE8), users see the custom font, but not the rounded corners or the drop shadow. (IE9 plans to support these attributes.)

    ie8

  • In the most recent versions of browsers like Firefox (shown: Firefox 3.6), Safari, Opera, and Safari derivatives like Chrome, users can see all the features — and as browsers continue to update, more and more users will see these effects without any changes to our code.

    ff3.6

And, here’s what it looks like in your browser!

Using Searchlogic to Simplify Rails Search

posted November 23rd, 2009 by ClaraClara

We’ve been working on a new social networking site, and I’ve been integrating Searchlogic for the first time to help make searching for users and posts easier. I saw Searchlogic’s creator give a presentation at a Boston Ruby meetup, and I was pretty psyched to learn about the existence of this simple way to keep the code for this common task clean and DRY.

First, we needed a way for visitors to search for user profiles simply by the fields that are in the database. Easy! Searchlogic has this built-in.

In the view:

<% form_for @search, :html => {:method => 'post'} do |f| %>
Username: <%= f.text_field :login_like %>
First Name: <%= f.text_field :first_name_like %>
Last Name: <%= f.text_field :last_name_like %>
Bio: <%= f.text_field :bio_like %>
Career: <%= f.text_field :career_like %>
Education: <%= f.text_field :education_like %>
<%= submit_tag 'search' %>
<% end %>

And in the controller, where the real savings happens:

if request.post?
 @search = User.search(params[:search])
 @users = @search.all
else
 @search = User.search
end

Searching on all the user’s fields, with just a couple lines of code!

In searching posts, we needed some slightly more complicated searches; we’re using acts_as_taggable_on_steroids and wanted users to be able to search for posts with particular tags, and we also wanted a way to use the post’s belongs_to association to allow users to search for posts entered by a particular user. Since Searchlogic allows us to define our own named scopes, we just need to add a couple of lines to the model to be ready to use the same tricks we used searching on database fields:

named_scope :has_tags, lambda {  |tags|
    Post.find_options_for_find_tagged_with(tags, :match_all => true)
  }
named_scope :poster_login_like, lambda { |c| { :joins => ["LEFT OUTER JOIN users ON (users.id = posts.poster_id)"], :conditions => ['users.login LIKE ?', c]
  }}

We also wanted searching for post content to include a search of the post body. So the view looks like this:

<% form_for @search, :html => {:method => 'post'} do |f| %>
Containing:  <%= f.text_field :content_like %></p>
<p>Tagged with: <%= f.text_field :has_tags %></p>
<p>By Username: <%= f.text_field :poster_login_like %></p>
<%= submit_tag 'search' %>
<% end %>

And the controller has the same super-simple:

    if request.post?
      @search = Post.search(params[:search])
      @posts = @search.all
    else
      @search = Post.search
    end

This is one of the things I love about working with Rails — thanks to all the great gems and plugins out there, we can do complex stuff with just a few lines of code rather than re-inventing the wheel.