Drawing a grid using CSS
Asked Answered
D

7

35

I'm looking for a way to draw a grid (i.e. http://www.artlex.com/ArtLex/g/images/grid.gif) inside of a div, using CSS (and JS if necessary). It feels like it should be relatively straight forward, but I haven't been able to figure it out. Any advice would be greatly appreciated.

Thank you in advance, Lenny

Diaphysis answered 16/11, 2010 at 4:34 Comment(3)
possible duplicate of How to make a grid (like graph paper grid) with just css?Angelaangele
The ideal solution in my case would involve no images, as I need to scale the grid dynamically, and fill in blocks with various colors. I could manage this with different image types, but that would get quite hairy.Diaphysis
Possible duplicate of How to make a grid (like graph paper grid) with just css?Fencer
A
22

Here's a simple solution using jQuery. This script will try to fill in as many grid element as possible without overflowing. The function accepts a single parameter, which defines the size of the grid.

function createGrid(size) {
    var ratioW = Math.floor($(window).width()/size),
        ratioH = Math.floor($(window).height()/size);

    var parent = $('<div />', {
        class: 'grid',
        width: ratioW  * size,
        height: ratioH  * size
    }).addClass('grid').appendTo('body');

    for (var i = 0; i < ratioH; i++) {
        for(var p = 0; p < ratioW; p++){
            $('<div />', {
                width: size - 1,
                height: size - 1
            }).appendTo(parent);
        }
    }
}

It also requires a simple CSS style:

.grid {
    border: 1px solid #ccc;
    border-width: 1px 0 0 1px;
}

.grid div {
    border: 1px solid #ccc;
    border-width: 0 1px 1px 0;
    float: left;
}

See a simple demo here: http://jsfiddle.net/yijiang/nsYyc/1/


Here's one using native DOM functions. I should also change the initial ratio calculation to use DOM functions but I cannot for the life of me get window.innerWidth to return accurate numbers fixed that:

function createGrid(size) {
    var ratioW = Math.floor((window.innerWidth || document.documentElement.offsetWidth) / size),
        ratioH = Math.floor((window.innerHeight || document.documentElement.offsetHeight) / size);

    var parent = document.createElement('div');
    parent.className = 'grid';
    parent.style.width = (ratioW * size) + 'px';
    parent.style.height = (ratioH * size) + 'px';

    for (var i = 0; i < ratioH; i++) {
        for (var p = 0; p < ratioW; p++) {
            var cell = document.createElement('div');
            cell.style.height = (size - 1) + 'px';
            cell.style.width = (size - 1) + 'px';
            parent.appendChild(cell);
        }
    }

    document.body.appendChild(parent);
}

createGrid(10);

It's basically a direct translation of the jQuery code. If you need even more performance you can switch to generating the boxes using strings pushed to an array:

arr.push('<div style="width:', (size - 1), 'px;height:', (size - 1), 'px;"></div>');

then at the end

parent.innerHTML = arr.join('');
Angelaangele answered 16/11, 2010 at 5:3 Comment(5)
BTW, any advice on making this more efficient? Anything in this code I can cache or replace jquery with native JS to make it run faster?Diaphysis
@Diaphysis Definitely! The whole thing can be rewritten in native JS, in fact. Also, you might want to not append elements in a loop, but instead append it to something else then outside the loop append the whole thing to the body. I can rewrite it into something more performant if you want.Angelaangele
If you have any spare cycles, I would LOVE to get the performant version. My JS skills are not quite there yet, would probably take me a couple hours to get it right.Diaphysis
@YiJang: You are a true hero.Diaphysis
Very nice! Playing around with adding a gutter. Any advice? Was also thinking of labeling in the gutter, but one step at a time. Example: jsfiddle.net/Twisty/18erqbqvSisley
T
95

Here is a simple CSS-only solution, using linear gradients:

