Pinboard Layout Using CSS Grid
One of the joys of CSS Grid is being able to easily create designs with overlapping content. As a demonstration we've expanded our CSS Grid masonry technique to create a responsive virtual pinboard effect.
The example
You can see this technique in action on our CSS Grid pinboard example page where you can just jump straight in by hitting view source
if you are so inclined.
The grid setup
To make the pinboard we first create a responsive grid with enough rows and columns to allow us to lay out the items on the board and we name the grid lines. For our example we've created a 20 row / 20 column grid with a simple numbering system for the grid lines. The width is 100vw
(that's the whole viewport) and the height is fixed at 56.3vw
so we have a nice pinboard-like aspect ratio. Here's the code:
.s-grid {
display: grid;
height: 56.3vw;
width: 100vw;
grid-template-rows: [y0] 2vw [y1] 1fr [y2] 1fr [y3] 1fr [y4] 1fr [y5] 1fr [y6] 1fr [y7] 1fr [y8] 1fr [y9] 1fr [y10] 1fr [y11] 1fr [y12] 1fr [y13] 1fr [y14] 1fr [y15] 1fr [y16] 1fr [y17] 1fr [y18] 2vw [y19] 1fr [y20];
grid-template-columns: [x0] 2vw [x1] 1fr [x2] 1fr [x3] 1fr [x4] 1fr [x5] 1fr [x6] 1fr [x7] 1fr [x8] 1fr [x9] 1fr [x10] 1fr [x11] 1fr [x12] 1fr [x13] 1fr [x14] 1fr [x15] 1fr [x16] 1fr [x17] 1fr [x18] 1fr [x19] 2vw [x20];
}
The notation in square brackets (e.g. [y0]
) is the naming of the grid lines and the majority of our grid rows and columns are defined in fr
units. An fr
unit is a 'fraction' and it gives us an easy way to tell the grid to divide up automatically without having to manually work out percentages (lots more on fr
units here).
As well as all those 1fr
rows and columns you'll see that there are also 2 rows and 2 columns that are defined as being 2vw
units in size. These rows and columns will be used to form the frame of our pinboard.
The last thing to notice is that the frame is defined between lines y18
and y19
. This leaves us a free row between y19
and y20
that we can use to contain items which hang off the bottom of the pinboard.
Styling the pinboard
Next up we will style the pinboard itself as it makes it much easier to see what's going on when we lay out the items. Here's the HTML
for the bare pinboard:
<div class="s-grid">
<div class="block-rim">
</div>
<div class="block-board">
</div>
</div>
block-rim
and block-board
are just two rectangles sat one on top of the other. As block-board
appears after block-rim
in the code it is placed on top of it by default. Here's the CSS (background images from Tiling Textures):
.block-rim {
grid-area: y0 / x0 / y19 / x20;
background-image: url('/assets/pinboard/corkboard-rim.jpg');
}
.block-board {
grid-area: y1 / x1 / y18 / x19;
background-image: url('/assets/pinboard/corkboard.jpg');
}
Here we are defining the position and size of the two rectangles using row-start / column-start / row-end / column-end
notation which is where named grid lines that we defined come in to play. So for block-rim
the notation y0 / x0 / y19 / x20
means that the top left corner is where grid lines y0
and x0
cross, and the bottom right corner is where grid lines y19
and x20
cross (leaving the bottom row of our grid free for items to hang off the bottom). block-board
is slightly smaller and centered over block-rim
.
Add items to the pinboard
Adding basic items to the pinboard is simple – just create a block-level element (e.g. a div
) within the grid, give it a unique class name and assign it to the appropriate area using row-start / column-start / row-end / column-end
notation. Remember that elements defined later in the HTML
will be on top of elements defined earlier if they overlap. Here's the basics for the four elements on our example pinboard – first the HTML
:
<div class="block block-1">
<p>Two ghostly white figures in coveralls and helmets are softly dancing preserve and cherish that pale blue dot permanence of the stars Rig Veda Apollonius of Perga Orion's sword?</p>
<p>Paroxysm of global death descended from astronomers network of wormholes citizens of distant epochs dream of the mind's eye emerged into consciousness?</p>
</div>
<div class="block block-2">
<img class="cover" src="https://picsum.photos/640/480" alt="" />
</div>
<div class="block block-3">
<img class="cover" src="https://picsum.photos/480/640" alt="" />
</div>
<div class="block block-4">
<p>- Milk<br/>- Eggs<br/> - Sugar<br/>- Cornflour</p>
</div>
The text in block-1
come from Sagan Ipsum. The extra block
class that each element has will be used for some styling later, here's the layout aspect of the CSS
first:
.block-1 {
grid-area: y3 / x2 / y17 / x8;
}
.block-2 {
grid-area: y11 / x5 / y16 / x10;
}
.block-3 {
grid-area: y10 / x11 / y20 / x16;
}
.block-4 {
grid-area: y4 / x13 / y11 / x18;
}
Note that block-3
stretches all the way down to y20
so it's hanging below the bottom of our pinboard (which stops at y19
).
Styling the items on the pinboard
All that's left to do now is to style the items on the pinboard so that they look, well, more like items on a pinboard.
First up we add a box-shadow
and a thumb tack to each element (those items don't stay on the pinboard using magic, you know):
.block {
position: relative;
width: 100%;
height: 100%;
object-fit: cover;
-webkit-box-shadow: 0 0 4px rgba(0, 0, 0, 0.2), inset 0 0 50px rgba(0, 0, 0, 0.1);
box-shadow: 0 0 5px rgba(0, 0, 0, 0.5), inset 0 0 50px rgba(0, 0, 0, 0.4);
}
.block:after {
content: url('/assets/pinboard/thumb-tack-2.png');
display: block;
position: absolute;
top: -12px;
left: 49%;
z-index: 800;
}
The thumb tack image was adapted by me from an original image by Marco Verch available on flickr under a Creative Commons 2.0 (attribution required) license.
Next, we make sure that the text fits nicely on the two text items and that it scales with the pinboard when the screen size is changed. We do this by defining the text size using vw
units and padding in %
(note that these styles are in addition to the styles we already have for these blocks). We will also style the backgrounds on these two elements to make them look like a sheet of lined paper and a Post-It note respectively:
.block-1 {
padding: 7% 2% 2% 20%;
background-color: #FFFF99;
background-image: url('/assets/pinboard/old_notepaper_texture_by_polkapebble.jpg');
background-size: cover;
color: #1295e6;
font-style: italic;
font-size: 1.85vw;
}
.block-4 {
padding: 5%;
background-color: #FFFF99;
color: #1295e6;
font-style: italic;
font-size: 2.5vw;
}
The lined paper background image is from polkapebble on DeviantArt.
We also need to make sure that the two photographs on the pinboard respect the size of their defined grid areas and scale properly, like this:
img.cover {
height: 100%;
width: 100%;
object-fit: cover;
}
For the example we are dynamically loading images from Lorem Picsum.
Now we use a CSS transform to rotate each element slightly. We've used transform: rotate(0.5deg);
with a slightly different rotation value for each element.
Just one thing left now – as it is block-4
(the Post-It note) overlays the thumb tack for block-3
(a photo). So, we'll move the thumb tack over slightly on block-3
so that it's visible, like this:
.block-3.block:after {
left: 25%
}
And that's it! See it in action on the example page.
Taking it further
In practice you rarely want your pinboard to take up the full viewport width at larger screen sizes, so you might want to add a few extra style rules enclosed in a CSS media query to provide a maximum size. You can see this in action on this page if you take a look at the source code.
You can add as many things as you like to your pinboard but as the number of items goes up it can get tricky to handle. Also, the more grid lines you add the slower the rendering speed will be, so if you are going to add a lot of items then I suggest building a custom grid just like in our CSS Grid masonry layout article to keep the grid lines to a minimum. This is the approach we took when creating the project pinboard on the [RPress] home page – you can see the test grid we used to create the layout here if you are interested. The project pinboard also uses art direction via the <picture>
element to provide a different layout for small screen sizes where the pinboard would look too busy.
Questions or comments?
Hit us up on Twitter @RefinedPractice, drop Paul Ratcliffe a line on LinkedIn or get in touch using the details below ↓.