Create Your Own Sliding Resizable Grid

Create Your Own Sliding Resizable Grid

by Zack Grossbart on August 12, 2009

Fork me on GitHub

I’ve focused on web programming for a while now, but I still miss GridBagLayout. GridBag is a Java layout manager and one of the best form layout managers I’ve used in any language. It makes it possible to create forms where any screen size is the perfect size.

There are a few different layout managers you can use with JavaScript, but they are mostly simple. I tend to skip them and just do the layout by hand using CSS. That’s why I was so excited when I saw the website for the English design firm Zaum & Brown. If you follow the link resize your browser window after the page loads.

See it
in Action

Your browser window is always the perfect size for the Zaum & Brown website. I really liked the effect so I’ve created an improved and simplified version of a sliding resizable grid and released it under the Apache License 2.0.

The HTML

The HTML for this grid is very simple. It uses three classes, slidegrid, cell, and bigcell. Check it out:

<div class="slidegrid">
    <div class="cell bigcell">Big Cell 1</div>
    <div class="cell">Cell 2</div>
    <div class="cell">Cell 3</div>
    <div class="cell">Cell 4</div>
    ...

The grid starts with the slidegrid class. This class is just a marker for the JavaScript code in slidegrid.js. After it finds slidegrid the JavaScript looks for cell classes underneath the slidegrid. I made mine div tags, but they could contain any other content.

slidegrid and cell would be enough for something simple, but I wanted to get a little fancy so I added the bigcell class. Every big cell is twice as large as a normal cell.

The JavaScript

Get the
source code

The JavaScript for this code is also relatively simple, and much of the credit for that goes to JQuery. The most important function here is alignGrid. It does all the heavy lifting of iterating through the div tags and lining them up in the grid.

Here’s a simplified version of the function. There is some extra handling in the real code for big cells, but I’ll let you find that on your own.

jQuery(".slidegrid").each(function() {
        
    var cols = Math.floor($(window).width() / ((cellWidth + padding) * 
        getComputedEm(jQuery(this))));
    
    jQuery(this).css("position", "relative");
    
    var children = jQuery(this).children("div");
    
    for (var i = 0; i < children.length; i++) {
        
        styleCell(children.eq(i), x, y, cellWidth, cellHeight, hasDrawn);
    }
    
    if ((count % cols) == 0) {
        
        /* 
         * This means it is time to bump down to the next row
         */
         
        curCol = 0;
        curRow++;
        x = 0;
        y += cellHeight + padding;
    } else {
        x += cellWidth + padding;
        curCol++;
    }
    
    count++;
});

When you resize the page we’re using an animation effect to show the cells moving. The animation is defined in the styleCell function. JQuery makes custom animation effects very easy so this function is very small.

function styleCell(cell, x, y, cellWidth, cellHeight, /*boolean*/animate) {
    if (animate) {
        /*
         * We only want to do the animation when the resize happens.
         */
        cell.animate({ 
            left: x + "em",
            top: y + "em"
            }, 500, "swing" );
    } else {
        cell.css({
            width: cellWidth + "em",
            height: cellHeight + "em",
            position: "absolute",
            left: x + "em",
            top: y + "em"
        });
    }
}

The last step is to make sure we redo the layout of the grid when the window is resized. For that we add a little bit of code to the document’s ready function.

$(document).ready(function() {
    alignGrid(10, 10, 1);
    
    /*
     * Redraw the grid when the page size changes
     */
    $(window).bind("resize", resizeWindow);
    function resizeWindow(e) {
        var newWindowHeight = $(window).height();
        alignGrid(10, 10, 1);
    }
});

This makes sure we align the grid the first time and then change it whenever the window is resized. That is really all it takes.

Get Creative

This is a simple mechanism, but it is powerful. The div tags are flexible enough to add almost any content. Please make use of this code and post a comment if you do so we can all check it out.

