Egil Hansen's dot com

Software engineering, web design, Drupal, .net

Get background image to resize with browser window using CSS and jQuery

Using a photo as a background for a web page can look pretty good, but making that photo fill out the entire browser window no matter its size and proportions is not straight forward, if you also want to keep the photo in its original aspect ratio. Not clear what I mean – check out the demo page to see the effect in action (try resizing it).

Some of the new CSS3 tricks come pretty close, but they still seem to lack the ability to let the user expand the browser window in any direction and also keep the photos aspect ratio. If we also want a solution that works with older browsers (e.g. IE7/IE8), we need to go a different route.

jQuery to the rescue

First let’s add the HTML to our page that will display the photo. The HTML can be placed anywhere inside your pages body tags, but I recommend putting it at the very bottom to keep it out of the way. Make sure to update the src attribute to point to the photo you want as your background.

<div id="bgimgwrapper">
    <img alt="" src="photo.jpg" id="bgimg" style="width: 100%;" />
</div>

Next we need to add the following CSS to our stylesheet. This code will fix the bgimg to the page (position: fixed;), and make sure it is positioned behind everything else on the page (z-index: -1;).

#bgimgwrapper {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  z-index: -1;
  overflow: hidden;
}

#bgimg { 
  display: block; 
  -ms-interpolation-mode: bicubic; 
}

Last we need the following JavaScript added to our page. The script makes sure the photo resizes itself properly when the browser window is resized, while keeping its original aspect ratio intact. To make the script run a little faster, we only update the #bgimg DOM element when we absolutely have to, which is when we switch between having the image expand in height or width.

(function($){
  var pr = 0, bgWidth = true, bgResize;

  bgResize = function(){
    var wr = $(window).width() / $(window).height();

    if(wr > pr && !bgWidth) {
      $('#bgimg').css('width', '100%').css('height', '');
      bgWidth = true;
    } else if(wr < pr && bgWidth) {
      $('#bgimg').css('height', '100%').css('width', '');
      bgWidth = false;
    }
  };

  $(document).ready(function() {
    var img = $('#bgimg');
    if(img.height()) {
      pr = $('#bgimg').width() / $('#bgimg').height();
      bgResize();
    } else {
      img.load(function(){
        pr = $('#bgimg').width() / $('#bgimg').height();
        bgResize();
      });
    }

    $(window).resize(bgResize);
    prettyPrint();
  });
})(jQuery);

If anybody has a way to improve on this, please post a comment. As far as I can see the code is pretty robust, but I have only tested in Chrome, Internet Explorer [7|8|9], Firefox 6, and Safari 5.1, so there might be issues I am not aware of.

Go to the demo page check out the finished result.

CSS trick: Semi transparent CSS background that works in all browsers

This simple CSS class will create a semi transparent background, letting whatever is underneath the element shine through. It works across all browsers, that means Internet Explorer 6.0 as well. The newest browsers will use the background:rgba(0,0,0,.75); setting, the rest (IE6-IE8) will use the gradiant filter to achieve the same effect.

