how to replicate pinterest.com's absolute div stacking layout

56,144

Solution 1

You could also check on the jQuery Plug-in Masonry, for this kind of functionality.

Solution 2

I wrote the Pinterest script. The ID's are unrelated to the layout, and are used for other interaction-related JS. Here's the base of how it works:

Beforehand:

  • Absolutely position the pin containers
  • Determine column width
  • Determine margin between columns (the gutter)

Setup an array:

  • Get the width of the parent container; calculate the # of columns that will fit
  • Create an empty array, with a length equaling the # of columns. Use this array to store the height of each column as you build the layout, e.g. the height of column 1 is stored as array[0]

Loop through each pin:

  • Put each pin in the shortest column at the moment it is added
  • "left:" === the column # (index array) times the column width + margin
  • "top:" === The value in the array (height) for the shortest column at that time
  • Finally, add the height of the pin to the column height (array value)

The result is lightweight. In Chrome, laying out a full page of 50+ pins takes <10ms.

Solution 3

We released a jQuery plugin because we got the same question several times for Wookmark. It creates exactly this type of layout. View it here - Wookmark jQuery plugin

Solution 4

Having looked at all options, I ended up implementing the layout similar to Pinterest in this way:

All DIVs are:

div.tile {
    display: inline-block;
    vertical-align: top;
}

This makes them position in rows better than when they are floated.

Then when the page is loaded, I iterate all DIVs in JavaScript to remove gaps between them. It works acceptably well when:

  1. DIVs are not very different in height.
  2. You don't mind some minor violations of ordering (some elements that were below can be pulled up above).
  3. You don't mind the bottom line being of different height.

The benefit of this approach - your HTML make sense for search engines, can work with JavaScript disabled/blocked by firewall, the sequence of elements in HTML matches the logical sequence (the newer items before older)

Share:
56,144

Related videos on Youtube

chrickso
Author by

chrickso

Updated on November 17, 2020

Comments

  • chrickso
    chrickso over 3 years

    I am looking to replicate Pinterest.com's div layout, specifically how the number of columns adjusts to fit more/less on browser resize and the vertical stacking is not dependent on adjacent column heights. The source code shows that each div is position absolute. A co-founder has answered a Quora post stating it is done with custom jQuery and CSS. I would like the results sorted left to right. Any direction you could provide to make it myself would be greatly appreciated.

    • Andrew WC Brown
      Andrew WC Brown over 9 years
      I coded my own with simple Jquery and CSS. If you want this to change on resize you just wrap it in a function and watch on resize on container element jsfiddle.net/92gxyugb/1
  • Bojangles
    Bojangles almost 13 years
    +1 For having a look through their source code.
  • ant_Ti
    ant_Ti almost 13 years
    It was interesting for me but i think there is beter solution with less js calculations
  • Bojangles
    Bojangles almost 13 years
    You could use display: inline-block I suppose, but items of differing vertical height wouldn't sit together.
  • ant_Ti
    ant_Ti almost 13 years
    better to use columns containers (divs with float:left; and last one with overflow: hidden;) and store elements there
  • Bojangles
    Bojangles almost 13 years
    Good point. If you really wanted to go the JavaScript route, you could use jQuery Masonry?
  • chrickso
    chrickso almost 13 years
    I'm trying to wrap my head around what the code would look like to: on browser resize > grab the new width > determine how many columns will fit > add/remove columns > assign the next available column # to div > determine absolute position based on end of previous div in that column. Am I missing any steps? Any tutorials u could point me to for positioning divs based on browser width & retriggered on resize?
  • chrickso
    chrickso almost 13 years
    Getting them to fit together vertically is the magic I'm after so floating/online blocks are not an option.
  • ant_Ti
    ant_Ti almost 13 years
    jQuery.Masonry is the simplest way but not the best. The main idea of good frontend developer is to use less js and more css if it's posible
  • Michael Giovanni Pumo
    Michael Giovanni Pumo almost 13 years
    How do you mean calculate the height of the column? How do you know how high it should be if you don't know the number and height of items within it? Any chance you could layout some pseudo code to demonstrate?
  • hollandben
    hollandben over 12 years
    here's a solid tutorial - benholland.me/javascript/…
  • ahmet alp balkan
    ahmet alp balkan about 12 years
    Truly amazing library. Now I'm using it without any problems.
  • oers
    oers about 12 years
    Feedback from an anonymus user (found in edit queue): Curiously I did exactly the same script in jQuery, with the slight difference of actually creating a table with 1 row and N columns, and just appending them to the shortest column from left to right priority. Even though I also added a "Minimum height difference" Constant required to actually skip a column when positioning from left to right, this gives the layout a chronologically intuitive display without loosing the heights being as even as possible
  • Michael L Watson
    Michael L Watson over 11 years
    This solution seems to load faster than masonry
  • Hanna
    Hanna about 11 years
    According to Evan Sharp the IDs are completely unrelated and this answer doesn't really help much.
  • Lukas Oppermann
    Lukas Oppermann almost 11 years
    Hey, could you tell me how you calculated the offset you had to substract? And also how did you solve the problem of the last element being on the right side, because there is one element that is a little bit bigger and pushes it there.
  • esp
    esp almost 11 years
    @LukasOppermann 1) The offset for the tile is the sum of the offset for the tile in the same column in the previous row and the difference between the height of the highest tile in the previous row and the height of the tile in the same column in the previous row. Have a look at dev.sheeporpig.com/news (you first need to click on the link dev.sheeporpig.com/sheep/3210 to get access to the development site - so you can see uncompressed&commented scripts in separate files), script file stock_news.js, function compressTiles.
  • esp
    esp almost 11 years
    @LukasOppermann 2) If you use CSS as in answer (especially display:inline-block) it doesn't happen. It only happens if you float:left your divs. I don't use float.
  • Ramje
    Ramje almost 11 years
    which do you find better? the wookmark or the masonry?
  • nerdburn
    nerdburn over 10 years
    I prefer this over masonry, seems faster like Michael said.
  • ptgamr
    ptgamr almost 10 years
    @MichaelGiovanniPumo I think the height should be known prior to the layout (in case of Pinterest), they do not have an "initial" state which have divs overlap each other. This can not be done if height is not known.
  • Lukmo
    Lukmo over 9 years
    @hollandben's link is dead, new link : benholland.me/javascript/2012/02/20/…
  • Muhammad Umer
    Muhammad Umer over 8 years
    https has expired or something