…and maybe one day I’ll feel ambitious enough to try to write GridBagLayout for JavaScript.

  • GJ

    Hi Zack!

    This is a great script, thanks a lot. Loved the zaum script, so your explanation on how to get this working really came in handy!

    Just one drawback, where the zaum script seems to work perfectly in Safari, this script doesn’t seems to be a bit buggy in safari on the mac. Do you got any reccomendations on this particular issue?

    Also, can you please tell me how I can alter the height and width of the divs, without messing up the grid?

    Anyway, Tnx a lot, you did a great job!

  • Zack Grossbart

    Hello,

    I’m glad you liked the code. I just tested this using Safari 4.0.3 on my Mac and it worked well. What issues are you seeing and what version of Safari are you using?

    Changing the cell sizes is easy. There are two places where it calls the alignGrid function. This function takes three arguments: the width of each cell, the height of each cell, and padding between them. All of these numbers are in EMs. Just change the numbers and the cell size changes.

  • Zack Grossbart

    I did a little more testing with the grid and saw some slightly funny behavior on Safari with the grid moving at the wrong time. I made a small fix for this which also made the code cleaner. Let me know if you still see the problem. Thanks.

  • GJ

    Hi Zack,

    I use Safari 3.2 on the Mac and that’s accacly what’s happening here. Problem still appears to be there on safari 3.2. I will try upgrading to Safari 4.0 and see if the problem is solved.

    Also i was wondering if it is difficult to add a extra size for te gridblocks. For lay-out purposes it would be nice to have three differents sizes, just like the Zaum grid has.

  • Zack Grossbart

    @GJ

    Right now the grid has cells and big cells. Big cells are twice as large as cells. You could easily add a really big cell that was three times as large. On line 148 it checks for the class bigcell. You can just add a check for what ever other class you want. Just set the size of the cell and call the setUsed function to make sure the other cells don’t overlap.

  • GJ

    Tnx! i was accacly trying that right now :-)

  • Tommy

    This is great!

    But what if I want to have varying cell heights, like it seemes the Zaum & Brown site has? Do I have to set a fixed height in the script?

  • Zack Grossbart

    I’m glad you liked it. This script allows for two types of cells. The standard cell is the height and width you specify when calling the alignGrid function. Big cells (denoted by the class bigcell are twice the width and height of normal cells. So the short answer to your question is yes you do have to specify a fixed height.

    However, if you’re comfortable with JavaScript you could change the alignGrid function to do whatever layout you want. You could even specify the width and height of each cell in the HTML if you changed the script. This script is totally open source so you can use it to do whatever you want. If you do please post a comment and let us know.

  • Jesse

    Hey Zack,

    Thanks for writing this! You’ve given me some interesting ideas.

    I’m sure you’ve noticed the minor issues with big cells on the rightmost edge (resize the demo to a seven-column width, for example). I’m going to explore the feasibility of an algorithm that shifts elements to later in the array if they’re too large to be rendered in the remaining space.

  • http://www.zackgrossbart.com Zack Grossbart

    I did notice that. It happens when a big cell is in the last column of the table. I tried making it move down to the new row, but it left a space that looked funny. The only way to fix this is dynamically change the order of the cells, but that is tricky unless you know what data is in them.

    I’m curious to see what solutions you come up with.

  • http://www.jessedubay.com/ Jesse

    Well, here’s my (in the spirit of the blog title) hackish attempt:

    http://www.jessedubay.com/p/grid/proto_1.html

    On resize, it grabs the list of cells to place and exhausts them one by one, looking for a narrower, later one if the next cell won’t fit in the available space. The tradeoff is that you’re not guaranteed that the cells will render in order, but it usually ends up close enough.

    This prototype’s source code is terribly ugly and I would recommend against anyone actually using it in its current form, but the functionality could eventually be turned into a neat plugin.

  • http://www.zackgrossbart.com Zack Grossbart

    Great job Jesse. Putting the width and height right in the class of the cell is a neat idea. This worked well on Firefox and Chrome, but it didn’t resize when I resized my window in IE 8. Probably just a minor issue.

    Thanks for sharing.

  • Cristian G

    Hey! A friend recommended this script to me when I was looking for a way to maximize browser real estate. Very nice!

    I’m getting my feet wet with this and I’m having trouble adding another kind of cell. I want a cell that spans 2 columns but takes up just one row. I can modify the bigcell to make it behave this way, but it won’t work if I try to add the behavior.

    Also, I’m trying to change the font size both on the HTML document or on the CSS file, and the file size directly affects the size of the cell, overriding what the java file states. Do you have any ideas?

    Thanks for the tips !

  • http://www.zackgrossbart.com Zack Grossbart

    Hello Cristian,

    I want a cell that spans 2 columns but takes up just one row.

    Making a cell span two columns shouldn’t be too difficult. If you can make it work with a big cell you should be able to just copy that code and give it a different class name. Maybe something like wide cell. If you are still haven’t trouble you can post your changes somewhere and I would be happy to take a look.

    I’m trying to change the font size both on the HTML document or on the CSS file, and the file size directly affects the size of the cell, overriding what the java file states.

    The grid uses a unit called EMs. Theses are the size of an uppercase “M” in the current font. Changing the font size changes the width and height of an EM. If you want to change the font size without changing the cell size you need to either add a new div to each cell or change the units the grid is using to something else. You might try pixels.

    And don’t forget to share your results with us. We would love to see what you come up with.

  • http://www.joranquinten.nl/ Joran

    Great script! Tried it out today. I had some problems combining this script with a footer (and compatibility with IE6); the container height is set before rendering I think, this causes IE6 to NOT generate a vertical scrollbar, and footers get placed behind the gridded content.
    Solved the problem with this code (added at line 206), thought it might interest you;

    //* Fix height of container *//
    var slideContainer = $(“.slidegrid”);
    slideContainer.css({ height: (curRow+1)*(cellHeight+padding)+”em” });

    Regards!

  • http://xtraboy.com Oleg

    Power!!!!!!!!

  • Michael

    Doesn’t work when I zoom in to 150% (IE8).

    My tv is my monitor so I zoom in to see better from the couch.

  • Cristian G.

    Well, I’m about 95% done with my website using this. All I’d need for it to be “perfect” would be to automatically center the whole thing like the Zaum&Braum’s site and for it to set a limited width on the whole grid, say 1440px. Other than that, it works superbly!

    Here it is: http://designbycristian.com/

  • http://www.zackgrossbart.com Zack Grossbart

    Cristian, Your site looks great. Limiting the size of the grid is easy. On line 128 we compute the number of columns like this:

    var cols = Math.floor($(window).width() / ((cellWidth + padding)));

    Replace that line with this:

    var cols = Math.floor(Math.min($(window).width(), 1440) / ((cellWidth + padding)));

    For centering the grid you need to change the grid layout to take into account the remainder of space after the grid is layed out and pad the first column with that width divided by 2.

    Good luck.

  • http://www.comsolit.ch Lars

    Very cool! thanks a lot.

    I’m now very inspired and, will definitely make a gallery site with this.

    (only a little bit browser workarounds are necessary)

    Thanks ;-)

  • Giulio

    I’m wondering how to reduce or eliminate the padding between cells. Would it be possible to have the cells flush with each other?

    Thanks for the great script!

  • http://www.zackgrossbart.com Zack Grossbart

    Thanks for trying it Giulio. When you call alignGrid that last argument is the padding in EMs. You can make it 10 like this:

    alignGrid(10, 10, 0);

    Just change every place you call alignGrid and you should be all set.

  • trusktr

    Aha!! I comented on your other post, but then i found this! I noticed that when i resize my browser by dragging, your code looks at *every* size of the browser and the layout will resize multiple times instead of just going to the final position corresponding to the final browser size you stopped at…

    Anyways, i’d like to make this dynamic so that when you expand a box, it will re-arrange everything like on robclarke.com…

    robclarke.com doesn’t have the neat animation though… so this would be awesome.

  • http://www.zackgrossbart.com Zack Grossbart

    Hello Trusktr,

    Thank you for trying the example. You might want to add a timer on the resize event. Every time the window was resized you could wait half a second before you called the alignGrid function again. That would stop it resizing too often.

    You also can use this script to get an effect very similar to robclarke.com. The grid supports bigcells as well as normal cells. If you want to have one cell dynamically get larger just set it to have a class of bigcell and call the alignGrid function.

    Good luck and please share anything you make.

  • Aegean BM

    Zaum & Brown, Zack’s sliding resizable grid, and Cristian’s site, they’re all terribly sexy. And yet, I pushed Cristian’s too far, and I began to wonder if it was lipstick on a pig. Let me explain.

    I resized http://designbycristian.com/ 7 columns down to 2 back to 6, 5, 4, 3. It was not only sexy, but fun. And yet… 3 had warts toward the bottom. Not bad warts. In fact, entirely forgivable warts on most sites. I’d love to have those kind of warts on my site. But up til then I saw perfection. I believed it was possible. It was like a diamond shattering and I realized it was only glass. I was reminded that, oh yeah, there’s code behind this interface and it can’t cope.

    That’s when I had the epiphany. Cristian’s wares are handcrafted. His site feels handcrafted. When I hit the warts, it didn’t feel handcrafted. It felt automated. Other sites don’t have the handcrafted feel, so the warts would be more acceptable.

    Others already discussed variations like restrict the content to one size and allow re-ordering for better fit. I think a further restriction would allow us to have our cake and eat it too. So… I suggest if you know the cell sizes and order will stay static, you preview and approve the number of columns that fit perfectly. Then you use an array of acceptable widths [2,4,5,6,7].

    I really deserve a comment stating my solution also shatters the illusion of perfection because the design doesn’t increment evenly. How come the user never sees 3? Is that a bigger wart? Is it more glaring? Maybe the cure is worse than the disease. Design is always about balancing the trade offs.

    So we’re clear, I’m absolutely going to use sliding resizable grid somewhere. It’s a great solution. … Now to find a great problem to use it on.

  • http://www.zackgrossbart.com Zack Grossbart

    Thank you for your comment. It is always difficult to find the right balance between making a website slick, organic, and feel good. I’ve used the sliding grid in a number of other projects and made some improvements over that time, but it all comes down to trade offs.

    Figuring out how to make every possible grid layout for your contents perfect is a complex problem which changes depending on your site. I would encourage you to make any improvements to the sliding grid you think are necessary.

    Thanks for looking and please let us know how your efforts turn out.

    Thanks,
    Zack

  • Pingback: picture music » slide grid door

  • Pingback: » [jQuery]自動で時系列を崩さないリキッドレイアウトを実装するプラグインJ-snippet

  • Diego

    Great Script Zack!nnI tricked it out to work for my website, http://www.estudiantesdearquitectura.cl, works like charm.nnGreetsnDiegonn

  • http://www.zackgrossbart.com Zack Grossbart

    Very cool. Thanks for sharing Diego.

  • Pingback: Modern CSS Layouts, Part 2: The Essential Techniques - Smashing Magazine

  • http://www.lacostepoloshirtsshop.co.uk lacoste polo shirts

    Hi, I knew this article and i am real concern in this spot and tract. So i require few otherwise fundamental article in this place,because i necessity to engaged at this parcel. 

  • Pingback: Modern CSS Layouts, Part 2: The Essential Techniques - Goodfav Howto

  • skipmontanaro

    Coming very late to the party. I have two cell sizes, cell and bigcell, though all start out as cell. When I double-click, I transmogrify them into bigcell. A second double-click switches them back. This almost works, but I don’t quite know how to kick slidegrid into properly restyling the when a cell changes its spots.

  • http://www.zackgrossbart.com Zack Grossbart

    I tried your fiddle and it looks OK. It sounds like you might be running into a couple of bugs that I found when handling big cells at the end of the row. I’ve been making more changes and bug fixes to this script as part of the Spiffy UI project. You should try the sliding grid from that project.

    https://github.com/spiffyui/spiffyui/blob/master/spiffyui/src/main/js/lib/slidegrid.js

    Good luck,
    Zack

  • skipmontanaro

    Thanks. I’ll take a look at the new-and-improved version.

    I eventually figured out my problem. I was selecting the axes by their

    class, e.g.:

    d3.select(“.x.axis”)

    and thus always got the X and Y axes of the first plot. I needed

    to select the plot first, then its axis, e.g.:

    d3.select(“#”+chartid)
    .select(“.x.axis”)