How to fold a Map with CSS

Prologue

Experimenting with virtual map folding is something I have been doing for a while. Mostly because I am dazzled by the way light interacts with the elements of the physical World. But also for the reason that I am obsessed with the foldings of a paper map and with paper maps in general (yes, even in the WebGIS epoch there are romantic people that prefer paper to screen)!

Digital maps lack this impression of realism, because they present the artwork on a smooth, flawless, luminus plane. For the majority of occassions this is alright, but sometimes it is well needed to showcase my map with its supposed folding. Either for presenting to my client, or just uploading my work on my Portfolio, simulating the folds is one nice, creative task that I am happy to spend hours (or days) with!

So far, I have been producing the virtual folds of my maps in ArcGIS Pro, which rules! I have written a series of two articles about doing this in Pro, which you may read on Esri’s blog here Digital map folding part 1: 2D and here Digital map folding part 2: 3D, both hosted by John Nelson.

The present blog post is about doing more or less the same thing, but on a browser by writting CSS, which rules! I make heavy use of CSS Gradients and I leverage other amazing capabilities like CSS Grid, CSS Flex and CSS Image Filters.

If you have absolutely no idea what CSS is, hold it right there! Before proceeding to my post, do yourself a favor and learn CSS from scratch (as I once did)! You will never regret it! On the other hand, If you daily breathe CSS, you may simply read my pen Pretty Map folding with CSS, that I have uploaded on my CodePen account.

If you live somewhere in between the two aforementioned extremes (as I do), keep reading! Basic understanding of HTML and CSS is enough. The logic is the same as the one I exhibit on my blog posts about ArcGIS Pro, which I strongly recommend you to read for better understanding of map folding.

At the following paragraphs I go through every single line of my code to explain how and why it works. It would be really helpful if you follow along having my pen Pretty Map folding with CSS open side-by-side with the post.

The HTML

The HTML structure is simple. I create a <figure> element with class=”folded”, where I store an <img> element and three blocks of <span> elements. The <img> element has class=”fold-me-please” and it is about to hold the map in an image format (e.g. jpg or png), via its src (source) attribute. The map must have been uploaded somewhere on the internet in order to possess a path. This is the path I assign to the src attribute (Picture 1).

Picture 1: The HTML structure.
Picture 1: The HTML structure.

The three blocks of <span> elements are the folds. If you read my articles about digital folding in ArcGIS Pro, you will see that I have three families of folding. One main, one vertical and one horizontal. I also use a grid of cells to simulate the edges of the folds.

Therefore, on my HTML document the three parent <span> elements have a common class=”folds” and, besides this, each one of them has its own family class, namely main, vertical and horizontal (Picture 1).

The child <span> elements, of the three blocks, have a common class=”cell” and, besides this, each one of them has its own family class, which is its parent class name with an identifier number (e.g. main-1, main-2 or vertical-1, vertical-2, vertical-3 etc), as shown in Picture 1.

The CSS

The first thing to style in the CSS part is the <figure> element, which will behave as the container of the image and of the associated folds. The most important parameter is to assign a relative position, in order to have the absolute position of its children <span> elements working (Picture 2).

Picture 2: Defining the <figure> and the <img loading=
Picture 2: Defining the <figure> and the <img> CSS parameters.

It is also important to hide the overflow, for the image to be properly clipped when scaled. Finally, I define an appropriate box-shadow property to give the illusion that the folded map is lying on a surface.

Next I define the parameters of the image. I give 100% for width and height and an object-fit:cover. This will automatically adjust to the original dimensions of any image. Note, that I have not defined any dimensions for the parent <figure> element, which will adjust to the dimensions of its child image.

I also define CSS filters for the image. These will help me to refine a number of parameters, like brightness or contrast for instance, and to produce an aesthetically better result.

Another useful parameter is the scale. It is frequent to find a map on the internet which has been scanned without having been cropped. Scale will allow me to increase its size, without affecting its defined width/height parameters. And since its parent element has an overflow:hidden, the map will be effectively clipped.

Finally, I can control the visibility of the image. When visibility is defined as hidden, the image is not shown on the browser, but its occupied space is still present. This is how I sustain the folds without the image, as shown in Picture 2.

The parent <span> elements with class=”folds” will hold their children <span> elements with class=”cell”. For this, I set the display of the parents span.folds to grid and I assign five times the value auto to the grid-template-columns parameter (Picture 3). This will produce a grid of five columns and one row, provided I have created five children <span> elements (see the HTML structure).

Picture 3: CSS Grid of five columns and one row.
Picture 3: CSS Grid of five columns and one row.

For the parent <span> elements I also give an absolute position with the values of all marginal parameters (top, right, bottom, left) set to zero. This will force the grid to expand to the overall extent of its parent, which is the <figure> element. And since the <figure> element adjusts to the dimensions and proportions of the image, the grid will also adjust to the dimensions and proportions of the image! With this I make sure that the grid, hence the folds, will always match any given image.

The span.cell elements must not have any border. For demonstration reasons only, I left a 1px border in Picture 3, which normally should be set to zero. No other parameter is necessary for the .cell class, but I have included a few Flex parameters to define the way text or other content will behave inside the span.cell elements.

The Main Folds

The first block of <span> elements, apart from the .folds class, also has the .main class (see the HTML structure). In my CSS code, I define only two parameters for the .main class, the visibility with which I can control whether the main folds will be visible or not, as well as the opacity, with which I can control their overall opacity, which is the opposite of transparency (Picture 4).

