使用CSS绘制网格

34
我正在寻找一种使用CSS(和必要时JS)在div内绘制网格的方法(例如http://www.artlex.com/ArtLex/g/images/grid.gif)。感觉应该相对直接,但我还没有弄清楚。非常感谢您的建议。
提前致谢, Lenny

1
可能是重复的问题:如何只使用CSS制作网格(如图纸网格)? - Yi Jiang
在我的情况下,理想的解决方案将不涉及任何图片,因为我需要动态缩放网格,并填充各种颜色的块。我可以使用不同类型的图片来实现这一点,但那将会变得非常混乱。 - lennysan
可能是如何只使用CSS制作网格(如图纸网格)?的重复问题。 - mfluehr
7个回答

90

这里有一个简单的 CSS 纯解决方案,使用线性渐变:

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>


10
非常出色的纯CSS解决方案,避免了任何JavaScript或DOM噪音。 - Jim Morrison
2
我采用了这个绝妙的技巧,并将其制作成了一个Sass包:Artboard。该包的主要目的是公开一个Sass变量,以便轻松更改网格的大小。 - robenkleene
1
如果我想在网格中放置数字,如何使用此示例进行操作? - yongchang
优秀的答案 - java-addict301

22

这里有一个使用 jQuery 的简单解决方案。该脚本将尝试填充尽可能多的网格元素而不会溢出。函数接受一个参数,定义网格的大小。

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);
        }
    }
}

还需要一个简单的CSS样式:

.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;
}

这里有一个简单的演示:http://jsfiddle.net/yijiang/nsYyc/1/


下面是使用原生 DOM 函数的代码。我还应该更改初始比率计算来使用 DOM 函数,但我无论如何都不能让window.innerWidth返回准确的数字 已经修复了:

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);

这基本上是jQuery代码的直接翻译。如果需要更高的性能,您可以切换到使用推送到数组中的字符串来生成框:

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

最后

parent.innerHTML = arr.join('');

顺便问一下,有没有关于如何提高效率的建议?这段代码中是否有任何可以缓存或替换jquery为本地JS以使其运行更快的部分? - lennysan
@lennysan 当然!实际上,整个东西都可以用本地JS重写。此外,你可能不想在循环中附加元素,而是将其附加到其他某些元素,然后在循环之外将整个内容附加到正文中。如果你愿意,我可以将其重新编写成更高效的形式。 - Yi Jiang
如果你有任何空闲时间,我非常希望得到高效的版本。我的JS技能还不够好,可能需要我几个小时才能做到正确。 - lennysan
1
@YiJang:你是一个真正的英雄。 - lennysan
非常好!正在尝试添加间距。有什么建议吗?我还在考虑在间距中添加标签,但是一步一步来。示例:http://jsfiddle.net/Twisty/18erqbqv/ - Twisty

6
我知道这个问题已经有答案了,但是我对这个问题进行了大量的工作,因为我在一个项目中遇到了这个问题,所以我想分享一下我的发现。渲染速度对我来说是一个巨大的问题,就像@YiJiang一样,我开始通过从循环内部附加节点来解决问题,但我发现这不是一个非常高效的解决方案,所以我研究了优化算法的方法。
从算法上讲,嵌套循环会导致O(n^2)的复杂度,在这种情况下可以通过生成行HTML一次(因为每行都是相同的),然后将这个字符串连接到每行中来避免。这导致O(n)的复杂度,并且是我找到的迄今为止最有效的解决方案。
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;
}

这将创建网格的基本HTML结构,然后可以使用CSS适当地进行样式设置。

5

"纯CSS" 精确100px2网格。

(这是上面得票最高的 答案 的变种。)

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); 
     }


3
这是一个解决方案,是对@YiJiang的答案进行编辑以将其复杂度降至O(n)。我之所以添加了我的解决方案,是因为它包含完整的CSS和jsfiddle示例(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);

2
三年后… @user3061127,我爱你!
其他答案都很好,但只需使用一些非常简单的HTML和CSS就可以得到我想要的完美、美丽的网格。我本来会在评论中发布一个链接到fiddle的简单评论,但我还不够酷,因此我选择回答。
以下是基于您原始代码的我的修改,它可以给出您在专业图纸上看到的两层网格外观(是的,这全部是因为我太顽固了,不愿意去买一些!)
如果您有不同尺寸的纸张,只需更改#main的高度和宽度即可。如果您需要不同尺寸的网格,只需更改background-size属性和background-image中的尺寸即可。请注意,重复的背景图像很棘手。尺寸必须与background-size匹配,否则根本没有重复的线条。
<!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>

这是一个演示代码的网站: http://jsfiddle.net/ykotfuaw/5/


请注意,只有在启用打印背景颜色和图像选项时,此内容才能正确打印。目前,Edge没有这样的选项。奇怪的是,Chrome可以打印大部分但不是全部行,因此也不值得使用。幸运的是,Firefox可以正确地打印。想要更细的线条吗?您无法创建小于1px的线条,但是您可以“欺骗”并将#main尺寸加倍,然后在打印时使用收缩以适应或50%选项。 - John T.

1
这是我的做法:
1)制作一个L形图像,其中L的每一侧都等于网格中一个正方形的大小。
2)将其设置为div的背景图像,在x和y轴上重复。
3)在顶部和右侧给div加上1px的黑色边框。
4)你就得到了想要的效果!
希望能有所帮助。
在看到您的无图像评论后进行编辑:
为什么不使用表格来制作网格(因为没有图像,您无法实现所需的效果),并用绝对定位的内容div覆盖表格?

这听起来是个合理的解决方案,但使用图像会使得很难轻松地缩放这个网格(这在这种情况下是很重要的,我忘了提到)。希望还有其他方法出现,否则你就赢了 :) - lennysan
这个网站速度太快了。 - lennysan
请使用JS确保您的div覆盖层与表格大小相同。 - Darko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接