.black {
    background:rgb(0,0,0);
    background:rgba(0,0,0,.75);
    *background:transparent;
    *filter:progid:DXImageTransform.Microsoft.gradient(startColorStr=#BF000000,endColorStr=#BF000000);
    *-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorstr=#BF000000,endColorstr=#BF000000)";
}

If you want to change the transparency level, you have to adjust both the RGBA values and the color values in the gradient filters. For example will background:rgba(0,0,0,.4); and #6F000000 make elements more transparent.

For more opacity/rgba tricks, take a look at the article CSS Opacity: A Comprehensive Reference over at Impressive Webs. The code snippet above was originally found on pastie.org, all credit to the person who posted it there.

Design by Contract should become this decades TDD

I am currently taking CSE 218 at UCSD, “Advanced Topics in Software Engineering - Methods and Tools for Software Modularity”, where we recently read the paper “Applying ‘Design by Contract’” by Bertrand Meyer. I already knew a little about the concept, and after reading that paper and playing with the concept in a micro project, I am sold. I really think Design by Contract has a chance at being this decades TDD. It is pretty clear to me why it is a good idea to do “Contract First” development. Let me try to explain why.

For me, at least, when developing a new class or module, no matter if there is a detailed interface contract or design document in place or I am gong-ho-agile-styling it, it is an iterative process, where I add one bit of functionality after the other as I go. Most of the time, unless it’s just a simple utility library, there is state involved, and at the time I add the local variable to hold a state, I also find myself trying to restrict that variable as much as possible with various parameters, modifiers, checks, encapsulation, etc., to prevent the state of the object from going bad. That process of preventing bad state never really stops until all functionality that deals with that state is added, which is tedious and error prone.

Enter code contracts. When I declare my local state variable, I also declare my class invariants for it, in the same way we create unit tests to verify our code, before I start adding functionality to manipulate the state. The benefits are obvious to me:

  • With good tooling, I get compile time suggestions about what methods and properties might break my invariants as I continue to develop my class.
  • The maintainability of my code just sky-rocked. Another developer can pick up the code and do his modifications, without worry that he might break an implicit contract.
  • The code that is much more self-documenting. Again, with proper tooling, contracts can be extracted and presented to the users, there is basically no hidden information left in the code anymore (e.g. comments like “// must not be zero!”). And documentation doesn’t become stale.

The downside is that you have to define those invariants (and requires/ensures), just like you have to create your tests in TDD.

Several things were brought up in the discussion in class. Somebody asked why this is not more widely used in the industry. I think the answer is that tooling for the most widely used languages (C, C++, Java, C#) are just starting to get there. The amazing thing is that, compared to TDD, the benefits of the effort of adding contracts to our code will continue to grow as new tools become available. Automated bug finding tools would probably be much better if they could also consider contracts. I can also see tools for finding security vulnerabilities reaching a higher level, being able to detect more complex security exploits, with less false positives, if they could draw on contracts to do their analysis. And when a updated or new tools is available, we can just run the tool on our existing code and instantly get the benefits it provides.

It was also mentioned by somebody with personal experience that it is hard to add contract to existing systems, and I can indeed imagine it being very hard to an existing codebase, especially one that is large and complex. It is probably, just like with unit tests, much harder to add contracts as an afterthought than it is to do it up front, so contracts might be too costly to add to existing systems. For new systems, it is hard for me to argue against design by contracts.

For more info and links to tools (I played with Code Contracts from Microsoft), I recommend the Design by Contracts page on Wikipedia.

Why platforms should be the pillar of every product

A few days ago Googler Steve Yegge accidently posted an internal memo to the world about Google’s struggles with building products. As embarrassing for Steve as it might have been (it has now been taken of his Google+ page), it is a very interesting read that gives a good candid insight into a two of the biggest companies in our industry, Amazon and Google. Steve compares Google’s product-first to Amazon’s platform-first approache; he argues strongly for the platform-first approach, for eating your own dog food, for not being so arrogant as to try to deliver a product that is right for everyone, and why a platform cannot be developed as an afterthought.

A product is useless without a platform, or more precisely and accurately, a platform-less product will always be replaced by an equivalent platform-ized product.” – Steve Yegge

If you are in software development, this is a must read. Head over to Silicon Angle to read the full text.

RIP Steve Jobs (1955 - 2011) – thank you for all your contributions

It is not often I find myself struck by the passing of a public figure, but with Steve Jobs it is hard not to feel touched. The man who has had such a great influence on the tech industry and the world in general, leaves us with a large collection of important innovations and ideas, that will continue to inspire for many years to come.

I will leave you with this fantastic quote from his Stanford Commencement Address in 2005.

Remembering that I’ll be dead soon is the most important tool I’ve ever encountered to help me make the big choices in life. Because almost everything – all external expectations, all pride, all fear of embarrassment or failure – these things just fall away in the face of death, leaving only what is truly important. Remembering that you are going to die is the best way I know to avoid the trap of thinking you have something to lose. You are already naked. There is no reason not to follow your heart.” – Steve Jobs

Drupal: Extending Markdown syntax to add CSS classes to images

If you are using input filters such as the Markdown filter module, you may run in to a situation where the script behind the module does not provide you with all the formatting options you want.

This was the case for me with a Drupal site I am currently building, I wanted to allow the editors of the site to specify the position of the image, i.e. float left, float right, or centered, but this is not supported by the otherwise excellent Markdown syntax, so I decided to use the Custom filter module to solve my problem.

Another option is to hack the Markdown module or Markdown itself, but neither is a good option as newer versions of either could break the hack. The solution with the Customer filter module does not do this, since it just adds a new filter that can be applied after the Markdown filter. Straight from the Custom filter page:

Instead of creating a new filter module for every filter you need, you can use this module [Custom filter] for tasks like creating your own tags, replacing token values and all changes you need in the text.

The syntax I wanted to create looks like this: ![Alt text](/path/to/img.jpg){css classes}

What differs from the original Markdown image syntax is the {css classes} at the end. The idea is to basically add what is between the curly brackets as css classes to the img tag, so that end result will be:

![Alt text](/path/to/img.jpg){css classes} becomes
<img src="/path/to/img.jpg" alt="Alt text" class="css classes" />

With this in place, it is easy to control left and right floating of an image by having the user write {left} or {right} and the have the appropriate styling in your style sheet.

How to add custom css classes to the generated img tag:

  1. First install and configure the Markdown module as you normally would.
  2. Then install the Custom filters module.
  3. Go to admin/settings/customfilter and create a new Filter Set.
  4. Add a new Replacement Rule to the just created filter with the following data:
    Name: whatever you like
    Description: whatever you like
    Pattern: /(<img.*)\/>\{([A-Za-z0-9-_\s]*)\}/
    Replacement text: ${1}class="${2}" />
  5. Go to your Markdown text filter (input filter in Drupal 6) and select you newly created filter set and make sure that it is listed below Markdown in the filter processing order list.

For more information about creating filters with the Custom filter module, see the Getting Started section and the Creating filters section in the documentation for the Custom filter module.

Getting all DNS records form a Internet domain via nslookup

This is a quick and easy way to grab all DNS records from a domain. All you need is the name of the domain you want to query and the DNS server that is handling the domain. Here is how you do:

Open up a command prompt and type:

C:\> nslookup - your.dns.server

In the nslookup prompt, type:

> set q=any
> ls -d domain.name

Hope this helps.

Pages