html, 
body,
.grid {
    height: 100%;
    width: 100%;
    margin: 0;
}
.grid {
    background-image:
      repeating-linear-gradient(#ccc 0 1px, transparent 1px 100%),
      repeating-linear-gradient(90deg, #ccc 0 1px, transparent 1px 100%);
    background-size: 71px 71px;
}
<div class="grid"></div>
Topnotch answered 5/2, 2015 at 12:34 Comment(5)
Great pure CSS answer, which avoids any .js or dom noise.Backboard
I took this brilliant hack and made a Sass package out of it: Artboard. The main reason for the package is to expose a Sass variable to easily change the size of the grid.Milk
what if i want to put numbers inside the gird, how to do it with this example?Braddock
outstanding answerArroba
a tiny observation - whilst setting the background-size is important, you dont actually need "repeating" gradients here. backgrounds repeat by default so a simple linear-gradient is fineEider
A
22

Here's a simple solution using jQuery. This script will try to fill in as many grid element as possible without overflowing. The function accepts a single parameter, which defines the size of the grid.

function createGrid(size) {
    var ratioW = Math.floor($(window).width()/size),
        ratioH = Math.floor($(window).height()/size);

    var parent = $('<div />', {
        class: 'grid',
        width: ratioW  * size,
        height: ratioH  * size
    }).addClass('grid').appendTo('body');

    for (var i = 0; i < ratioH; i++) {
        for(var p = 0; p < ratioW; p++){
            $('<div />', {
                width: size - 1,
                height: size - 1
            }).appendTo(parent);
        }
    }
}

It also requires a simple CSS style:

.grid {
    border: 1px solid #ccc;
    border-width: 1px 0 0 1px;
}

.grid div {
    border: 1px solid #ccc;
    border-width: 0 1px 1px 0;
    float: left;
}

See a simple demo here: http://jsfiddle.net/yijiang/nsYyc/1/


Here's one using native DOM functions. I should also change the initial ratio calculation to use DOM functions but I cannot for the life of me get window.innerWidth to return accurate numbers fixed that:

function createGrid(size) {
    var ratioW = Math.floor((window.innerWidth || document.documentElement.offsetWidth) / size),
        ratioH = Math.floor((window.innerHeight || document.documentElement.offsetHeight) / size);

    var parent = document.createElement('div');
    parent.className = 'grid';
    parent.style.width = (ratioW * size) + 'px';
    parent.style.height = (ratioH * size) + 'px';

    for (var i = 0; i < ratioH; i++) {
        for (var p = 0; p < ratioW; p++) {
            var cell = document.createElement('div');
            cell.style.height = (size - 1) + 'px';
            cell.style.width = (size - 1) + 'px';
            parent.appendChild(cell);
        }
    }

    document.body.appendChild(parent);
}

createGrid(10);

It's basically a direct translation of the jQuery code. If you need even more performance you can switch to generating the boxes using strings pushed to an array:

arr.push('<div style="width:', (size - 1), 'px;height:', (size - 1), 'px;"></div>');

then at the end

parent.innerHTML = arr.join('');
Angelaangele answered 16/11, 2010 at 5:3 Comment(5)
BTW, any advice on making this more efficient? Anything in this code I can cache or replace jquery with native JS to make it run faster?Diaphysis
@Diaphysis Definitely! The whole thing can be rewritten in native JS, in fact. Also, you might want to not append elements in a loop, but instead append it to something else then outside the loop append the whole thing to the body. I can rewrite it into something more performant if you want.Angelaangele
If you have any spare cycles, I would LOVE to get the performant version. My JS skills are not quite there yet, would probably take me a couple hours to get it right.Diaphysis
@YiJang: You are a true hero.Diaphysis
Very nice! Playing around with adding a gutter. Any advice? Was also thinking of labeling in the gutter, but one step at a time. Example: jsfiddle.net/Twisty/18erqbqvSisley
S
6

I know this question has already been answered, but I've done considerable work on this exact problem for a project I was working on, so I thought I would share my findings. Rendering speed was a massive issue for me, and like @YiJiang, I started by appending nodes from inside the loop, but I found that this was not a very performant solution, so I looked into ways to optimise the algorithm.

Algorithmically speaking, nesting loops causes O(n^2) complexity, which in this case can be avoided by generating the row html once (as it is the same for each row), and then concatenating this string into each row. This results in O(n) complexity, and is by far the most efficient solution I've found.

function drawGrid(width, height) {
    var grid = '<div id="grid">',
        cell_html = '',
        i = 0, j = 0;

    for( ; i < width; i++) {
        cell_html += '<div class="cell"></div>';
    }

    for( ; j < height; j++) {
        grid += '<div class="row">' + cell_html + '</div>';
    }

    grid += '</div>';

    return grid;
}

This creates the basic HTML structure for the grid, which can then be styled appropriately using CSS.

Skerl answered 1/4, 2011 at 15:11 Comment(0)
G
5

"Pure CSS" and exactly 100px2 grid.

(A variation of the top-voted answer, above.)

body { box-sizing:border-box; margin:0; height:100%; width:100%; background-size:100px 100px;
       background-image: repeating-linear-gradient(0deg, transparent, transparent 99px, #ccc 99px, #ccc 100px), 
       repeating-linear-gradient(-90deg, transparent, transparent 99px, #ccc 99px, #ccc 100px); 
     }
Ganof answered 7/1, 2020 at 10:1 Comment(0)
S
3

Here is a solution that is an edited version of @YiJiang's answer to reduce it to O(n) complexity. The only reason I added my solution was that it is complete with css and jsfiddle sample (http://jsfiddle.net/madstop/bM5Kr/)

css:

.gridlines { display: none; position:absolute; background-color:#ccc; }

javascript/jquery:

function createGrid(size) {
var i, 
    height = $(window).height(),
    width = $(window).width(),
    ratioW = Math.floor(width/size),    
    ratioH = Math.floor(height/size); 

for (i=0; i<= ratioW; i++)  // vertical grid lines
    $('<div />').css({
            'top': 1, 
            'left': i * size, 
            'width': 1, 
            'height': height })
        .addClass('gridlines')
        .appendTo('body');

    for (i=0; i<= ratioH; i++) // horizontal grid lines
        $('<div />').css({
            'top': 1 + i * size, 
            'left': 0, 
            'width': width, 
            'height': 1 })
        .addClass('gridlines')
        .appendTo('body');

    $('.gridlines').show();
}

createGrid(50);
Suisse answered 17/4, 2014 at 16:35 Comment(0)
A
2

Three years later... @user3061127, I love you!

The other answers are great, but just using some very simple HTML and CSS yields exactly what I want. A wonderful, beautiful grid. I'd have posted a simple comment with a link to the fiddle, but I'm not cool enough yet, hence my answer instead.

Here's my take based on your original, which gives the two-layered grid look you see on professional graph paper (yes, all this is because I am too stubborn to go out and just buy some!)

If you have different sized paper, all you have to do is change the height and width of #main and you're good to go. If you want a different sized grid, all you have to do is change the background-size attributes and the dimensions in the background-image. Note that the repeating background image is finicky. The dimensions have to match up to the background-size or you'll get no repeating lines at all.

<!DOCTYPE html>
<html>
    <head>
        <style>
            html, body {
                margin: 0;
            }
            #main {
                height: 11in; /* Double this and print at 50% */
                position: relative;
                width: 8.5in; /* Double this and print at 50% */
            }
            .grid {
                background-image: repeating-linear-gradient(0deg,transparent,transparent 69px,#88F 69px,#88F 70px),
                                repeating-linear-gradient(-90deg,transparent,transparent 69px,#88F 69px,#88F 70px);
                background-size: 70px 70px;
                height: 100%;
                position: absolute;
                width: 100%;
            }
            .smallgrid {
                background-image: repeating-linear-gradient(0deg,transparent,transparent 13px,#CCF 13px,#CCF 14px),
                                repeating-linear-gradient(-90deg,transparent,transparent 13px,#CCF 13px,#CCF 14px);
                background-size: 14px 14px;
                height: 100%;
                position: absolute;
                width: 100%;
            }
        </style>
    </head>
    <body>
        <div id="main">
            <div class="smallgrid"></div>
            <div class="grid"></div>
        </div>
    </body>
</html>

The fiddle: http://jsfiddle.net/ykotfuaw/5/

Applied answered 5/7, 2018 at 14:5 Comment(1)
Note that this will only print properly when you enable the option to print background colors and images. At this time, Edge has no such option. Oddly, Chrome prints most, but not all of the lines, so it's not worthwhile either. Firefox does it right, luckily. Want finer lines? You can't create lines smaller than 1px, but you can "cheat" and double your #main dimensions and then use a shrink to fit or 50% option when printing.Applied
C
1

This is how i'd do it:

1) Make image of an L where each side of the L is the equal to one of your squares in the grid.

2) set this as bg image of your div, repeat on x and y axis

3) give your div a 1px black border on the top and right

4) you have the desired effect!

hope that helps

Edit after seeing your no images comment:

why not just use a table to make the grid (as you wont be able to do what you want without images) and overlay the table with an absolutely positioned content div?

Consolidate answered 16/11, 2010 at 4:39 Comment(3)
That sounds like reasonable solution, however using an image would make it difficult to scale this grid easily (something I forgot to mention is important in this case). Hopefully there are other approaches that come along, otherwise you win :)Diaphysis
This site is too freaking fast.Diaphysis
see edit :) also you can use JS to make sure your div overlay stays the same size as your tableConsolidate

© 2022 - 2024 — McMap. All rights reserved.