Picture 4: The Main folds.
Picture 4: The Main folds.

Inside the span.main element I have five <span> children elements with classes .main-1 and .main-2. To each one of them I define a linear gradient for background image with a “to right” direction (Picture 4).

These gradients are similar to their equivalent I have included in my ArcGIS Pro Style. The first ones (.main-1) have darker gradients, while the second ones (.main-2) are significantly lighter. This implies the interaction of the map with a main light source, which in my example is supposed to come from the left. The effect is ok but it needs a significant enhancement to the edges of the folds.

The Vertical Folds

The second block of <span> elements, apart from the .folds class, also has the .vertical class (see the HTML structure). In my CSS code, I define only two parameters for the .vertical class, the visibility with which I can control whether the vertical folds will be visible or not, as well as the opacity, with which I can control their overall opacity (Picture 5).

Picture 5: The Vertical folds.
Picture 5: The Vertical folds.

Inside the span.vertical element I have five <span> children elements with classes .vertical-1.vertical-2, .vertical-3, .vertical-4 and .vertical-5. To each one of them I define a linear gradient for background image with a “to right” direction (Pictures 5 and 6).

The gradients for the vertical children <span> elements are more complex. They actually intend to emphasise the vertical edges of the folds. For this I have created a larger number of stops, from 0% to 100%, and an apt selection of opacity for each stop.

Picture 5 indicates the vertical folds by themselves, without the image, while Picture 6 also indicates the image.

Unambiguously their presence is essential for a more realistic result, since they successfully enhance the edges of the folds, but they fail to illustrate the interaction of the map with the main light source. They also imply that the map has been folded five times vertically, but not horizontally, which is not likely for the majority of actual maps.

Picture 6: The Vertical folds.
Picture 6: The Vertical folds.

The Horizontal Folds

The third block of <span> elements, apart from the .folds class, also has the .horizontal class (see the HTML structure). In my CSS code, I define only two parameters for the .horizontal class, the visibility with which I can control whether the horizontal folds will be visible or not, as well as the opacity, with which I can control their overall opacity (Picture 7).

Picture 7: The Horizontal folds in a five column / two rows grid.
Picture 7: The Horizontal folds in a five column / two rows grid.

Inside the span.horizontal element I have ten <span> children elements with classes .horizontal-1.horizontal-2, .horizontal-3, and .horizontal-4. The first five of them will be pushed to the first row of the grid, while the rest of them will be pushed to the second row of the grid (have I mentioned that I love CSS Grids?), since their parent has a grid-template-columns parameter set to “auto auto auto auto auto” (= five times auto)!

To each one of them I define a linear gradient for background image with either a “to bottom” or a “to top” direction (Pictures 7 and 8). The gradients for the horizontal children <span> elements are as complex as those of the vertical. They actually intend to emphasise the horizontal edges of the folds. For this I have created a larger number of stops, from 0% to 100%, and an apt selection of opacity for each stop.

Picture 7 indicates the horizontal folds by themselves, without the image, while Picture 8 also indicates the image. The horizontal gradients effectively enhance the horizontal edges of the folds, but alone only very poorly can give the illusion of an actual folded map.

Picture 8: The Horizontal folds.
Picture 8: The Horizontal folds.

Putting them all together!

It is obvious that each fold family alone cannot provide any impressive results, but when shown simultaneously the result is stunning (Picture 9). With the opacity filter of each family I can control the amount of their prominence to the final result.

Picture 9: Turning all fold families on.
Picture 9: Turning all fold families on.

And here is a live demonstration of the final result (Picture 10). The image is actually a sample map I exported in JPEG format from ArcGIS Pro and uploaded at the Media Library of my website. The rest is the exact same HTML and CSS code as described at the previous paragraphs, which I incorporated on my website.


Picture 10: The final result

Being Creative

Being creative means spending an entire Weekend surfing the internet to find vintage online maps to fold! And I found a lot! For the purposes of my blog post I selected the Nuova pianta topografica della città e del porto di Genova from the libraries and archives of Harvard University.

But when introduced the map to my CodePen via its path, I realized that it had a white border around its extent, which I didn’t really like. Also the map needed a little visual refinement (Picture 11).

Picture 11: A raw map as an image without any CSS enhancements.
Picture 11: A raw map as an image without any CSS enhancements.

So I changed a little its CSS parameters (Picture 12)!

I rotated the hue a few degrees to the left (where vibrant red colors live), I increased the saturation and enhanced the brightness and contrast. All done with CSS Filters. I also slightly increased its scale to clip the undesirable white border.

Picture 12: A raw map as an image with CSS enhancements.
Picture 12: A raw map as an image with CSS enhancements.

So, here is a live version of the filtered, clipped, folded version of the Nuova pianta topografica della città e del porto di Genova original map (I have literally fallen in love with that map and there is a high chance that I will spend the forthcoming week(s) trying to design something similar to it)!


Picture 13: Filtering, clipping and folding the Nuova pianta topografica della città e del porto di Genova!

Epilogue

Reaching the end of my blog post I would like to thank you all my readers for following along with me this short journey to the infinite magical possibilities of CSS and to the charm of map folding.

Please feel free to visit my CodePen and upload your own maps for folding (licence CC BY-NC-SA 4.0)! And don’t forget to share the results. An embedded version of the same Pen lives at the bottom of this post.

Kindest regards from Crete, Greece

Spiros


See the Pen Pretty Map folding with CSS by Spiros Staridas (@spiros-staridas) on CodePen.